feat(shader): add ssa building impl for recompiler

This commit is contained in:
boykopovar 2026-09-18 12:09:32 +03:00
parent 3400a2b6e5
commit 6f0ccde6ff
14 changed files with 694 additions and 108 deletions

View File

@ -3,90 +3,95 @@ function(add_shader_recompiler target runtimeTarget)
message(FATAL_ERROR "Shader recompiler requires an existing runtime target: ${runtimeTarget}")
endif()
add_library(${target} STATIC EXCLUDE_FROM_ALL
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Recompiler.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/RdnaDecoder/src/RdnaOpcode.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/RdnaDecoder/src/RdnaProgram.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/RdnaDecoder/src/RdnaInstructionDecoder.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/RdnaDecoder/src/RdnaScalarOpDecoder.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/RdnaDecoder/src/RdnaVectorOpDecoder.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/RdnaDecoder/src/RdnaMemoryOpDecoder.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/RdnaDecoder/src/RdnaImageOpDecoder.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/RdnaDecoder/src/RdnaExportOpDecoder.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/RdnaDecoder/src/RdnaDescriptorFormat.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ControlFlow/src/ControlFlowGraph.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ControlFlow/src/GraphBuilder.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ControlFlow/src/Structurizer.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/IntermediateRepresentation/src/IrType.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/IntermediateRepresentation/src/GuestRegister.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/IntermediateRepresentation/src/IrOpcode.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/IntermediateRepresentation/src/IrValue.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/IntermediateRepresentation/src/IrBlock.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/IntermediateRepresentation/src/IrProgram.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/IntermediateRepresentation/src/IrBuilder/IrBuilderInternal.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/IntermediateRepresentation/src/IrBuilder/IrBuilderCore.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/IntermediateRepresentation/src/IrBuilder/IrBuilderConstants.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/IntermediateRepresentation/src/IrBuilder/IrBuilderRegisters.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/IntermediateRepresentation/src/IrBuilder/IrBuilderControlFlow.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/IntermediateRepresentation/src/IrBuilder/IrBuilderExtendedRegisters.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/IntermediateRepresentation/src/IrBuilder/IrBuilderConversions.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/IntermediateRepresentation/src/IrBuilder/IrBuilderArithmetic.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/IntermediateRepresentation/src/IrBuilder/IrBuilderLogic.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/EmbeddedVertexFetch.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/InstructionTranslator.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/ShaderInputInfoBuilder.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/TranslationContext/OperandAccess.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/TranslationContext/SubwordPacking.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/TranslationContext/ExecMask.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/ScalarInstructions.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/VectorInstructions.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/FloatInstructions.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/IntegerInstructions.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/CompareInstructions.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/ControlFlowInstructions.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/ConvertInstructions.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/MemoryInstructions/MemoryResourceHelpers.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/MemoryInstructions/ScalarBufferInstructions.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/MemoryInstructions/BufferInstructions.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/MemoryInstructions/FlatInstructions.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/MemoryInstructions/ImageInstructions.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/MemoryInstructions/SharedMemoryInstructions.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/MemoryInstructions/MemoryInstructionDispatch.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/AttributeInstructions.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/DispatchInstructions.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/SsaBuilder.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/ConstantFolder.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/DeadCodeEliminator.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/ReadLaneEliminator.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/ResourceTracker.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/ResourceMaterializer.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/BindingAllocator.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/ShaderInfoCollector.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/SharedMemoryBarrierInserter.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/SrtWalker/SrtAddressArithmetic.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/SrtWalker/SrtDescriptorEvaluation.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/SrtWalker/SrtDiagnostics.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/SrtWalker/SrtEvaluator.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/SrtWalker/SrtInstructionPredicates.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/SrtWalker/SrtPlanBuilder.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/SrtWalker/SrtRuntimeValidator.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/SrtWalker/SrtWalker.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/SpirvBackend/src/SpirvModule.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/SpirvBackend/src/SpirvAnalysis.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/SpirvBackend/src/SpirvAluEmitter.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/SpirvBackend/src/SpirvFlowEmitter.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/SpirvBackend/src/SpirvImageEmitter.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/SpirvBackend/src/SpirvMemoryEmitter.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/SpirvBackend/src/SpirvModuleEmitter.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/SpirvBackend/src/SpirvEmitter.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Recompiler.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/RdnaDecoder/src/RdnaOpcode.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/RdnaDecoder/src/RdnaProgram.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/RdnaDecoder/src/RdnaInstructionDecoder.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/RdnaDecoder/src/RdnaScalarOpDecoder.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/RdnaDecoder/src/RdnaVectorOpDecoder.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/RdnaDecoder/src/RdnaMemoryOpDecoder.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/RdnaDecoder/src/RdnaImageOpDecoder.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/RdnaDecoder/src/RdnaExportOpDecoder.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/RdnaDecoder/src/RdnaDescriptorFormat.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ControlFlow/src/ControlFlowGraph.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ControlFlow/src/GraphBuilder.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ControlFlow/src/Structurizer.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/IntermediateRepresentation/src/IrType.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/IntermediateRepresentation/src/GuestRegister.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/IntermediateRepresentation/src/IrOpcode.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/IntermediateRepresentation/src/IrValue.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/IntermediateRepresentation/src/IrBlock.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/IntermediateRepresentation/src/IrProgram.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/IntermediateRepresentation/src/IrBuilder/IrBuilderInternal.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/IntermediateRepresentation/src/IrBuilder/IrBuilderCore.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/IntermediateRepresentation/src/IrBuilder/IrBuilderConstants.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/IntermediateRepresentation/src/IrBuilder/IrBuilderRegisters.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/IntermediateRepresentation/src/IrBuilder/IrBuilderControlFlow.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/IntermediateRepresentation/src/IrBuilder/IrBuilderExtendedRegisters.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/IntermediateRepresentation/src/IrBuilder/IrBuilderConversions.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/IntermediateRepresentation/src/IrBuilder/IrBuilderArithmetic.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/IntermediateRepresentation/src/IrBuilder/IrBuilderLogic.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/EmbeddedVertexFetch.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/InstructionTranslator.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/ShaderInputInfoBuilder.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/TranslationContext/OperandAccess.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/TranslationContext/SubwordPacking.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/TranslationContext/ExecMask.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/ScalarInstructions.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/VectorInstructions.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/FloatInstructions.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/IntegerInstructions.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/CompareInstructions.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/ControlFlowInstructions.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/ConvertInstructions.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/MemoryInstructions/MemoryResourceHelpers.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/MemoryInstructions/ScalarBufferInstructions.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/MemoryInstructions/BufferInstructions.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/MemoryInstructions/FlatInstructions.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/MemoryInstructions/ImageInstructions.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/MemoryInstructions/SharedMemoryInstructions.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/MemoryInstructions/MemoryInstructionDispatch.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/AttributeInstructions.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/src/DispatchInstructions.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/SsaBuilder/SsaBuilder.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/SsaBuilder/SsaVariable.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/SsaBuilder/SsaDefTable.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/SsaBuilder/SsaPass.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/SsaBuilder/SsaInstructionVisitor.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/SsaBuilder/SsaRegisterStateCleanup.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/ConstantFolder.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/DeadCodeEliminator.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/ReadLaneEliminator.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/ResourceTracker.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/ResourceMaterializer.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/BindingAllocator.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/ShaderInfoCollector.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/SharedMemoryBarrierInserter.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/SrtWalker/SrtAddressArithmetic.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/SrtWalker/SrtDescriptorEvaluation.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/SrtWalker/SrtDiagnostics.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/SrtWalker/SrtEvaluator.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/SrtWalker/SrtInstructionPredicates.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/SrtWalker/SrtPlanBuilder.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/SrtWalker/SrtRuntimeValidator.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/src/SrtWalker/SrtWalker.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/SpirvBackend/src/SpirvModule.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/SpirvBackend/src/SpirvAnalysis.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/SpirvBackend/src/SpirvAluEmitter.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/SpirvBackend/src/SpirvFlowEmitter.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/SpirvBackend/src/SpirvImageEmitter.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/SpirvBackend/src/SpirvMemoryEmitter.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/SpirvBackend/src/SpirvModuleEmitter.cpp
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/SpirvBackend/src/SpirvEmitter.cpp
)
target_include_directories(${target} PUBLIC
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/RdnaDecoder/include
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ControlFlow/include
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/IntermediateRepresentation/include
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/include
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/include
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/SpirvBackend/include
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/RdnaDecoder/include
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ControlFlow/include
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/IntermediateRepresentation/include
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Translation/include
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Optimization/include
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/SpirvBackend/include
)
target_compile_features(${target} PUBLIC cxx_std_20)

