[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.
This commit is contained in:
wildcard 2025-09-20 21:19:58 +02:00 committed by crueter
parent c725641f13
commit e0c83e1575

View file

@ -50,8 +50,55 @@ struct IndirectBranchVariable {
auto operator<=>(const IndirectBranchVariable&) const noexcept = default; 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>(IR::PredIndex(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>; using ValueMap = std::unordered_map<IR::Block*, IR::Value>;
struct DefTable { struct DefTable {
@ -124,6 +171,10 @@ IR::Opcode UndefOpcode(IR::Reg) noexcept {
return IR::Opcode::UndefU32; return IR::Opcode::UndefU32;
} }
IR::Opcode UndefOpcode(GotoVariable) noexcept {
return IR::Opcode::UndefU32;
}
IR::Opcode UndefOpcode(IR::Pred) noexcept { IR::Opcode UndefOpcode(IR::Pred) noexcept {
return IR::Opcode::UndefU1; return IR::Opcode::UndefU1;
} }
@ -194,13 +245,14 @@ public:
IR::Inst* phi{&*block->PrependNewInst(block->begin(), IR::Opcode::Phi)}; IR::Inst* phi{&*block->PrependNewInst(block->begin(), IR::Opcode::Phi)};
phi->SetFlags(IR::TypeOf(UndefOpcode(variable))); 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}; stack.back().result = IR::Value{&*phi};
} else if (const std::span imm_preds = block->ImmPredecessors(); } else if (const std::span imm_preds = block->ImmPredecessors();
imm_preds.size() == 1) { imm_preds.size() == 1) {
// Optimize the common case of one predecessor: no phi needed // Tail-advance: reuse this frame
stack.back().pc = Status::SetValue; stack.back().block = imm_preds.front();
stack.emplace_back(imm_preds.front()); stack.back().pc = Status::Start;
break; break;
} else { } else {
// Break potential cycles with operandless phi // Break potential cycles with operandless phi
@ -239,13 +291,29 @@ public:
} }
void SealBlock(IR::Block* block) { void SealBlock(IR::Block* block) {
const auto it{incomplete_phis.find(block)}; if (auto it = incomplete_phis.find(block); it != incomplete_phis.end()) {
if (it != incomplete_phis.end()) { for (auto& [key, phi] : it->second) {
for (auto& pair : it->second) { switch (static_cast<VarTag>(key.tag_index >> 24)) {
auto& variant{pair.first}; case VarTag::Reg:
auto& phi{pair.second}; AddPhiOperands(IR::Reg(static_cast<uint32_t>(key.tag_index & 0xFFFFFF)), *phi, block);
std::visit([&](auto& variable) { AddPhiOperands(variable, *phi, block); }, variant); 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(); block->SsaSeal();
} }
@ -295,7 +363,7 @@ private:
return same; 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; DefTable current_def;
}; };