Compare commits

...
Sign in to create a new pull request.

3 commits

Author SHA1 Message Date
d7b8a72c98 Update src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp
All checks were successful
eden-license / license-header (pull_request) Successful in 20s
test-1 fix rendering bugs
2025-09-28 16:33:43 +02:00
f85753be8d Update src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp 2025-09-28 16:33:43 +02:00
e0c83e1575 [Shader Recompiler] Optimize SSA rewrite using better data structures.
Optimize SSA rewrite using,
Better data structures.
Tail End optimization,
Change from std:visit with direct switch case.
Better hash function.
2025-09-28 16:33:43 +02:00

View file

@ -1,3 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -50,8 +52,55 @@ struct IndirectBranchVariable {
auto operator<=>(const IndirectBranchVariable&) const noexcept = default;
};
using Variant = std::variant<IR::Reg, IR::Pred, ZeroFlagTag, SignFlagTag, CarryFlagTag,
OverflowFlagTag, GotoVariable, IndirectBranchVariable>;
enum class VarTag : uint8_t { Reg, Pred, Z, S, C, O, Goto, Indirect };
struct VariableKey {
uint32_t tag_index; // [31:24]=tag, [23:0]=index
bool operator==(const VariableKey&) const = default;
};
struct VariableKeyHash {
size_t operator()(VariableKey k) const noexcept {
uint64_t x = k.tag_index * 0x9E3779B185EBCA87ull;
x ^= (x >> 33); x *= 0xC2B2AE3D27D4EB4Full; x ^= (x >> 29);
return static_cast<size_t>(x);
}
};
constexpr uint32_t PackKey(VarTag tag, uint32_t idx = 0) {
return (static_cast<uint32_t>(tag) << 24) | (idx & 0x00FFFFFFu);
}
inline VariableKey KeyOf(IR::Reg r){
return {PackKey(VarTag::Reg, static_cast<uint32_t>(r))};
}
inline VariableKey KeyOf(IR::Pred p){
return {PackKey(VarTag::Pred, static_cast<uint32_t>(p))};
}
inline VariableKey KeyOf(ZeroFlagTag){
return {PackKey(VarTag::Z)};
}
inline VariableKey KeyOf(SignFlagTag){
return {PackKey(VarTag::S)};
}
inline VariableKey KeyOf(CarryFlagTag){
return {PackKey(VarTag::C)};
}
inline VariableKey KeyOf(OverflowFlagTag){
return {PackKey(VarTag::O)};
}
inline VariableKey KeyOf(GotoVariable g){
return {PackKey(VarTag::Goto, g.index)};
}
inline VariableKey KeyOf(IndirectBranchVariable){
return {PackKey(VarTag::Indirect)};
}
using IncompleteMap = std::unordered_map<VariableKey, IR::Inst*, VariableKeyHash>;
using ValueMap = std::unordered_map<IR::Block*, IR::Value>;
struct DefTable {
@ -124,6 +173,10 @@ IR::Opcode UndefOpcode(IR::Reg) noexcept {
return IR::Opcode::UndefU32;
}
IR::Opcode UndefOpcode(GotoVariable) noexcept {
return IR::Opcode::UndefU32;
}
IR::Opcode UndefOpcode(IR::Pred) noexcept {
return IR::Opcode::UndefU1;
}
@ -194,11 +247,11 @@ public:
IR::Inst* phi{&*block->PrependNewInst(block->begin(), IR::Opcode::Phi)};
phi->SetFlags(IR::TypeOf(UndefOpcode(variable)));
incomplete_phis[block].insert_or_assign(variable, phi);
incomplete_phis[block].insert_or_assign(KeyOf(variable), phi);
WriteVariable(variable, block, IR::Value{phi});
stack.back().result = IR::Value{&*phi};
} else if (const std::span imm_preds = block->ImmPredecessors();
imm_preds.size() == 1) {
// Optimize the common case of one predecessor: no phi needed
stack.back().pc = Status::SetValue;
stack.emplace_back(imm_preds.front());
break;
@ -239,13 +292,29 @@ public:
}
void SealBlock(IR::Block* block) {
const auto it{incomplete_phis.find(block)};
if (it != incomplete_phis.end()) {
for (auto& pair : it->second) {
auto& variant{pair.first};
auto& phi{pair.second};
std::visit([&](auto& variable) { AddPhiOperands(variable, *phi, block); }, variant);
if (auto it = incomplete_phis.find(block); it != incomplete_phis.end()) {
for (auto& [key, phi] : it->second) {
switch (static_cast<VarTag>(key.tag_index >> 24)) {
case VarTag::Reg:
AddPhiOperands(IR::Reg(static_cast<uint32_t>(key.tag_index & 0xFFFFFF)), *phi, block);
break;
case VarTag::Pred:
AddPhiOperands(static_cast<IR::Pred>(key.tag_index & 0xFFFFFF), *phi, block);
break;
case VarTag::Z: AddPhiOperands(ZeroFlagTag{}, *phi, block); break;
case VarTag::S: AddPhiOperands(SignFlagTag{}, *phi, block); break;
case VarTag::C: AddPhiOperands(CarryFlagTag{}, *phi, block); break;
case VarTag::O: AddPhiOperands(OverflowFlagTag{}, *phi, block); break;
case VarTag::Goto:
AddPhiOperands(GotoVariable{static_cast<uint32_t>(key.tag_index & 0xFFFFFF)}, *phi, block);
break;
case VarTag::Indirect:
AddPhiOperands(IndirectBranchVariable{}, *phi, block);
break;
}
}
it->second.clear();
incomplete_phis.erase(it);
}
block->SsaSeal();
}
@ -295,7 +364,7 @@ private:
return same;
}
std::unordered_map<IR::Block*, std::map<Variant, IR::Inst*>> incomplete_phis;
std::unordered_map<IR::Block*, IncompleteMap> incomplete_phis;
DefTable current_def;
};