View File

@ -10,12 +10,7 @@ namespace ShaderRecompiler {
class SsaBuilder {
public:
void Rewrite(IrProgram& program) const;
void Rewrite(std::span<IrBlock* const> blocks) const;
private:
void insertPhiNodes(IrProgram& program) const;
void renameVariables(IrProgram& program) const;
void Rewrite(IrProgram& program, std::span<IrBlock* const> blocks) const;
};
}

View File

@ -0,0 +1,55 @@
#ifndef CORE_SHADER_RECOMPILIER_OPTIMIZATION_SSABUILDER_SSADEFTABLE_HPP
#define CORE_SHADER_RECOMPILIER_OPTIMIZATION_SSABUILDER_SSADEFTABLE_HPP
#include "IntermediateRepresentation/IrBlock.hpp"
#include "IntermediateRepresentation/IrValue.hpp"
#include "Optimization/SsaBuilder/SsaVariable.hpp"
#include <cstdint>
#include <unordered_map>
namespace ShaderRecompiler::Detail {
class DefTable {
public:
[[nodiscard]] IrValue* Get(IrBlock& block, ScalarReg reg) const;
void Set(IrBlock& block, ScalarReg reg, IrValue* value);
[[nodiscard]] IrValue* Get(IrBlock& block, ThreadBitScalarReg variable) const;
void Set(IrBlock& block, ThreadBitScalarReg variable, IrValue* value);
[[nodiscard]] IrValue* Get(IrBlock& block, ScalarMaskTag variable) const;
void Set(IrBlock& block, ScalarMaskTag variable, IrValue* value);
[[nodiscard]] IrValue* Get(IrBlock& block, VectorReg reg) const;
void Set(IrBlock& block, VectorReg reg, IrValue* value);
[[nodiscard]] IrValue* Get(IrBlock& block, GotoVariable variable) const;
void Set(IrBlock& block, GotoVariable variable, IrValue* value);
[[nodiscard]] IrValue* Get(IrBlock& block, SccTag variable) const;
void Set(IrBlock& block, SccTag variable, IrValue* value);
[[nodiscard]] IrValue* Get(IrBlock& block, ExecTag variable) const;
void Set(IrBlock& block, ExecTag variable, IrValue* value);
[[nodiscard]] IrValue* Get(IrBlock& block, ExecLoTag variable) const;
void Set(IrBlock& block, ExecLoTag variable, IrValue* value);
[[nodiscard]] IrValue* Get(IrBlock& block, ExecHiTag variable) const;
void Set(IrBlock& block, ExecHiTag variable, IrValue* value);
[[nodiscard]] IrValue* Get(IrBlock& block, VccTag variable) const;
void Set(IrBlock& block, VccTag variable, IrValue* value);
[[nodiscard]] IrValue* Get(IrBlock& block, VccLoTag variable) const;
void Set(IrBlock& block, VccLoTag variable, IrValue* value);
[[nodiscard]] IrValue* Get(IrBlock& block, VccHiTag variable) const;
void Set(IrBlock& block, VccHiTag variable, IrValue* value);
[[nodiscard]] IrValue* Get(IrBlock& block, M0Tag variable) const;
void Set(IrBlock& block, M0Tag variable, IrValue* value);
private:
std::unordered_map<IrBlock*, IrValue*> _scc;
std::unordered_map<IrBlock*, IrValue*> _exec;
std::unordered_map<IrBlock*, IrValue*> _execLo;
std::unordered_map<IrBlock*, IrValue*> _execHi;
std::unordered_map<IrBlock*, IrValue*> _vcc;
std::unordered_map<IrBlock*, IrValue*> _vccLo;
std::unordered_map<IrBlock*, IrValue*> _vccHi;
std::unordered_map<IrBlock*, IrValue*> _m0;
std::unordered_map<std::uint32_t, std::unordered_map<IrBlock*, IrValue*>> _gotoVariables;
};
}
#endif

