| |
| #include "radeon_compiler.h" |
| #include "radeon_compiler_util.h" |
| #include "radeon_dataflow.h" |
| #include "radeon_program.h" |
| #include "radeon_program_constants.h" |
| |
| struct vert_fc_state { |
| struct radeon_compiler *C; |
| unsigned BranchDepth; |
| unsigned LoopDepth; |
| unsigned LoopsReserved; |
| int PredStack[R500_PVS_MAX_LOOP_DEPTH]; |
| int PredicateReg; |
| unsigned InCFBreak; |
| }; |
| |
| static void build_pred_src( |
| struct rc_src_register * src, |
| struct vert_fc_state * fc_state) |
| { |
| src->Swizzle = RC_MAKE_SWIZZLE(RC_SWIZZLE_UNUSED, RC_SWIZZLE_UNUSED, |
| RC_SWIZZLE_UNUSED, RC_SWIZZLE_W); |
| src->File = RC_FILE_TEMPORARY; |
| src->Index = fc_state->PredicateReg; |
| } |
| |
| static void build_pred_dst( |
| struct rc_dst_register * dst, |
| struct vert_fc_state * fc_state) |
| { |
| dst->WriteMask = RC_MASK_W; |
| dst->File = RC_FILE_TEMPORARY; |
| dst->Index = fc_state->PredicateReg; |
| } |
| |
| static void mark_write(void * userdata, struct rc_instruction * inst, |
| rc_register_file file, unsigned int index, unsigned int mask) |
| { |
| unsigned int * writemasks = userdata; |
| |
| if (file != RC_FILE_TEMPORARY) |
| return; |
| |
| if (index >= R300_VS_MAX_TEMPS) |
| return; |
| |
| writemasks[index] |= mask; |
| } |
| |
| static int reserve_predicate_reg(struct vert_fc_state * fc_state) |
| { |
| int i; |
| unsigned int writemasks[RC_REGISTER_MAX_INDEX]; |
| struct rc_instruction * inst; |
| memset(writemasks, 0, sizeof(writemasks)); |
| for(inst = fc_state->C->Program.Instructions.Next; |
| inst != &fc_state->C->Program.Instructions; |
| inst = inst->Next) { |
| rc_for_all_writes_mask(inst, mark_write, writemasks); |
| } |
| |
| for(i = 0; i < fc_state->C->max_temp_regs; i++) { |
| /* Most of the control flow instructions only write the |
| * W component of the Predicate Register, but |
| * the docs say that ME_PRED_SET_CLR and |
| * ME_PRED_SET_RESTORE write all components of the |
| * register, so we must reserve a register that has |
| * all its components free. */ |
| if (!writemasks[i]) { |
| fc_state->PredicateReg = i; |
| break; |
| } |
| } |
| if (i == fc_state->C->max_temp_regs) { |
| rc_error(fc_state->C, "No free temporary to use for" |
| " predicate stack counter.\n"); |
| return -1; |
| } |
| return 1; |
| } |
| |
| static void lower_bgnloop( |
| struct rc_instruction * inst, |
| struct vert_fc_state * fc_state) |
| { |
| struct rc_instruction * new_inst = |
| rc_insert_new_instruction(fc_state->C, inst->Prev); |
| |
| if ((!fc_state->C->is_r500 |
| && fc_state->LoopsReserved >= R300_VS_MAX_LOOP_DEPTH) |
| || fc_state->LoopsReserved >= R500_PVS_MAX_LOOP_DEPTH) { |
| rc_error(fc_state->C, "Loops are nested too deep."); |
| return; |
| } |
| |
| if (fc_state->LoopDepth == 0 && fc_state->BranchDepth == 0) { |
| if (fc_state->PredicateReg == -1) { |
| if (reserve_predicate_reg(fc_state) == -1) { |
| return; |
| } |
| } |
| |
| /* Initialize the predicate bit to true. */ |
| new_inst->U.I.Opcode = RC_ME_PRED_SEQ; |
| build_pred_dst(&new_inst->U.I.DstReg, fc_state); |
| new_inst->U.I.SrcReg[0].Index = 0; |
| new_inst->U.I.SrcReg[0].File = RC_FILE_NONE; |
| new_inst->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_0000; |
| } else { |
| fc_state->PredStack[fc_state->LoopDepth] = |
| fc_state->PredicateReg; |
| /* Copy the the current predicate value to this loop's |
| * predicate register */ |
| |
| /* Use the old predicate value for src0 */ |
| build_pred_src(&new_inst->U.I.SrcReg[0], fc_state); |
| |
| /* Reserve this loop's predicate register */ |
| if (reserve_predicate_reg(fc_state) == -1) { |
| return; |
| } |
| |
| /* Copy the old predicate value to the new register */ |
| new_inst->U.I.Opcode = RC_OPCODE_ADD; |
| build_pred_dst(&new_inst->U.I.DstReg, fc_state); |
| new_inst->U.I.SrcReg[1].Index = 0; |
| new_inst->U.I.SrcReg[1].File = RC_FILE_NONE; |
| new_inst->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_0000; |
| } |
| |
| } |
| |
| static void lower_brk( |
| struct rc_instruction * inst, |
| struct vert_fc_state * fc_state) |
| { |
| if (fc_state->LoopDepth == 1) { |
| inst->U.I.Opcode = RC_OPCODE_RCP; |
| inst->U.I.DstReg.Pred = RC_PRED_INV; |
| inst->U.I.SrcReg[0].Index = 0; |
| inst->U.I.SrcReg[0].File = RC_FILE_NONE; |
| inst->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_0000; |
| } else { |
| inst->U.I.Opcode = RC_ME_PRED_SET_CLR; |
| inst->U.I.DstReg.Pred = RC_PRED_SET; |
| } |
| |
| build_pred_dst(&inst->U.I.DstReg, fc_state); |
| } |
| |
| static void lower_endloop( |
| struct rc_instruction * inst, |
| struct vert_fc_state * fc_state) |
| { |
| struct rc_instruction * new_inst = |
| rc_insert_new_instruction(fc_state->C, inst); |
| |
| new_inst->U.I.Opcode = RC_ME_PRED_SET_RESTORE; |
| build_pred_dst(&new_inst->U.I.DstReg, fc_state); |
| /* Restore the previous predicate register. */ |
| fc_state->PredicateReg = fc_state->PredStack[fc_state->LoopDepth - 1]; |
| build_pred_src(&new_inst->U.I.SrcReg[0], fc_state); |
| } |
| |
| static void lower_if( |
| struct rc_instruction * inst, |
| struct vert_fc_state * fc_state) |
| { |
| /* Reserve a temporary to use as our predicate stack counter, if we |
| * don't already have one. */ |
| if (fc_state->PredicateReg == -1) { |
| /* If we are inside a loop, the Predicate Register should |
| * have already been defined. */ |
| assert(fc_state->LoopDepth == 0); |
| |
| if (reserve_predicate_reg(fc_state) == -1) { |
| return; |
| } |
| } |
| |
| if (inst->Next->U.I.Opcode == RC_OPCODE_BRK) { |
| fc_state->InCFBreak = 1; |
| } |
| if ((fc_state->BranchDepth == 0 && fc_state->LoopDepth == 0) |
| || (fc_state->LoopDepth == 1 && fc_state->InCFBreak)) { |
| if (fc_state->InCFBreak) { |
| inst->U.I.Opcode = RC_ME_PRED_SEQ; |
| inst->U.I.DstReg.Pred = RC_PRED_SET; |
| } else { |
| inst->U.I.Opcode = RC_ME_PRED_SNEQ; |
| } |
| } else { |
| unsigned swz; |
| inst->U.I.Opcode = RC_VE_PRED_SNEQ_PUSH; |
| memcpy(&inst->U.I.SrcReg[1], &inst->U.I.SrcReg[0], |
| sizeof(inst->U.I.SrcReg[1])); |
| swz = rc_get_scalar_src_swz(inst->U.I.SrcReg[1].Swizzle); |
| /* VE_PRED_SNEQ_PUSH needs to the branch condition to be in the |
| * w component */ |
| inst->U.I.SrcReg[1].Swizzle = RC_MAKE_SWIZZLE(RC_SWIZZLE_UNUSED, |
| RC_SWIZZLE_UNUSED, RC_SWIZZLE_UNUSED, swz); |
| build_pred_src(&inst->U.I.SrcReg[0], fc_state); |
| } |
| build_pred_dst(&inst->U.I.DstReg, fc_state); |
| } |
| |
| void rc_vert_fc(struct radeon_compiler *c, void *user) |
| { |
| struct rc_instruction * inst; |
| struct vert_fc_state fc_state; |
| |
| memset(&fc_state, 0, sizeof(fc_state)); |
| fc_state.PredicateReg = -1; |
| fc_state.C = c; |
| |
| for(inst = c->Program.Instructions.Next; |
| inst != &c->Program.Instructions; |
| inst = inst->Next) { |
| |
| switch (inst->U.I.Opcode) { |
| |
| case RC_OPCODE_BGNLOOP: |
| lower_bgnloop(inst, &fc_state); |
| fc_state.LoopDepth++; |
| break; |
| |
| case RC_OPCODE_BRK: |
| lower_brk(inst, &fc_state); |
| break; |
| |
| case RC_OPCODE_ENDLOOP: |
| if (fc_state.BranchDepth != 0 |
| || fc_state.LoopDepth != 1) { |
| lower_endloop(inst, &fc_state); |
| } |
| fc_state.LoopDepth--; |
| /* Skip PRED_RESTORE */ |
| inst = inst->Next; |
| break; |
| case RC_OPCODE_IF: |
| lower_if(inst, &fc_state); |
| fc_state.BranchDepth++; |
| break; |
| |
| case RC_OPCODE_ELSE: |
| inst->U.I.Opcode = RC_ME_PRED_SET_INV; |
| build_pred_dst(&inst->U.I.DstReg, &fc_state); |
| build_pred_src(&inst->U.I.SrcReg[0], &fc_state); |
| break; |
| |
| case RC_OPCODE_ENDIF: |
| if (fc_state.LoopDepth == 1 && fc_state.InCFBreak) { |
| struct rc_instruction * to_delete = inst; |
| inst = inst->Prev; |
| rc_remove_instruction(to_delete); |
| /* XXX: Delete the endif instruction */ |
| } else { |
| inst->U.I.Opcode = RC_ME_PRED_SET_POP; |
| build_pred_dst(&inst->U.I.DstReg, &fc_state); |
| build_pred_src(&inst->U.I.SrcReg[0], &fc_state); |
| } |
| fc_state.InCFBreak = 0; |
| fc_state.BranchDepth--; |
| break; |
| |
| default: |
| if (fc_state.BranchDepth || fc_state.LoopDepth) { |
| inst->U.I.DstReg.Pred = RC_PRED_SET; |
| } |
| break; |
| } |
| |
| if (c->Error) { |
| return; |
| } |
| } |
| } |