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; }
/** * 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); }
/** * 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); } }
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; }