View File

@ -0,0 +1,14 @@
#ifndef CORE_SHADER_RECOMPILIER_OPTIMIZATION_SSABUILDER_SSAINSTRUCTIONVISITOR_HPP
#define CORE_SHADER_RECOMPILIER_OPTIMIZATION_SSABUILDER_SSAINSTRUCTIONVISITOR_HPP
#include "IntermediateRepresentation/IrBlock.hpp"
#include "IntermediateRepresentation/IrValue.hpp"
#include "Optimization/SsaBuilder/SsaPass.hpp"
namespace ShaderRecompiler::Detail {
void VisitInstruction(Pass& pass, IrBlock& block, IrValue& inst);
}
#endif

View File

@ -0,0 +1,32 @@
#ifndef CORE_SHADER_RECOMPILIER_OPTIMIZATION_SSABUILDER_SSAPASS_HPP
#define CORE_SHADER_RECOMPILIER_OPTIMIZATION_SSABUILDER_SSAPASS_HPP
#include "IntermediateRepresentation/IrProgram.hpp"
#include "Optimization/SsaBuilder/SsaDefTable.hpp"
#include "Optimization/SsaBuilder/SsaVariable.hpp"
#include <map>
#include <unordered_map>
namespace ShaderRecompiler::Detail {
class Pass {
public:
explicit Pass(IrProgram& program) : _program(program) {}
[[nodiscard]] IrValue* Read(Variable variable, IrBlock* root);
void Write(Variable variable, IrBlock* block, IrValue* value);
void Seal(IrBlock* block);
private:
[[nodiscard]] IrValue* AddPhiOperands(Variable variable, IrValue& phi, IrBlock* block);
[[nodiscard]] IrValue* TryRemoveTrivialPhi(IrValue& phi, Variable variable);
[[nodiscard]] IrValue* MakeUndef(Variable variable);
IrProgram& _program;
DefTable _definitions;
std::unordered_map<IrBlock*, std::map<Variable, IrValue*>> _incompletePhis;
};
}
#endif

