From 67159e3be76cf468288ae492ea22fc43a77a9d1e Mon Sep 17 00:00:00 2001 From: ameerj <52414509+ameerj@users.noreply.github.com> Date: Tue, 22 Mar 2022 18:34:31 -0400 Subject: [PATCH] dead_code_elimination_pass: Remove unreachable Phi arguments --- .../frontend/ir/microinstruction.cpp | 5 ++++ src/shader_recompiler/frontend/ir/value.h | 4 +++ .../ir_opt/dead_code_elimination_pass.cpp | 27 +++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/src/shader_recompiler/frontend/ir/microinstruction.cpp b/src/shader_recompiler/frontend/ir/microinstruction.cpp index 631446cf7..4a2564f47 100644 --- a/src/shader_recompiler/frontend/ir/microinstruction.cpp +++ b/src/shader_recompiler/frontend/ir/microinstruction.cpp @@ -326,6 +326,11 @@ void Inst::AddPhiOperand(Block* predecessor, const Value& value) { phi_args.emplace_back(predecessor, value); } +void Inst::ErasePhiOperand(size_t index) { + const auto operand_it{phi_args.begin() + static_cast(index)}; + phi_args.erase(operand_it); +} + void Inst::OrderPhiArgs() { if (op != Opcode::Phi) { throw LogicError("{} is not a Phi instruction", op); diff --git a/src/shader_recompiler/frontend/ir/value.h b/src/shader_recompiler/frontend/ir/value.h index 947579852..14f6e55bc 100644 --- a/src/shader_recompiler/frontend/ir/value.h +++ b/src/shader_recompiler/frontend/ir/value.h @@ -179,9 +179,13 @@ public: /// Get a pointer to the block of a phi argument. [[nodiscard]] Block* PhiBlock(size_t index) const; + /// Add phi operand to a phi instruction. void AddPhiOperand(Block* predecessor, const Value& value); + // Erase the phi operand at the given index. + void ErasePhiOperand(size_t index); + /// Orders the Phi arguments from farthest away to nearest. void OrderPhiArgs(); diff --git a/src/shader_recompiler/ir_opt/dead_code_elimination_pass.cpp b/src/shader_recompiler/ir_opt/dead_code_elimination_pass.cpp index 6c7c7b32d..6697fde85 100644 --- a/src/shader_recompiler/ir_opt/dead_code_elimination_pass.cpp +++ b/src/shader_recompiler/ir_opt/dead_code_elimination_pass.cpp @@ -2,6 +2,10 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include + +#include + #include "shader_recompiler/frontend/ir/basic_block.h" #include "shader_recompiler/frontend/ir/value.h" #include "shader_recompiler/ir_opt/passes.h" @@ -25,7 +29,26 @@ void DeadInstElimination(IR::Block* const block) { } } +void DeletedPhiArgElimination(IR::Program& program, std::span dead_blocks) { + for (IR::Block* const block : program.blocks) { + for (IR::Inst& phi : *block) { + if (!IR::IsPhi(phi)) { + continue; + } + for (size_t i = 0; i < phi.NumArgs(); ++i) { + if (std::ranges::find(dead_blocks, phi.PhiBlock(i)) == dead_blocks.end()) { + continue; + } + // Phi operand at this index is an unreachable block + phi.ErasePhiOperand(i); + --i; + } + } + } +} + void DeadBranchElimination(IR::Program& program) { + boost::container::small_vector dead_blocks; const auto begin_it{program.syntax_list.begin()}; for (auto node_it = begin_it; node_it != program.syntax_list.end(); ++node_it) { if (node_it->type != IR::AbstractSyntaxNode::Type::If) { @@ -55,6 +78,7 @@ void DeadBranchElimination(IR::Program& program) { case IR::AbstractSyntaxNode::Type::Block: { IR::Block* const block{node_it->data.block}; DeadInstElimination(block); + dead_blocks.push_back(block); break; } default: @@ -66,6 +90,9 @@ void DeadBranchElimination(IR::Program& program) { // Account for loop increment --node_it; } + if (!dead_blocks.empty()) { + DeletedPhiArgElimination(program, std::span(dead_blocks.data(), dead_blocks.size())); + } } } // namespace