static void emit_flowcontrol(struct emit_state * s, struct rc_instruction * inst) { unsigned int newip; if (s->Code->inst_end >= s->C->max_alu_insts-1) { rc_error(s->C, "emit_tex: Too many instructions"); return; } newip = ++s->Code->inst_end; /* Currently all loops use the same integer constant to intialize * the loop variables. */ if(!s->Code->int_constants[0]) { s->Code->int_constants[0] = R500_FC_INT_CONST_KR(0xff); s->Code->int_constant_count = 1; } s->Code->inst[newip].inst0 = R500_INST_TYPE_FC | R500_INST_ALU_WAIT; switch(inst->U.I.Opcode){ struct branch_info * branch; struct r500_loop_info * loop; case RC_OPCODE_BGNLOOP: memory_pool_array_reserve(&s->C->Pool, struct r500_loop_info, s->Loops, s->CurrentLoopDepth, s->LoopsReserved, 1); loop = &s->Loops[s->CurrentLoopDepth++]; memset(loop, 0, sizeof(struct r500_loop_info)); loop->BranchDepth = s->CurrentBranchDepth; loop->BgnLoop = newip; s->Code->inst[newip].inst2 = R500_FC_OP_LOOP | R500_FC_JUMP_FUNC(0x00) | R500_FC_IGNORE_UNCOVERED ; break; case RC_OPCODE_BRK: loop = &s->Loops[s->CurrentLoopDepth - 1]; memory_pool_array_reserve(&s->C->Pool, int, loop->Brks, loop->BrkCount, loop->BrkReserved, 1); loop->Brks[loop->BrkCount++] = newip; s->Code->inst[newip].inst2 = R500_FC_OP_BREAKLOOP | R500_FC_JUMP_FUNC(0xff) | R500_FC_B_OP1_DECR | R500_FC_B_POP_CNT( s->CurrentBranchDepth - loop->BranchDepth) | R500_FC_IGNORE_UNCOVERED ; break; case RC_OPCODE_CONT: loop = &s->Loops[s->CurrentLoopDepth - 1]; memory_pool_array_reserve(&s->C->Pool, int, loop->Conts, loop->ContCount, loop->ContReserved, 1); loop->Conts[loop->ContCount++] = newip; s->Code->inst[newip].inst2 = R500_FC_OP_CONTINUE | R500_FC_JUMP_FUNC(0xff) | R500_FC_B_OP1_DECR | R500_FC_B_POP_CNT( s->CurrentBranchDepth - loop->BranchDepth) | R500_FC_IGNORE_UNCOVERED ; break; case RC_OPCODE_ENDLOOP: { loop = &s->Loops[s->CurrentLoopDepth - 1]; /* Emit ENDLOOP */ s->Code->inst[newip].inst2 = R500_FC_OP_ENDLOOP | R500_FC_JUMP_FUNC(0xff) | R500_FC_JUMP_ANY | R500_FC_IGNORE_UNCOVERED ; /* The constant integer at index 0 is used by all loops. */ s->Code->inst[newip].inst3 = R500_FC_INT_ADDR(0) | R500_FC_JUMP_ADDR(loop->BgnLoop + 1) ; /* Set jump address and int constant for BGNLOOP */ s->Code->inst[loop->BgnLoop].inst3 = R500_FC_INT_ADDR(0) | R500_FC_JUMP_ADDR(newip) ; /* Set jump address for the BRK instructions. */ while(loop->BrkCount--) { s->Code->inst[loop->Brks[loop->BrkCount]].inst3 = R500_FC_JUMP_ADDR(newip + 1); } /* Set jump address for CONT instructions. */ while(loop->ContCount--) { s->Code->inst[loop->Conts[loop->ContCount]].inst3 = R500_FC_JUMP_ADDR(newip); } s->CurrentLoopDepth--; break; } case RC_OPCODE_IF: if ( s->CurrentBranchDepth >= R500_PFS_MAX_BRANCH_DEPTH_FULL) { rc_error(s->C, "Branch depth exceeds hardware limit"); return; } memory_pool_array_reserve(&s->C->Pool, struct branch_info, s->Branches, s->CurrentBranchDepth, s->BranchesReserved, 1); branch = &s->Branches[s->CurrentBranchDepth++]; branch->If = newip; branch->Else = -1; branch->Endif = -1; if (s->CurrentBranchDepth > s->MaxBranchDepth) s->MaxBranchDepth = s->CurrentBranchDepth; /* actual instruction is filled in at ENDIF time */ break; case RC_OPCODE_ELSE: if (!s->CurrentBranchDepth) { rc_error(s->C, "%s: got ELSE outside a branch", __FUNCTION__); return; } branch = &s->Branches[s->CurrentBranchDepth - 1]; branch->Else = newip; /* actual instruction is filled in at ENDIF time */ break; case RC_OPCODE_ENDIF: if (!s->CurrentBranchDepth) { rc_error(s->C, "%s: got ELSE outside a branch", __FUNCTION__); return; } branch = &s->Branches[s->CurrentBranchDepth - 1]; branch->Endif = newip; s->Code->inst[branch->Endif].inst2 = R500_FC_OP_JUMP | R500_FC_A_OP_NONE /* no address stack */ | R500_FC_JUMP_ANY /* docs says set this, but I don't understand why */ | R500_FC_B_OP0_DECR /* decrement branch counter if stay */ | R500_FC_B_OP1_NONE /* no branch counter if stay */ | R500_FC_B_POP_CNT(1) ; s->Code->inst[branch->Endif].inst3 = R500_FC_JUMP_ADDR(branch->Endif + 1); s->Code->inst[branch->If].inst2 = R500_FC_OP_JUMP | R500_FC_A_OP_NONE /* no address stack */ | R500_FC_JUMP_FUNC(0x0f) /* jump if ALU result is false */ | R500_FC_B_OP0_INCR /* increment branch counter if stay */ | R500_FC_IGNORE_UNCOVERED ; if (branch->Else >= 0) { /* increment branch counter also if jump */ s->Code->inst[branch->If].inst2 |= R500_FC_B_OP1_INCR; s->Code->inst[branch->If].inst3 = R500_FC_JUMP_ADDR(branch->Else + 1); s->Code->inst[branch->Else].inst2 = R500_FC_OP_JUMP | R500_FC_A_OP_NONE /* no address stack */ | R500_FC_B_ELSE /* all active pixels want to jump */ | R500_FC_B_OP0_NONE /* no counter op if stay */ | R500_FC_B_OP1_DECR /* decrement branch counter if jump */ | R500_FC_B_POP_CNT(1) ; s->Code->inst[branch->Else].inst3 = R500_FC_JUMP_ADDR(branch->Endif + 1); } else { /* don't touch branch counter on jump */ s->Code->inst[branch->If].inst2 |= R500_FC_B_OP1_NONE; s->Code->inst[branch->If].inst3 = R500_FC_JUMP_ADDR(branch->Endif + 1); } s->CurrentBranchDepth--; break; default: rc_error(s->C, "%s: unknown opcode %s\n", __FUNCTION__, rc_get_opcode_info(inst->U.I.Opcode)->Name); } }
static void emit_flowcontrol(struct emit_state * s, struct rc_instruction * inst) { if (s->Code->inst_end >= 511) { rc_error(s->C, "emit_tex: Too many instructions"); return; } unsigned int newip = ++s->Code->inst_end; s->Code->inst[newip].inst0 = R500_INST_TYPE_FC | R500_INST_ALU_WAIT; if (inst->U.I.Opcode == RC_OPCODE_IF) { if (s->CurrentBranchDepth >= 32) { rc_error(s->C, "Branch depth exceeds hardware limit"); return; } if (s->CurrentBranchDepth >= s->BranchesReserved) grow_branches(s); struct branch_info * branch = &s->Branches[s->CurrentBranchDepth++]; branch->If = newip; branch->Else = -1; branch->Endif = -1; if (s->CurrentBranchDepth > s->MaxBranchDepth) s->MaxBranchDepth = s->CurrentBranchDepth; /* actual instruction is filled in at ENDIF time */ } else if (inst->U.I.Opcode == RC_OPCODE_ELSE) { if (!s->CurrentBranchDepth) { rc_error(s->C, "%s: got ELSE outside a branch", __FUNCTION__); return; } struct branch_info * branch = &s->Branches[s->CurrentBranchDepth - 1]; branch->Else = newip; /* actual instruction is filled in at ENDIF time */ } else if (inst->U.I.Opcode == RC_OPCODE_ENDIF) { if (!s->CurrentBranchDepth) { rc_error(s->C, "%s: got ELSE outside a branch", __FUNCTION__); return; } struct branch_info * branch = &s->Branches[s->CurrentBranchDepth - 1]; branch->Endif = newip; s->Code->inst[branch->If].inst2 = R500_FC_OP_JUMP | R500_FC_A_OP_NONE /* no address stack */ | R500_FC_JUMP_FUNC(0x0f) /* jump if ALU result is false */ | R500_FC_B_OP0_INCR /* increment branch counter if stay */ ; if (branch->Else >= 0) { /* increment branch counter also if jump */ s->Code->inst[branch->If].inst2 |= R500_FC_B_OP1_INCR; s->Code->inst[branch->If].inst3 = R500_FC_JUMP_ADDR(branch->Else + 1); s->Code->inst[branch->Else].inst2 = R500_FC_OP_JUMP | R500_FC_A_OP_NONE /* no address stack */ | R500_FC_B_ELSE /* all active pixels want to jump */ | R500_FC_B_OP0_NONE /* no counter op if stay */ | R500_FC_B_OP1_DECR /* decrement branch counter if jump */ | R500_FC_B_POP_CNT(1) ; s->Code->inst[branch->Else].inst3 = R500_FC_JUMP_ADDR(branch->Endif + 1); } else { /* don't touch branch counter on jump */ s->Code->inst[branch->If].inst2 |= R500_FC_B_OP1_NONE; s->Code->inst[branch->If].inst3 = R500_FC_JUMP_ADDR(branch->Endif + 1); } s->Code->inst[branch->Endif].inst2 = R500_FC_OP_JUMP | R500_FC_A_OP_NONE /* no address stack */ | R500_FC_JUMP_ANY /* docs says set this, but I don't understand why */ | R500_FC_B_OP0_DECR /* decrement branch counter if stay */ | R500_FC_B_OP1_NONE /* no branch counter if stay */ | R500_FC_B_POP_CNT(1) ; s->Code->inst[branch->Endif].inst3 = R500_FC_JUMP_ADDR(branch->Endif + 1); s->CurrentBranchDepth--; } else { rc_error(s->C, "%s: unknown opcode %i\n", __FUNCTION__, inst->U.I.Opcode); } }