View File

@ -0,0 +1,16 @@
#ifndef CORE_SHADER_RECOMPILIER_OPTIMIZATION_SSABUILDER_SSAREGISTERSTATECLEANUP_HPP
#define CORE_SHADER_RECOMPILIER_OPTIMIZATION_SSABUILDER_SSAREGISTERSTATECLEANUP_HPP
#include "IntermediateRepresentation/IrBlock.hpp"
#include "IntermediateRepresentation/IrOpcode.hpp"
#include <span>
namespace ShaderRecompiler::Detail {
[[nodiscard]] bool IsRegisterStateWrite(IrOpcode opcode);
void RemoveRegisterStatePseudos(std::span<IrBlock* const> blocks);
}
#endif

View File

@ -0,0 +1,31 @@
#ifndef CORE_SHADER_RECOMPILIER_OPTIMIZATION_SSABUILDER_SSAVARIABLE_HPP
#define CORE_SHADER_RECOMPILIER_OPTIMIZATION_SSABUILDER_SSAVARIABLE_HPP
#include "IntermediateRepresentation/GuestRegister.hpp"
#include "IntermediateRepresentation/IrType.hpp"
#include <compare>
#include <cstdint>
#include <variant>
namespace ShaderRecompiler::Detail {
struct SccTag { auto operator<=>(const SccTag&) const = default; };
struct ThreadBitScalarReg { ScalarReg reg{}; auto operator<=>(const ThreadBitScalarReg&) const = default; };
struct ScalarMaskTag { ScalarReg reg{}; auto operator<=>(const ScalarMaskTag&) const = default; };
struct ExecTag { auto operator<=>(const ExecTag&) const = default; };
struct ExecLoTag { auto operator<=>(const ExecLoTag&) const = default; };
struct ExecHiTag { auto operator<=>(const ExecHiTag&) const = default; };
struct VccTag { auto operator<=>(const VccTag&) const = default; };
struct VccLoTag { auto operator<=>(const VccLoTag&) const = default; };
struct VccHiTag { auto operator<=>(const VccHiTag&) const = default; };
struct M0Tag { auto operator<=>(const M0Tag&) const = default; };
struct GotoVariable { std::uint32_t index = 0; auto operator<=>(const GotoVariable&) const = default; };
using Variable = std::variant<ScalarReg, ThreadBitScalarReg, ScalarMaskTag, VectorReg,
GotoVariable, SccTag, ExecTag, ExecLoTag, ExecHiTag, VccTag, VccLoTag, VccHiTag, M0Tag>;
[[nodiscard]] IrType VariableType(const Variable& variable);
}
#endif

View File

@ -1,20 +0,0 @@
#include "Optimization/SsaBuilder.hpp"
#include <stdexcept>
namespace ShaderRecompiler {
void SsaBuilder::Rewrite(IrProgram& program) const {
throw std::runtime_error("SsaBuilder::Rewrite not implemented");
}
void SsaBuilder::insertPhiNodes(IrProgram& program) const {
throw std::runtime_error("SsaBuilder::insertPhiNodes not implemented");
}
void SsaBuilder::renameVariables(IrProgram& program) const {
throw std::runtime_error("SsaBuilder::renameVariables not implemented");
}
void SsaBuilder::Rewrite(std::span<IrBlock* const> blocks) const {
throw std::runtime_error("SsaBuilder::Rewrite not implemented");
}
}

View File

@ -0,0 +1,25 @@
#include "Optimization/SsaBuilder.hpp"
#include "Optimization/SsaBuilder/SsaInstructionVisitor.hpp"
#include "Optimization/SsaBuilder/SsaPass.hpp"
#include "Optimization/SsaBuilder/SsaRegisterStateCleanup.hpp"
namespace ShaderRecompiler {
void SsaBuilder::Rewrite(IrProgram& program, std::span<IrBlock* const> blocks) const {
Detail::Pass pass(program);
for (IrBlock* block : blocks) {
for (IrValue* inst : block->Instructions()) {
Detail::VisitInstruction(pass, *block, *inst);
}
}
for (IrBlock* block : blocks) {
pass.Seal(block);
}
Detail::RemoveRegisterStatePseudos(blocks);
}
void SsaBuilder::Rewrite(IrProgram& program) const {
Rewrite(program, program.BlockOrder());
}
}

View File

@ -0,0 +1,150 @@
#include "Optimization/SsaBuilder/SsaDefTable.hpp"
#include <stdexcept>
namespace ShaderRecompiler::Detail {
IrValue* DefTable::Get(IrBlock& block, ScalarReg reg) const {
const auto index = RegIndex(reg);
if (index >= NumScalarRegs) {
throw std::out_of_range("DefTable::Get scalar register index is out of range");
}
return block.ssaScalarValues[index];
}
void DefTable::Set(IrBlock& block, ScalarReg reg, IrValue* value) {
const auto index = RegIndex(reg);
if (index >= NumScalarRegs) {
throw std::out_of_range("DefTable::Set scalar register index is out of range");
}
block.ssaScalarValues[index] = value;
}
IrValue* DefTable::Get(IrBlock& block, ThreadBitScalarReg variable) const {
const auto index = RegIndex(variable.reg);
if (index >= NumScalarRegs) {
throw std::out_of_range("DefTable::Get thread bit scalar register index is out of range");
}
return block.ssaThreadBitScalarValues[index];
}
void DefTable::Set(IrBlock& block, ThreadBitScalarReg variable, IrValue* value) {
const auto index = RegIndex(variable.reg);
if (index >= NumScalarRegs) {
throw std::out_of_range("DefTable::Set thread bit scalar register index is out of range");
}
block.ssaThreadBitScalarValues[index] = value;
}
IrValue* DefTable::Get(IrBlock& block, ScalarMaskTag variable) const {
const auto index = RegIndex(variable.reg);
if (index >= NumScalarRegs) {
throw std::out_of_range("DefTable::Get scalar mask tag index is out of range");
}
return block.ssaScalarMaskTags[index];
}
void DefTable::Set(IrBlock& block, ScalarMaskTag variable, IrValue* value) {
const auto index = RegIndex(variable.reg);
if (index >= NumScalarRegs) {
throw std::out_of_range("DefTable::Set scalar mask tag index is out of range");
}
block.ssaScalarMaskTags[index] = value;
}
IrValue* DefTable::Get(IrBlock& block, VectorReg reg) const {
return block.ssaVectorValues[RegIndex(reg)];
}
void DefTable::Set(IrBlock& block, VectorReg reg, IrValue* value) {
block.ssaVectorValues[RegIndex(reg)] = value;
}
IrValue* DefTable::Get(IrBlock& block, GotoVariable variable) const {
const auto found = _gotoVariables.find(variable.index);
if (found == _gotoVariables.end()) {
return nullptr;
}
const auto blockFound = found->second.find(&block);
if (blockFound == found->second.end()) {
return nullptr;
}
return blockFound->second;
}
void DefTable::Set(IrBlock& block, GotoVariable variable, IrValue* value) {
_gotoVariables[variable.index][&block] = value;
}
IrValue* DefTable::Get(IrBlock& block, SccTag) const {
const auto found = _scc.find(&block);
return found == _scc.end() ? nullptr : found->second;
}
void DefTable::Set(IrBlock& block, SccTag, IrValue* value) {
_scc[&block] = value;
}
IrValue* DefTable::Get(IrBlock& block, ExecTag) const {
const auto found = _exec.find(&block);
return found == _exec.end() ? nullptr : found->second;
}
void DefTable::Set(IrBlock& block, ExecTag, IrValue* value) {
_exec[&block] = value;
}
IrValue* DefTable::Get(IrBlock& block, ExecLoTag) const {
const auto found = _execLo.find(&block);
return found == _execLo.end() ? nullptr : found->second;
}
void DefTable::Set(IrBlock& block, ExecLoTag, IrValue* value) {
_execLo[&block] = value;
}
IrValue* DefTable::Get(IrBlock& block, ExecHiTag) const {
const auto found = _execHi.find(&block);
return found == _execHi.end() ? nullptr : found->second;
}
void DefTable::Set(IrBlock& block, ExecHiTag, IrValue* value) {
_execHi[&block] = value;
}
IrValue* DefTable::Get(IrBlock& block, VccTag) const {
const auto found = _vcc.find(&block);
return found == _vcc.end() ? nullptr : found->second;
}
void DefTable::Set(IrBlock& block, VccTag, IrValue* value) {
_vcc[&block] = value;
}
IrValue* DefTable::Get(IrBlock& block, VccLoTag) const {
const auto found = _vccLo.find(&block);
return found == _vccLo.end() ? nullptr : found->second;
}
void DefTable::Set(IrBlock& block, VccLoTag, IrValue* value) {
_vccLo[&block] = value;
}
IrValue* DefTable::Get(IrBlock& block, VccHiTag) const {
const auto found = _vccHi.find(&block);
return found == _vccHi.end() ? nullptr : found->second;
}
void DefTable::Set(IrBlock& block, VccHiTag, IrValue* value) {
_vccHi[&block] = value;
}
IrValue* DefTable::Get(IrBlock& block, M0Tag) const {
const auto found = _m0.find(&block);
return found == _m0.end() ? nullptr : found->second;
}
void DefTable::Set(IrBlock& block, M0Tag, IrValue* value) {
_m0[&block] = value;
}
}

View File

@ -0,0 +1,78 @@
#include "Optimization/SsaBuilder/SsaInstructionVisitor.hpp"
#include <stdexcept>
namespace ShaderRecompiler::Detail {
namespace {
ScalarReg expectScalarRegister(IrValue& operand, RegisterBank bank) {
const GuestRegister reg = operand.Register();
if (reg.bank != bank) {
throw std::runtime_error("SsaInstructionVisitor expected a scalar register operand");
}
return static_cast<ScalarReg>(reg.index);
}
VectorReg expectVectorRegister(IrValue& operand, RegisterBank bank) {
const GuestRegister reg = operand.Register();
if (reg.bank != bank) {
throw std::runtime_error("SsaInstructionVisitor expected a vector register operand");
}
return static_cast<VectorReg>(reg.index);
}
}
void VisitInstruction(Pass& pass, IrBlock& block, IrValue& inst) {
switch (inst.Opcode()) {
case IrOpcode::SetScalarRegister:
pass.Write(expectScalarRegister(*inst.Argument(0), RegisterBank::Scalar), &block, inst.Argument(1));
break;
case IrOpcode::SetThreadBitScalarRegister:
pass.Write(ThreadBitScalarReg{expectScalarRegister(*inst.Argument(0), RegisterBank::ThreadBitScalar)}, &block, inst.Argument(1));
break;
case IrOpcode::SetScalarMaskTag:
pass.Write(ScalarMaskTag{expectScalarRegister(*inst.Argument(0), RegisterBank::ScalarMaskTag)}, &block, inst.Argument(1));
break;
case IrOpcode::SetVectorRegister:
pass.Write(expectVectorRegister(*inst.Argument(0), RegisterBank::Vector), &block, inst.Argument(1));
break;
case IrOpcode::SetGotoVariable:
pass.Write(GotoVariable{inst.Argument(0)->ImmediateU32()}, &block, inst.Argument(1));
break;
case IrOpcode::SetScc: pass.Write(SccTag{}, &block, inst.Argument(0)); break;
case IrOpcode::SetExec: pass.Write(ExecTag{}, &block, inst.Argument(0)); break;
case IrOpcode::SetExecLo: pass.Write(ExecLoTag{}, &block, inst.Argument(0)); break;
case IrOpcode::SetExecHi: pass.Write(ExecHiTag{}, &block, inst.Argument(0)); break;
case IrOpcode::SetVcc: pass.Write(VccTag{}, &block, inst.Argument(0)); break;
case IrOpcode::SetVccLo: pass.Write(VccLoTag{}, &block, inst.Argument(0)); break;
case IrOpcode::SetVccHi: pass.Write(VccHiTag{}, &block, inst.Argument(0)); break;
case IrOpcode::SetM0: pass.Write(M0Tag{}, &block, inst.Argument(0)); break;
case IrOpcode::GetScalarRegister:
inst.ReplaceUsesWith(pass.Read(expectScalarRegister(*inst.Argument(0), RegisterBank::Scalar), &block), true);
break;
case IrOpcode::GetThreadBitScalarRegister:
inst.ReplaceUsesWith(pass.Read(ThreadBitScalarReg{expectScalarRegister(*inst.Argument(0), RegisterBank::ThreadBitScalar)}, &block), true);
break;
case IrOpcode::GetScalarMaskTag:
inst.ReplaceUsesWith(pass.Read(ScalarMaskTag{expectScalarRegister(*inst.Argument(0), RegisterBank::ScalarMaskTag)}, &block), true);
break;
case IrOpcode::GetVectorRegister:
inst.ReplaceUsesWith(pass.Read(expectVectorRegister(*inst.Argument(0), RegisterBank::Vector), &block), true);
break;
case IrOpcode::GetGotoVariable:
inst.ReplaceUsesWith(pass.Read(GotoVariable{inst.Argument(0)->ImmediateU32()}, &block), true);
break;
case IrOpcode::GetScc: inst.ReplaceUsesWith(pass.Read(SccTag{}, &block), true); break;
case IrOpcode::GetExec: inst.ReplaceUsesWith(pass.Read(ExecTag{}, &block), true); break;
case IrOpcode::GetExecLo: inst.ReplaceUsesWith(pass.Read(ExecLoTag{}, &block), true); break;
case IrOpcode::GetExecHi: inst.ReplaceUsesWith(pass.Read(ExecHiTag{}, &block), true); break;
case IrOpcode::GetVcc: inst.ReplaceUsesWith(pass.Read(VccTag{}, &block), true); break;
case IrOpcode::GetVccLo: inst.ReplaceUsesWith(pass.Read(VccLoTag{}, &block), true); break;
case IrOpcode::GetVccHi: inst.ReplaceUsesWith(pass.Read(VccHiTag{}, &block), true); break;
case IrOpcode::GetM0: inst.ReplaceUsesWith(pass.Read(M0Tag{}, &block), true); break;
default: break;
}
}
}

