src/lima/pp_lir/peephole.c
//Splits up the varying definition & moves it before each use, taking care of
//cases where it's used directly as a texture coordinate. 
Splits up the varying definition & moves it before each use, taking care of
cases where it's used directly as a texture coordinate.
Splits up the varying definition & moves it before each use taking care of cases where it ' s used directly as a texture coordinate .
static bool peephole_varying(lima_pp_lir_scheduled_instr_t* instr,
							 bool* progress)
{
	*progress = false;
	if (!instr->varying_instr || instr->varying_instr->dest.pipeline ||
		instr->varying_instr->op == lima_pp_hir_op_mov ||
		instr->varying_instr->op == lima_pp_hir_op_normalize3)
		return true;
	lima_pp_lir_reg_t* reg = instr->varying_instr->dest.reg;
	if (ptrset_size(reg->defs) > 1)
		return true;
	if (instr->texld_instr ||
		instr->uniform_instr ||
		instr->temp_store_instr ||
		instr->branch_instr)
		return true;
	unsigned i;
	for (i = 0; i < 5; i++)
		if (instr->alu_instrs[i])
			return true;
	if (lima_pp_hir_op[instr->varying_instr->op].args == 1)
	{
		return true;
	}
	if (ptrset_size(instr->succs) == 0)
		return true;
	if (ptrset_size(instr->succs) == 1)
	{
		lima_pp_lir_scheduled_instr_t* use = ptrset_first(instr->succs);
		if (!has_texload_use(use, reg) ||
			(is_proj_or_cube(use->texld_instr->op) &&
			 has_non_texload_use(use, reg)))
		{
			return true;
		}
	}
	ptrset_t unprocessed;
	if (!ptrset_copy(&unprocessed, instr->min_succs))
		return false;
	while (ptrset_size(unprocessed))
	{
		lima_pp_lir_scheduled_instr_t* use = ptrset_first(unprocessed);
		lima_pp_lir_scheduled_instr_t* other;
		ptrset_iter_t iter = ptrset_iter_create(instr->succs);
		ptrset_iter_for_each(iter, other)
		{
			if (other == use)
				continue;
			if (ptrset_contains(instr->min_succs, other))
			{
				if (lima_pp_lir_instr_combine_indep(use, other))
				{
					lima_pp_lir_block_remove(other);
					ptrset_remove(&unprocessed, other);
				}
			}
			else if (ptrset_contains(use->min_succs, other))
			{
				if (lima_pp_lir_instr_combine_after(other, use))
					lima_pp_lir_block_remove(other);
			}
		}
		ptrset_remove(&unprocessed, use);
	}
	ptrset_delete(unprocessed);
	lima_pp_lir_scheduled_instr_t* use;
	ptrset_iter_t iter = ptrset_iter_create(instr->succs);
	ptrset_iter_for_each(iter, use)
	{
		if (has_texload_use(use, reg) &&
			(!is_proj_or_cube(use->texld_instr->op) ||
			 !has_non_texload_use(use, reg)))
		{
			lima_pp_lir_instr_delete(use->varying_instr);
			use->varying_instr = copy_varying_instr(instr->varying_instr);
			if (!use->varying_instr)
				return false;
			use->varying_instr->sched_instr = use;
			if (has_non_texload_use(use, reg))
			{
				lima_pp_lir_reg_t* new_reg = lima_pp_lir_reg_create();
				if (!new_reg)
					return false;
				new_reg->index = instr->block->prog->reg_alloc++;
				new_reg->precolored = false;
				new_reg->size = reg->size;
				new_reg->beginning = true;
				if (!lima_pp_lir_prog_append_reg(instr->block->prog, new_reg))
				{
					lima_pp_lir_reg_delete(new_reg);
					return false;
				}
				use->varying_instr->dest.pipeline = false;
				use->varying_instr->dest.reg = new_reg;
				ptrset_add(&new_reg->defs, use->varying_instr);
				sched_instr_replace_uses(use, reg, new_reg);
			}
			else
			{
				use->varying_instr->dest.pipeline = true;
				use->varying_instr->dest.pipeline_reg =
					lima_pp_lir_pipeline_reg_discard;
			}
		}
		else
		{
			lima_pp_lir_instr_t* varying_instr =
				copy_varying_instr(instr->varying_instr);
			if (!varying_instr)
				return false;
			lima_pp_lir_reg_t* new_reg = lima_pp_lir_reg_create();
			if (!new_reg)
			{
				lima_pp_lir_instr_delete(varying_instr);
				return false;
			}
			new_reg->index = instr->block->prog->reg_alloc++;
			new_reg->precolored = false;
			new_reg->size = reg->size;
			new_reg->beginning = true;
			if (!lima_pp_lir_prog_append_reg(instr->block->prog, new_reg))
			{
				lima_pp_lir_reg_delete(new_reg);
				lima_pp_lir_instr_delete(varying_instr);
				return false;
			}
			varying_instr->dest.pipeline = false;
			varying_instr->dest.reg = new_reg;
			ptrset_add(&new_reg->defs, varying_instr);
			sched_instr_replace_uses(use, reg, new_reg);
			if (use->varying_instr)
			{
				lima_pp_lir_scheduled_instr_t* new_def =
					lima_pp_lir_scheduled_instr_create();
				if (!new_def)
				{
					lima_pp_lir_instr_delete(varying_instr);
					return false;
				}
				new_def->varying_instr = varying_instr;
				new_def->varying_instr->sched_instr = new_def;
				lima_pp_lir_block_insert_before(new_def, use);
				ptrset_add(&use->preds, new_def);
				ptrset_add(&new_def->succs, use);
				ptrset_add(&use->true_preds, new_def);
				ptrset_add(&new_def->true_succs, use);
				ptrset_add(&use->min_preds, new_def);
				ptrset_add(&new_def->min_succs, use);
			}
			else
			{
				use->varying_instr = varying_instr;
				use->varying_instr->sched_instr = use;
			}
		}
	}
	delete_reg(reg, instr->block->prog);
	remove_instr(instr);
	*progress = true;
	return true;
}
static bool peephole_varying ( lima_pp_lir_scheduled_instr_t * instr , bool * progress ) { * progress = false ; if ( ! instr -> varying_instr || instr -> varying_instr -> dest . pipeline || instr -> varying_instr -> op == lima_pp_hir_op_mov || instr -> varying_instr -> op == lima_pp_hir_op_normalize3 ) return true ; lima_pp_lir_reg_t * reg = instr -> varying_instr -> dest . reg ; if ( ptrset_size ( reg -> defs ) > 1 ) return true ; if ( instr -> texld_instr || instr -> uniform_instr || instr -> temp_store_instr || instr -> branch_instr ) return true ; unsigned i ; for ( i = 0 ; i < 5 ; i ++ ) if ( instr -> alu_instrs [ i ] ) return true ; if ( lima_pp_hir_op [ instr -> varying_instr -> op ] . args == 1 ) { return true ; } if ( ptrset_size ( instr -> succs ) == 0 ) return true ; if ( ptrset_size ( instr -> succs ) == 1 ) { lima_pp_lir_scheduled_instr_t * use = ptrset_first ( instr -> succs ) ; if ( ! has_texload_use ( use , reg ) || ( is_proj_or_cube ( use -> texld_instr -> op ) && has_non_texload_use ( use , reg ) ) ) { return true ; } } ptrset_t unprocessed ; if ( ! ptrset_copy ( & unprocessed , instr -> min_succs ) ) return false ; while ( ptrset_size ( unprocessed ) ) { lima_pp_lir_scheduled_instr_t * use = ptrset_first ( unprocessed ) ; lima_pp_lir_scheduled_instr_t * other ; ptrset_iter_t iter = ptrset_iter_create ( instr -> succs ) ; ptrset_iter_for_each ( iter , other ) { if ( other == use ) continue ; if ( ptrset_contains ( instr -> min_succs , other ) ) { if ( lima_pp_lir_instr_combine_indep ( use , other ) ) { lima_pp_lir_block_remove ( other ) ; ptrset_remove ( & unprocessed , other ) ; } } else if ( ptrset_contains ( use -> min_succs , other ) ) { if ( lima_pp_lir_instr_combine_after ( other , use ) ) lima_pp_lir_block_remove ( other ) ; } } ptrset_remove ( & unprocessed , use ) ; } ptrset_delete ( unprocessed ) ; lima_pp_lir_scheduled_instr_t * use ; ptrset_iter_t iter = ptrset_iter_create ( instr -> succs ) ; ptrset_iter_for_each ( iter , use ) { if ( has_texload_use ( use , reg ) && ( ! is_proj_or_cube ( use -> texld_instr -> op ) || ! has_non_texload_use ( use , reg ) ) ) { lima_pp_lir_instr_delete ( use -> varying_instr ) ; use -> varying_instr = copy_varying_instr ( instr -> varying_instr ) ; if ( ! use -> varying_instr ) return false ; use -> varying_instr -> sched_instr = use ; if ( has_non_texload_use ( use , reg ) ) { lima_pp_lir_reg_t * new_reg = lima_pp_lir_reg_create ( ) ; if ( ! new_reg ) return false ; new_reg -> index = instr -> block -> prog -> reg_alloc ++ ; new_reg -> precolored = false ; new_reg -> size = reg -> size ; new_reg -> beginning = true ; if ( ! lima_pp_lir_prog_append_reg ( instr -> block -> prog , new_reg ) ) { lima_pp_lir_reg_delete ( new_reg ) ; return false ; } use -> varying_instr -> dest . pipeline = false ; use -> varying_instr -> dest . reg = new_reg ; ptrset_add ( & new_reg -> defs , use -> varying_instr ) ; sched_instr_replace_uses ( use , reg , new_reg ) ; } else { use -> varying_instr -> dest . pipeline = true ; use -> varying_instr -> dest . pipeline_reg = lima_pp_lir_pipeline_reg_discard ; } } else { lima_pp_lir_instr_t * varying_instr = copy_varying_instr ( instr -> varying_instr ) ; if ( ! varying_instr ) return false ; lima_pp_lir_reg_t * new_reg = lima_pp_lir_reg_create ( ) ; if ( ! new_reg ) { lima_pp_lir_instr_delete ( varying_instr ) ; return false ; } new_reg -> index = instr -> block -> prog -> reg_alloc ++ ; new_reg -> precolored = false ; new_reg -> size = reg -> size ; new_reg -> beginning = true ; if ( ! lima_pp_lir_prog_append_reg ( instr -> block -> prog , new_reg ) ) { lima_pp_lir_reg_delete ( new_reg ) ; lima_pp_lir_instr_delete ( varying_instr ) ; return false ; } varying_instr -> dest . pipeline = false ; varying_instr -> dest . reg = new_reg ; ptrset_add ( & new_reg -> defs , varying_instr ) ; sched_instr_replace_uses ( use , reg , new_reg ) ; if ( use -> varying_instr ) { lima_pp_lir_scheduled_instr_t * new_def = lima_pp_lir_scheduled_instr_create ( ) ; if ( ! new_def ) { lima_pp_lir_instr_delete ( varying_instr ) ; return false ; } new_def -> varying_instr = varying_instr ; new_def -> varying_instr -> sched_instr = new_def ; lima_pp_lir_block_insert_before ( new_def , use ) ; ptrset_add ( & use -> preds , new_def ) ; ptrset_add ( & new_def -> succs , use ) ; ptrset_add ( & use -> true_preds , new_def ) ; ptrset_add ( & new_def -> true_succs , use ) ; ptrset_add ( & use -> min_preds , new_def ) ; ptrset_add ( & new_def -> min_succs , use ) ; } else { use -> varying_instr = varying_instr ; use -> varying_instr -> sched_instr = use ; } } } delete_reg ( reg , instr -> block -> prog ) ; remove_instr ( instr ) ; * progress = true ; return true ; }
Splits up the varying definition & moves it before each use, taking care of
cases where it's used directly as a texture coordinate.
Splits up the varying definition & moves it before each use taking care of cases where it ' s used directly as a texture coordinate .
//To help make sure we don't run this pass twice when unneccesary, bail out //if there are any other instructions in the scheduled instruction other //than the varying load instruction... the linear->scheduled code will //always put varying instructions by themselves, so if there's anything else //than we know this pass has been run already //Thinking about the case where there's an offset makes my brain hurt, //and apparently the binary compiler doesn't bother either so let's //just bail out... even if we bail out if the # of def's for the offset //register is > 1, then we still have to deal with the fact that the //varying instr will have a predecessor, meaning that when we move //it into the uses, we could introduce a triangle of dependencies which //would be a Bad Thing (tm) for other passes //Will this pass actually do anything? //Try to combine uses, in order to not hinder scheduling... if we push the //varying definition down to two instructions, which could be combined //together, then we could hinder scheduling down the line since the //scheduler won't be able to combine those instructions //Now, move the varying definition into each instruction in instr->succs