Ejemplo n.º 1
0
static void ei_if(struct r300_vertex_program_compiler * compiler,
					struct rc_instruction *rci,
					unsigned int * inst,
					unsigned int branch_depth)
{
	unsigned int predicate_opcode;
	int is_math = 0;

	if (!compiler->Base.is_r500) {
		rc_error(&compiler->Base,"Opcode IF not supported\n");
		return;
	}

	/* Reserve a temporary to use as our predicate stack counter, if we
	 * don't already have one. */
	if (!compiler->PredicateMask) {
		unsigned int writemasks[RC_REGISTER_MAX_INDEX];
		struct rc_instruction * inst;
		unsigned int i;
		memset(writemasks, 0, sizeof(writemasks));
		for(inst = compiler->Base.Program.Instructions.Next;
				inst != &compiler->Base.Program.Instructions;
							inst = inst->Next) {
			rc_for_all_writes_mask(inst, mark_write, writemasks);
		}
		for(i = 0; i < compiler->Base.max_temp_regs; i++) {
			unsigned int mask = ~writemasks[i] & RC_MASK_XYZW;
			/* Only the W component can be used fo the predicate
			 * stack counter. */
			if (mask & RC_MASK_W) {
				compiler->PredicateMask = RC_MASK_W;
				compiler->PredicateIndex = i;
				break;
			}
		}
		if (i == compiler->Base.max_temp_regs) {
			rc_error(&compiler->Base, "No free temporary to use for"
					" predicate stack counter.\n");
			return;
		}
	}
	predicate_opcode =
			branch_depth ? VE_PRED_SET_NEQ_PUSH : ME_PRED_SET_NEQ;

	rci->U.I.SrcReg[0].Swizzle = RC_MAKE_SWIZZLE_SMEAR(GET_SWZ(rci->U.I.SrcReg[0].Swizzle,0));
	if (branch_depth == 0) {
		is_math = 1;
		predicate_opcode = ME_PRED_SET_NEQ;
		inst[1] = t_src(compiler->code, &rci->U.I.SrcReg[0]);
		inst[2] = 0;
	} else {
		predicate_opcode = VE_PRED_SET_NEQ_PUSH;
		inst[1] = t_pred_src(compiler);
		inst[2] = t_src(compiler->code, &rci->U.I.SrcReg[0]);
	}

	inst[0] = t_pred_dst(compiler, predicate_opcode, is_math);
	inst[3] = 0;

}
Ejemplo n.º 2
0
/**
 * Calls a callback function for all written register channels.
 *
 * \warning Does not report output registers for paired instructions!
 */
void rc_for_all_writes_chan(struct rc_instruction * inst, rc_read_write_chan_fn cb, void * userdata)
{
	struct mask_to_chan_data d;
	d.UserData = userdata;
	d.Fn = cb;
	rc_for_all_writes_mask(inst, &mask_to_chan_cb, &d);
}
Ejemplo n.º 3
0
/**
 * This function fills in the parameter 'used' with a writemask that
 * represent which components of each temporary register are used by the
 * program.  This is meant to be combined with rc_find_free_temporary_list as a
 * more efficient version of rc_find_free_temporary.
 * @param used The function does not initialize this parameter.
 */
void rc_get_used_temporaries(
	struct radeon_compiler * c,
	unsigned char * used,
	unsigned int used_length)
{
	struct rc_instruction * inst;
	struct get_used_temporaries_data d;
	d.Used = used;
	d.UsedLength = used_length;

	for(inst = c->Program.Instructions.Next;
			inst != &c->Program.Instructions; inst = inst->Next) {

		rc_for_all_reads_mask(inst, get_used_temporaries_cb, &d);
		rc_for_all_writes_mask(inst, get_used_temporaries_cb, &d);
	}
}
Ejemplo n.º 4
0
static void compute_live_intervals(struct radeon_compiler *c,
				   struct regalloc_state *s)
{
	memset(s, 0, sizeof(*s));
	s->C = c;
	s->NumHwTemporaries = c->max_temp_regs;
	s->HwTemporary =
		memory_pool_malloc(&c->Pool,
				   s->NumHwTemporaries * sizeof(struct hardware_register));
	memset(s->HwTemporary, 0, s->NumHwTemporaries * sizeof(struct hardware_register));

	rc_recompute_ips(s->C);

	for(struct rc_instruction * inst = s->C->Program.Instructions.Next;
	    inst != &s->C->Program.Instructions;
	    inst = inst->Next) {

		/* For all instructions inside of a loop, the ENDLOOP
		 * instruction is used as the end of the live interval. */
		if (inst->U.I.Opcode == RC_OPCODE_BGNLOOP && !s->end_loop) {
			int loops = 1;
			struct rc_instruction * tmp;
			for(tmp = inst->Next;
					tmp != &s->C->Program.Instructions;
					tmp = tmp->Next) {
				if (tmp->U.I.Opcode == RC_OPCODE_BGNLOOP) {
					loops++;
				} else if (tmp->U.I.Opcode
							== RC_OPCODE_ENDLOOP) {
					if(!--loops) {
						s->end_loop = tmp->IP;
						break;
					}
				}
			}
		}

		if (inst->IP == s->end_loop)
			s->end_loop = 0;

		rc_for_all_reads_mask(inst, scan_callback, s);
		rc_for_all_writes_mask(inst, scan_callback, s);
	}
}
/**
 * If c->max_alu_inst is -1, then all eligible loops will be unrolled regardless
 * of how many iterations they have.
 */
