From f4994f6717ff4ac01a665282050931d25de1bf17 Mon Sep 17 00:00:00 2001 From: DH Date: Thu, 14 Nov 2024 00:06:52 +0300 Subject: [PATCH] gpu: extend resource evaluation rules to handle relative resources implement evaluation of x16 dword loads fixed evaluation of binary expressions --- rpcsx/gpu/Cache.cpp | 18 +- .../include/shader/GcnConverter.hpp | 2 +- .../lib/gcn-shader/include/shader/analyze.hpp | 15 +- .../lib/gcn-shader/include/shader/eval.hpp | 5 +- rpcsx/gpu/lib/gcn-shader/src/GcnConverter.cpp | 410 ++++++++++++++---- rpcsx/gpu/lib/gcn-shader/src/analyze.cpp | 62 ++- rpcsx/gpu/lib/gcn-shader/src/eval.cpp | 23 +- 7 files changed, 419 insertions(+), 116 deletions(-) diff --git a/rpcsx/gpu/Cache.cpp b/rpcsx/gpu/Cache.cpp index 7b688859..a63a8bb0 100644 --- a/rpcsx/gpu/Cache.cpp +++ b/rpcsx/gpu/Cache.cpp @@ -146,6 +146,13 @@ static ConverterFn *getPrimConverterFn(gnm::PrimitiveType primType, static_cast(primType)); } } +shader::eval::Value Cache::ShaderResources::eval(shader::ir::Value op) { + if (op == ir::sop2::ADD_U32 || op == ir::sop2::ADDC_U32) { + return eval(op.getOperand(1)) + eval(op.getOperand(2)); + } + + return Evaluator::eval(op); +} void Cache::ShaderResources::loadResources( gcn::Resources &res, std::span userSgprs) { @@ -454,8 +461,11 @@ Cache::ShaderResources::eval(ir::InstructionId instId, case 32: result = readPointer>(address); break; + case 64: + result = readPointer>(address); + break; default: - rx::die("unexpected pointer load size"); + rx::die("unexpected pointer load size %u", loadSize); } return result; @@ -1275,9 +1285,9 @@ Cache::Shader Cache::Tag::getShader(const ShaderKey &key, // deserialized.print(std::cerr, context.ns); - converted = gcn::convertToSpv(context, deserialized, - mParent->mDevice->gcnSemanticModuleInfo, - key.stage, env); + converted = gcn::convertToSpv( + context, deserialized, mParent->mDevice->gcnSemantic, + mParent->mDevice->gcnSemanticModuleInfo, key.stage, env); if (!converted) { return {}; } diff --git a/rpcsx/gpu/lib/gcn-shader/include/shader/GcnConverter.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/GcnConverter.hpp index c45932db..6bcdcba4 100644 --- a/rpcsx/gpu/lib/gcn-shader/include/shader/GcnConverter.hpp +++ b/rpcsx/gpu/lib/gcn-shader/include/shader/GcnConverter.hpp @@ -211,7 +211,7 @@ struct ConvertedShader { std::optional convertToSpv(Context &context, ir::Region body, + const SemanticInfo &semanticInfo, const SemanticModuleInfo &semanticModule, Stage stage, const Environment &state); - } // namespace shader::gcn diff --git a/rpcsx/gpu/lib/gcn-shader/include/shader/analyze.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/analyze.hpp index a4ce417d..f7d8af27 100644 --- a/rpcsx/gpu/lib/gcn-shader/include/shader/analyze.hpp +++ b/rpcsx/gpu/lib/gcn-shader/include/shader/analyze.hpp @@ -191,7 +191,8 @@ CFG buildCFG(ir::Instruction firstInstruction, MemorySSA buildMemorySSA(CFG &cfg, ModuleInfo *moduleInfo = nullptr); MemorySSA buildMemorySSA(CFG &cfg, const SemanticInfo &instructionSemantic, - std::function getRegisterVarCb); + std::function getRegisterVarCb, + ModuleInfo *moduleInfo = nullptr); bool dominates(ir::Instruction a, ir::Instruction b, bool isPostDom, graph::DomTree &domTree); @@ -385,10 +386,8 @@ struct Construct { CFG &getCfg() { return analysis.get([this] { if (parent != nullptr) { - return parent->getCfg().buildView( - header, - &parent->getPostDomTree(), - {header, merge}); + return parent->getCfg().buildView(header, &parent->getPostDomTree(), + {header, merge}); } return buildCFG(header); @@ -402,10 +401,8 @@ struct Construct { return analysis.get>([this] { if (parent != nullptr) { - return parent->getCfg().buildView( - header, - &parent->getPostDomTree(), - {header, merge}, loopContinue); + return parent->getCfg().buildView(header, &parent->getPostDomTree(), + {header, merge}, loopContinue); } return buildCFG(header, {}, loopContinue); diff --git a/rpcsx/gpu/lib/gcn-shader/include/shader/eval.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/eval.hpp index 948731dc..e02f8f44 100644 --- a/rpcsx/gpu/lib/gcn-shader/include/shader/eval.hpp +++ b/rpcsx/gpu/lib/gcn-shader/include/shader/eval.hpp @@ -2,9 +2,9 @@ #include "Vector.hpp" #include "ir/Value.hpp" +#include #include #include -#include namespace shader::eval { struct Value { @@ -15,7 +15,8 @@ struct Value { u16vec2, u16vec3, u16vec4, i16vec2, i16vec3, i16vec4, u32vec2, u32vec3, u32vec4, i32vec2, i32vec3, i32vec4, u64vec2, u64vec3, u64vec4, i64vec2, i64vec3, i64vec4, f32vec2, f32vec3, f32vec4, f64vec2, f64vec3, f64vec4, - f16vec2, f16vec3, f16vec4, bool, bvec2, bvec3, bvec4, std::array>; + f16vec2, f16vec3, f16vec4, bool, bvec2, bvec3, bvec4, + std::array, std::array>; static constexpr auto StorageSize = std::variant_size_v; Storage storage; diff --git a/rpcsx/gpu/lib/gcn-shader/src/GcnConverter.cpp b/rpcsx/gpu/lib/gcn-shader/src/GcnConverter.cpp index 2b57aacb..52ce6275 100644 --- a/rpcsx/gpu/lib/gcn-shader/src/GcnConverter.cpp +++ b/rpcsx/gpu/lib/gcn-shader/src/GcnConverter.cpp @@ -71,6 +71,10 @@ inline int stageToDescriptorSet(gcn::Stage stage) { static void printFlat(std::ostream &os, ir::Instruction inst, ir::NameStorage &ns) { + if (inst == nullptr) { + os << "null"; + return; + } os << ir::getInstructionName(inst.getKind(), inst.getOp()); os << '('; @@ -91,29 +95,165 @@ static void printFlat(std::ostream &os, ir::Instruction inst, os << ')'; } +static bool isEqual(ir::Value lhs, ir::Value rhs); + +static bool isEqual(const ir::Operand &lhs, const ir::Operand &rhs) { + return std::visit( + [](const Lhs &lhs, const Rhs &rhs) { + if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { + return isEqual(lhs, rhs); + } else { + return lhs == rhs; + } + } else { + return false; + } + }, + lhs.value, rhs.value); +} + +static bool isEqual(ir::Value lhs, ir::Value rhs) { + if (lhs == rhs) { + return true; + } + + if ((lhs == nullptr) != (rhs == nullptr)) { + return false; + } + + if (lhs.getInstId() != rhs.getInstId()) { + return false; + } + + if (lhs.getOperandCount() != rhs.getOperandCount()) { + return false; + } + + for (std::size_t i = 0, end = lhs.getOperandCount(); i < end; ++i) { + if (!isEqual(lhs.getOperand(i), rhs.getOperand(i))) { + return false; + } + } + + return true; +} + struct ResourcesBuilder { gcn::Resources resources; ir::NameStorage *ns; - void addPointer(gcn::Resources::Pointer p) { + int addPointer(gcn::Resources::Pointer p) { + for (auto &pointer : resources.pointers) { + if (pointer.size != p.size) { + continue; + } + + if (!isEqual(pointer.base, p.base)) { + continue; + } + + if (!isEqual(pointer.offset, p.offset)) { + continue; + } + + return pointer.resourceSlot; + } + p.resourceSlot = resources.slots++; resources.pointers.push_back(p); + return p.resourceSlot; } - void addTexture(gcn::Resources::Texture p) { + int addTexture(gcn::Resources::Texture p) { + for (auto &texture : resources.textures) { + bool equal = true; + + for (std::size_t i = 0; i < std::size(texture.words); ++i) { + if (!isEqual(texture.words[i], p.words[i])) { + equal = false; + break; + } + } + + if (!equal) { + continue; + } + + texture.access |= p.access; + return texture.resourceSlot; + } + p.resourceSlot = resources.slots++; resources.textures.push_back(p); + return p.resourceSlot; } - void addImageBuffer(gcn::Resources::ImageBuffer p) { + int addImageBuffer(gcn::Resources::ImageBuffer p) { + for (auto &buffer : resources.imageBuffers) { + bool equal = true; + + for (std::size_t i = 0; i < std::size(buffer.words); ++i) { + if (!isEqual(buffer.words[i], p.words[i])) { + equal = false; + break; + } + } + + if (!equal) { + continue; + } + + buffer.access |= p.access; + return buffer.resourceSlot; + } + p.resourceSlot = resources.slots++; resources.imageBuffers.push_back(p); + return p.resourceSlot; } - void addBuffer(gcn::Resources::Buffer p) { + int addBuffer(gcn::Resources::Buffer p) { + for (auto &buffer : resources.buffers) { + bool equal = true; + + for (std::size_t i = 0; i < std::size(buffer.words); ++i) { + if (!isEqual(buffer.words[i], p.words[i])) { + equal = false; + break; + } + } + + if (!equal) { + continue; + } + + buffer.access |= p.access; + return buffer.resourceSlot; + } + p.resourceSlot = resources.slots++; resources.buffers.push_back(p); + return p.resourceSlot; } - void addSampler(gcn::Resources::Sampler p) { + int addSampler(gcn::Resources::Sampler p) { + for (auto &sampler : resources.samplers) { + bool equal = true; + + for (std::size_t i = 0; i < std::size(sampler.words); ++i) { + if (!isEqual(sampler.words[i], p.words[i])) { + equal = false; + break; + } + } + + if (!equal) { + continue; + } + + return sampler.resourceSlot; + } + p.resourceSlot = resources.slots++; resources.samplers.push_back(p); + return p.resourceSlot; } ir::Value unpackFunctionCall(MemorySSA &memorySSA, spv::Import &importer, @@ -163,6 +303,30 @@ struct ResourcesBuilder { return nullptr; } + ir::Instruction unpackInstruction(MemorySSA &memorySSA, spv::Import &importer, + ir::Instruction inst) { + for (auto &op : inst.getOperands()) { + auto value = op.getAsValue(); + if (!value) { + continue; + } + + if (value == ir::spv::OpVariable || value == ir::spv::OpAccessChain) { + auto varDef = memorySSA.getDefInst(inst, value); + if (varDef == ir::spv::OpStore) { + varDef = varDef.getOperand(1).getAsValue(); + } + if (varDef == ir::amdgpu::POINTER) { + return importIR(memorySSA, importer, varDef).staticCast(); + } + } else if (value == ir::amdgpu::POINTER) { + return importIR(memorySSA, importer, value).staticCast(); + } + } + + return inst; + } + ir::Instruction unpackResourceDef(MemorySSA &memorySSA, spv::Import &importer, ir::memssa::Def def) { if (def == nullptr) { @@ -180,6 +344,11 @@ struct ResourcesBuilder { defInst.staticCast()); } + if (defInst.getKind() != ir::Kind::Spv && + defInst.getKind() != ir::Kind::AmdGpu) { + return unpackInstruction(memorySSA, importer, defInst); + } + return importIR(memorySSA, importer, defInst); } @@ -194,6 +363,7 @@ struct ResourcesBuilder { phi.getOperand(i + 1).getAsValue().staticCast(); auto inst = unpackResourceDef(memorySSA, importer, def); + if (inst == nullptr) { resources.hasUnknown = true; } @@ -205,6 +375,7 @@ struct ResourcesBuilder { resourcePhi.addOperand(value); } else { auto block = resources.context.create(inst.getLocation()); + inst.erase(); block.addChild(inst); resourcePhi.addOperand(block); } @@ -216,6 +387,20 @@ struct ResourcesBuilder { return importIR(memorySSA, importer, def.getLinkedInst()); } + ir::Value toValue(ir::Instruction inst) { + if (inst == nullptr) { + return {}; + } + + if (auto value = inst.cast()) { + return value; + } + + auto block = resources.context.create(inst.getLocation()); + block.addChild(inst); + return block; + } + ir::Instruction importIR(MemorySSA &memorySSA, spv::Import &importer, ir::Instruction resource) { auto result = ir::clone(resource, resources.context, importer); @@ -240,16 +425,15 @@ struct ResourcesBuilder { continue; } - if (auto value = resourceInst.cast()) { - cloned.staticCast().replaceAllUsesWith(value); - } else { - auto block = - resources.context.create(resourceInst.getLocation()); - block.addChild(resourceInst); - cloned.staticCast().replaceAllUsesWith(block); - } + if (resourceInst != cloned) { + if (resource == inst) { + result = resourceInst; + } - continue; + cloned.staticCast().replaceAllUsesWith( + toValue(resourceInst)); + continue; + } } if (inst == ir::spv::OpFunctionCall) { @@ -258,8 +442,55 @@ struct ResourcesBuilder { if (unpacked) { cloned.staticCast().replaceAllUsesWith(unpacked); + if (resource == inst) { + result = unpacked; + } + if (visited.insert(unpacked).second) { - workList.push_back(unpacked); + workList.emplace_back(unpacked); + } + + continue; + } + } + + if (inst.getKind() != ir::Kind::Spv && + inst.getKind() != ir::Kind::AmdGpu) { + auto unpacked = unpackInstruction(memorySSA, importer, inst); + + if (unpacked) { + if (unpacked != inst) { + cloned.staticCast().replaceAllUsesWith( + toValue(unpacked)); + + if (resource == inst) { + result = unpacked; + } + + if (visited.insert(unpacked).second) { + workList.emplace_back(unpacked); + } + + continue; + } + + // FIXME: pass read only parameters as value and remove this + // workaround + for (std::size_t i = 0, end = cloned.getOperandCount(); i < end; + ++i) { + auto valueOp = cloned.getOperand(i).getAsValue(); + if (valueOp == nullptr) { + continue; + } + if (valueOp != ir::spv::OpVariable) { + continue; + } + + auto def = memorySSA.getDef(inst, inst.getOperand(i).getAsValue()); + if (auto resourceInst = + unpackResourceDef(memorySSA, importer, def)) { + cloned.replaceOperand(i, toValue(resourceInst)); + } } continue; @@ -268,8 +499,13 @@ struct ResourcesBuilder { for (auto &operand : inst.getOperands()) { if (auto value = operand.getAsValue()) { + if (value.getKind() == ir::Kind::Spv && + ir::spv::isTypeOp(value.getOp())) { + continue; + } + if (visited.insert(value).second) { - workList.push_back(value); + workList.emplace_back(value); } } } @@ -286,9 +522,13 @@ struct ResourcesBuilder { int slot = -1; - if (resourceSet.size() == 1 && resourceSet[0] != nullptr) { - slot = resources.slots; - } + auto trackResource = [&](int resourceSlot) { + if (slot == -1) { + slot = resourceSlot; + } else if (slot != resourceSlot) { + slot = -2; + } + }; for (auto inst : resourceSet) { if (inst == ir::amdgpu::POINTER) { @@ -296,11 +536,11 @@ struct ResourcesBuilder { auto base = inst.getOperand(2).getAsValue(); auto offset = inst.getOperand(3).getAsValue(); - addPointer({ + trackResource(addPointer({ .size = loadSize, .base = base, .offset = offset, - }); + })); continue; } @@ -309,11 +549,11 @@ struct ResourcesBuilder { auto access = static_cast(*inst.getOperand(1).getAsInt32()); auto words = inst.getOperands().subspan(2); - addBuffer({ + trackResource(addBuffer({ .access = access, .words = {words[0].getAsValue(), words[1].getAsValue(), words[2].getAsValue(), words[3].getAsValue()}, - }); + })); continue; } @@ -322,19 +562,19 @@ struct ResourcesBuilder { auto access = static_cast(*inst.getOperand(1).getAsInt32()); auto words = inst.getOperands().subspan(2); if (words.size() > 4) { - addTexture({ + trackResource(addTexture({ .access = access, .words = {words[0].getAsValue(), words[1].getAsValue(), words[2].getAsValue(), words[3].getAsValue(), words[4].getAsValue(), words[5].getAsValue(), words[6].getAsValue(), words[7].getAsValue()}, - }); + })); } else { - addTexture({ + trackResource(addTexture({ .access = access, .words = {words[0].getAsValue(), words[1].getAsValue(), words[2].getAsValue(), words[3].getAsValue()}, - }); + })); } continue; } @@ -343,19 +583,19 @@ struct ResourcesBuilder { auto access = static_cast(*inst.getOperand(1).getAsInt32()); auto words = inst.getOperands().subspan(2); if (words.size() > 4) { - addImageBuffer({ + trackResource(addImageBuffer({ .access = access, .words = {words[0].getAsValue(), words[1].getAsValue(), words[2].getAsValue(), words[3].getAsValue(), words[4].getAsValue(), words[5].getAsValue(), words[6].getAsValue(), words[7].getAsValue()}, - }); + })); } else { - addImageBuffer({ + trackResource(addImageBuffer({ .access = access, .words = {words[0].getAsValue(), words[1].getAsValue(), words[2].getAsValue(), words[3].getAsValue()}, - }); + })); } continue; } @@ -363,11 +603,11 @@ struct ResourcesBuilder { if (inst == ir::amdgpu::SAMPLER) { auto words = inst.getOperands().subspan(1); auto unorm = *inst.getOperand(5).getAsBool(); - addSampler({ + trackResource(addSampler({ .unorm = unorm, .words = {words[0].getAsValue(), words[1].getAsValue(), words[2].getAsValue(), words[3].getAsValue()}, - }); + })); continue; } @@ -877,6 +1117,7 @@ static void expToSpv(GcnConverter &converter, gcn::Stage stage, static void instructionsToSpv(GcnConverter &converter, gcn::Import &importer, gcn::Stage stage, const gcn::Environment &env, + const SemanticInfo &semanticInfo, const SemanticModuleInfo &semanticModuleInfo, gcn::ShaderInfo &info, ir::Region body) { auto &context = converter.gcnContext; @@ -927,10 +1168,6 @@ static void instructionsToSpv(GcnConverter &converter, gcn::Import &importer, } for (auto inst : body.children()) { - if (inst.getKind() == ir::Kind::Spv) { - continue; - } - if (inst == ir::exp::EXP) { expToSpv(converter, stage, info, inst); inst.remove(); @@ -941,6 +1178,57 @@ static void instructionsToSpv(GcnConverter &converter, gcn::Import &importer, inst == ir::amdgpu::SAMPLER || inst == ir::amdgpu::TBUFFER || inst == ir::amdgpu::IMAGE_BUFFER) { toAnalyze.push_back(inst.staticCast()); + } + } + + if (!toAnalyze.empty()) { + auto &cfg = + context.analysis.get([&] { return buildCFG(body.getFirst()); }); + + ModuleInfo moduleInfo; + collectModuleInfo(moduleInfo, context.layout); + auto memorySSA = buildMemorySSA( + cfg, semanticInfo, + [&](int regId) { + return context.getOrCreateRegisterVariable(gcn::RegId(regId)); + }, + &moduleInfo); + + spv::Import resourceImporter; + // memorySSA.print(std::cerr, body, context.ns); + + ResourcesBuilder resourcesBuilder; + std::map resourceConfigSlots; + resourcesBuilder.ns = &context.ns; + for (auto inst : toAnalyze) { + std::uint32_t configSlot = -1; + int resourceSlot = + resourcesBuilder.importResource(memorySSA, resourceImporter, inst); + if (resourceSlot >= 0) { + configSlot = info.create(gcn::ConfigType::ResourceSlot, resourceSlot); + } + + resourceConfigSlots[inst] = configSlot; + } + + for (auto [inst, slot] : resourceConfigSlots) { + auto builder = gcn::Builder::createInsertBefore(context, inst); + if (slot >= 0) { + auto value = converter.createReadConfig(stage, builder, slot); + value = builder.createSpvBitcast(inst.getLocation(), + context.getTypeSInt32(), value); + inst.replaceAllUsesWith(value); + } else { + inst.replaceAllUsesWith(context.simm32(-1)); + } + inst.remove(); + } + + info.resources = std::move(resourcesBuilder.resources); + } + + for (auto inst : body.children()) { + if (inst.getKind() == ir::Kind::Spv) { continue; } @@ -1290,47 +1578,6 @@ static void instructionsToSpv(GcnConverter &converter, gcn::Import &importer, inst.remove(); } - if (!toAnalyze.empty()) { - auto &cfg = - context.analysis.get([&] { return buildCFG(body.getFirst()); }); - - ModuleInfo moduleInfo; - collectModuleInfo(moduleInfo, context.layout); - auto memorySSA = buildMemorySSA(cfg, &moduleInfo); - spv::Import resourceImporter; - - // memorySSA.print(std::cerr, body, context.ns); - - ResourcesBuilder resourcesBuilder; - std::map resourceConfigSlots; - resourcesBuilder.ns = &context.ns; - for (auto inst : toAnalyze) { - std::uint32_t configSlot = -1; - int resourceSlot = - resourcesBuilder.importResource(memorySSA, resourceImporter, inst); - if (resourceSlot >= 0) { - configSlot = info.create(gcn::ConfigType::ResourceSlot, resourceSlot); - } - - resourceConfigSlots[inst] = configSlot; - } - - for (auto [inst, slot] : resourceConfigSlots) { - auto builder = gcn::Builder::createInsertBefore(context, inst); - if (slot >= 0) { - auto value = converter.createReadConfig(stage, builder, slot); - value = builder.createSpvBitcast(inst.getLocation(), - context.getTypeSInt32(), value); - inst.replaceAllUsesWith(value); - } else { - inst.replaceAllUsesWith(context.simm32(-1)); - } - inst.remove(); - } - - info.resources = std::move(resourcesBuilder.resources); - } - for (auto inst : body.children()) { if (inst.getKind() == ir::Kind::Spv) { continue; @@ -1704,15 +1951,16 @@ static void createInitialValues(GcnConverter &converter, std::optional gcn::convertToSpv(Context &context, ir::Region body, - const SemanticModuleInfo &semanticInfo, Stage stage, + const SemanticInfo &semanticInfo, + const SemanticModuleInfo &semanticModule, Stage stage, const Environment &env) { gcn::ConvertedShader result; GcnConverter converter{context}; gcn::Import importer; createInitialValues(converter, env, stage, result.info, body); - instructionsToSpv(converter, importer, stage, env, semanticInfo, result.info, - body); + instructionsToSpv(converter, importer, stage, env, semanticInfo, + semanticModule, result.info, body); if (stage != gcn::Stage::Cs) { replaceVariableWithConstant( context.getOrCreateRegisterVariable(gcn::RegId::ThreadId), diff --git a/rpcsx/gpu/lib/gcn-shader/src/analyze.cpp b/rpcsx/gpu/lib/gcn-shader/src/analyze.cpp index c4c224d5..d7e996d7 100644 --- a/rpcsx/gpu/lib/gcn-shader/src/analyze.cpp +++ b/rpcsx/gpu/lib/gcn-shader/src/analyze.cpp @@ -964,13 +964,12 @@ MemorySSA MemorySSABuilder::build(CFG &cfg, auto &&handleInst) { return std::move(memSSA); } -MemorySSA -shader::buildMemorySSA(CFG &cfg, const SemanticInfo &instructionSemantic, - std::function getRegisterVarCb) { - return MemorySSABuilder{}.build(cfg, [&](MemorySSABuilder &builder, - ir::memssa::Scope scope, - ir::Instruction inst) { - using IRBuilder = MemorySSABuilder::IRBuilder; +MemorySSA shader::buildMemorySSA(CFG &cfg, + const SemanticInfo &instructionSemantic, + std::function getRegisterVarCb, + ModuleInfo *moduleInfo) { + auto handleSemantic = [&](MemorySSABuilder &builder, ir::memssa::Scope scope, + ir::Instruction inst) { auto semantic = instructionSemantic.findSemantic(inst.getInstId()); if (semantic == nullptr) { return false; @@ -1006,6 +1005,53 @@ shader::buildMemorySSA(CFG &cfg, const SemanticInfo &instructionSemantic, } return true; + }; + + auto handleModuleInfo = [&](MemorySSABuilder &builder, + ir::memssa::Scope scope, ir::Instruction inst) { + if (inst != ir::spv::OpFunctionCall) { + return false; + } + + auto callee = inst.getOperand(1).getAsValue(); + auto it = moduleInfo->functions.find(callee); + auto fnInfo = it == moduleInfo->functions.end() ? nullptr : &it->second; + + if (fnInfo == nullptr) { + return false; + } + + for (auto [variable, access] : fnInfo->variables) { + builder.createPointerAccess(inst, scope, variable, VarSearchType::Root, + access); + } + + auto args = inst.getOperands(); + args = args.subspan(args.size() - fnInfo->parameters.size()); + + for (std::size_t i = 0; i < args.size(); ++i) { + auto arg = args[i].getAsValue(); + auto param = fnInfo->parameters[i]; + + if (param.access == Access::None) { + continue; + } + + builder.createPointerAccess(inst, scope, arg, VarSearchType::Root, + param.access); + } + + return true; + }; + + return MemorySSABuilder{}.build(cfg, [&](MemorySSABuilder &builder, + ir::memssa::Scope scope, + ir::Instruction inst) { + if (handleSemantic(builder, scope, inst)) { + return true; + } + + return moduleInfo != nullptr && handleModuleInfo(builder, scope, inst); }); } @@ -1013,8 +1059,6 @@ MemorySSA shader::buildMemorySSA(CFG &cfg, ModuleInfo *moduleInfo) { return MemorySSABuilder{}.build(cfg, [&](MemorySSABuilder &builder, ir::memssa::Scope scope, ir::Instruction inst) { - using IRBuilder = MemorySSABuilder::IRBuilder; - if (moduleInfo == nullptr) { return false; } diff --git a/rpcsx/gpu/lib/gcn-shader/src/eval.cpp b/rpcsx/gpu/lib/gcn-shader/src/eval.cpp index f748f23f..a634427a 100644 --- a/rpcsx/gpu/lib/gcn-shader/src/eval.cpp +++ b/rpcsx/gpu/lib/gcn-shader/src/eval.cpp @@ -364,7 +364,8 @@ eval::Value eval::Value::compositeExtract(const Value &index) const { eval::Value eval::Value::isNan() const { using Cond = decltype([](auto type) { - return std::is_floating_point_v> && !IsArray; + return std::is_floating_point_v> && + !IsArray; }); return visit(*this, [](auto &&value) -> Value { @@ -384,7 +385,8 @@ eval::Value eval::Value::isNan() const { eval::Value eval::Value::isInf() const { using Cond = decltype([](auto type) { - return std::is_floating_point_v> && !IsArray; + return std::is_floating_point_v> && + !IsArray; }); return visit(*this, [](auto &&value) -> Value { @@ -472,7 +474,7 @@ eval::Value eval::Value::makeSigned() const { eval::Value eval::Value::all() const { using Cond = decltype([](auto type) { return std::is_same_v, bool> && - (Components > 1) && !IsArray; + (Components > 1) && !IsArray; }); return visit(*this, [](auto &&value) { @@ -506,7 +508,8 @@ eval::Value eval::Value::any() const { eval::Value eval::Value::select(const Value &trueValue, const Value &falseValue) const { using Cond = decltype([](auto type) consteval { - return std::is_same_v, bool> && !IsArray; + return std::is_same_v, bool> && + !IsArray; }); return visit(*this, [&](auto &&cond) -> Value { @@ -548,7 +551,8 @@ eval::Value eval::Value::iConvert(ir::Value type, bool isSigned) const { using Type = std::remove_cvref_t; return std::is_integral_v> && - !std::is_same_v> && !IsArray; + !std::is_same_v> && + !IsArray; }); using PairCond = decltype([](auto lhs, auto rhs) { @@ -571,7 +575,8 @@ eval::Value eval::Value::iConvert(ir::Value type, bool isSigned) const { } eval::Value eval::Value::fConvert(ir::Value type) const { using Cond = decltype([](auto type) { - return std::is_floating_point_v> && !IsArray; + return std::is_floating_point_v> && + !IsArray; }); using PairCond = decltype([](auto lhs, auto rhs) { @@ -640,10 +645,8 @@ std::optional eval::Value::sExtScalar() const { } #define DEFINE_BINARY_OP(OP) \ - eval::Value eval::Value::operator OP(const Value & rhs) const { \ - using LhsCond = decltype([](auto &&lhs) { \ - return requires { static_cast(lhs OP rhs); }; \ - }); \ + eval::Value eval::Value::operator OP(const Value &rhs) const { \ + using LhsCond = decltype([](auto &&lhs) { return true; }); \ return visit(*this, [&](Lhs &&lhs) -> Value { \ using RhsCond = decltype([](auto &&rhs) { \ return requires(Lhs lhs) { static_cast(lhs OP rhs); }; \