From 001fe8c236b6c45b565658eade1dd5dd6876754e Mon Sep 17 00:00:00 2001 From: Georg Lehmann Date: Mon, 26 May 2025 15:11:03 +0200 Subject: [PATCH] aco: optimize boolean phi with empty else block MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can keep the else empty by handling the phi in the "then" block. Foz-DB Navi21: Totals from 921 (1.15% of 80065) affected shaders: Instrs: 4532598 -> 4527309 (-0.12%); split: -0.12%, +0.00% CodeSize: 24498484 -> 24481780 (-0.07%); split: -0.08%, +0.01% Latency: 41016915 -> 41020477 (+0.01%); split: -0.10%, +0.11% InvThroughput: 9998405 -> 9991873 (-0.07%); split: -0.08%, +0.02% SClause: 128261 -> 128267 (+0.00%) Copies: 409949 -> 408585 (-0.33%); split: -0.36%, +0.02% Branches: 169740 -> 169222 (-0.31%); split: -0.58%, +0.27% PreSGPRs: 64408 -> 64398 (-0.02%) VALU: 2972521 -> 2972518 (-0.00%) SALU: 673844 -> 668973 (-0.72%); split: -0.72%, +0.00% Reviewed-by: Daniel Schürmann Part-of: --- src/amd/compiler/aco_lower_phis.cpp | 71 +++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 4 deletions(-) diff --git a/src/amd/compiler/aco_lower_phis.cpp b/src/amd/compiler/aco_lower_phis.cpp index 88ab6fbc2da..c7d872e9eb8 100644 --- a/src/amd/compiler/aco_lower_phis.cpp +++ b/src/amd/compiler/aco_lower_phis.cpp @@ -184,7 +184,6 @@ build_const_else_merge_code(Program* program, Block& invert_block, aco_ptroperands[0]; const Operand els = phi->operands[1]; @@ -220,6 +219,61 @@ build_const_else_merge_code(Program* program, Block& invert_block, aco_ptroperands[1] = Operand(tmp); } +bool +block_is_empty(Block& block) +{ + for (auto& instr : block.instructions) { + if (instr->opcode != aco_opcode::p_logical_start && + instr->opcode != aco_opcode::p_logical_end && instr->opcode != aco_opcode::p_branch) + return false; + } + return true; +} + +void +build_empty_else_merge_code(Program* program, Block& merge_block, Block& invert_block, + aco_ptr& phi) +{ + /* If the else block is empty, we know that the else phi operand dominates the + * then block, so we can handle the phi only in the then block. + */ + Builder bld(program); + Block& then_block = program->blocks[merge_block.logical_preds[0]]; + Operand then_op = phi->operands[0]; + Operand else_op = phi->operands[1]; + + auto before_logical_end = + std::find_if(then_block.instructions.begin(), then_block.instructions.end(), + [](const aco_ptr& instr) -> bool + { return instr->opcode == aco_opcode::p_logical_end; }); + bld.reset(&then_block.instructions, before_logical_end); + + Operand new_op; + + if (then_op.constantEquals(-1)) { + new_op = + bld.sop2(Builder::s_or, bld.def(bld.lm), bld.def(s1, scc), else_op, Operand(exec, bld.lm)); + } else if (then_op.constantEquals(0)) { + new_op = bld.sop2(Builder::s_andn2, bld.def(bld.lm), bld.def(s1, scc), else_op, + Operand(exec, bld.lm)); + } else { + new_op = bld.sop2(Builder::s_andn2, bld.def(bld.lm), bld.def(s1, scc), else_op, + Operand(exec, bld.lm)); + then_op = bld.sop2(Builder::s_and, bld.def(bld.lm), bld.def(s1, scc), then_op, + Operand(exec, bld.lm)); + new_op = bld.sop2(Builder::s_or, bld.def(bld.lm), bld.def(s1, scc), then_op, new_op); + } + + /* Insert new linear phi in the invert block, make merge block phi trivial to not invalidate + * iterators. */ + bld.reset(&invert_block.instructions, invert_block.instructions.begin()); + Temp tmp = bld.pseudo(aco_opcode::p_linear_phi, bld.def(bld.lm), new_op, else_op); + + phi->opcode = aco_opcode::p_linear_phi; + phi->operands[0] = Operand(tmp); + phi->operands[1] = Operand(tmp); +} + void init_state(Program* program, Block* block, ssa_state* state, aco_ptr& phi) { @@ -337,9 +391,18 @@ lower_phi_to_linear(Program* program, ssa_state* state, Block* block, aco_ptrkind & block_kind_merge) && phi->opcode == aco_opcode::p_boolean_phi && - phi->operands.size() == 2 && phi->operands[1].isConstant()) { - build_const_else_merge_code(program, program->blocks[block->linear_idom], phi); - return; + phi->operands.size() == 2) { + Block& invert_block = program->blocks[block->linear_idom]; + Block& els_block = program->blocks[block->logical_preds[1]]; + assert(invert_block.kind & block_kind_invert); + if (phi->operands[1].isConstant()) { + build_const_else_merge_code(program, invert_block, phi); + return; + } else if (phi->operands[1].isTemp() && block_is_empty(els_block) && + els_block.linear_preds[0] == invert_block.index) { + build_empty_else_merge_code(program, *block, invert_block, phi); + return; + } } init_state(program, block, state, phi);