diff --git a/rpcsx/gpu/lib/gcn-shader/include/shader/SpvConverter.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/SpvConverter.hpp index 0010f2344..6d42a7356 100644 --- a/rpcsx/gpu/lib/gcn-shader/include/shader/SpvConverter.hpp +++ b/rpcsx/gpu/lib/gcn-shader/include/shader/SpvConverter.hpp @@ -28,6 +28,7 @@ struct Context : ir::Context { Context(); + ir::Region createRegion(ir::Location loc); ir::Value createRegionWithLabel(ir::Location loc); void setName(ir::spv::IdRef inst, std::string name); @@ -35,6 +36,7 @@ struct Context : ir::Context { ir::Value getOrCreateConstant(ir::Value typeValue, const ir::Operand &value); ir::Value getNull(ir::Value typeValue); + ir::Value getUndef(ir::Value typeValue); ir::Value getType(ir::spv::Op baseType, int width, bool isSigned); ir::Value getType(const TypeInfo &info); diff --git a/rpcsx/gpu/lib/gcn-shader/include/shader/analyze.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/analyze.hpp index f7d8af271..3b1f00b57 100644 --- a/rpcsx/gpu/lib/gcn-shader/include/shader/analyze.hpp +++ b/rpcsx/gpu/lib/gcn-shader/include/shader/analyze.hpp @@ -15,8 +15,6 @@ #include namespace shader { -struct DomTree; -struct PostDomTree; class CFG { public: class Node { @@ -42,7 +40,6 @@ public: mSuccessors.insert(to); } - bool hasPredecessor(Node *node) { return mPredecessors.contains(node); } bool hasSuccessor(Node *node) { return mSuccessors.contains(node); } auto &getPredecessors() { return mPredecessors; } auto &getSuccessors() { return mSuccessors; } @@ -118,16 +115,6 @@ public: void print(std::ostream &os, ir::NameStorage &ns, bool subgraph = false, std::string_view nameSuffix = ""); std::string genTest(); - - CFG buildView(CFG::Node *from, PostDomTree *domTree = nullptr, - const std::unordered_set &stopLabels = {}, - ir::Value continueLabel = nullptr); - - CFG buildView(ir::Value from, PostDomTree *domTree = nullptr, - const std::unordered_set &stopLabels = {}, - ir::Value continueLabel = nullptr) { - return buildView(getNode(from), domTree, stopLabels, continueLabel); - } }; class MemorySSA { @@ -182,11 +169,27 @@ bool isWithoutSideEffects(ir::InstructionId id); bool isTerminator(ir::Instruction inst); bool isBranch(ir::Instruction inst); ir::Value unwrapPointer(ir::Value pointer); + +ir::Instruction getTerminator(ir::RegionLike region); +std::vector> getAllSuccessors(ir::Block region); +std::vector> getAllPredecessors(ir::Block region); + +std::unordered_set getSuccessors(ir::Block region); +std::unordered_set getPredecessors(ir::Block region); +std::size_t getSuccessorCount(ir::Block region); +std::size_t getPredecessorCount(ir::Block region); +bool hasSuccessor(ir::Block region, ir::Block successor); +bool hasAtLeastSuccessors(ir::Block region, std::size_t count); +ir::Block getUniqSuccessor(ir::Block region); + +graph::DomTree buildDomTree(ir::Block block); +graph::DomTree buildPostDomTree(ir::Block block); +graph::DomTree buildDomTree(ir::RegionLike region); +graph::DomTree buildPostDomTree(ir::RegionLike region); graph::DomTree buildDomTree(CFG &cfg, ir::Value root = nullptr); graph::DomTree buildPostDomTree(CFG &cfg, ir::Value root); -CFG buildCFG(ir::Instruction firstInstruction, - const std::unordered_set &exitLabels = {}, +CFG buildCFG(ir::Instruction firstInstruction, ir::Value exitLabel = nullptr, ir::Value continueLabel = nullptr); MemorySSA buildMemorySSA(CFG &cfg, ModuleInfo *moduleInfo = nullptr); @@ -200,23 +203,6 @@ bool dominates(ir::Instruction a, ir::Instruction b, bool isPostDom, ir::Value findNearestCommonDominator(ir::Instruction a, ir::Instruction b, graph::DomTree &domTree); -class BackEdgeStorage { - std::unordered_map> backEdges; - -public: - BackEdgeStorage() = default; - BackEdgeStorage(CFG &cfg); - - const std::unordered_set *get(ir::Value value) { - if (auto it = backEdges.find(value); it != backEdges.end()) { - return &it->second; - } - return nullptr; - } - - auto &all() { return backEdges; } -}; - struct AnalysisStorage { template requires(sizeof...(T) > 0) @@ -245,9 +231,7 @@ struct AnalysisStorage { { void *result = getImpl( rx::TypeId::get(), getDeleter(), - [&] { - return std::make_unique(std::forward(args)...).release(); - }, + [&] { return new T(std::forward(args)...); }, [&](void *object) { *reinterpret_cast(object) = T(std::forward(args)...); }); @@ -261,10 +245,7 @@ struct AnalysisStorage { { void *result = getImpl( rx::TypeId::get(), getDeleter(), - [&] { - return std::make_unique(std::forward(builder)()) - .release(); - }, + [&] { return new T(std::forward(builder)()); }, [&](void *object) { *reinterpret_cast(object) = std::forward(builder)(); }); @@ -304,20 +285,20 @@ private: std::map mStorage; }; -struct PostDomTree : graph::DomTree { +struct PostDomTree : graph::DomTree { PostDomTree() = default; - PostDomTree(graph::DomTree &&other) - : graph::DomTree::DomTree(std::move(other)) {} - PostDomTree(CFG &cfg, ir::Value root) - : PostDomTree(buildPostDomTree(cfg, root)) {} + PostDomTree(graph::DomTree &&other) + : graph::DomTree::DomTree(std::move(other)) {} + PostDomTree(ir::Block block) : PostDomTree(buildPostDomTree(block)) {} + PostDomTree(ir::RegionLike region) : DomTree(buildPostDomTree(region)) {} }; -struct DomTree : graph::DomTree { +struct DomTree : graph::DomTree { DomTree() = default; - DomTree(graph::DomTree &&other) - : graph::DomTree::DomTree(std::move(other)) {} - DomTree(CFG &cfg, ir::Value root = nullptr) - : DomTree(buildDomTree(cfg, root)) {} + DomTree(graph::DomTree &&other) + : graph::DomTree::DomTree(std::move(other)) {} + DomTree(ir::Block block) : DomTree(buildDomTree(block)) {} + DomTree(ir::RegionLike region) : DomTree(buildDomTree(region)) {} }; template struct Tag : T { @@ -337,107 +318,4 @@ template struct Tag : T { } }; -struct Construct { - Construct *parent; - std::forward_list children; - ir::Value header; - ir::Value merge; - ir::Value loopBody; - ir::Value loopContinue; - AnalysisStorage analysis; - - static std::unique_ptr createRoot(ir::RegionLike region, - ir::Value merge) { - auto result = std::make_unique(); - auto &cfg = - result->analysis.get([&] { return buildCFG(region.getFirst()); }); - result->header = cfg.getEntryLabel(); - result->merge = merge; - return result; - } - - Construct *createChild(ir::Value header, ir::Value merge) { - auto &result = children.emplace_front(); - result.parent = this; - result.header = header; - result.merge = merge; - return &result; - } - - Construct *createChild(ir::Value header, ir::Value merge, - ir::Value loopContinue, ir::Value loopBody) { - auto &result = children.emplace_front(); - result.parent = this; - result.header = header; - result.merge = merge; - result.loopContinue = loopContinue; - result.loopBody = loopBody; - return &result; - } - - Construct createTemporaryChild(ir::Value header, ir::Value merge) { - Construct result; - result.parent = this; - result.header = header; - result.merge = merge; - return result; - } - - CFG &getCfg() { - return analysis.get([this] { - if (parent != nullptr) { - return parent->getCfg().buildView(header, &parent->getPostDomTree(), - {header, merge}); - } - - return buildCFG(header); - }); - } - - CFG &getCfgWithoutContinue() { - if (loopContinue == nullptr) { - return getCfg(); - } - - return analysis.get>([this] { - if (parent != nullptr) { - return parent->getCfg().buildView(header, &parent->getPostDomTree(), - {header, merge}, loopContinue); - } - - return buildCFG(header, {}, loopContinue); - }); - } - - DomTree &getDomTree() { return analysis.get(getCfg(), header); } - PostDomTree &getPostDomTree() { - return analysis.get(getCfg(), merge); - } - BackEdgeStorage &getBackEdgeStorage() { - return analysis.get(getCfg()); - } - BackEdgeStorage &getBackEdgeWithoutContinueStorage() { - if (loopContinue == nullptr) { - return getBackEdgeStorage(); - } - return analysis.get>( - getCfgWithoutContinue()); - } - auto getBackEdges(ir::Value node) { return getBackEdgeStorage().get(node); } - auto getBackEdgesWithoutContinue(ir::Value node) { - return getBackEdgeWithoutContinueStorage().get(node); - } - auto getBackEdges() { return getBackEdges(header); } - void invalidate(); - void invalidateAll(); - - bool isNull() const { return header == nullptr; } - - void removeLastChild() { children.pop_front(); } - -private: - enum { - kWithoutContinue, - }; -}; } // namespace shader diff --git a/rpcsx/gpu/lib/gcn-shader/include/shader/dialect/builtin.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/dialect/builtin.hpp index ac965896d..c30b100e6 100644 --- a/rpcsx/gpu/lib/gcn-shader/include/shader/dialect/builtin.hpp +++ b/rpcsx/gpu/lib/gcn-shader/include/shader/dialect/builtin.hpp @@ -1,6 +1,8 @@ #pragma once #include "../ir/Block.hpp" #include "../ir/Builder.hpp" +#include "../ir/LoopConstruct.hpp" +#include "../ir/SelectionConstruct.hpp" #include "../ir/Value.hpp" namespace shader::ir { @@ -11,8 +13,9 @@ namespace shader::ir::builtin { enum Op { INVALID_INSTRUCTION, BLOCK, - IF_ELSE, - LOOP, + LOOP_CONSTRUCT, + CONTINUE_CONSTRUCT, + SELECTION_CONSTRUCT, }; inline const char *getInstructionName(unsigned id) { @@ -23,11 +26,14 @@ inline const char *getInstructionName(unsigned id) { case BLOCK: return "block"; - case IF_ELSE: - return "ifElse"; + case LOOP_CONSTRUCT: + return "loop_construct"; - case LOOP: - return "loop"; + case CONTINUE_CONSTRUCT: + return "continue_construct"; + + case SELECTION_CONSTRUCT: + return "selection_construct"; } return nullptr; } @@ -46,23 +52,30 @@ struct Builder : BuilderFacade, ImplT> { INVALID_INSTRUCTION); } - Instruction createIfElse(Location location, Value cond, Block ifTrue, - Block ifFalse = {}) { - std::vector operands = {{cond, ifTrue}}; - if (ifFalse) { - operands.push_back(ifFalse); - } - return this->template create(location, Kind::Builtin, IF_ELSE, - operands); + SelectionConstruct createSelectionConstruct(Location location, ir::Block body, + ir::Block merge) { + return this->template create( + location, Kind::Builtin, SELECTION_CONSTRUCT, + std::span{{body, merge}}); } - Instruction createLoop(Location location, Block body) { - return this->template create(location, Kind::Builtin, IF_ELSE, - {{body}}); + ContinueConstruct createContinueConstruct(Location location, ir::Block body, + ir::Block merge) { + return this->template create( + location, Kind::Builtin, CONTINUE_CONSTRUCT, + std::span{{body, merge}}); + } + + LoopConstruct createLoopConstruct(Location location, ir::Block body, + ir::Block merge, + ContinueConstruct continueConstruct) { + return this->template create( + location, Kind::Builtin, LOOP_CONSTRUCT, + std::span{{body, merge, continueConstruct}}); } auto createBlock(Location location) { - return this->template create(location); + return this->template create(location, Kind::Builtin, BLOCK); } auto createRegion(Location location) { diff --git a/rpcsx/gpu/lib/gcn-shader/include/shader/dialect/memssa.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/dialect/memssa.hpp index 293d9c0a1..c95f00093 100644 --- a/rpcsx/gpu/lib/gcn-shader/include/shader/dialect/memssa.hpp +++ b/rpcsx/gpu/lib/gcn-shader/include/shader/dialect/memssa.hpp @@ -14,6 +14,7 @@ enum Op { OpBarrier, OpJump, OpExit, + OpScope, OpCount, }; @@ -24,8 +25,9 @@ template struct BaseImpl : BaseT { using BaseT::BaseT; using BaseT::operator=; - void print(std::ostream &os, NameStorage &ns) const override { - BaseT::print(os, ns); + void print(std::ostream &os, NameStorage &ns, + const PrintOptions &opts) const override { + BaseT::print(os, ns, opts); if (link) { os << " : "; @@ -220,7 +222,7 @@ struct ScopeWrapper : BaseWrapper { std::set result; std::vector workList; - for (auto comp : var.getOperands()) { + for (auto &comp : var.getOperands()) { auto compVar = comp.getAsValue().staticCast(); result.insert(compVar); @@ -235,7 +237,7 @@ struct ScopeWrapper : BaseWrapper { auto var = workList.back(); workList.pop_back(); - for (auto comp : var.getOperands()) { + for (auto &comp : var.getOperands()) { auto compVar = comp.getAsValue().staticCast(); result.insert(compVar); @@ -353,7 +355,8 @@ struct Builder : BuilderFacade, ImplT> { } Scope createScope(ir::Instruction labelInst) { - Scope result = this->template create(labelInst.getLocation()); + Scope result = this->template create(labelInst.getLocation(), + ir::Kind::MemSSA, OpScope); result.impl->link = labelInst; return result; } @@ -417,6 +420,8 @@ inline const char *getInstructionName(unsigned op) { return "jump"; case OpExit: return "exit"; + case OpScope: + return "scope"; } return nullptr; } diff --git a/rpcsx/gpu/lib/gcn-shader/include/shader/ir/Block.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/ir/Block.hpp index e5134d323..64de2b3aa 100644 --- a/rpcsx/gpu/lib/gcn-shader/include/shader/ir/Block.hpp +++ b/rpcsx/gpu/lib/gcn-shader/include/shader/ir/Block.hpp @@ -19,10 +19,12 @@ struct Block : BlockWrapper { }; struct BlockImpl : ValueImpl, RegionLikeImpl { - BlockImpl(Location loc); + using ValueImpl::ValueImpl; + Node clone(Context &context, CloneMap &map) const override; - void print(std::ostream &os, NameStorage &ns) const override { + void print(std::ostream &os, NameStorage &ns, + const PrintOptions &opts) const override { os << '%' << ns.getNameOf(const_cast(this)); os << " = "; @@ -41,11 +43,13 @@ struct BlockImpl : ValueImpl, RegionLikeImpl { } os << "{\n"; + auto childOpts = opts.nextLevel(); for (auto child : children()) { - os << " "; - child.print(os, ns); + childOpts.printIdent(os); + child.print(os, ns, childOpts); os << "\n"; } + opts.printIdent(os); os << "}"; } }; diff --git a/rpcsx/gpu/lib/gcn-shader/include/shader/ir/Builder.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/ir/Builder.hpp index 9fcdeafc6..01a85128f 100644 --- a/rpcsx/gpu/lib/gcn-shader/include/shader/ir/Builder.hpp +++ b/rpcsx/gpu/lib/gcn-shader/include/shader/ir/Builder.hpp @@ -22,6 +22,46 @@ template struct BuilderFacade { } }; +class InsertionPoint { + RegionLike mInsertionStorage; + Instruction mInsertionPoint; + +public: + InsertionPoint() = default; + + InsertionPoint(RegionLike storage, Instruction point) + : mInsertionStorage(storage), mInsertionPoint(point) {} + + static InsertionPoint createInsertAfter(Instruction point) { + return {point.getParent(), point}; + } + + static InsertionPoint createInsertBefore(Instruction point) { + return {point.getParent(), point.getPrev()}; + } + + static InsertionPoint createAppend(RegionLike storage) { + return {storage, storage.getLast()}; + } + + static InsertionPoint createPrepend(RegionLike storage) { + return {storage, nullptr}; + } + + RegionLike getInsertionStorage() { return mInsertionStorage; } + Instruction getInsertionPoint() { return mInsertionPoint; } + + void insert(ir::Instruction inst) { + getInsertionStorage().insertAfter(getInsertionPoint(), inst); + mInsertionPoint = inst; + } + + void eraseAndInsert(ir::Instruction inst) { + inst.erase(); + insert(inst); + } +}; + template