X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fprogram%2Fprog_optimize.c;h=7efdcadc1220edd84a9b91ad2a5348883281f11d;hb=9d9a2819ee0e862f60abf50ba239a341b664845a;hp=acf0f60eae8fc98550caaaedf43f9a0eac07823f;hpb=257cc48de2f4e472eb651a4c70042e5cb6b9fe0e;p=mesa.git diff --git a/src/mesa/program/prog_optimize.c b/src/mesa/program/prog_optimize.c index acf0f60eae8..7efdcadc122 100644 --- a/src/mesa/program/prog_optimize.c +++ b/src/mesa/program/prog_optimize.c @@ -1,6 +1,5 @@ /* * Mesa 3-D graphics library - * Version: 7.5 * * Copyright (C) 2009 VMware, Inc. All Rights Reserved. * @@ -58,55 +57,46 @@ get_src_arg_mask(const struct prog_instruction *inst, GLuint read_mask, channel_mask; GLuint comp; - ASSERT(arg < _mesa_num_inst_src_regs(inst->Opcode)); + assert(arg < _mesa_num_inst_src_regs(inst->Opcode)); /* Form the dst register, find the written channels */ - if (inst->CondUpdate) { + switch (inst->Opcode) { + case OPCODE_MOV: + case OPCODE_MIN: + case OPCODE_MAX: + case OPCODE_ABS: + case OPCODE_ADD: + case OPCODE_MAD: + case OPCODE_MUL: + case OPCODE_SUB: + case OPCODE_CMP: + case OPCODE_FLR: + case OPCODE_FRC: + case OPCODE_LRP: + case OPCODE_SGE: + case OPCODE_SLT: + case OPCODE_SSG: + channel_mask = inst->DstReg.WriteMask & dst_mask; + break; + case OPCODE_RCP: + case OPCODE_SIN: + case OPCODE_COS: + case OPCODE_RSQ: + case OPCODE_POW: + case OPCODE_EX2: + case OPCODE_LOG: + channel_mask = WRITEMASK_X; + break; + case OPCODE_DP2: + channel_mask = WRITEMASK_XY; + break; + case OPCODE_DP3: + case OPCODE_XPD: + channel_mask = WRITEMASK_XYZ; + break; + default: channel_mask = WRITEMASK_XYZW; - } - else { - switch (inst->Opcode) { - case OPCODE_MOV: - case OPCODE_MIN: - case OPCODE_MAX: - case OPCODE_ABS: - case OPCODE_ADD: - case OPCODE_MAD: - case OPCODE_MUL: - case OPCODE_SUB: - case OPCODE_CMP: - case OPCODE_FLR: - case OPCODE_FRC: - case OPCODE_LRP: - case OPCODE_SEQ: - case OPCODE_SGE: - case OPCODE_SGT: - case OPCODE_SLE: - case OPCODE_SLT: - case OPCODE_SNE: - case OPCODE_SSG: - channel_mask = inst->DstReg.WriteMask & dst_mask; - break; - case OPCODE_RCP: - case OPCODE_SIN: - case OPCODE_COS: - case OPCODE_RSQ: - case OPCODE_POW: - case OPCODE_EX2: - case OPCODE_LOG: - channel_mask = WRITEMASK_X; - break; - case OPCODE_DP2: - channel_mask = WRITEMASK_XY; - break; - case OPCODE_DP3: - case OPCODE_XPD: - channel_mask = WRITEMASK_XYZ; - break; - default: - channel_mask = WRITEMASK_XYZW; - break; - } + break; } /* Now, given the src swizzle and the written channels, find which @@ -115,7 +105,6 @@ get_src_arg_mask(const struct prog_instruction *inst, read_mask = 0x0; for (comp = 0; comp < 4; ++comp) { const GLuint coord = GET_SWZ(inst->SrcReg[arg].Swizzle, comp); - ASSERT(coord < 4); if (channel_mask & (1 << comp) && coord <= SWIZZLE_W) read_mask |= 1 << coord; } @@ -135,7 +124,7 @@ get_dst_mask_for_mov(const struct prog_instruction *mov, GLuint src_mask) GLuint comp; GLuint updated_mask = 0x0; - ASSERT(mov->Opcode == OPCODE_MOV); + assert(mov->Opcode == OPCODE_MOV); for (comp = 0; comp < 4; ++comp) { GLuint src_comp; @@ -170,13 +159,14 @@ is_swizzle_regular(GLuint swz) * \return number of instructions removed */ static GLuint -remove_instructions(struct gl_program *prog, const GLboolean *removeFlags) +remove_instructions(struct gl_program *prog, const GLboolean *removeFlags, + void *mem_ctx) { GLint i, removeEnd = 0, removeCount = 0; GLuint totalRemoved = 0; /* go backward */ - for (i = prog->NumInstructions - 1; i >= 0; i--) { + for (i = prog->arb.NumInstructions - 1; i >= 0; i--) { if (removeFlags[i]) { totalRemoved++; if (removeCount == 0) { @@ -195,7 +185,7 @@ remove_instructions(struct gl_program *prog, const GLboolean *removeFlags) */ if (removeCount > 0) { GLint removeStart = removeEnd - removeCount + 1; - _mesa_delete_instructions(prog, removeStart, removeCount); + _mesa_delete_instructions(prog, removeStart, removeCount, mem_ctx); removeStart = removeCount = 0; /* reset removal info */ } } @@ -203,7 +193,7 @@ remove_instructions(struct gl_program *prog, const GLboolean *removeFlags) /* Finish removing if the first instruction was to be removed. */ if (removeCount > 0) { GLint removeStart = removeEnd - removeCount + 1; - _mesa_delete_instructions(prog, removeStart, removeCount); + _mesa_delete_instructions(prog, removeStart, removeCount, mem_ctx); } return totalRemoved; } @@ -220,20 +210,20 @@ replace_regs(struct gl_program *prog, gl_register_file file, const GLint map[]) { GLuint i; - for (i = 0; i < prog->NumInstructions; i++) { - struct prog_instruction *inst = prog->Instructions + i; + for (i = 0; i < prog->arb.NumInstructions; i++) { + struct prog_instruction *inst = prog->arb.Instructions + i; const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); GLuint j; for (j = 0; j < numSrc; j++) { if (inst->SrcReg[j].File == file) { GLuint index = inst->SrcReg[j].Index; - ASSERT(map[index] >= 0); + assert(map[index] >= 0); inst->SrcReg[j].Index = map[index]; } } if (inst->DstReg.File == file) { const GLuint index = inst->DstReg.Index; - ASSERT(map[index] >= 0); + assert(map[index] >= 0); inst->DstReg.Index = map[index]; } } @@ -247,7 +237,7 @@ replace_regs(struct gl_program *prog, gl_register_file file, const GLint map[]) * write to such registers. Be careful with condition code setters. */ static GLboolean -_mesa_remove_dead_code_global(struct gl_program *prog) +_mesa_remove_dead_code_global(struct gl_program *prog, void *mem_ctx) { GLboolean tempRead[REG_ALLOCATE_MAX_PROGRAM_TEMPS][4]; GLboolean *removeInst; /* per-instruction removal flag */ @@ -260,12 +250,12 @@ _mesa_remove_dead_code_global(struct gl_program *prog) /*_mesa_print_program(prog);*/ } - removeInst = (GLboolean *) - calloc(1, prog->NumInstructions * sizeof(GLboolean)); + removeInst = + calloc(prog->arb.NumInstructions, sizeof(GLboolean)); /* Determine which temps are read and written */ - for (i = 0; i < prog->NumInstructions; i++) { - const struct prog_instruction *inst = prog->Instructions + i; + for (i = 0; i < prog->arb.NumInstructions; i++) { + const struct prog_instruction *inst = prog->arb.Instructions + i; const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); GLuint j; @@ -274,7 +264,7 @@ _mesa_remove_dead_code_global(struct gl_program *prog) if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) { const GLuint index = inst->SrcReg[j].Index; GLuint read_mask; - ASSERT(index < REG_ALLOCATE_MAX_PROGRAM_TEMPS); + assert(index < REG_ALLOCATE_MAX_PROGRAM_TEMPS); read_mask = get_src_arg_mask(inst, j, NO_MASK); if (inst->SrcReg[j].RelAddr) { @@ -285,42 +275,30 @@ _mesa_remove_dead_code_global(struct gl_program *prog) for (comp = 0; comp < 4; comp++) { const GLuint swz = GET_SWZ(inst->SrcReg[j].Swizzle, comp); - ASSERT(swz < 4); - if ((read_mask & (1 << swz)) == 0) - continue; - if (swz <= SWIZZLE_W) + if (swz <= SWIZZLE_W) { + if ((read_mask & (1 << swz)) == 0) + continue; tempRead[index][swz] = GL_TRUE; + } } } } /* check dst reg */ if (inst->DstReg.File == PROGRAM_TEMPORARY) { - const GLuint index = inst->DstReg.Index; - ASSERT(index < REG_ALLOCATE_MAX_PROGRAM_TEMPS); + assert(inst->DstReg.Index < REG_ALLOCATE_MAX_PROGRAM_TEMPS); if (inst->DstReg.RelAddr) { if (dbg) printf("abort remove dead code (indirect temp)\n"); goto done; } - - if (inst->CondUpdate) { - /* If we're writing to this register and setting condition - * codes we cannot remove the instruction. Prevent removal - * by setting the 'read' flag. - */ - tempRead[index][0] = GL_TRUE; - tempRead[index][1] = GL_TRUE; - tempRead[index][2] = GL_TRUE; - tempRead[index][3] = GL_TRUE; - } } } /* find instructions that write to dead registers, flag for removal */ - for (i = 0; i < prog->NumInstructions; i++) { - struct prog_instruction *inst = prog->Instructions + i; + for (i = 0; i < prog->arb.NumInstructions; i++) { + struct prog_instruction *inst = prog->arb.Instructions + i; const GLuint numDst = _mesa_num_inst_dst_regs(inst->Opcode); if (numDst != 0 && inst->DstReg.File == PROGRAM_TEMPORARY) { @@ -348,7 +326,7 @@ _mesa_remove_dead_code_global(struct gl_program *prog) } /* now remove the instructions which aren't needed */ - rem = remove_instructions(prog, removeInst); + rem = remove_instructions(prog, removeInst, mem_ctx); if (dbg) { printf("Optimize: End dead code removal.\n"); @@ -387,12 +365,11 @@ find_next_use(const struct gl_program *prog, { GLuint i; - for (i = start; i < prog->NumInstructions; i++) { - const struct prog_instruction *inst = prog->Instructions + i; + for (i = start; i < prog->arb.NumInstructions; i++) { + const struct prog_instruction *inst = prog->arb.Instructions + i; switch (inst->Opcode) { case OPCODE_BGNLOOP: case OPCODE_BGNSUB: - case OPCODE_BRA: case OPCODE_CAL: case OPCODE_CONT: case OPCODE_IF: @@ -411,7 +388,7 @@ find_next_use(const struct gl_program *prog, for (j = 0; j < numSrc; j++) { if (inst->SrcReg[j].RelAddr || (inst->SrcReg[j].File == PROGRAM_TEMPORARY && - inst->SrcReg[j].Index == index && + inst->SrcReg[j].Index == (GLint)index && (get_src_arg_mask(inst,j,NO_MASK) & mask))) return READ; } @@ -439,7 +416,6 @@ _mesa_is_flow_control_opcode(enum prog_opcode opcode) switch (opcode) { case OPCODE_BGNLOOP: case OPCODE_BGNSUB: - case OPCODE_BRA: case OPCODE_CAL: case OPCODE_CONT: case OPCODE_IF: @@ -465,15 +441,9 @@ can_downward_mov_be_modifed(const struct prog_instruction *mov) { return mov->Opcode == OPCODE_MOV && - mov->CondUpdate == GL_FALSE && mov->SrcReg[0].RelAddr == 0 && mov->SrcReg[0].Negate == 0 && - mov->SrcReg[0].Abs == 0 && - mov->SrcReg[0].HasIndex2 == 0 && - mov->SrcReg[0].RelAddr2 == 0 && - mov->DstReg.RelAddr == 0 && - mov->DstReg.CondMask == COND_TR && - mov->SaturateMode == SATURATE_OFF; + mov->DstReg.RelAddr == 0; } @@ -482,7 +452,8 @@ can_upward_mov_be_modifed(const struct prog_instruction *mov) { return can_downward_mov_be_modifed(mov) && - mov->DstReg.File == PROGRAM_TEMPORARY; + mov->DstReg.File == PROGRAM_TEMPORARY && + !mov->Saturate; } @@ -511,8 +482,8 @@ _mesa_remove_extra_move_use(struct gl_program *prog) * FOO tmpY, arg0, arg1; */ - for (i = 0; i + 1 < prog->NumInstructions; i++) { - const struct prog_instruction *mov = prog->Instructions + i; + for (i = 0; i + 1 < prog->arb.NumInstructions; i++) { + const struct prog_instruction *mov = prog->arb.Instructions + i; GLuint dst_mask, src_mask; if (can_upward_mov_be_modifed(mov) == GL_FALSE) continue; @@ -527,8 +498,8 @@ _mesa_remove_extra_move_use(struct gl_program *prog) * rewritten or we get into some flow-control, eliminating the use of * this MOV. */ - for (j = i + 1; j < prog->NumInstructions; j++) { - struct prog_instruction *inst2 = prog->Instructions + j; + for (j = i + 1; j < prog->arb.NumInstructions; j++) { + struct prog_instruction *inst2 = prog->arb.Instructions + j; GLuint arg; if (_mesa_is_flow_control_opcode(inst2->Opcode)) @@ -540,8 +511,7 @@ _mesa_remove_extra_move_use(struct gl_program *prog) if (inst2->SrcReg[arg].File != mov->DstReg.File || inst2->SrcReg[arg].Index != mov->DstReg.Index || - inst2->SrcReg[arg].RelAddr || - inst2->SrcReg[arg].Abs) + inst2->SrcReg[arg].RelAddr) continue; read_mask = get_src_arg_mask(inst2, arg, NO_MASK); @@ -599,16 +569,16 @@ _mesa_remove_extra_move_use(struct gl_program *prog) * with a proper control flow graph */ static GLboolean -_mesa_remove_dead_code_local(struct gl_program *prog) +_mesa_remove_dead_code_local(struct gl_program *prog, void *mem_ctx) { GLboolean *removeInst; GLuint i, arg, rem = 0; - removeInst = (GLboolean *) - calloc(1, prog->NumInstructions * sizeof(GLboolean)); + removeInst = + calloc(prog->arb.NumInstructions, sizeof(GLboolean)); - for (i = 0; i < prog->NumInstructions; i++) { - const struct prog_instruction *inst = prog->Instructions + i; + for (i = 0; i < prog->arb.NumInstructions; i++) { + const struct prog_instruction *inst = prog->arb.Instructions + i; const GLuint index = inst->DstReg.Index; const GLuint mask = inst->DstReg.WriteMask; enum inst_use use; @@ -631,7 +601,7 @@ _mesa_remove_dead_code_local(struct gl_program *prog) removeInst[i] = GL_TRUE; } - rem = remove_instructions(prog, removeInst); + rem = remove_instructions(prog, removeInst, mem_ctx); done: free(removeInst); @@ -657,6 +627,8 @@ _mesa_merge_mov_into_inst(struct prog_instruction *inst, if (mask != (inst->DstReg.WriteMask & mask)) return GL_FALSE; + inst->Saturate |= mov->Saturate; + /* Depending on the instruction, we may need to recompute the swizzles. * Also, some other instructions (like TEX) are not linear. We will only * consider completely active sources and destinations @@ -678,7 +650,7 @@ _mesa_merge_mov_into_inst(struct prog_instruction *inst, for (dst_comp = 0; dst_comp < 4; ++dst_comp) { if (mov->DstReg.WriteMask & (1 << dst_comp)) { const GLuint src_comp = GET_SWZ(mov->SrcReg[0].Swizzle, dst_comp); - ASSERT(src_comp < 4); + assert(src_comp < 4); dst_to_src_comp[dst_comp] = src_comp; } } @@ -694,9 +666,9 @@ _mesa_merge_mov_into_inst(struct prog_instruction *inst, if ((mov->DstReg.WriteMask & (1 << dst_comp)) == 0) continue; src_comp = dst_to_src_comp[dst_comp]; - ASSERT(src_comp < 4); + assert(src_comp < 4); arg_comp = GET_SWZ(arg_swz, src_comp); - ASSERT(arg_comp < 4); + assert(arg_comp < 4); inst->SrcReg[arg].Swizzle |= arg_comp << (3*dst_comp); } } @@ -733,7 +705,7 @@ _mesa_merge_mov_into_inst(struct prog_instruction *inst, * Try to remove extraneous MOV instructions from the given program. */ static GLboolean -_mesa_remove_extra_moves(struct gl_program *prog) +_mesa_remove_extra_moves(struct gl_program *prog, void *mem_ctx) { GLboolean *removeInst; /* per-instruction removal flag */ GLuint i, rem = 0, nesting = 0; @@ -743,8 +715,8 @@ _mesa_remove_extra_moves(struct gl_program *prog) _mesa_print_program(prog); } - removeInst = (GLboolean *) - calloc(1, prog->NumInstructions * sizeof(GLboolean)); + removeInst = + calloc(prog->arb.NumInstructions, sizeof(GLboolean)); /* * Look for sequences such as this: @@ -754,8 +726,8 @@ _mesa_remove_extra_moves(struct gl_program *prog) * FOO tmpY, arg0, arg1; */ - for (i = 0; i < prog->NumInstructions; i++) { - const struct prog_instruction *mov = prog->Instructions + i; + for (i = 0; i < prog->arb.NumInstructions; i++) { + const struct prog_instruction *mov = prog->arb.Instructions + i; switch (mov->Opcode) { case OPCODE_BGNLOOP: @@ -784,13 +756,11 @@ _mesa_remove_extra_moves(struct gl_program *prog) prevI = i - 1; while (prevI > 0 && removeInst[prevI]) prevI--; - prevInst = prog->Instructions + prevI; + prevInst = prog->arb.Instructions + prevI; if (prevInst->DstReg.File == PROGRAM_TEMPORARY && prevInst->DstReg.Index == id && - prevInst->DstReg.RelAddr == 0 && - prevInst->DstReg.CondSrc == 0 && - prevInst->DstReg.CondMask == COND_TR) { + prevInst->DstReg.RelAddr == 0) { const GLuint dst_mask = prevInst->DstReg.WriteMask; enum inst_use next_use = find_next_use(prog, i+1, id, dst_mask); @@ -821,7 +791,7 @@ _mesa_remove_extra_moves(struct gl_program *prog) } /* now remove the instructions which aren't needed */ - rem = remove_instructions(prog, removeInst); + rem = remove_instructions(prog, removeInst, mem_ctx); free(removeInst); @@ -874,7 +844,7 @@ insert_interval_by_end(struct interval_list *list, const struct interval *inv) { GLuint i; for (i = 0; i + 1 < list->Num; i++) { - ASSERT(list->Intervals[i].End <= list->Intervals[i + 1].End); + assert(list->Intervals[i].End <= list->Intervals[i + 1].End); } } #endif @@ -890,8 +860,8 @@ remove_interval(struct interval_list *list, const struct interval *inv) for (k = 0; k < list->Num; k++) { if (list->Intervals[k].Reg == inv->Reg) { /* found, remove it */ - ASSERT(list->Intervals[k].Start == inv->Start); - ASSERT(list->Intervals[k].End == inv->End); + assert(list->Intervals[k].Start == inv->Start); + assert(list->Intervals[k].End == inv->End); while (k < list->Num - 1) { list->Intervals[k] = list->Intervals[k + 1]; k++; @@ -927,7 +897,7 @@ sort_interval_list_by_start(struct interval_list *list) { GLuint i; for (i = 0; i + 1 < list->Num; i++) { - ASSERT(list->Intervals[i].Start <= list->Intervals[i + 1].Start); + assert(list->Intervals[i].Start <= list->Intervals[i + 1].Start); } } #endif @@ -947,7 +917,7 @@ update_interval(GLint intBegin[], GLint intEnd[], struct loop_info *loopStack, GLuint loopStackDepth, GLuint index, GLuint ic) { - int i; + unsigned i; GLuint begin = ic; GLuint end = ic; @@ -969,9 +939,9 @@ update_interval(GLint intBegin[], GLint intEnd[], begin = loopStack[0].Start; } - ASSERT(index < REG_ALLOCATE_MAX_PROGRAM_TEMPS); + assert(index < REG_ALLOCATE_MAX_PROGRAM_TEMPS); if (intBegin[index] == -1) { - ASSERT(intEnd[index] == -1); + assert(intEnd[index] == -1); intBegin[index] = begin; intEnd[index] = end; } @@ -1064,7 +1034,8 @@ find_live_intervals(struct gl_program *prog, } /* build intermediate arrays */ - if (!_mesa_find_temp_intervals(prog->Instructions, prog->NumInstructions, + if (!_mesa_find_temp_intervals(prog->arb.Instructions, + prog->arb.NumInstructions, intBegin, intEnd)) return GL_FALSE; @@ -1179,7 +1150,7 @@ _mesa_reallocate_registers(struct gl_program *prog) else { /* Interval 'inv' has expired */ const GLint regNew = registerMap[inv->Reg]; - ASSERT(regNew >= 0); + assert(regNew >= 0); if (dbg) printf(" expire interval for reg %u\n", inv->Reg); @@ -1191,7 +1162,7 @@ _mesa_reallocate_registers(struct gl_program *prog) /* return register regNew to the free pool */ if (dbg) printf(" free reg %d\n", regNew); - ASSERT(usedRegs[regNew] == GL_TRUE); + assert(usedRegs[regNew] == GL_TRUE); usedRegs[regNew] = GL_FALSE; } } @@ -1224,7 +1195,7 @@ _mesa_reallocate_registers(struct gl_program *prog) */ replace_regs(prog, PROGRAM_TEMPORARY, registerMap); - prog->NumTemporaries = maxTemp + 1; + prog->arb.NumTemporaries = maxTemp + 1; } if (dbg) { @@ -1239,33 +1210,125 @@ _mesa_reallocate_registers(struct gl_program *prog) #if 0 static void print_it(struct gl_context *ctx, struct gl_program *program, const char *txt) { - fprintf(stderr, "%s (%u inst):\n", txt, program->NumInstructions); + fprintf(stderr, "%s (%u inst):\n", txt, program->arb.NumInstructions); _mesa_print_program(program); _mesa_print_program_parameters(ctx, program); fprintf(stderr, "\n\n"); } #endif +/** + * This pass replaces CMP T0, T1 T2 T0 with MOV T0, T2 when the CMP + * instruction is the first instruction to write to register T0. The are + * several lowering passes done in GLSL IR (e.g. branches and + * relative addressing) that create a large number of conditional assignments + * that ir_to_mesa converts to CMP instructions like the one mentioned above. + * + * Here is why this conversion is safe: + * CMP T0, T1 T2 T0 can be expanded to: + * if (T1 < 0.0) + * MOV T0, T2; + * else + * MOV T0, T0; + * + * If (T1 < 0.0) evaluates to true then our replacement MOV T0, T2 is the same + * as the original program. If (T1 < 0.0) evaluates to false, executing + * MOV T0, T0 will store a garbage value in T0 since T0 is uninitialized. + * Therefore, it doesn't matter that we are replacing MOV T0, T0 with MOV T0, T2 + * because any instruction that was going to read from T0 after this was going + * to read a garbage value anyway. + */ +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->arb.NumInstructions; i++) { + struct prog_instruction *inst = program->arb.Instructions + i; + GLuint prevWriteMask; + + /* Give up if we encounter relative addressing or flow control. */ + 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; + } else { + /* No other register type can be a destination register. */ + continue; + } + + /* 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]; + + /* Unused operands are expected to have the file set to + * PROGRAM_UNDEFINED. This is how _mesa_init_instructions initializes + * all of the sources. + */ + inst->SrcReg[1].File = PROGRAM_UNDEFINED; + inst->SrcReg[1].Swizzle = SWIZZLE_NOOP; + inst->SrcReg[2].File = PROGRAM_UNDEFINED; + inst->SrcReg[2].Swizzle = SWIZZLE_NOOP; + } + } + if (dbg) { + printf("Optimize: End reads without writes\n"); + _mesa_print_program(program); + } +} /** * Apply optimizations to the given program to eliminate unnecessary * instructions, temp regs, etc. */ void -_mesa_optimize_program(struct gl_context *ctx, struct gl_program *program) +_mesa_optimize_program(struct gl_program *program, void *mem_ctx) { GLboolean any_change; + _mesa_simplify_cmp(program); /* Stop when no modifications were output */ do { any_change = GL_FALSE; _mesa_remove_extra_move_use(program); - if (_mesa_remove_dead_code_global(program)) + if (_mesa_remove_dead_code_global(program, mem_ctx)) any_change = GL_TRUE; - if (_mesa_remove_extra_moves(program)) + if (_mesa_remove_extra_moves(program, mem_ctx)) any_change = GL_TRUE; - if (_mesa_remove_dead_code_local(program)) + if (_mesa_remove_dead_code_local(program, mem_ctx)) any_change = GL_TRUE; + + any_change = _mesa_constant_fold(program) || any_change; _mesa_reallocate_registers(program); } while (any_change); }