diff --git a/rpcsx-gpu2/lib/gcn-shader/include/shader/SpvConverter.hpp b/rpcsx-gpu2/lib/gcn-shader/include/shader/SpvConverter.hpp index 0c4ae8c35..05ef9070c 100644 --- a/rpcsx-gpu2/lib/gcn-shader/include/shader/SpvConverter.hpp +++ b/rpcsx-gpu2/lib/gcn-shader/include/shader/SpvConverter.hpp @@ -33,6 +33,7 @@ struct Context : ir::Context { void setConstantName(ir::Value constant); ir::Value getOrCreateConstant(ir::Value typeValue, const ir::Operand &value); + ir::Value getNull(ir::Value typeValue); ir::Value getType(ir::spv::Op baseType, int width, bool isSigned); ir::Value getType(const TypeInfo &info); diff --git a/rpcsx-gpu2/lib/gcn-shader/src/SpvConverter.cpp b/rpcsx-gpu2/lib/gcn-shader/src/SpvConverter.cpp index 6e861c89f..e01ded15f 100644 --- a/rpcsx-gpu2/lib/gcn-shader/src/SpvConverter.cpp +++ b/rpcsx-gpu2/lib/gcn-shader/src/SpvConverter.cpp @@ -321,15 +321,19 @@ void spv::Context::setConstantName(ir::Value constant) { } ir::Value spv::Context::getOrCreateConstant(ir::Value typeValue, - const ir::Operand &value) { + const ir::Operand &value) { if (typeValue == getTypeBool()) { return *value.getAsBool() ? getTrue() : getFalse(); } return getOrCreateGlobal(ir::spv::OpConstant, {{typeValue, value}}); } +ir::Value spv::Context::getNull(ir::Value typeValue) { + return getOrCreateGlobal(ir::spv::OpConstantNull, {{typeValue}}); +} + ir::Value spv::Context::getType(ir::spv::Op baseType, int width, - bool isSigned) { + bool isSigned) { switch (baseType) { case ir::spv::OpTypeInt: return getTypeInt(width, isSigned); @@ -377,7 +381,7 @@ void spv::Context::setTypeName(ir::Value type) { ir::Value spv::Context::findGlobal(ir::spv::Op op, - std::span operands) const { + std::span operands) const { auto it = globals.find(ir::getInstructionId(ir::Kind::Spv, op)); if (it == globals.end()) { @@ -407,9 +411,8 @@ spv::Context::findGlobal(ir::spv::Op op, return nullptr; } -ir::Value -spv::Context::createGlobal(ir::spv::Op op, - std::span operands) { +ir::Value spv::Context::createGlobal(ir::spv::Op op, + std::span operands) { auto builder = Builder::createAppend(*this, layout.getOrCreateGlobals(*this)); auto result = builder.createValue(getUnknownLocation(), ir::Kind::Spv, op, operands); @@ -423,8 +426,9 @@ spv::Context::createGlobal(ir::spv::Op op, return result; } -ir::Value spv::Context::getOrCreateGlobal( - ir::spv::Op op, std::span operands) { +ir::Value +spv::Context::getOrCreateGlobal(ir::spv::Op op, + std::span operands) { if (auto result = findGlobal(op, operands)) { return result; } @@ -432,8 +436,7 @@ ir::Value spv::Context::getOrCreateGlobal( return createGlobal(op, operands); } -ir::Value spv::Context::getOperandValue(const ir::Operand &op, - ir::Value type) { +ir::Value spv::Context::getOperandValue(const ir::Operand &op, ir::Value type) { if (auto result = op.getAsValue()) { return result; } @@ -504,9 +507,8 @@ void spv::Context::createPerVertex() { ir::spv::StorageClass::Output); } -ir::Value spv::Context::createUniformBuffer(int descriptorSet, - int binding, - ir::Value structType) { +ir::Value spv::Context::createUniformBuffer(int descriptorSet, int binding, + ir::Value structType) { auto globals = Builder::createAppend(*this, layout.getOrCreateGlobals(*this)); auto annotations = Builder::createAppend(*this, layout.getOrCreateAnnotations(*this)); @@ -526,8 +528,9 @@ ir::Value spv::Context::createUniformBuffer(int descriptorSet, return blockVariable; } -ir::Value spv::Context::createRuntimeArrayUniformBuffer( - int descriptorSet, int binding, ir::Value elementType) { +ir::Value spv::Context::createRuntimeArrayUniformBuffer(int descriptorSet, + int binding, + ir::Value elementType) { auto globals = Builder::createAppend(*this, layout.getOrCreateGlobals(*this)); auto annotations = Builder::createAppend(*this, layout.getOrCreateAnnotations(*this)); @@ -602,8 +605,8 @@ ir::Value spv::Context::createInput(ir::Location loc, int index) { return result; } -ir::Value spv::Context::createAttr(ir::Location loc, int attrId, - bool perVertex, bool flat) { +ir::Value spv::Context::createAttr(ir::Location loc, int attrId, bool perVertex, + bool flat) { auto &result = inputs[attrId]; if (result == nullptr) { diff --git a/rpcsx-gpu2/lib/gcn-shader/src/gcn.cpp b/rpcsx-gpu2/lib/gcn-shader/src/gcn.cpp index deac7e0ad..fcd017e28 100644 --- a/rpcsx-gpu2/lib/gcn-shader/src/gcn.cpp +++ b/rpcsx-gpu2/lib/gcn-shader/src/gcn.cpp @@ -1,29 +1,27 @@ #include "gcn.hpp" - #include "Evaluator.hpp" +#include "GcnInstruction.hpp" #include "SemanticInfo.hpp" #include "SpvConverter.hpp" #include "analyze.hpp" +#include "dialect.hpp" #include "ir.hpp" +#include "spv.hpp" +#include "transform.hpp" + +#include + +#include +#include +#include +#include #include #include #include - -#include "GcnInstruction.hpp" -#include "dialect.hpp" -#include "ir/Region.hpp" -#include "ir/Value.hpp" - -#include "spv.hpp" -#include "transform.hpp" -#include -#include -#include #include #include #include -#include #include #include #include @@ -716,6 +714,13 @@ static ir::Value deserializeGcnRegion( ir::Value uint64TV = converter.getTypeUInt64(); ir::Value sint64TV = converter.getTypeSInt64(); + auto execTestSem = + semInfo.findSemantic(ir::getInstructionId(ir::amdgpu::EXEC_TEST)); + + if (execTestSem == nullptr) { + rx::die("Failed to find semantic of EXEC_TEST"); + } + unsigned currentOp = 0; auto createOperandReadImpl = [&](ir::Location loc, gcn::Builder &builder, @@ -917,14 +922,9 @@ static ir::Value deserializeGcnRegion( } }; - auto createOperandWrite = [&](ir::Location loc, gcn::Builder &builder, - const GcnOperand &op, ir::Value value, - ir::Value lane = nullptr) { - if (op.clamp || op.omod != 0) { - value = builder.createValue(loc, ir::amdgpu::OMOD, value.getOperand(0), - op.clamp, op.omod, value); - } - + auto createOperandWriteImpl = [&](ir::Location loc, gcn::Builder &builder, + const GcnOperand &op, ir::Value value, + ir::Value lane) { switch (op.kind) { case GcnOperand::Kind::Constant: case GcnOperand::Kind::Immediate: @@ -966,6 +966,33 @@ static ir::Value deserializeGcnRegion( std::abort(); }; + auto createOperandWrite = [&](ir::Location loc, gcn::Builder &builder, + bool injectExecTest, const GcnOperand &op, + ir::Value value, ir::Value lane = nullptr) { + if (op.clamp || op.omod != 0) { + value = builder.createValue(loc, ir::amdgpu::OMOD, value.getOperand(0), + op.clamp, op.omod, value); + } + + if (injectExecTest) { + ir::Value testFailureValue; + auto type = value.getOperand(0).getAsValue(); + if (op.kind == GcnOperand::Kind::Sgpr) { + testFailureValue = converter.getNull(type); + } else { + testFailureValue = createOperandRead(loc, builder, type, op); + } + + auto exec = + builder.createValue(loc, ir::amdgpu::EXEC_TEST, + converter.getType(execTestSem->returnType)); + + value = builder.createSpvSelect(loc, type, exec, value, testFailureValue); + } + + return createOperandWriteImpl(loc, builder, op, value, lane); + }; + if (converter.body == nullptr) { converter.body = converter.create(locBuilder.getLocation(address)); @@ -978,33 +1005,27 @@ static ir::Value deserializeGcnRegion( bodyRegion, address) .first; - auto execTestSem = - semInfo.findSemantic(ir::getInstructionId(ir::amdgpu::EXEC_TEST)); + auto requiresExecTest = [&](ir::InstructionId instId) { + switch (ir::getInstructionKind(instId)) { + case ir::Kind::Sop2: + case ir::Kind::Smrd: + case ir::Kind::Sopc: + case ir::Kind::Sopk: + case ir::Kind::Sop1: + case ir::Kind::Sopp: + return false; + default: + break; + } - if (execTestSem == nullptr) { - std::fprintf(stderr, "Failed to find semantic of EXEC_TEST\n"); - std::abort(); - } + if (instId == ir::vop1::READFIRSTLANE_B32 || + instId == ir::vop2::READLANE_B32 || instId == ir::vop2::WRITELANE_B32 || + instId == ir::vop3::READFIRSTLANE_B32 || + instId == ir::vop3::READLANE_B32 || instId == ir::vop3::WRITELANE_B32) { + return false; + } - auto injectExecTest = [&](ir::Location loc, gcn::Builder &builder, - ir::Instruction point) { - return; - auto mergeBlock = builder.createSpvLabel(loc); - gcn::Builder::createInsertBefore(converter, mergeBlock) - .createSpvBranch(loc, mergeBlock); - - auto instBlock = - gcn::Builder::createInsertAfter(converter, point).createSpvLabel(loc); - auto prependInstBuilder = - gcn::Builder::createInsertBefore(converter, instBlock); - - auto exec = prependInstBuilder.createValue( - loc, ir::amdgpu::EXEC_TEST, converter.getType(execTestSem->returnType)); - - prependInstBuilder.createSpvSelectionMerge(loc, mergeBlock, - ir::spv::SelectionControl::None); - prependInstBuilder.createSpvBranchConditional(loc, exec, instBlock, - mergeBlock); + return true; }; std::vector workList; @@ -1050,6 +1071,9 @@ static ir::Value deserializeGcnRegion( auto builder = converter.createBuilder(instRegion, bodyRegion, instStart); auto instrBegin = builder.getInsertionPoint(); + auto injectExecTest = + requiresExecTest(ir::getInstructionId(isaInst.kind, isaInst.op)); + auto variablesBuilder = gcn::Builder::createAppend(converter, converter.localVariables); @@ -1085,7 +1109,7 @@ static ir::Value deserializeGcnRegion( if (isaInst == ir::sop1::SWAPPC_B64) { auto target = createOperandRead(loc, builder, uint64TV, isaInst.getOperand(1)); - createOperandWrite(loc, builder, isaInst.getOperand(0), + createOperandWrite(loc, builder, injectExecTest, isaInst.getOperand(0), converter.imm64(instAddress)); branchesToUnknown.push_back(builder.createInstruction( loc, ir::Kind::AmdGpu, ir::amdgpu::BRANCH, target)); @@ -1093,7 +1117,7 @@ static ir::Value deserializeGcnRegion( } if (isaInst == ir::sop1::GETPC_B64) { - createOperandWrite(loc, builder, isaInst.getOperand(0), + createOperandWrite(loc, builder, injectExecTest, isaInst.getOperand(0), converter.imm64(instAddress)); continue; } @@ -1164,7 +1188,7 @@ static ir::Value deserializeGcnRegion( srcIndex = builder.createSpvSelect(loc, uint32TV, srcInBounds, srcIndex, converter.imm32(0)); createOperandWrite( - loc, builder, isaInst.getOperand(0), + loc, builder, injectExecTest, isaInst.getOperand(0), converter.readReg( loc, builder, (isaInst == ir::sop1::MOVRELS_B64 ? uint64TV : uint32TV), @@ -1224,12 +1248,7 @@ static ir::Value deserializeGcnRegion( auto regTypeValue = is64Bit ? uint64TV : uint32TV; auto value = createOperandRead(loc, builder, regTypeValue, operands[1]); - createOperandWrite(loc, builder, operands[0], value); - - if (isaInst.kind == ir::Kind::Vop1 || - isaInst.kind == ir::Kind::Vop3) { - injectExecTest(loc, builder, instrBegin); - } + createOperandWrite(loc, builder, injectExecTest, operands[0], value); continue; } @@ -1249,7 +1268,6 @@ static ir::Value deserializeGcnRegion( inst.addOperand(createOperandRead(loc, paramBuilder, uint32TV, op)); } - injectExecTest(loc, builder, instrBegin); continue; } @@ -1297,7 +1315,8 @@ static ir::Value deserializeGcnRegion( loc, float32TV, createOperandRead(loc, builder, float32TV, isaInst.getOperand(2))); - createOperandWrite(loc, builder, isaInst.getOperand(0), rawValue); + createOperandWrite(loc, builder, injectExecTest, isaInst.getOperand(0), + rawValue); } continue; @@ -1359,7 +1378,7 @@ static ir::Value deserializeGcnRegion( } if (resultOperand) { - createOperandWrite(loc, builder, *resultOperand, inst); + createOperandWrite(loc, builder, injectExecTest, *resultOperand, inst); } for (std::size_t index = 0; auto &op : operands) { @@ -1373,25 +1392,8 @@ static ir::Value deserializeGcnRegion( auto paramType = converter.getType(params[opIndex].type); auto value = builder.createSpvLoad(loc, paramType, arg); - createOperandWrite(loc, builder, op, value); + createOperandWrite(loc, builder, injectExecTest, op, value); } - - if (isaInst.kind == ir::Kind::Sop2 || isaInst.kind == ir::Kind::Sopk || - isaInst.kind == ir::Kind::Smrd || isaInst.kind == ir::Kind::Sop1 || - isaInst.kind == ir::Kind::Sopc || isaInst.kind == ir::Kind::Sopp) { - continue; - } - - if (isaInst == ir::vop1::READFIRSTLANE_B32 || - isaInst == ir::vop2::READLANE_B32 || - isaInst == ir::vop2::WRITELANE_B32 || - isaInst == ir::vop3::READFIRSTLANE_B32 || - isaInst == ir::vop3::READLANE_B32 || - isaInst == ir::vop3::WRITELANE_B32) { - continue; - } - - injectExecTest(loc, builder, instrBegin); } converter.analysis.invalidateAll();