View File

@ -0,0 +1,134 @@
#include "Optimization/SsaBuilder/SsaPass.hpp"
#include <cstddef>
#include <vector>
namespace ShaderRecompiler::Detail {
namespace {
enum class ReadStep { Start, SetValue, PushPhiArgument };
struct ReadState {
IrBlock* block = nullptr;
IrValue* result = nullptr;
IrValue* phi = nullptr;
std::size_t pred = 0;
ReadStep step = ReadStep::Start;
};
}
void Pass::Write(Variable variable, IrBlock* block, IrValue* value) {
std::visit([&](auto tag) { _definitions.Set(*block, tag, value); }, variable);
}
IrValue* Pass::Read(Variable variable, IrBlock* root) {
std::vector<ReadState> stack{ReadState{}, ReadState{.block = root}};
const auto preparePhi = [&]() {
auto& state = stack.back();
const auto& predecessors = state.block->Predecessors();
if (state.pred == predecessors.size()) {
IrValue* result = TryRemoveTrivialPhi(*state.phi, variable);
IrBlock* block = state.block;
stack.pop_back();
stack.back().result = result;
Write(variable, block, result);
return;
}
state.step = ReadStep::PushPhiArgument;
stack.push_back(ReadState{.block = predecessors[state.pred]});
};
do {
auto& state = stack.back();
IrBlock* block = state.block;
switch (state.step) {
case ReadStep::Start: {
IrValue* def = std::visit([&](auto tag) { return _definitions.Get(*block, tag); }, variable);
if (def != nullptr) {
state.result = def;
} else if (!block->IsSsaSealed()) {
IrValue& phi = _program.CreateValue(IrOpcode::Phi, VariableType(variable));
block->InsertInstructionBefore(nullptr, &phi);
_incompletePhis[block][variable] = &phi;
state.result = &phi;
} else if (const auto& predecessors = block->Predecessors(); predecessors.size() == 1) {
state.step = ReadStep::SetValue;
stack.push_back(ReadState{.block = predecessors.front()});
break;
} else {
IrValue& phi = _program.CreateValue(IrOpcode::Phi, VariableType(variable));
block->InsertInstructionBefore(nullptr, &phi);
Write(variable, block, &phi);
state.phi = &phi;
preparePhi();
break;
}
[[fallthrough]];
}
case ReadStep::SetValue: {
IrValue* result = state.result;
Write(variable, block, result);
stack.pop_back();
stack.back().result = result;
break;
}
case ReadStep::PushPhiArgument: {
const auto& predecessors = block->Predecessors();
state.phi->AddPhiOperand(predecessors[state.pred], state.result);
state.pred++;
preparePhi();
break;
}
}
} while (stack.size() > 1);
return stack.back().result;
}
void Pass::Seal(IrBlock* block) {
if (const auto found = _incompletePhis.find(block); found != _incompletePhis.end()) {
for (auto& [variable, phi] : found->second) {
AddPhiOperands(variable, *phi, block);
}
}
block->SsaSeal();
}
IrValue* Pass::AddPhiOperands(Variable variable, IrValue& phi, IrBlock* block) {
for (IrBlock* predecessor : block->Predecessors()) {
phi.AddPhiOperand(predecessor, Read(variable, predecessor));
}
return TryRemoveTrivialPhi(phi, variable);
}
IrValue* Pass::TryRemoveTrivialPhi(IrValue& phi, Variable variable) {
IrValue* same = nullptr;
for (std::size_t index = 0; index < phi.ArgumentCount(); index++) {
IrValue* operand = phi.Argument(index)->Resolve();
if (operand == same || operand == &phi) {
continue;
}
if (same != nullptr) {
return &phi;
}
same = operand;
}
if (same == nullptr) {
same = MakeUndef(variable);
}
std::vector<IrValue*> users = phi.Uses();
phi.ReplaceUsesWith(same, true);
for (IrValue* user : users) {
if (user->IsPhi()) {
TryRemoveTrivialPhi(*user, variable);
}
}
return same;
}
IrValue* Pass::MakeUndef(Variable variable) {
const IrType type = VariableType(variable);
const IrOpcode opcode = (type == IrType::Bool) ? IrOpcode::UndefU1 : IrOpcode::UndefU32;
return &_program.CreateValue(opcode, type);
}
}

View File

@ -0,0 +1,42 @@
#include "Optimization/SsaBuilder/SsaRegisterStateCleanup.hpp"
namespace ShaderRecompiler::Detail {
bool IsRegisterStateWrite(IrOpcode opcode) {
switch (opcode) {
case IrOpcode::SetScalarRegister:
case IrOpcode::SetThreadBitScalarRegister:
case IrOpcode::SetScalarMaskTag:
case IrOpcode::SetVectorRegister:
case IrOpcode::SetGotoVariable:
case IrOpcode::SetScc:
case IrOpcode::SetExec:
case IrOpcode::SetExecLo:
case IrOpcode::SetExecHi:
case IrOpcode::SetVcc:
case IrOpcode::SetVccLo:
case IrOpcode::SetVccHi:
case IrOpcode::SetM0:
return true;
default:
return false;
}
}
void RemoveRegisterStatePseudos(std::span<IrBlock* const> blocks) {
for (IrBlock* block : blocks) {
auto& instructions = block->Instructions();
for (auto it = instructions.begin(); it != instructions.end();) {
IrValue* inst = *it;
if (!IsRegisterStateWrite(inst->Opcode())) {
++it;
continue;
}
inst->Invalidate();
it = instructions.erase(it);
inst->SetParent(nullptr);
}
}
}
}

View File

@ -0,0 +1,29 @@
#include "Optimization/SsaBuilder/SsaVariable.hpp"
namespace ShaderRecompiler::Detail {
namespace {
struct VariableTypeVisitor {
IrType operator()(ScalarReg) const { return IrType::U32; }
IrType operator()(ThreadBitScalarReg) const { return IrType::Bool; }
IrType operator()(ScalarMaskTag) const { return IrType::Bool; }
IrType operator()(VectorReg) const { return IrType::U32; }
IrType operator()(GotoVariable) const { return IrType::Bool; }
IrType operator()(SccTag) const { return IrType::Bool; }
IrType operator()(ExecTag) const { return IrType::Bool; }
IrType operator()(ExecLoTag) const { return IrType::U32; }
IrType operator()(ExecHiTag) const { return IrType::U32; }
IrType operator()(VccTag) const { return IrType::Bool; }
IrType operator()(VccLoTag) const { return IrType::U32; }
IrType operator()(VccHiTag) const { return IrType::U32; }
IrType operator()(M0Tag) const { return IrType::U32; }
};
}
IrType VariableType(const Variable& variable) {
return std::visit(VariableTypeVisitor{}, variable);
}
}