diff --git a/core/shader/recompiler/CMakeLists.txt b/core/shader/recompiler/CMakeLists.txt index a54e0ff2d..6d8501495 100644 --- a/core/shader/recompiler/CMakeLists.txt +++ b/core/shader/recompiler/CMakeLists.txt @@ -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) diff --git a/core/shader/recompiler/Optimization/include/Optimization/SsaBuilder.hpp b/core/shader/recompiler/Optimization/include/Optimization/SsaBuilder.hpp index 7497af0f1..68faee1f0 100644 --- a/core/shader/recompiler/Optimization/include/Optimization/SsaBuilder.hpp +++ b/core/shader/recompiler/Optimization/include/Optimization/SsaBuilder.hpp @@ -10,12 +10,7 @@ namespace ShaderRecompiler { class SsaBuilder { public: void Rewrite(IrProgram& program) const; - - void Rewrite(std::span blocks) const; - -private: - void insertPhiNodes(IrProgram& program) const; - void renameVariables(IrProgram& program) const; + void Rewrite(IrProgram& program, std::span blocks) const; }; } diff --git a/core/shader/recompiler/Optimization/include/Optimization/SsaBuilder/SsaDefTable.hpp b/core/shader/recompiler/Optimization/include/Optimization/SsaBuilder/SsaDefTable.hpp new file mode 100644 index 000000000..d0ea8d6da --- /dev/null +++ b/core/shader/recompiler/Optimization/include/Optimization/SsaBuilder/SsaDefTable.hpp @@ -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 +#include + +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 _scc; + std::unordered_map _exec; + std::unordered_map _execLo; + std::unordered_map _execHi; + std::unordered_map _vcc; + std::unordered_map _vccLo; + std::unordered_map _vccHi; + std::unordered_map _m0; + std::unordered_map> _gotoVariables; +}; + +} + +#endif diff --git a/core/shader/recompiler/Optimization/include/Optimization/SsaBuilder/SsaInstructionVisitor.hpp b/core/shader/recompiler/Optimization/include/Optimization/SsaBuilder/SsaInstructionVisitor.hpp new file mode 100644 index 000000000..4af398cc3 --- /dev/null +++ b/core/shader/recompiler/Optimization/include/Optimization/SsaBuilder/SsaInstructionVisitor.hpp @@ -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 diff --git a/core/shader/recompiler/Optimization/include/Optimization/SsaBuilder/SsaPass.hpp b/core/shader/recompiler/Optimization/include/Optimization/SsaBuilder/SsaPass.hpp new file mode 100644 index 000000000..350b17ba8 --- /dev/null +++ b/core/shader/recompiler/Optimization/include/Optimization/SsaBuilder/SsaPass.hpp @@ -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 +#include + +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> _incompletePhis; +}; + +} + +#endif diff --git a/core/shader/recompiler/Optimization/include/Optimization/SsaBuilder/SsaRegisterStateCleanup.hpp b/core/shader/recompiler/Optimization/include/Optimization/SsaBuilder/SsaRegisterStateCleanup.hpp new file mode 100644 index 000000000..246694551 --- /dev/null +++ b/core/shader/recompiler/Optimization/include/Optimization/SsaBuilder/SsaRegisterStateCleanup.hpp @@ -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 + +namespace ShaderRecompiler::Detail { + +[[nodiscard]] bool IsRegisterStateWrite(IrOpcode opcode); + +void RemoveRegisterStatePseudos(std::span blocks); + +} + +#endif diff --git a/core/shader/recompiler/Optimization/include/Optimization/SsaBuilder/SsaVariable.hpp b/core/shader/recompiler/Optimization/include/Optimization/SsaBuilder/SsaVariable.hpp new file mode 100644 index 000000000..a17a4525d --- /dev/null +++ b/core/shader/recompiler/Optimization/include/Optimization/SsaBuilder/SsaVariable.hpp @@ -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 +#include +#include + +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; + +[[nodiscard]] IrType VariableType(const Variable& variable); + +} + +#endif diff --git a/core/shader/recompiler/Optimization/src/SsaBuilder.cpp b/core/shader/recompiler/Optimization/src/SsaBuilder.cpp deleted file mode 100644 index df82518c4..000000000 --- a/core/shader/recompiler/Optimization/src/SsaBuilder.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "Optimization/SsaBuilder.hpp" -#include - -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 blocks) const { - throw std::runtime_error("SsaBuilder::Rewrite not implemented"); -} - -} diff --git a/core/shader/recompiler/Optimization/src/SsaBuilder/SsaBuilder.cpp b/core/shader/recompiler/Optimization/src/SsaBuilder/SsaBuilder.cpp new file mode 100644 index 000000000..43a841a69 --- /dev/null +++ b/core/shader/recompiler/Optimization/src/SsaBuilder/SsaBuilder.cpp @@ -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 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()); +} + +} diff --git a/core/shader/recompiler/Optimization/src/SsaBuilder/SsaDefTable.cpp b/core/shader/recompiler/Optimization/src/SsaBuilder/SsaDefTable.cpp new file mode 100644 index 000000000..3a1415333 --- /dev/null +++ b/core/shader/recompiler/Optimization/src/SsaBuilder/SsaDefTable.cpp @@ -0,0 +1,150 @@ +#include "Optimization/SsaBuilder/SsaDefTable.hpp" +#include + +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; +} + +} diff --git a/core/shader/recompiler/Optimization/src/SsaBuilder/SsaInstructionVisitor.cpp b/core/shader/recompiler/Optimization/src/SsaBuilder/SsaInstructionVisitor.cpp new file mode 100644 index 000000000..b66567845 --- /dev/null +++ b/core/shader/recompiler/Optimization/src/SsaBuilder/SsaInstructionVisitor.cpp @@ -0,0 +1,78 @@ +#include "Optimization/SsaBuilder/SsaInstructionVisitor.hpp" +#include + +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(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(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; + } +} + +} diff --git a/core/shader/recompiler/Optimization/src/SsaBuilder/SsaPass.cpp b/core/shader/recompiler/Optimization/src/SsaBuilder/SsaPass.cpp new file mode 100644 index 000000000..dd5190b6d --- /dev/null +++ b/core/shader/recompiler/Optimization/src/SsaBuilder/SsaPass.cpp @@ -0,0 +1,134 @@ +#include "Optimization/SsaBuilder/SsaPass.hpp" +#include +#include + +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 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] = φ + state.result = φ + } 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 = φ + 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 φ + } + same = operand; + } + if (same == nullptr) { + same = MakeUndef(variable); + } + std::vector 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); +} + +} diff --git a/core/shader/recompiler/Optimization/src/SsaBuilder/SsaRegisterStateCleanup.cpp b/core/shader/recompiler/Optimization/src/SsaBuilder/SsaRegisterStateCleanup.cpp new file mode 100644 index 000000000..8854b2ae2 --- /dev/null +++ b/core/shader/recompiler/Optimization/src/SsaBuilder/SsaRegisterStateCleanup.cpp @@ -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 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); + } + } +} + +} diff --git a/core/shader/recompiler/Optimization/src/SsaBuilder/SsaVariable.cpp b/core/shader/recompiler/Optimization/src/SsaBuilder/SsaVariable.cpp new file mode 100644 index 000000000..4f053fc22 --- /dev/null +++ b/core/shader/recompiler/Optimization/src/SsaBuilder/SsaVariable.cpp @@ -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); +} + +}