static void debug_insn( struct prog_instruction *inst, const char *fn, GLuint line ) { if (DISASSEM) { static const char *last_fn; if (fn != last_fn) { last_fn = fn; _mesa_printf("%s:\n", fn); } _mesa_printf("%d:\t", line); _mesa_print_instruction(inst); } }
/** * Emit all ready texture instructions in a single block. * * Emit as a single block to (hopefully) sample many textures in parallel, * and to avoid hardware indirections on R300. * * In R500, we don't really know when the result of a texture instruction * arrives. So allocate all destinations first, to make sure they do not * arrive early and overwrite a texture coordinate we're going to use later * in the block. */ static void emit_all_tex(struct pair_state *s) { struct pair_state_instruction *readytex; struct pair_state_instruction *pairinst; ASSERT(s->ReadyTEX); // Don't let the ready list change under us! readytex = s->ReadyTEX; s->ReadyTEX = 0; // Allocate destination hardware registers in one block to avoid conflicts. for(pairinst = readytex; pairinst; pairinst = pairinst->NextReady) { int ip = pairinst - s->Instructions; struct prog_instruction *inst = s->Program->Instructions + ip; if (inst->Opcode != OPCODE_KIL) get_hw_reg(s, inst->DstReg.File, inst->DstReg.Index); } if (s->Debug) _mesa_printf(" BEGIN_TEX\n"); if (s->Handler->BeginTexBlock) s->Error = s->Error || !s->Handler->BeginTexBlock(s->UserData); for(pairinst = readytex; pairinst; pairinst = pairinst->NextReady) { int ip = pairinst - s->Instructions; struct prog_instruction *inst = s->Program->Instructions + ip; commit_instruction(s, ip); if (inst->Opcode != OPCODE_KIL) inst->DstReg.Index = get_hw_reg(s, inst->DstReg.File, inst->DstReg.Index); inst->SrcReg[0].Index = get_hw_reg(s, inst->SrcReg[0].File, inst->SrcReg[0].Index); if (s->Debug) { _mesa_printf(" "); _mesa_print_instruction(inst); } s->Error = s->Error || !s->Handler->EmitTex(s->UserData, inst); } if (s->Debug) _mesa_printf(" END_TEX\n"); }
static void print_insns( const struct prog_instruction *insn, GLuint nr ) { GLuint i; for (i = 0; i < nr; i++, insn++) { printf("%3d: ", i); if (insn->Opcode < MAX_OPCODE) _mesa_print_instruction(insn); else if (insn->Opcode < MAX_WM_OPCODE) { GLuint idx = insn->Opcode - MAX_OPCODE; _mesa_print_alu_instruction(insn, wm_opcode_strings[idx], 3); } else printf("965 Opcode %d\n", insn->Opcode); } }
/** * 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 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);*/ } }