/** * Complements dead_code_global. Try to remove code in block of code by * carefully monitoring the swizzles. Both functions should be merged into one * with a proper control flow graph */ static GLboolean _mesa_remove_dead_code_local(struct gl_program *prog) { GLboolean *removeInst; GLuint i, arg, rem = 0; removeInst = (GLboolean *) calloc(1, prog->NumInstructions * sizeof(GLboolean)); for (i = 0; i < prog->NumInstructions; i++) { const struct prog_instruction *inst = prog->Instructions + i; const GLuint index = inst->DstReg.Index; const GLuint mask = inst->DstReg.WriteMask; enum inst_use use; /* We must deactivate the pass as soon as some indirection is used */ if (inst->DstReg.RelAddr) goto done; for (arg = 0; arg < _mesa_num_inst_src_regs(inst->Opcode); arg++) if (inst->SrcReg[arg].RelAddr) goto done; if (_mesa_is_flow_control_opcode(inst->Opcode) || _mesa_num_inst_dst_regs(inst->Opcode) == 0 || inst->DstReg.File != PROGRAM_TEMPORARY || inst->DstReg.RelAddr) continue; use = find_next_use(prog, i+1, index, mask); if (use == WRITE || use == END) removeInst[i] = GL_TRUE; } rem = remove_instructions(prog, removeInst); done: free(removeInst); return rem != 0; }
/** * Try to remove extraneous MOV instructions from the given program. */ static GLboolean _mesa_remove_extra_moves(struct gl_program *prog) { GLboolean *removeInst; /* per-instruction removal flag */ GLuint i, rem = 0, nesting = 0; if (dbg) { printf("Optimize: Begin remove extra moves\n"); _mesa_print_program(prog); } removeInst = (GLboolean *) calloc(1, prog->NumInstructions * sizeof(GLboolean)); /* * Look for sequences such as this: * FOO tmpX, arg0, arg1; * MOV tmpY, tmpX; * and convert into: * FOO tmpY, arg0, arg1; */ for (i = 0; i < prog->NumInstructions; i++) { const struct prog_instruction *mov = prog->Instructions + i; switch (mov->Opcode) { case OPCODE_BGNLOOP: case OPCODE_BGNSUB: case OPCODE_IF: nesting++; break; case OPCODE_ENDLOOP: case OPCODE_ENDSUB: case OPCODE_ENDIF: nesting--; break; case OPCODE_MOV: if (i > 0 && can_downward_mov_be_modifed(mov) && mov->SrcReg[0].File == PROGRAM_TEMPORARY && nesting == 0) { /* see if this MOV can be removed */ const GLuint id = mov->SrcReg[0].Index; struct prog_instruction *prevInst; GLuint prevI; /* get pointer to previous instruction */ prevI = i - 1; while (prevI > 0 && removeInst[prevI]) prevI--; prevInst = prog->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) { const GLuint dst_mask = prevInst->DstReg.WriteMask; enum inst_use next_use = find_next_use(prog, i+1, id, dst_mask); if (next_use == WRITE || next_use == END) { /* OK, we can safely remove this MOV instruction. * Transform: * prevI: FOO tempIndex, x, y; * i: MOV z, tempIndex; * Into: * prevI: FOO z, x, y; */ if (_mesa_merge_mov_into_inst(prevInst, mov)) { removeInst[i] = GL_TRUE; if (dbg) { printf("Remove MOV at %u\n", i); printf("new prev inst %u: ", prevI); _mesa_print_instruction(prevInst); } } } } } break; default: ; /* nothing */ } } /* now remove the instructions which aren't needed */ rem = remove_instructions(prog, removeInst); free(removeInst); if (dbg) { printf("Optimize: End remove extra moves. %u instructions removed\n", rem); /*_mesa_print_program(prog);*/ } return rem != 0; }
/** * Try to remove extraneous MOV instructions from the given program. */ static void _mesa_remove_extra_moves(struct gl_program *prog) { GLboolean *removeInst; /* per-instruction removal flag */ GLuint i, rem, loopNesting = 0, subroutineNesting = 0; if (dbg) { _mesa_printf("Optimize: Begin remove extra moves\n"); _mesa_print_program(prog); } removeInst = (GLboolean *) _mesa_calloc(prog->NumInstructions * sizeof(GLboolean)); /* * Look for sequences such as this: * FOO tmpX, arg0, arg1; * MOV tmpY, tmpX; * and convert into: * FOO tmpY, arg0, arg1; */ for (i = 0; i < prog->NumInstructions; i++) { const struct prog_instruction *inst = prog->Instructions + i; switch (inst->Opcode) { case OPCODE_BGNLOOP: loopNesting++; break; case OPCODE_ENDLOOP: loopNesting--; break; case OPCODE_BGNSUB: subroutineNesting++; break; case OPCODE_ENDSUB: subroutineNesting--; break; case OPCODE_MOV: if (i > 0 && loopNesting == 0 && subroutineNesting == 0 && inst->SrcReg[0].File == PROGRAM_TEMPORARY && inst->SrcReg[0].Swizzle == SWIZZLE_XYZW) { /* see if this MOV can be removed */ const GLuint tempIndex = inst->SrcReg[0].Index; struct prog_instruction *prevInst; GLuint prevI; /* get pointer to previous instruction */ prevI = i - 1; while (removeInst[prevI] && prevI > 0) prevI--; prevInst = prog->Instructions + prevI; if (prevInst->DstReg.File == PROGRAM_TEMPORARY && prevInst->DstReg.Index == tempIndex && prevInst->DstReg.WriteMask == WRITEMASK_XYZW) { enum temp_use next_use = find_next_temp_use(prog, i + 1, tempIndex); if (next_use == WRITE || next_use == END) { /* OK, we can safely remove this MOV instruction. * Transform: * prevI: FOO tempIndex, x, y; * i: MOV z, tempIndex; * Into: * prevI: FOO z, x, y; */ /* patch up prev inst */ prevInst->DstReg.File = inst->DstReg.File; prevInst->DstReg.Index = inst->DstReg.Index; /* flag this instruction for removal */ removeInst[i] = GL_TRUE; if (dbg) { _mesa_printf("Remove MOV at %u\n", i); _mesa_printf("new prev inst %u: ", prevI); _mesa_print_instruction(prevInst); } } } } break; default: ; /* nothing */ } } /* now remove the instructions which aren't needed */ rem = remove_instructions(prog, removeInst); if (dbg) { _mesa_printf("Optimize: End remove extra moves. %u instructions removed\n", rem); /*_mesa_print_program(prog);*/ } }
/** * Remove dead instructions from the given program. * This is very primitive for now. Basically look for temp registers * that are written to but never read. Remove any instructions that * write to such registers. Be careful with condition code setters. */ static GLboolean _mesa_remove_dead_code_global(struct gl_program *prog) { GLboolean tempRead[REG_ALLOCATE_MAX_PROGRAM_TEMPS][4]; GLboolean *removeInst; /* per-instruction removal flag */ GLuint i, rem = 0, comp; memset(tempRead, 0, sizeof(tempRead)); if (dbg) { printf("Optimize: Begin dead code removal\n"); /*_mesa_print_program(prog);*/ } removeInst = (GLboolean *) calloc(1, prog->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; const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); GLuint j; /* check src regs */ for (j = 0; j < numSrc; j++) { if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) { const GLuint index = inst->SrcReg[j].Index; GLuint read_mask; ASSERT(index < REG_ALLOCATE_MAX_PROGRAM_TEMPS); read_mask = get_src_arg_mask(inst, j, NO_MASK); if (inst->SrcReg[j].RelAddr) { if (dbg) printf("abort remove dead code (indirect temp)\n"); goto done; } 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) 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); 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; const GLuint numDst = _mesa_num_inst_dst_regs(inst->Opcode); if (numDst != 0 && inst->DstReg.File == PROGRAM_TEMPORARY) { GLint chan, index = inst->DstReg.Index; for (chan = 0; chan < 4; chan++) { if (!tempRead[index][chan] && inst->DstReg.WriteMask & (1 << chan)) { if (dbg) { printf("Remove writemask on %u.%c\n", i, chan == 3 ? 'w' : 'x' + chan); } inst->DstReg.WriteMask &= ~(1 << chan); rem++; } } if (inst->DstReg.WriteMask == 0) { /* If we cleared all writes, the instruction can be removed. */ if (dbg) printf("Remove instruction %u: \n", i); removeInst[i] = GL_TRUE; } } } /* now remove the instructions which aren't needed */ rem = remove_instructions(prog, removeInst); if (dbg) { printf("Optimize: End dead code removal.\n"); printf(" %u channel writes removed\n", rem); printf(" %u instructions removed\n", rem); /*_mesa_print_program(prog);*/ } done: free(removeInst); return rem != 0; }
/** * Remove dead instructions from the given program. * This is very primitive for now. Basically look for temp registers * that are written to but never read. Remove any instructions that * write to such registers. Be careful with condition code setters. */ static void _mesa_remove_dead_code(struct gl_program *prog) { GLboolean tempWritten[MAX_PROGRAM_TEMPS], tempRead[MAX_PROGRAM_TEMPS]; GLboolean *removeInst; /* per-instruction removal flag */ GLuint i, rem; memset(tempWritten, 0, sizeof(tempWritten)); memset(tempRead, 0, sizeof(tempRead)); if (dbg) { _mesa_printf("Optimize: Begin dead code removal\n"); /*_mesa_print_program(prog);*/ } removeInst = (GLboolean *) _mesa_calloc(prog->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; const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); GLuint j; /* check src regs */ for (j = 0; j < numSrc; j++) { if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) { const GLuint index = inst->SrcReg[j].Index; ASSERT(index < MAX_PROGRAM_TEMPS); if (inst->SrcReg[j].RelAddr) { if (dbg) _mesa_printf("abort remove dead code (indirect temp)\n"); return; } tempRead[index] = GL_TRUE; } } /* check dst reg */ if (inst->DstReg.File == PROGRAM_TEMPORARY) { const GLuint index = inst->DstReg.Index; ASSERT(index < MAX_PROGRAM_TEMPS); if (inst->DstReg.RelAddr) { if (dbg) _mesa_printf("abort remove dead code (indirect temp)\n"); return; } tempWritten[index] = GL_TRUE; 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] = GL_TRUE; } } } if (dbg) { for (i = 0; i < MAX_PROGRAM_TEMPS; i++) { if (tempWritten[i] && !tempRead[i]) _mesa_printf("Remove writes to tmp %u\n", i); } } /* find instructions that write to dead registers, flag for removal */ for (i = 0; i < prog->NumInstructions; i++) { const struct prog_instruction *inst = prog->Instructions + i; if (inst->DstReg.File == PROGRAM_TEMPORARY) { GLint index = inst->DstReg.Index; removeInst[i] = (tempWritten[index] && !tempRead[index]); if (dbg && removeInst[i]) { _mesa_printf("Remove inst %u: ", i); _mesa_print_instruction(inst); } } } /* now remove the instructions which aren't needed */ rem = remove_instructions(prog, removeInst); _mesa_free(removeInst); if (dbg) { _mesa_printf("Optimize: End dead code removal. %u instructions removed\n", rem); /*_mesa_print_program(prog);*/ } }