[Mesa-dev] [PATCH 2/2] prog_optimize: Add simplify CMP optimization pass

Tom Stellard tstellar at gmail.com
Mon Apr 4 23:20:47 PDT 2011


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



More information about the mesa-dev mailing list