r300: copy propagate constant swizzles

For example:
SIN temp[1].x, temp[0].x___;
MOV temp[1].y, none._1__;
ADD temp[2].xyz, temp[1].xy__, const[0].ww__;

could be transformed into

SIN temp[1].x, temp[0].x___;
ADD temp[0].xyz, temp[1].x1__, const[0].ww__;

Shader-db RV410:
total instructions in shared programs: 112613 -> 112451 (-0.14%)
instructions in affected programs: 15613 -> 15451 (-1.04%)
helped: 148
HURT: 1
total temps in shared programs: 18149 -> 18129 (-0.11%)
temps in affected programs: 297 -> 277 (-6.73%)
helped: 21
HURT: 2
total cycles in shared programs: 169432 -> 169273 (-0.09%)
cycles in affected programs: 17779 -> 17620 (-0.89%)
helped: 145
HURT: 4

RV530:
total instructions in shared programs: 128650 -> 128443 (-0.16%)
instructions in affected programs: 21647 -> 21440 (-0.96%)
helped: 206
HURT: 4
total temps in shared programs: 17014 -> 17010 (-0.02%)
temps in affected programs: 216 -> 212 (-1.85%)
helped: 11
HURT: 6
total cycles in shared programs: 190719 -> 190523 (-0.10%)
cycles in affected programs: 28892 -> 28696 (-0.68%)
helped: 203
HURT: 8

Signed-off-by: Pavel Ondračka <pavel.ondracka@gmail.com>
Reviewed-by: Filip Gawin <None>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/33275>
This commit is contained in:
Pavel Ondračka
2025-01-25 08:56:18 +01:00
committed by Marge Bot
parent 9835a2df83
commit c031a53a78
@@ -1321,6 +1321,77 @@ merge_A0_loads(struct radeon_compiler *c, struct rc_instruction *inst, bool is_A
}
}
/**
* Search for instructions where we could copy propagate the constant swizzle
* to the reader, for example the following sequence
*
* SIN temp[1].x, temp[0].x___;
* MOV temp[1].y, none._1__;
* ADD temp[2].xyz, temp[1].xy__, const[0].ww__;
*
* could be transformed into
*
* SIN temp[1].x, temp[0].x___;
* ADD temp[0].xyz, temp[1].x1__, const[0].ww__;
*/
static void
copy_propagate_constant_swizzle(struct radeon_compiler *c, struct rc_instruction *inst)
{
unsigned int orig_dst_reg = inst->U.I.DstReg.Index;
unsigned int orig_dst_wmask = inst->U.I.DstReg.WriteMask;
struct rc_instruction *cur = inst;
while (cur != &c->Program.Instructions) {
cur = cur->Next;
const struct rc_opcode_info *opcode = rc_get_opcode_info(cur->U.I.Opcode);
/* Keep it simple for now and stop when encountering any control flow. */
if (opcode->IsFlowControl)
break;
/* We should not see the original destination overwritten (within a control flow block).
* If that happens, we don't have SSA-like anymore and several later assumptions would
* be broken. */
assert(orig_dst_reg != cur->U.I.DstReg.Index || RC_FILE_TEMPORARY != cur->U.I.DstReg.File ||
(orig_dst_wmask & cur->U.I.DstReg.WriteMask) == 0);
for (unsigned int src = 0; src < opcode->NumSrcRegs; src++) {
if (cur->U.I.SrcReg[src].File == RC_FILE_TEMPORARY &&
cur->U.I.SrcReg[src].Index == orig_dst_reg &&
rc_swizzle_to_writemask(cur->U.I.SrcReg[src].Swizzle) & orig_dst_wmask) {
/* Construct the new swizzle. */
unsigned new_swizzle = cur->U.I.SrcReg[src].Swizzle;
unsigned negate = 0;
for (unsigned chan = 0; chan < 4; chan++) {
unsigned swz = GET_SWZ(new_swizzle, chan);
unsigned swz_to_propagate = GET_SWZ(inst->U.I.SrcReg[0].Swizzle, swz);
if (swz_to_propagate > RC_SWIZZLE_W && swz_to_propagate < RC_SWIZZLE_UNUSED) {
SET_SWZ(new_swizzle, chan, swz_to_propagate);
negate |= inst->U.I.SrcReg[0].Negate & (1 << swz);
}
}
struct rc_src_register new_src = cur->U.I.SrcReg[src];
new_src.Swizzle = new_swizzle;
new_src.Negate ^= negate;
if (!c->SwizzleCaps->IsNative(cur->U.I.Opcode, new_src))
continue;
cur->U.I.SrcReg[src] = new_src;
}
}
}
/* Now check if we can delete the original MOV. Specifically if we still have some
* readers left.
*/
struct rc_reader_data readers;
readers.ExitOnAbort = 0;
rc_get_readers(c, inst, &readers, NULL, NULL, NULL);
if (readers.ReaderCount == 0)
rc_remove_instruction(inst);
}
/**
* According to the GLSL spec, round is only 1.30 and up
* so the only reason why we should ever see round is if it actually
@@ -1420,6 +1491,17 @@ rc_optimize(struct radeon_compiler *c, void *user)
}
}
/* Copy propagate constant swizzles */
inst = c->Program.Instructions.Next;
while (inst != &c->Program.Instructions) {
struct rc_instruction *cur = inst;
inst = inst->Next;
if (cur->U.I.Opcode == RC_OPCODE_MOV && cur->U.I.SrcReg[0].File == RC_FILE_NONE &&
cur->U.I.DstReg.File == RC_FILE_TEMPORARY) {
copy_propagate_constant_swizzle(c, cur);
}
}
if (c->type != RC_FRAGMENT_PROGRAM) {
return;
}