aco: Improve SCC nocompare optimization when SCC is clobbered.
When SCC is clobbered between s_cmp and its operand's writer, the current optimization that eliminates s_cmp won't kick in. However, when s_cmp is the only user of its operand temporary, it is possible to "pull down" the instruction that wrote the operand. Fossil DB stats on Navi 21: Totals from 63302 (46.92% of 134906) affected shaders: CodeSize: 176689272 -> 176418332 (-0.15%) Instrs: 33552237 -> 33484502 (-0.20%) Latency: 205847485 -> 205816205 (-0.02%); split: -0.02%, +0.00% InvThroughput: 34321285 -> 34319908 (-0.00%); split: -0.00%, +0.00% Signed-off-by: Timur Kristóf <timur.kristof@gmail.com> Reviewed-by: Rhys Perry <pendingchaos02@gmail.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/16266>
This commit is contained in:
@@ -267,10 +267,9 @@ try_optimize_scc_nocompare(pr_opt_ctx& ctx, aco_ptr<Instruction>& instr)
|
||||
if (ctx.uses[instr->operands[0].tempId()] > 1)
|
||||
return;
|
||||
|
||||
/* Make sure both SCC and Operand 0 are written by the same instruction. */
|
||||
/* Find the writer instruction of Operand 0. */
|
||||
Idx wr_idx = last_writer_idx(ctx, instr->operands[0]);
|
||||
Idx sccwr_idx = last_writer_idx(ctx, scc, s1);
|
||||
if (!wr_idx.found() || wr_idx != sccwr_idx)
|
||||
if (!wr_idx.found())
|
||||
return;
|
||||
|
||||
Instruction* wr_instr = ctx.get(wr_idx);
|
||||
@@ -313,6 +312,49 @@ try_optimize_scc_nocompare(pr_opt_ctx& ctx, aco_ptr<Instruction>& instr)
|
||||
default: return;
|
||||
}
|
||||
|
||||
/* Check whether both SCC and Operand 0 are written by the same instruction. */
|
||||
Idx sccwr_idx = last_writer_idx(ctx, scc, s1);
|
||||
if (wr_idx != sccwr_idx) {
|
||||
/* Check whether the current instruction is the only user of its first operand. */
|
||||
if (ctx.uses[wr_instr->definitions[1].tempId()] ||
|
||||
ctx.uses[wr_instr->definitions[0].tempId()] > 1)
|
||||
return;
|
||||
|
||||
/* Check whether the operands of the writer are clobbered. */
|
||||
for (const Operand& op : wr_instr->operands) {
|
||||
if (!op.isConstant() && is_clobbered_since(ctx, op, wr_idx))
|
||||
return;
|
||||
}
|
||||
|
||||
aco_opcode pulled_opcode = wr_instr->opcode;
|
||||
if (instr->opcode == aco_opcode::s_cmp_eq_u32 ||
|
||||
instr->opcode == aco_opcode::s_cmp_eq_i32 ||
|
||||
instr->opcode == aco_opcode::s_cmp_eq_u64) {
|
||||
/* When s_cmp_eq is used, it effectively inverts the SCC def.
|
||||
* However, we can't simply invert the opcodes here because that
|
||||
* would change the meaning of the program.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
Definition scc_def = instr->definitions[0];
|
||||
ctx.uses[wr_instr->definitions[0].tempId()]--;
|
||||
|
||||
/* Copy the writer instruction, but use SCC from the current instr.
|
||||
* This means that the original instruction will be eliminated.
|
||||
*/
|
||||
if (wr_instr->format == Format::SOP2) {
|
||||
instr.reset(create_instruction<SOP2_instruction>(pulled_opcode, Format::SOP2, 2, 2));
|
||||
instr->operands[1] = wr_instr->operands[1];
|
||||
} else if (wr_instr->format == Format::SOP1) {
|
||||
instr.reset(create_instruction<SOP1_instruction>(pulled_opcode, Format::SOP1, 1, 2));
|
||||
}
|
||||
instr->definitions[0] = wr_instr->definitions[0];
|
||||
instr->definitions[1] = scc_def;
|
||||
instr->operands[0] = wr_instr->operands[0];
|
||||
return;
|
||||
}
|
||||
|
||||
/* Use the SCC def from wr_instr */
|
||||
ctx.uses[instr->operands[0].tempId()]--;
|
||||
instr->operands[0] = Operand(wr_instr->definitions[1].getTemp(), scc);
|
||||
|
||||
Reference in New Issue
Block a user