mesa: Improve the eliminate-move-use to work across multiple instructions.
This shaves more instructions off of the VS of my GL demo, but no performance difference this time at n=6. This also fixes a regression that was in this path, which is now piglit's glsl-vs-mov-after-deref.
This commit is contained in:
@@ -65,6 +65,7 @@ get_src_arg_mask(const struct prog_instruction *inst, int arg)
|
||||
case OPCODE_DP2:
|
||||
return WRITEMASK_XY;
|
||||
case OPCODE_DP3:
|
||||
case OPCODE_XPD:
|
||||
return WRITEMASK_XYZ;
|
||||
default:
|
||||
return WRITEMASK_XYZW;
|
||||
@@ -396,6 +397,26 @@ find_next_temp_use(const struct gl_program *prog, GLuint start, GLuint index)
|
||||
return END;
|
||||
}
|
||||
|
||||
static GLboolean _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:
|
||||
case OPCODE_ELSE:
|
||||
case OPCODE_END:
|
||||
case OPCODE_ENDIF:
|
||||
case OPCODE_ENDLOOP:
|
||||
case OPCODE_ENDSUB:
|
||||
case OPCODE_RET:
|
||||
return GL_TRUE;
|
||||
default:
|
||||
return GL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to remove use of extraneous MOV instructions, to free them up for dead
|
||||
@@ -404,7 +425,7 @@ find_next_temp_use(const struct gl_program *prog, GLuint start, GLuint index)
|
||||
static void
|
||||
_mesa_remove_extra_move_use(struct gl_program *prog)
|
||||
{
|
||||
GLuint i;
|
||||
GLuint i, j;
|
||||
|
||||
if (dbg) {
|
||||
_mesa_printf("Optimize: Begin remove extra move use\n");
|
||||
@@ -414,63 +435,86 @@ _mesa_remove_extra_move_use(struct gl_program *prog)
|
||||
/*
|
||||
* Look for sequences such as this:
|
||||
* MOV tmpX, arg0;
|
||||
* ...
|
||||
* FOO tmpY, tmpX, arg1;
|
||||
* and convert into:
|
||||
* MOV tmpX, arg0;
|
||||
* ...
|
||||
* FOO tmpY, arg0, arg1;
|
||||
*/
|
||||
|
||||
for (i = 0; i < prog->NumInstructions - 1; i++) {
|
||||
const struct prog_instruction *mov = prog->Instructions + i;
|
||||
struct prog_instruction *inst2 = prog->Instructions + i + 1;
|
||||
int arg;
|
||||
|
||||
if (mov->Opcode != OPCODE_MOV ||
|
||||
mov->DstReg.File != PROGRAM_TEMPORARY ||
|
||||
mov->DstReg.RelAddr ||
|
||||
mov->DstReg.CondMask != COND_TR ||
|
||||
mov->SaturateMode != SATURATE_OFF)
|
||||
mov->SaturateMode != SATURATE_OFF ||
|
||||
mov->SrcReg[0].RelAddr)
|
||||
continue;
|
||||
|
||||
for (arg = 0; arg < _mesa_num_inst_src_regs(inst2->Opcode); arg++) {
|
||||
int comp;
|
||||
int read_mask = get_src_arg_mask(inst2, arg);
|
||||
/* Walk through remaining instructions until the or src reg gets
|
||||
* 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;
|
||||
int arg;
|
||||
|
||||
if (inst2->SrcReg[arg].File != mov->DstReg.File ||
|
||||
inst2->SrcReg[arg].Index != mov->DstReg.Index ||
|
||||
inst2->SrcReg[arg].RelAddr ||
|
||||
inst2->SrcReg[arg].Abs)
|
||||
continue;
|
||||
if (_mesa_is_flow_control_opcode(inst2->Opcode))
|
||||
break;
|
||||
|
||||
/* Check that all the sources for this arg of inst2 come from inst1
|
||||
* or constants.
|
||||
*/
|
||||
for (comp = 0; comp < 4; comp++) {
|
||||
int src_swz = GET_SWZ(inst2->SrcReg[arg].Swizzle, comp);
|
||||
/* First rewrite this instruction's args if appropriate. */
|
||||
for (arg = 0; arg < _mesa_num_inst_src_regs(inst2->Opcode); arg++) {
|
||||
int comp;
|
||||
int read_mask = get_src_arg_mask(inst2, arg);
|
||||
|
||||
/* If the MOV didn't write that channel, can't use it. */
|
||||
if ((read_mask & (1 << comp)) &&
|
||||
src_swz <= SWIZZLE_W &&
|
||||
(mov->DstReg.WriteMask & (1 << src_swz)) == 0)
|
||||
break;
|
||||
}
|
||||
if (comp != 4)
|
||||
continue;
|
||||
if (inst2->SrcReg[arg].File != mov->DstReg.File ||
|
||||
inst2->SrcReg[arg].Index != mov->DstReg.Index ||
|
||||
inst2->SrcReg[arg].RelAddr ||
|
||||
inst2->SrcReg[arg].Abs)
|
||||
continue;
|
||||
|
||||
/* Adjust the swizzles of inst2 to point at MOV's source */
|
||||
for (comp = 0; comp < 4; comp++) {
|
||||
int inst2_swz = GET_SWZ(inst2->SrcReg[arg].Swizzle, comp);
|
||||
/* Check that all the sources for this arg of inst2 come from inst1
|
||||
* or constants.
|
||||
*/
|
||||
for (comp = 0; comp < 4; comp++) {
|
||||
int src_swz = GET_SWZ(inst2->SrcReg[arg].Swizzle, comp);
|
||||
|
||||
if (inst2_swz <= SWIZZLE_W) {
|
||||
GLuint s = GET_SWZ(mov->SrcReg[0].Swizzle, inst2_swz);
|
||||
inst2->SrcReg[arg].Swizzle &= ~(7 << (3 * comp));
|
||||
inst2->SrcReg[arg].Swizzle |= s << (3 * comp);
|
||||
inst2->SrcReg[arg].Negate ^= (((mov->SrcReg[0].Negate >>
|
||||
inst2_swz) & 0x1) << comp);
|
||||
/* If the MOV didn't write that channel, can't use it. */
|
||||
if ((read_mask & (1 << comp)) &&
|
||||
src_swz <= SWIZZLE_W &&
|
||||
(mov->DstReg.WriteMask & (1 << src_swz)) == 0)
|
||||
break;
|
||||
}
|
||||
if (comp != 4)
|
||||
continue;
|
||||
|
||||
/* Adjust the swizzles of inst2 to point at MOV's source */
|
||||
for (comp = 0; comp < 4; comp++) {
|
||||
int inst2_swz = GET_SWZ(inst2->SrcReg[arg].Swizzle, comp);
|
||||
|
||||
if (inst2_swz <= SWIZZLE_W) {
|
||||
GLuint s = GET_SWZ(mov->SrcReg[0].Swizzle, inst2_swz);
|
||||
inst2->SrcReg[arg].Swizzle &= ~(7 << (3 * comp));
|
||||
inst2->SrcReg[arg].Swizzle |= s << (3 * comp);
|
||||
inst2->SrcReg[arg].Negate ^= (((mov->SrcReg[0].Negate >>
|
||||
inst2_swz) & 0x1) << comp);
|
||||
}
|
||||
}
|
||||
inst2->SrcReg[arg].File = mov->SrcReg[0].File;
|
||||
inst2->SrcReg[arg].Index = mov->SrcReg[0].Index;
|
||||
}
|
||||
inst2->SrcReg[arg].File = mov->SrcReg[0].File;
|
||||
inst2->SrcReg[arg].Index = mov->SrcReg[0].Index;
|
||||
|
||||
/* If this instruction overwrote part of the move, our time is up. */
|
||||
if ((inst2->DstReg.File == mov->DstReg.File &&
|
||||
(inst2->DstReg.RelAddr ||
|
||||
inst2->DstReg.Index == mov->DstReg.Index)) ||
|
||||
(inst2->DstReg.File == mov->SrcReg[0].File &&
|
||||
(inst2->DstReg.RelAddr ||
|
||||
inst2->DstReg.Index == mov->SrcReg[0].Index)))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user