This pass removes conditions from conditional assignments when possible. This pass is useful for hardware that requires a lot of lowering passes that generate many CMP instructions. --- src/mesa/program/prog_optimize.c | 87 ++++++++++++++++++++++++++++++++++++++ 1 files changed, 87 insertions(+), 0 deletions(-)
diff --git a/src/mesa/program/prog_optimize.c b/src/mesa/program/prog_optimize.c index f62d890..cf579d5 100644 --- a/src/mesa/program/prog_optimize.c +++ b/src/mesa/program/prog_optimize.c @@ -1236,6 +1236,92 @@ print_it(struct gl_context *ctx, struct gl_program *program, const char *txt) { } #endif +/** + * This pass removes the condition from conditional assignments by converting + * CMP instructions to MOV instructions in the case where the CMP instruction + * is the first instruction to write to its destination register. + * + * There are two scenarios when the condition can be safely removed from a + * conditional assignment. The first is: + * int a; + * + * if (cond) + * a = foo; + * + * If 'a' is used after this when 'cond' is false, the behavior is + * undefined, and if we set 'a' to 'foo' when 'cond' is false, we haven't + * changed the behavior of the program. + * + * The second scenario is: + * int a; + * + * if (cond) + * a = foo; + * else + * a = bar; + * + * This is equivalent to these two conditional assignments: + * if (cond) a = foo; + * if (!cond) a = bar; + * + * In this case, it is safe to set 'a' to 'foo' when 'cond' is false, because + * 'a' will be overwritten with the value of 'bar' by the second conditional. + */ +static void +_mesa_simplify_cmp(struct gl_program * program) +{ + GLuint tempWrites[REG_ALLOCATE_MAX_PROGRAM_TEMPS]; + GLuint outputWrites[MAX_PROGRAM_OUTPUTS]; + GLuint i; + + if (dbg) { + printf("Optimize: Begin reads without writes\n"); + _mesa_print_program(program); + } + + for (i = 0; i < REG_ALLOCATE_MAX_PROGRAM_TEMPS; i++) { + tempWrites[i] = 0; + } + + for (i = 0; i < MAX_PROGRAM_OUTPUTS; i++) { + outputWrites[i] = 0; + } + + for (i = 0; i < program->NumInstructions; i++) { + struct prog_instruction *inst = program->Instructions + i; + GLuint prevWriteMask; + + if (_mesa_is_flow_control_opcode(inst->Opcode) || inst->DstReg.RelAddr) { + return; + } + + if (inst->DstReg.File == PROGRAM_OUTPUT) { + assert(inst->DstReg.Index < MAX_PROGRAM_OUTPUTS); + prevWriteMask = outputWrites[inst->DstReg.Index]; + outputWrites[inst->DstReg.Index] |= inst->DstReg.WriteMask; + } else if (inst->DstReg.File == PROGRAM_TEMPORARY) { + assert(inst->DstReg.Index < REG_ALLOCATE_MAX_PROGRAM_TEMPS); + prevWriteMask = tempWrites[inst->DstReg.Index]; + tempWrites[inst->DstReg.Index] |= inst->DstReg.WriteMask; + } + + /* For a CMP to be considered a conditional write, the destination + * register and source register two must be the same. */ + if (inst->Opcode == OPCODE_CMP + && !(inst->DstReg.WriteMask & prevWriteMask) + && inst->SrcReg[2].File == inst->DstReg.File + && inst->SrcReg[2].Index == inst->DstReg.Index + && inst->DstReg.WriteMask == get_src_arg_mask(inst, 2, NO_MASK)) { + + inst->Opcode = OPCODE_MOV; + inst->SrcReg[0] = inst->SrcReg[1]; + } + } + if (dbg) { + printf("Optimize: End reads without writes\n"); + _mesa_print_program(program); + } +} /** * Apply optimizations to the given program to eliminate unnecessary @@ -1246,6 +1332,7 @@ _mesa_optimize_program(struct gl_context *ctx, struct gl_program *program) { GLboolean any_change; + _mesa_simplify_cmp(program); /* Stop when no modifications were output */ do { any_change = GL_FALSE; -- 1.7.3.4 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev