diff options
| -rw-r--r-- | src/shader_recompiler/frontend/ir/basic_block.h | 10 | ||||
| -rw-r--r-- | src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp | 64 |
2 files changed, 53 insertions, 21 deletions
diff --git a/src/shader_recompiler/frontend/ir/basic_block.h b/src/shader_recompiler/frontend/ir/basic_block.h index 6a1d615d9..3a4230755 100644 --- a/src/shader_recompiler/frontend/ir/basic_block.h +++ b/src/shader_recompiler/frontend/ir/basic_block.h | |||
| @@ -101,6 +101,13 @@ public: | |||
| 101 | return branch_false; | 101 | return branch_false; |
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | void SetSsaRegValue(IR::Reg reg, const Value& value) noexcept { | ||
| 105 | ssa_reg_values[RegIndex(reg)] = value; | ||
| 106 | } | ||
| 107 | const Value& SsaRegValue(IR::Reg reg) const noexcept { | ||
| 108 | return ssa_reg_values[RegIndex(reg)]; | ||
| 109 | } | ||
| 110 | |||
| 104 | [[nodiscard]] bool empty() const { | 111 | [[nodiscard]] bool empty() const { |
| 105 | return instructions.empty(); | 112 | return instructions.empty(); |
| 106 | } | 113 | } |
| @@ -182,6 +189,9 @@ private: | |||
| 182 | /// Block immediate predecessors | 189 | /// Block immediate predecessors |
| 183 | std::vector<Block*> imm_predecessors; | 190 | std::vector<Block*> imm_predecessors; |
| 184 | 191 | ||
| 192 | /// Intrusively store the value of a register in the block. | ||
| 193 | std::array<Value, NUM_REGS> ssa_reg_values; | ||
| 194 | |||
| 185 | /// Intrusively stored host definition of this block. | 195 | /// Intrusively stored host definition of this block. |
| 186 | u32 definition{}; | 196 | u32 definition{}; |
| 187 | }; | 197 | }; |
diff --git a/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp b/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp index ddd679e39..bb1a90004 100644 --- a/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp +++ b/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp | |||
| @@ -57,39 +57,62 @@ using Variant = std::variant<IR::Reg, IR::Pred, ZeroFlagTag, SignFlagTag, CarryF | |||
| 57 | using ValueMap = boost::container::flat_map<IR::Block*, IR::Value, std::less<IR::Block*>>; | 57 | using ValueMap = boost::container::flat_map<IR::Block*, IR::Value, std::less<IR::Block*>>; |
| 58 | 58 | ||
| 59 | struct DefTable { | 59 | struct DefTable { |
| 60 | [[nodiscard]] ValueMap& operator[](IR::Reg variable) noexcept { | 60 | const IR::Value& Def(IR::Block* block, IR::Reg variable) noexcept { |
| 61 | return regs[IR::RegIndex(variable)]; | 61 | return block->SsaRegValue(variable); |
| 62 | } | ||
| 63 | void SetDef(IR::Block* block, IR::Reg variable, const IR::Value& value) noexcept { | ||
| 64 | block->SetSsaRegValue(variable, value); | ||
| 62 | } | 65 | } |
| 63 | 66 | ||
| 64 | [[nodiscard]] ValueMap& operator[](IR::Pred variable) noexcept { | 67 | const IR::Value& Def(IR::Block* block, IR::Pred variable) noexcept { |
| 65 | return preds[IR::PredIndex(variable)]; | 68 | return preds[IR::PredIndex(variable)][block]; |
| 69 | } | ||
| 70 | void SetDef(IR::Block* block, IR::Pred variable, const IR::Value& value) noexcept { | ||
| 71 | preds[IR::PredIndex(variable)].insert_or_assign(block, value); | ||
| 66 | } | 72 | } |
| 67 | 73 | ||
| 68 | [[nodiscard]] ValueMap& operator[](GotoVariable goto_variable) { | 74 | const IR::Value& Def(IR::Block* block, GotoVariable variable) noexcept { |
| 69 | return goto_vars[goto_variable.index]; | 75 | return goto_vars[variable.index][block]; |
| 76 | } | ||
| 77 | void SetDef(IR::Block* block, GotoVariable variable, const IR::Value& value) noexcept { | ||
| 78 | goto_vars[variable.index].insert_or_assign(block, value); | ||
| 70 | } | 79 | } |
| 71 | 80 | ||
| 72 | [[nodiscard]] ValueMap& operator[](IndirectBranchVariable) { | 81 | const IR::Value& Def(IR::Block* block, IndirectBranchVariable) noexcept { |
| 73 | return indirect_branch_var; | 82 | return indirect_branch_var[block]; |
| 83 | } | ||
| 84 | void SetDef(IR::Block* block, IndirectBranchVariable, const IR::Value& value) noexcept { | ||
| 85 | indirect_branch_var.insert_or_assign(block, value); | ||
| 74 | } | 86 | } |
| 75 | 87 | ||
| 76 | [[nodiscard]] ValueMap& operator[](ZeroFlagTag) noexcept { | 88 | const IR::Value& Def(IR::Block* block, ZeroFlagTag) noexcept { |
| 77 | return zero_flag; | 89 | return zero_flag[block]; |
| 90 | } | ||
| 91 | void SetDef(IR::Block* block, ZeroFlagTag, const IR::Value& value) noexcept { | ||
| 92 | zero_flag.insert_or_assign(block, value); | ||
| 78 | } | 93 | } |
| 79 | 94 | ||
| 80 | [[nodiscard]] ValueMap& operator[](SignFlagTag) noexcept { | 95 | const IR::Value& Def(IR::Block* block, SignFlagTag) noexcept { |
| 81 | return sign_flag; | 96 | return sign_flag[block]; |
| 97 | } | ||
| 98 | void SetDef(IR::Block* block, SignFlagTag, const IR::Value& value) noexcept { | ||
| 99 | sign_flag.insert_or_assign(block, value); | ||
| 82 | } | 100 | } |
| 83 | 101 | ||
| 84 | [[nodiscard]] ValueMap& operator[](CarryFlagTag) noexcept { | 102 | const IR::Value& Def(IR::Block* block, CarryFlagTag) noexcept { |
| 85 | return carry_flag; | 103 | return carry_flag[block]; |
| 104 | } | ||
| 105 | void SetDef(IR::Block* block, CarryFlagTag, const IR::Value& value) noexcept { | ||
| 106 | carry_flag.insert_or_assign(block, value); | ||
| 86 | } | 107 | } |
| 87 | 108 | ||
| 88 | [[nodiscard]] ValueMap& operator[](OverflowFlagTag) noexcept { | 109 | const IR::Value& Def(IR::Block* block, OverflowFlagTag) noexcept { |
| 89 | return overflow_flag; | 110 | return overflow_flag[block]; |
| 111 | } | ||
| 112 | void SetDef(IR::Block* block, OverflowFlagTag, const IR::Value& value) noexcept { | ||
| 113 | overflow_flag.insert_or_assign(block, value); | ||
| 90 | } | 114 | } |
| 91 | 115 | ||
| 92 | std::array<ValueMap, IR::NUM_USER_REGS> regs; | ||
| 93 | std::array<ValueMap, IR::NUM_USER_PREDS> preds; | 116 | std::array<ValueMap, IR::NUM_USER_PREDS> preds; |
| 94 | boost::container::flat_map<u32, ValueMap> goto_vars; | 117 | boost::container::flat_map<u32, ValueMap> goto_vars; |
| 95 | ValueMap indirect_branch_var; | 118 | ValueMap indirect_branch_var; |
| @@ -143,7 +166,7 @@ class Pass { | |||
| 143 | public: | 166 | public: |
| 144 | template <typename Type> | 167 | template <typename Type> |
| 145 | void WriteVariable(Type variable, IR::Block* block, const IR::Value& value) { | 168 | void WriteVariable(Type variable, IR::Block* block, const IR::Value& value) { |
| 146 | current_def[variable].insert_or_assign(block, value); | 169 | current_def.SetDef(block, variable, value); |
| 147 | } | 170 | } |
| 148 | 171 | ||
| 149 | template <typename Type> | 172 | template <typename Type> |
| @@ -170,9 +193,8 @@ public: | |||
| 170 | IR::Block* const block{stack.back().block}; | 193 | IR::Block* const block{stack.back().block}; |
| 171 | switch (stack.back().pc) { | 194 | switch (stack.back().pc) { |
| 172 | case Status::Start: { | 195 | case Status::Start: { |
| 173 | const ValueMap& def{current_def[variable]}; | 196 | if (const IR::Value& def = current_def.Def(block, variable); !def.IsEmpty()) { |
| 174 | if (const auto it{def.find(block)}; it != def.end()) { | 197 | stack.back().result = def; |
| 175 | stack.back().result = it->second; | ||
| 176 | } else if (!sealed_blocks.contains(block)) { | 198 | } else if (!sealed_blocks.contains(block)) { |
| 177 | // Incomplete CFG | 199 | // Incomplete CFG |
| 178 | IR::Inst* phi{&*block->PrependNewInst(block->begin(), IR::Opcode::Phi)}; | 200 | IR::Inst* phi{&*block->PrependNewInst(block->begin(), IR::Opcode::Phi)}; |