diff options
author | Tom Stellard <tstellar@gmail.com> | 2011-03-28 21:17:40 -0700 |
---|---|---|
committer | Tom Stellard <tstellar@gmail.com> | 2011-03-28 23:34:08 -0700 |
commit | 6cdef3a6f12c3172887d9e58d154600b909060af (patch) | |
tree | cfe3b4fa7742a6547fdecf2112255414f3cef22d | |
parent | 3b1d59f3a526748880d3528910c1499be33ef668 (diff) |
prog_optimize: Add reads without writes optimization passnew-register-allocator
This pass scans programs for instructions that read registers that have
not been written and replaces these reads with a read from a constant
register with the value of zero. This pass prevents phantom
dependencies from being introduced by the register allocator and
improves the efficiency of subsequent optimization passes.
-rw-r--r-- | src/mesa/program/prog_optimize.c | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/src/mesa/program/prog_optimize.c b/src/mesa/program/prog_optimize.c index b5f0fb31896..bc698fb5a06 100644 --- a/src/mesa/program/prog_optimize.c +++ b/src/mesa/program/prog_optimize.c @@ -30,6 +30,7 @@ #include "program.h" #include "prog_instruction.h" #include "prog_optimize.h" +#include "prog_parameter.h" #include "prog_print.h" @@ -1225,6 +1226,85 @@ print_it(struct gl_context *ctx, struct gl_program *program, const char *txt) { } #endif +/** This pass searches for registers that are read before they are written + * and replaces reads from these registers with a read from a constant + * register with the value of zero. This pass will not change the program + * if it has already been run, so it only needs to be run once per program. + * + * When CMP instructions are translated from GLSL IR to Mesa IR, usually + * source register 1 or source register 2 is set to value of the destination + * register. When the registers are reallocated by + * _mesa_reallocate_registers() there is the possibility of creating phantom + * dependencies where a source register is remapped so that it reads from a + * register that has been written by an instruction that is no longer live. + * Here is an example: + * + * 0: MUL TEMP[0], CONST[0] IN[0] + * 1: RCP TEMP[1], TEMP[0] + * 2: CMP TEMP[2], TEMP[1] CONST[0] TEMP[2] + * ... + * + * _mesa_reallocate_registers will remap registers 0->0, 1->1, 2->0 and + * the program will look like this: + * + * 0: MUL TEMP[0], CONST[0], IN[0] + * 1: RCP TEMP[1], TEMP[0] + * 2: CMP TEMP[0], TEMP[1] CONST[0] TEMP[0] + * ... + * + * This creates a phantom dependency, because instruction 2 now depends + * on the result of instruction 0 which was not the case in the original + * program. + */ +static void +_mesa_reads_without_writes(struct gl_program * program) +{ + GLfloat zeroArray[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + GLuint zeroSwizzle; + struct prog_src_register zeroReg; + GLuint regWrites[REG_ALLOCATE_MAX_PROGRAM_TEMPS]; + 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++) { + regWrites[i] = 0; + } + + memset(&zeroReg, 0, sizeof(zeroReg)); + zeroReg.File = PROGRAM_CONSTANT; + zeroReg.Index = _mesa_add_unnamed_constant(program->Parameters, zeroArray, + 1, &zeroSwizzle); + zeroReg.Swizzle = zeroSwizzle; + + for (i = 0; i < program->NumInstructions; i++) { + struct prog_instruction *inst = program->Instructions + i; + GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); + GLuint j; + for (j = 0; j < numSrc; j++) { + if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) { + const GLuint index = inst->SrcReg[j].Index; + if (!inst->SrcReg[j].RelAddr + && !(regWrites[index] & get_src_arg_mask(inst, j, NO_MASK))) { + inst->SrcReg[j] = zeroReg; + } + } + } + if (inst->DstReg.File == PROGRAM_TEMPORARY) { + if (inst->DstReg.RelAddr) { + return; + } + regWrites[inst->DstReg.Index] |= inst->DstReg.WriteMask; + } + } + if (dbg) { + printf("Optimize: End reads without writes\n"); + _mesa_print_program(program); + } +} /** * Apply optimizations to the given program to eliminate unnecessary @@ -1235,6 +1315,7 @@ _mesa_optimize_program(struct gl_context *ctx, struct gl_program *program) { GLboolean any_change; + _mesa_reads_without_writes(program); /* Stop when no modifications were output */ do { any_change = GL_FALSE; |