feat(shader): add ssa building impl for recompiler
This commit is contained in:
parent
3400a2b6e5
commit
6f0ccde6ff
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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] = φ
|
||||
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<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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue