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

Jerome Glisse j.glisse at gmail.com
Wed Apr 6 06:59:13 PDT 2011


On Tue, Apr 5, 2011 at 2:20 AM, Tom Stellard <tstellar at gmail.com> wrote:
> 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
>

The comment isn't very accurate on what the code does (comment is
about GLSL construct not ARB shader asm one). I think a comment
explaining what pattern the code replace would be helpful. If i am not
mistaken :
CMP A, x, y, A replaced MOV A, y
when A was not previoulsy written/modified in any previous instruction.

Otherwise this look good as it bail if there is control flow stuff
(maybe adding a comment to make sure no one remove the control flow
test).

Cheers,
Jerome


More information about the mesa-dev mailing list