static int try_unroll_loop(struct radeon_compiler * c, struct loop_info * loop)
{
	int end_loops;
	int iterations;
	struct count_inst count_inst;
	float limit_value;
	struct rc_src_register * counter;
	struct rc_src_register * limit;
	struct const_value counter_value;
	struct rc_instruction * inst;

	/* Find the counter and the upper limit */

	if(rc_src_reg_is_immediate(c, loop->Cond->U.I.SrcReg[0].File,
					loop->Cond->U.I.SrcReg[0].Index)){
		limit = &loop->Cond->U.I.SrcReg[0];
		counter = &loop->Cond->U.I.SrcReg[1];
	}
	else if(rc_src_reg_is_immediate(c, loop->Cond->U.I.SrcReg[1].File,
					loop->Cond->U.I.SrcReg[1].Index)){
		limit = &loop->Cond->U.I.SrcReg[1];
		counter = &loop->Cond->U.I.SrcReg[0];
	}
	else{
		DBG("No constant limit.\n");
		return 0;
	}

	/* Find the initial value of the counter */
	counter_value.Src = counter;
	counter_value.Value = 0.0f;
	counter_value.HasValue = 0;
	counter_value.C = c;
	for(inst = c->Program.Instructions.Next; inst != loop->BeginLoop;
							inst = inst->Next){
		rc_for_all_writes_mask(inst, update_const_value, &counter_value);
	}
	if(!counter_value.HasValue){
		DBG("Initial counter value cannot be determined.\n");
		return 0;
	}
	DBG("Initial counter value is %f\n", counter_value.Value);
	/* Determine how the counter is modified each loop */
	count_inst.C = c;
	count_inst.Index = counter->Index;
	count_inst.Swz = counter->Swizzle;
	count_inst.Amount = 0.0f;
	count_inst.Unknown = 0;
	count_inst.BranchDepth = 0;
	end_loops = 1;
	for(inst = loop->BeginLoop->Next; end_loops > 0; inst = inst->Next){
		switch(inst->U.I.Opcode){
		/* XXX In the future we might want to try to unroll nested
		 * loops here.*/
		case RC_OPCODE_BGNLOOP:
			end_loops++;
			break;
		case RC_OPCODE_ENDLOOP:
			loop->EndLoop = inst;
			end_loops--;
			break;
		case RC_OPCODE_BRK:
			/* Don't unroll loops if it has a BRK instruction
			 * other one used when testing the main conditional
			 * of the loop. */

			/* Make sure we haven't entered a nested loops. */
			if(inst != loop->Brk && end_loops == 1) {
				return 0;
			}
			break;
		case RC_OPCODE_IF:
			count_inst.BranchDepth++;
			break;
		case RC_OPCODE_ENDIF:
			count_inst.BranchDepth--;
			break;
		default:
			rc_for_all_writes_mask(inst, get_incr_amount, &count_inst);
			if(count_inst.Unknown){
				return 0;
			}
			break;
		}
	}
	/* Infinite loop */
	if(count_inst.Amount == 0.0f){
		return 0;
	}
	DBG("Counter is increased by %f each iteration.\n", count_inst.Amount);
	/* Calculate the number of iterations of this loop.  Keeping this
	 * simple, since we only support increment and decrement loops.
	 */
	limit_value = rc_get_constant_value(c, limit->Index, limit->Swizzle,
							limit->Negate, 0);
	DBG("Limit is %f.\n", limit_value);
	/* The iteration calculations are opposite of what you would expect.
	 * In a normal loop, if the condition is met, then loop continues, but
	 * with our loops, if the condition is met, the is exited. */
	switch(loop->Cond->U.I.Opcode){
	case RC_OPCODE_SGE:
	case RC_OPCODE_SLE:
		iterations = (int) ceilf((limit_value - counter_value.Value) /
							count_inst.Amount);
		break;

	case RC_OPCODE_SGT:
	case RC_OPCODE_SLT:
		iterations = (int) floorf((limit_value - counter_value.Value) /
							count_inst.Amount) + 1;
		break;
	default:
		return 0;
	}

	if (c->max_alu_insts > 0
		&& iterations > loop_max_possible_iterations(c, loop)) {
		return 0;
	}

	DBG("Loop will have %d iterations.\n", iterations);

	/* Prepare loop for unrolling */
	rc_remove_instruction(loop->Cond);
	rc_remove_instruction(loop->If);
	rc_remove_instruction(loop->Brk);
	rc_remove_instruction(loop->EndIf);

	unroll_loop(c, loop, iterations);
	loop->EndLoop = NULL;
	return 1;
}