From 316a2f8d96c8a801613f19c466d342a2e246f7a2 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Thu, 3 Sep 2020 03:54:54 +1200 Subject: [PATCH 01/16] IRValidation: Add arg liveness, numUses checks --- .../Interface/IR/Passes/IRValidation.cpp | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/External/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp b/External/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp index 6cc3607cc..d573b8897 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp @@ -2,6 +2,7 @@ #include "Interface/IR/Passes/RegisterAllocationPass.h" #include "Interface/Context/Context.h" #include "Interface/Core/OpcodeDispatcher.h" +#include "Common/BitSet.h" #include @@ -33,6 +34,11 @@ bool IRValidation::Run(IREmitter *IREmit) { std::ostringstream Errors; std::ostringstream Warnings; + BitSet NodeIsLive; + NodeIsLive.Allocate(CurrentIR.GetSSACount()); + + std::vector Uses(CurrentIR.GetSSACount(), 0); + auto Begin = CurrentIR.begin(); auto Op = Begin(); @@ -52,6 +58,8 @@ bool IRValidation::Run(IREmitter *IREmit) { BlockInfo *CurrentBlock = &OffsetToBlockMap.try_emplace(BlockNode->Wrapped(ListBegin).ID()).first->second; + + // We grab these nodes this way so we can iterate easily auto CodeBegin = CurrentIR.at(BlockIROp->Begin); auto CodeLast = CurrentIR.at(BlockIROp->Last); @@ -106,6 +114,9 @@ bool IRValidation::Run(IREmitter *IREmit) { } uint8_t NumArgs = IR::GetArgs(IROp->Op); + + if (NumArgs != IROp->NumArgs) + Errors << "%ssa" << CodeOp->ID() << ": Has wrong number of Args" << std::endl; for (uint32_t i = 0; i < NumArgs; ++i) { OrderedNodeWrapper Arg = IROp->Args[i]; // Was an argument defined after this node? @@ -113,8 +124,17 @@ bool IRValidation::Run(IREmitter *IREmit) { HadError |= true; Errors << "%ssa" << CodeOp->ID() << ": Arg[" << i << "] has definition after use at %ssa" << Arg.ID() << std::endl; } + + if (!NodeIsLive.Get(Arg.ID())) { + HadError |= true; + Errors << "%ssa" << CodeOp->ID() << ": Arg[" << i << "] refrences dead %ssa" << Arg.ID() << std::endl; + } + + Uses[Arg.ID()]++; } + NodeIsLive.Set(CodeOp->ID()); + switch (IROp->Op) { case IR::OP_EXITFUNCTION: { CurrentBlock->HasExit = true; @@ -231,6 +251,12 @@ bool IRValidation::Run(IREmitter *IREmit) { } } + for (int i = 0; i < CurrentIR.GetSSACount(); i++) { + auto Node = OrderedNodeWrapper::WrapOffset(i * sizeof(IR::OrderedNode)).GetNode(ListBegin); + if (Node->NumUses != Uses[i]) + Errors << "%ssa" << i << " Has " << Uses[i] << " Uses, but reports " << Node->NumUses << std::endl; + } + std::stringstream Out; HadWarning = false; From 446b261f24a93bca38f1419ee417012e598f23bb Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Thu, 3 Sep 2020 10:39:34 +1200 Subject: [PATCH 02/16] Iterator for blocks --- .../Core/Interpreter/InterpreterCore.cpp | 16 ++-- .../Interface/Core/JIT/Arm64/MiscOps.cpp | 1 - .../Source/Interface/Core/JIT/x86_64/JIT.cpp | 20 +---- .../Interface/Core/OpcodeDispatcher.cpp | 6 -- External/FEXCore/Source/Interface/IR/IR.cpp | 23 ++---- External/FEXCore/Source/Interface/IR/IR.json | 11 +-- .../FEXCore/Source/Interface/IR/IREmitter.cpp | 7 -- .../Source/Interface/IR/Passes/ConstProp.cpp | 19 +---- .../IR/Passes/DeadCodeElimination.cpp | 19 +---- .../IR/Passes/DeadContextStoreElimination.cpp | 28 +------ .../Interface/IR/Passes/IRCompaction.cpp | 27 ++----- .../Interface/IR/Passes/IRValidation.cpp | 18 +---- .../Interface/IR/Passes/PhiValidation.cpp | 18 +---- .../RedundantFlagCalculationElimination.cpp | 19 +---- .../IR/Passes/RegisterAllocationPass.cpp | 78 ++----------------- .../IR/Passes/SyscallOptimization.cpp | 19 +---- .../IR/Passes/ValueDominanceValidation.cpp | 28 +------ External/FEXCore/include/FEXCore/IR/IR.h | 29 +++---- .../FEXCore/include/FEXCore/IR/IREmitter.h | 43 ++++------ .../include/FEXCore/IR/IntrusiveIRList.h | 46 ++++++++++- Source/Tests/IRLoader/Loader.cpp | 13 ++-- 21 files changed, 140 insertions(+), 348 deletions(-) diff --git a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp index 9ff93c517..98e4a7cf1 100644 --- a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp +++ b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp @@ -99,7 +99,9 @@ void InterpreterCore::ExecuteCode(FEXCore::Core::InternalThreadState *Thread) { auto HeaderOp = HeaderNode->Op(DataBegin)->CW(); LogMan::Throw::A(HeaderOp->Header.Op == IR::OP_IRHEADER, "First op wasn't IRHeader"); - IR::OrderedNode const *BlockNode = HeaderOp->Blocks.GetNode(ListBegin); + auto BlockIterator = CurrentIR->getBlocks().begin(); + auto BlockEnd = CurrentIR->getBlocks().end(); + // Allocate 16 bytes per SSA void *SSAData = alloca(ListSize * 16); @@ -117,6 +119,7 @@ void InterpreterCore::ExecuteCode(FEXCore::Core::InternalThreadState *Thread) { while (1) { using namespace FEXCore::IR; + IR::OrderedNode const *BlockNode = BlockIterator()->GetNode(ListBegin); auto BlockIROp = BlockNode->Op(DataBegin)->C(); LogMan::Throw::A(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block"); @@ -142,7 +145,6 @@ void InterpreterCore::ExecuteCode(FEXCore::Core::InternalThreadState *Thread) { break; case IR::OP_ENDBLOCK: { auto Op = IROp->C(); - Thread->State.State.rip += Op->RIPIncrement; break; } case IR::OP_FENCE: { @@ -169,10 +171,10 @@ void InterpreterCore::ExecuteCode(FEXCore::Core::InternalThreadState *Thread) { auto Op = IROp->C(); uint64_t Arg = *GetSrc(SSAData, Op->Header.Args[0]); if (!!Arg) { - BlockNode = Op->Header.Args[1].GetNode(ListBegin); + BlockIterator = NodeWrapperIterator(ListBegin, DataBegin, Op->Header.Args[1]); } else { - BlockNode = Op->Header.Args[2].GetNode(ListBegin); + BlockIterator = NodeWrapperIterator(ListBegin, DataBegin, Op->Header.Args[2]); } BlockResults.Redo = true; return; @@ -180,7 +182,7 @@ void InterpreterCore::ExecuteCode(FEXCore::Core::InternalThreadState *Thread) { } case IR::OP_JUMP: { auto Op = IROp->C(); - BlockNode = Op->Header.Args[0].GetNode(ListBegin); + BlockIterator = NodeWrapperIterator(ListBegin, DataBegin, Op->Header.Args[0]); BlockResults.Redo = true; return; break; @@ -4230,10 +4232,8 @@ void InterpreterCore::ExecuteCode(FEXCore::Core::InternalThreadState *Thread) { continue; } - if (BlockIROp->Next.ID() == 0 || BlockResults.Quit) { + if (BlockResults.Quit || ++BlockIterator == BlockEnd) { break; - } else { - BlockNode = BlockIROp->Next.GetNode(ListBegin); } } diff --git a/External/FEXCore/Source/Interface/Core/JIT/Arm64/MiscOps.cpp b/External/FEXCore/Source/Interface/Core/JIT/Arm64/MiscOps.cpp index 25fd7a0dd..486d5489a 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/Arm64/MiscOps.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/Arm64/MiscOps.cpp @@ -10,7 +10,6 @@ DEF_OP(EndBlock) { auto Op = IROp->C(); if (Op->RIPIncrement) { ldr(TMP1, MemOperand(STATE, offsetof(FEXCore::Core::CPUState, rip))); - add(TMP1, TMP1, Operand(Op->RIPIncrement)); str(TMP1, MemOperand(STATE, offsetof(FEXCore::Core::CPUState, rip))); } } diff --git a/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp b/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp index 77747703d..0dbb09d9a 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp @@ -422,10 +422,7 @@ void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const uintptr_t ListBegin = CurrentIR->GetListData(); uintptr_t DataBegin = CurrentIR->GetData(); - auto HeaderIterator = CurrentIR->begin(); - IR::OrderedNodeWrapper *HeaderNodeWrapper = HeaderIterator(); - IR::OrderedNode *HeaderNode = HeaderNodeWrapper->GetNode(ListBegin); - auto HeaderOp = HeaderNode->Op(DataBegin)->CW(); + auto HeaderOp = CurrentIR->GetHeader(); LogMan::Throw::A(HeaderOp->Header.Op == IR::OP_IRHEADER, "First op wasn't IRHeader"); if (HeaderOp->ShouldInterpret) { @@ -514,10 +511,10 @@ void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const ret(); }; - IR::OrderedNode *BlockNode = HeaderOp->Blocks.GetNode(ListBegin); - while (1) { + for (auto Block : CurrentIR->getBlocks()) { using namespace FEXCore::IR; - auto BlockIROp = BlockNode->Op(DataBegin)->CW(); + auto BlockNode = Block.GetNode(ListBegin); + auto BlockIROp = BlockNode->Op(DataBegin)->CW(); LogMan::Throw::A(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block"); // We grab these nodes this way so we can iterate easily @@ -591,9 +588,6 @@ void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const } case IR::OP_ENDBLOCK: { auto Op = IROp->C(); - if (Op->RIPIncrement) { - add(qword [STATE + offsetof(FEXCore::Core::CPUState, rip)], Op->RIPIncrement); - } break; } case IR::OP_EXITFUNCTION: { @@ -4833,12 +4827,6 @@ void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const } ++CodeBegin; } - - if (BlockIROp->Next.ID() == 0) { - break; - } else { - BlockNode = BlockIROp->Next.GetNode(ListBegin); - } } void *Exit = getCurr(); diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index 6e72492db..689e89494 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -3658,12 +3658,6 @@ void OpDispatchBuilder::CreateJumpBlocks(std::vector const* IR, IR::RegisterAlloc uintptr_t ListBegin = IR->GetListData(); uintptr_t DataBegin = IR->GetData(); - auto Begin = IR->begin(); - auto Op = Begin(); - - OrderedNode *RealNode = Op->GetNode(ListBegin); - auto HeaderOp = RealNode->Op(DataBegin)->CW(); + auto HeaderOp = IR->GetHeader(); LogMan::Throw::A(HeaderOp->Header.Op == OP_IRHEADER, "First op wasn't IRHeader"); - OrderedNode *BlockNode = HeaderOp->Blocks.GetNode(ListBegin); int8_t CurrentIndent = 0; auto AddIndent = [&out, &CurrentIndent]() { for (uint8_t i = 0; i < CurrentIndent; ++i) { @@ -132,14 +127,15 @@ void Dump(std::stringstream *out, IRListView const* IR, IR::RegisterAlloc ++CurrentIndent; AddIndent(); - *out << "(%ssa" << std::to_string(RealNode->Wrapped(ListBegin).ID()) << ") " << "IRHeader "; + *out << "(%ssa0) " << "IRHeader "; *out << "#0x" << std::hex << HeaderOp->Entry << ", "; *out << "%ssa" << HeaderOp->Blocks.ID() << ", "; *out << "#" << std::dec << HeaderOp->BlockCount << std::endl; - while (1) { + for (auto Block : IR->getBlocks()) { + auto BlockNode = Block.GetNode(ListBegin); auto BlockIROp = BlockNode->Op(DataBegin)->CW(); - LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); + // LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); // We grab these nodes this way so we can iterate easily auto CodeBegin = IR->at(BlockIROp->Begin); @@ -149,8 +145,7 @@ void Dump(std::stringstream *out, IRListView const* IR, IR::RegisterAlloc *out << "(%ssa" << std::to_string(BlockNode->Wrapped(ListBegin).ID()) << ") " << "CodeBlock "; *out << "%ssa" << std::to_string(BlockIROp->Begin.ID()) << ", "; - *out << "%ssa" << std::to_string(BlockIROp->Last.ID()) << ", "; - *out << "%ssa" << std::to_string(BlockIROp->Next.ID()) << std::endl; + *out << "%ssa" << std::to_string(BlockIROp->Last.ID()) << std::endl; ++CurrentIndent; while (1) { @@ -268,12 +263,6 @@ void Dump(std::stringstream *out, IRListView const* IR, IR::RegisterAlloc } CurrentIndent = std::max(0, CurrentIndent - 1); - - if (BlockIROp->Next.ID() == 0) { - break; - } else { - BlockNode = BlockIROp->Next.GetNode(ListBegin); - } } } diff --git a/External/FEXCore/Source/Interface/IR/IR.json b/External/FEXCore/Source/Interface/IR/IR.json index 74a705dbf..3acb3cb5d 100644 --- a/External/FEXCore/Source/Interface/IR/IR.json +++ b/External/FEXCore/Source/Interface/IR/IR.json @@ -65,12 +65,11 @@ "CodeBlock": { "OpClass": "Misc", "SwitchGen": false, - "SSAArgs": "3", + "SSAArgs": "2", "RAOverride": "0", "SSANames": [ "Begin", - "Last", - "Next" + "Last" ] }, "BeginBlock": { @@ -81,8 +80,10 @@ "HasSideEffects": true, "OpClass": "Misc", "SwitchGen": false, - "Args": [ - "uint64_t", "RIPIncrement" + "SSAArgs": "1", + "RAOverride": "0", + "SSANames": [ + "BlockHeader" ] }, diff --git a/External/FEXCore/Source/Interface/IR/IREmitter.cpp b/External/FEXCore/Source/Interface/IR/IREmitter.cpp index 995b347ff..bf74f01ba 100644 --- a/External/FEXCore/Source/Interface/IR/IREmitter.cpp +++ b/External/FEXCore/Source/Interface/IR/IREmitter.cpp @@ -66,16 +66,9 @@ void IREmitter::Remove(OrderedNode *Node) { IREmitter::IRPair IREmitter::CreateNewCodeBlock() { auto OldCursor = GetWriteCursor(); - SetWriteCursor(CodeBlocks.back()); auto CodeNode = CreateCodeNode(); - auto NewNode = _Dummy(); - SetCodeNodeBegin(CodeNode, NewNode); - - auto EndBlock = _EndBlock(0); - SetCodeNodeLast(CodeNode, EndBlock); - if (CurrentCodeBlock) { LinkCodeBlocks(CurrentCodeBlock, CodeNode); } diff --git a/External/FEXCore/Source/Interface/IR/Passes/ConstProp.cpp b/External/FEXCore/Source/Interface/IR/Passes/ConstProp.cpp index 4a55c3460..bdefa5bc5 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/ConstProp.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/ConstProp.cpp @@ -20,19 +20,10 @@ bool ConstProp::Run(IREmitter *IREmit) { uintptr_t ListBegin = CurrentIR.GetListData(); uintptr_t DataBegin = CurrentIR.GetData(); - auto Begin = CurrentIR.begin(); - auto Op = Begin(); - - OrderedNode *RealNode = Op->GetNode(ListBegin); - auto HeaderOp = RealNode->Op(DataBegin)->CW(); - LogMan::Throw::A(HeaderOp->Header.Op == OP_IRHEADER, "First op wasn't IRHeader"); - - OrderedNode *BlockNode = HeaderOp->Blocks.GetNode(ListBegin); - auto OriginalWriteCursor = IREmit->GetWriteCursor(); - while (1) { - auto BlockIROp = BlockNode->Op(DataBegin)->CW(); + for (auto Block : CurrentIR.getBlocks()) { + auto BlockIROp = Block.GetNode(ListBegin)->Op(DataBegin)->CW(); LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); // We grab these nodes this way so we can iterate easily @@ -245,12 +236,6 @@ bool ConstProp::Run(IREmitter *IREmit) { } ++CodeBegin; } - - if (BlockIROp->Next.ID() == 0) { - break; - } else { - BlockNode = BlockIROp->Next.GetNode(ListBegin); - } } IREmit->SetWriteCursor(OriginalWriteCursor); diff --git a/External/FEXCore/Source/Interface/IR/Passes/DeadCodeElimination.cpp b/External/FEXCore/Source/Interface/IR/Passes/DeadCodeElimination.cpp index da6393be2..439fe9c25 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/DeadCodeElimination.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/DeadCodeElimination.cpp @@ -20,19 +20,10 @@ bool DeadCodeElimination::Run(IREmitter *IREmit) { uintptr_t ListBegin = CurrentIR.GetListData(); uintptr_t DataBegin = CurrentIR.GetData(); - auto Begin = CurrentIR.begin(); - auto Op = Begin(); - - OrderedNode *RealNode = Op->GetNode(ListBegin); - auto HeaderOp = RealNode->Op(DataBegin)->CW(); - LogMan::Throw::A(HeaderOp->Header.Op == OP_IRHEADER, "First op wasn't IRHeader"); - - OrderedNode *BlockNode = HeaderOp->Blocks.GetNode(ListBegin); - int NumRemoved = 0; - while (1) { - auto BlockIROp = BlockNode->Op(DataBegin)->CW(); + for (auto Block : CurrentIR.getBlocks()) { + auto BlockIROp = Block.GetNode(ListBegin)->Op(DataBegin)->CW(); LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); // We grab these nodes this way so we can iterate easily @@ -58,12 +49,6 @@ bool DeadCodeElimination::Run(IREmitter *IREmit) { } --CodeLast; } - - if (BlockIROp->Next.ID() == 0) { - break; - } else { - BlockNode = BlockIROp->Next.GetNode(ListBegin); - } } return NumRemoved != 0; diff --git a/External/FEXCore/Source/Interface/IR/Passes/DeadContextStoreElimination.cpp b/External/FEXCore/Source/Interface/IR/Passes/DeadContextStoreElimination.cpp index 7380565d5..15efeab68 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/DeadContextStoreElimination.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/DeadContextStoreElimination.cpp @@ -317,16 +317,8 @@ void RCLSE::CalculateControlFlowInfo(FEXCore::IR::IREmitter *IREmit) { uintptr_t ListBegin = CurrentIR.GetListData(); uintptr_t DataBegin = CurrentIR.GetData(); - auto Begin = CurrentIR.begin(); - auto Op = Begin(); - - OrderedNode *RealNode = Op->GetNode(ListBegin); - auto HeaderOp = RealNode->Op(DataBegin)->CW(); - LogMan::Throw::A(HeaderOp->Header.Op == OP_IRHEADER, "First op wasn't IRHeader"); - - // Walk the list and calculate the control flow - OrderedNode *BlockNode = HeaderOp->Blocks.GetNode(ListBegin); - while (1) { + for (auto Block : CurrentIR.getBlocks()) { + auto BlockNode = Block.GetNode(ListBegin); auto BlockIROp = BlockNode->Op(DataBegin)->CW(); LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); @@ -383,12 +375,6 @@ void RCLSE::CalculateControlFlowInfo(FEXCore::IR::IREmitter *IREmit) { } ++CodeBegin; } - - if (BlockIROp->Next.ID() == 0) { - break; - } else { - BlockNode = BlockIROp->Next.GetNode(ListBegin); - } } } @@ -449,8 +435,8 @@ bool RCLSE::RedundantStoreLoadElimination(FEXCore::IR::IREmitter *IREmit) { ContextInfo LocalInfo = ClassifiedStruct; - while (1) { - auto BlockIROp = BlockNode->Op(DataBegin)->CW(); + for (auto Block : CurrentIR.getBlocks()) { + auto BlockIROp = Block.GetNode(ListBegin)->Op(DataBegin)->CW(); LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); ResetClassificationAccesses(&LocalInfo); @@ -595,12 +581,6 @@ bool RCLSE::RedundantStoreLoadElimination(FEXCore::IR::IREmitter *IREmit) { } ++CodeBegin; } - - if (BlockIROp->Next.ID() == 0) { - break; - } else { - BlockNode = BlockIROp->Next.GetNode(ListBegin); - } } IREmit->SetWriteCursor(OriginalWriteCursor); diff --git a/External/FEXCore/Source/Interface/IR/Passes/IRCompaction.cpp b/External/FEXCore/Source/Interface/IR/Passes/IRCompaction.cpp index 5b1d4b439..2551fa37f 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/IRCompaction.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/IRCompaction.cpp @@ -48,10 +48,8 @@ bool IRCompaction::Run(IREmitter *IREmit) { uintptr_t ListBegin = CurrentIR.GetListData(); uintptr_t DataBegin = CurrentIR.GetData(); - auto HeaderIterator = CurrentIR.begin(); - OrderedNodeWrapper *HeaderNodeWrapper = HeaderIterator(); - OrderedNode *HeaderNode = HeaderNodeWrapper->GetNode(ListBegin); - auto HeaderOp = HeaderNode->Op(DataBegin)->CW(); + auto HeaderNode = CurrentIR.GetHeaderNode(); + auto HeaderOp = CurrentIR.GetHeader(); LogMan::Throw::A(HeaderOp->Header.Op == OP_IRHEADER, "First op wasn't IRHeader"); // This compaction pass is something that we need to ensure correct ordering and distances between IROps @@ -75,33 +73,24 @@ bool IRCompaction::Run(IREmitter *IREmit) { { // Generate our codeblocks and link them together - OrderedNode *BlockNode = HeaderOp->Blocks.GetNode(ListBegin); OrderedNode* PrevCodeBlock{}; - while (1) { + for (auto Block : CurrentIR.getBlocks()) { + auto BlockNode = Block.GetNode(ListBegin); auto BlockIROp = BlockNode->Op(DataBegin)->CW(); LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); - auto LocalBlockIRNode = LocalBuilder.CreateCodeNode(); + auto LocalBlockIRNode = LocalBuilder._CodeBlock(LocalHeaderOp, LocalHeaderOp); // Use LocalHeaderOp as a dummy arg for now OldToNewRemap[BlockNode->Wrapped(ListBegin).ID()] = LocalBlockIRNode.Node->Wrapped(LocalListBegin).ID(); GeneratedCodeBlocks.emplace_back(CodeBlockData{BlockNode, LocalBlockIRNode}); - - if (PrevCodeBlock) { - auto PrevLocalBlockIROp = PrevCodeBlock->Op(LocalDataBegin)->CW(); - PrevLocalBlockIROp->Next = LocalBlockIRNode.Node->Wrapped(LocalListBegin); - } - - if (BlockIROp->Next.ID() == 0) { - break; - } else { - BlockNode = BlockIROp->Next.GetNode(ListBegin); - PrevCodeBlock = LocalBlockIRNode; - } } // Link the IRHeader to the first code block LocalHeaderOp.first->Blocks = GeneratedCodeBlocks[0].NewNode->Wrapped(LocalListBegin); } + // Isolate the nodes from the Block headers + LocalBuilder.SetWriteCursor(nullptr); + { // Copy all of our IR ops over to the new location for (auto &Block : GeneratedCodeBlocks) { diff --git a/External/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp b/External/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp index d573b8897..61bd371b2 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp @@ -39,20 +39,16 @@ bool IRValidation::Run(IREmitter *IREmit) { std::vector Uses(CurrentIR.GetSSACount(), 0); - auto Begin = CurrentIR.begin(); - auto Op = Begin(); - - OrderedNode *RealNode = Op->GetNode(ListBegin); - auto HeaderOp = RealNode->Op(DataBegin)->CW(); + auto HeaderOp = CurrentIR.GetHeader(); LogMan::Throw::A(HeaderOp->Header.Op == OP_IRHEADER, "First op wasn't IRHeader"); - OrderedNode *BlockNode = HeaderOp->Blocks.GetNode(ListBegin); IR::RegisterAllocationPass * RAPass{}; if (Manager->HasRAPass() && !HeaderOp->ShouldInterpret) { RAPass = Manager->GetRAPass(); } - while (1) { + for (auto Block : CurrentIR.getBlocks()) { + auto BlockNode = Block.GetNode(ListBegin); auto BlockIROp = BlockNode->Op(DataBegin)->CW(); LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); @@ -80,7 +76,7 @@ bool IRValidation::Run(IREmitter *IREmit) { } // Does the node have zero uses? Should have been DCE'd - if (RealNode->GetUses() == 0) { + if (CodeNode->GetUses() == 0) { HadWarning |= true; Warnings << "%ssa" << CodeOp->ID() << ": Destination created but had no uses" << std::endl; } @@ -243,12 +239,6 @@ bool IRValidation::Run(IREmitter *IREmit) { }; } } - - if (BlockIROp->Next.ID() == 0) { - break; - } else { - BlockNode = BlockIROp->Next.GetNode(ListBegin); - } } for (int i = 0; i < CurrentIR.GetSSACount(); i++) { diff --git a/External/FEXCore/Source/Interface/IR/Passes/PhiValidation.cpp b/External/FEXCore/Source/Interface/IR/Passes/PhiValidation.cpp index ccce4abed..a819ca6c0 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/PhiValidation.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/PhiValidation.cpp @@ -18,17 +18,9 @@ bool PhiValidation::Run(IREmitter *IREmit) { std::ostringstream Errors; - auto Begin = CurrentIR.begin(); - auto Op = Begin(); - - OrderedNode *RealNode = Op->GetNode(ListBegin); - auto HeaderOp = RealNode->Op(DataBegin)->CW(); - LogMan::Throw::A(HeaderOp->Header.Op == OP_IRHEADER, "First op wasn't IRHeader"); - // Walk the list and calculate the control flow - OrderedNode *BlockNode = HeaderOp->Blocks.GetNode(ListBegin); - while (1) { - auto BlockIROp = BlockNode->Op(DataBegin)->CW(); + for (auto Block : CurrentIR.getBlocks()) { + auto BlockIROp = Block.GetNode(ListBegin)->Op(DataBegin)->CW(); LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); // We grab these nodes this way so we can iterate easily @@ -68,12 +60,6 @@ bool PhiValidation::Run(IREmitter *IREmit) { } ++CodeBegin; } - - if (BlockIROp->Next.ID() == 0) { - break; - } else { - BlockNode = BlockIROp->Next.GetNode(ListBegin); - } } std::stringstream Out; diff --git a/External/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp b/External/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp index 26883d5e2..d881124f7 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp @@ -27,17 +27,8 @@ bool DeadFlagCalculationEliminination::Run(IREmitter *IREmit) { uintptr_t ListBegin = CurrentIR.GetListData(); uintptr_t DataBegin = CurrentIR.GetData(); - auto Begin = CurrentIR.begin(); - auto Op = Begin(); - - OrderedNode *RealNode = Op->GetNode(ListBegin); - auto HeaderOp = RealNode->Op(DataBegin)->CW(); - LogMan::Throw::A(HeaderOp->Header.Op == OP_IRHEADER, "First op wasn't IRHeader"); - - OrderedNode *BlockNode = HeaderOp->Blocks.GetNode(ListBegin); - - while (1) { - auto BlockIROp = BlockNode->Op(DataBegin)->CW(); + for (auto Block : CurrentIR.getBlocks()) { + auto BlockIROp = Block.GetNode(ListBegin)->Op(DataBegin)->CW(); LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); // We grab these nodes this way so we can iterate easily @@ -65,12 +56,6 @@ bool DeadFlagCalculationEliminination::Run(IREmitter *IREmit) { ++CodeBegin; } - if (BlockIROp->Next.ID() == 0) { - break; - } else { - BlockNode = BlockIROp->Next.GetNode(ListBegin); - } - // If any flags are stored but not loaded by the end of the block, then erase them for (auto &Flag : LastValidFlagStores) { if (Flag != nullptr) { diff --git a/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp b/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp index f8677c0f3..e5a4211f1 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp @@ -261,16 +261,8 @@ namespace { uintptr_t ListBegin = IR->GetListData(); uintptr_t DataBegin = IR->GetData(); - auto Begin = IR->begin(); - auto Op = Begin(); - - FEXCore::IR::OrderedNode *RealNode = Op->GetNode(ListBegin); - auto HeaderOp = RealNode->Op(DataBegin)->CW(); - LogMan::Throw::A(HeaderOp->Header.Op == FEXCore::IR::OP_IRHEADER, "First op wasn't IRHeader"); - - FEXCore::IR::OrderedNode *BlockNode = HeaderOp->Blocks.GetNode(ListBegin); - - while (1) { + for (auto Block : IR->getBlocks()) { + auto BlockNode = Block.GetNode(ListBegin); auto BlockIROp = BlockNode->Op(DataBegin)->CW(); LogMan::Throw::A(BlockIROp->Header.Op == FEXCore::IR::OP_CODEBLOCK, "IR type failed to be a code block"); @@ -294,12 +286,6 @@ namespace { } ++CodeBegin; } - - if (BlockIROp->Next.ID() == 0) { - break; - } else { - BlockNode = BlockIROp->Next.GetNode(ListBegin); - } } } } @@ -398,17 +384,9 @@ namespace FEXCore::IR { uintptr_t ListBegin = IR->GetListData(); uintptr_t DataBegin = IR->GetData(); - auto Begin = IR->begin(); - auto Op = Begin(); - - IR::OrderedNode *RealNode = Op->GetNode(ListBegin); - auto HeaderOp = RealNode->Op(DataBegin)->CW(); - LogMan::Throw::A(HeaderOp->Header.Op == IR::OP_IRHEADER, "First op wasn't IRHeader"); - - IR::OrderedNode *BlockNode = HeaderOp->Blocks.GetNode(ListBegin); - constexpr uint32_t DEFAULT_REMAT_COST = 1000; - while (1) { + for (auto Block : IR->getBlocks()) { + auto BlockNode = Block.GetNode(ListBegin); auto BlockIROp = BlockNode->Op(DataBegin)->CW(); LogMan::Throw::A(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block"); @@ -482,12 +460,6 @@ namespace FEXCore::IR { } ++CodeBegin; } - - if (BlockIROp->Next.ID() == 0) { - break; - } else { - BlockNode = BlockIROp->Next.GetNode(ListBegin); - } } } @@ -496,16 +468,8 @@ namespace FEXCore::IR { uintptr_t ListBegin = IR->GetListData(); uintptr_t DataBegin = IR->GetData(); - auto Begin = IR->begin(); - auto Op = Begin(); - - IR::OrderedNode *RealNode = Op->GetNode(ListBegin); - auto HeaderOp = RealNode->Op(DataBegin)->CW(); - LogMan::Throw::A(HeaderOp->Header.Op == IR::OP_IRHEADER, "First op wasn't IRHeader"); - - IR::OrderedNode *BlockNode = HeaderOp->Blocks.GetNode(ListBegin); - - while (1) { + for (auto Block : IR->getBlocks()) { + auto BlockNode = Block.GetNode(ListBegin); auto BlockIROp = BlockNode->Op(DataBegin)->CW(); LogMan::Throw::A(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block"); @@ -537,12 +501,6 @@ namespace FEXCore::IR { } ++CodeBegin; } - - if (BlockIROp->Next.ID() == 0) { - break; - } else { - BlockNode = BlockIROp->Next.GetNode(ListBegin); - } } } @@ -565,16 +523,8 @@ namespace FEXCore::IR { uintptr_t ListBegin = IR->GetListData(); uintptr_t DataBegin = IR->GetData(); - auto Begin = IR->begin(); - auto Op = Begin(); - - IR::OrderedNode *RealNode = Op->GetNode(ListBegin); - auto HeaderOp = RealNode->Op(DataBegin)->CW(); - LogMan::Throw::A(HeaderOp->Header.Op == IR::OP_IRHEADER, "First op wasn't IRHeader"); - - IR::OrderedNode *BlockNode = HeaderOp->Blocks.GetNode(ListBegin); - - while (1) { + for (auto Block : IR->getBlocks()) { + auto BlockNode = Block.GetNode(ListBegin); auto BlockIROp = BlockNode->Op(DataBegin)->CW(); LogMan::Throw::A(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block"); @@ -624,12 +574,6 @@ namespace FEXCore::IR { } ++CodeBegin; } - - if (BlockIROp->Next.ID() == 0) { - break; - } else { - BlockNode = BlockIROp->Next.GetNode(ListBegin); - } } } @@ -1166,12 +1110,6 @@ namespace FEXCore::IR { } ++CodeBegin; } - - if (BlockIROp->Next.ID() == 0) { - break; - } else { - BlockNode = BlockIROp->Next.GetNode(ListBegin); - } } } diff --git a/External/FEXCore/Source/Interface/IR/Passes/SyscallOptimization.cpp b/External/FEXCore/Source/Interface/IR/Passes/SyscallOptimization.cpp index 1bb3f7c5a..b2b6a25ac 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/SyscallOptimization.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/SyscallOptimization.cpp @@ -17,17 +17,9 @@ bool SyscallOptimization::Run(IREmitter *IREmit) { uintptr_t ListBegin = CurrentIR.GetListData(); uintptr_t DataBegin = CurrentIR.GetData(); - auto Begin = CurrentIR.begin(); - auto Op = Begin(); - OrderedNode *RealNode = Op->GetNode(ListBegin); - auto HeaderOp = RealNode->Op(DataBegin)->CW(); - LogMan::Throw::A(HeaderOp->Header.Op == OP_IRHEADER, "First op wasn't IRHeader"); - - OrderedNode *BlockNode = HeaderOp->Blocks.GetNode(ListBegin); - - while (1) { - auto BlockIROp = BlockNode->Op(DataBegin)->CW(); + for (auto Block : CurrentIR.getBlocks()) { + auto BlockIROp = Block.GetNode(ListBegin)->Op(DataBegin)->CW(); LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); // We grab these nodes this way so we can iterate easily @@ -61,13 +53,6 @@ bool SyscallOptimization::Run(IREmitter *IREmit) { } ++CodeBegin; } - - if (BlockIROp->Next.ID() == 0) { - break; - } else { - BlockNode = BlockIROp->Next.GetNode(ListBegin); - } - } return Changed; diff --git a/External/FEXCore/Source/Interface/IR/Passes/ValueDominanceValidation.cpp b/External/FEXCore/Source/Interface/IR/Passes/ValueDominanceValidation.cpp index c4ace11e0..a2f74aadf 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/ValueDominanceValidation.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/ValueDominanceValidation.cpp @@ -30,16 +30,8 @@ bool ValueDominanceValidation::Run(IREmitter *IREmit) { std::unordered_map OffsetToBlockMap; - auto Begin = CurrentIR.begin(); - auto Op = Begin(); - - OrderedNode *RealNode = Op->GetNode(ListBegin); - auto HeaderOp = RealNode->Op(DataBegin)->CW(); - LogMan::Throw::A(HeaderOp->Header.Op == OP_IRHEADER, "First op wasn't IRHeader"); - - // Walk the list and calculate the control flow - OrderedNode *BlockNode = HeaderOp->Blocks.GetNode(ListBegin); - while (1) { + for (auto Block : CurrentIR.getBlocks()) { + auto BlockNode = Block.GetNode(ListBegin); auto BlockIROp = BlockNode->Op(DataBegin)->CW(); LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); @@ -96,16 +88,10 @@ bool ValueDominanceValidation::Run(IREmitter *IREmit) { } ++CodeBegin; } - - if (BlockIROp->Next.ID() == 0) { - break; - } else { - BlockNode = BlockIROp->Next.GetNode(ListBegin); - } } - BlockNode = HeaderOp->Blocks.GetNode(ListBegin); - while (1) { + for (auto Block : CurrentIR.getBlocks()) { + auto BlockNode = Block.GetNode(ListBegin); auto BlockIROp = BlockNode->Op(DataBegin)->CW(); LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); @@ -228,12 +214,6 @@ bool ValueDominanceValidation::Run(IREmitter *IREmit) { } ++CodeBegin; } - - if (BlockIROp->Next.ID() == 0) { - break; - } else { - BlockNode = BlockIROp->Next.GetNode(ListBegin); - } } std::stringstream Out; diff --git a/External/FEXCore/include/FEXCore/IR/IR.h b/External/FEXCore/include/FEXCore/IR/IR.h index 4dc134d88..3b8983c2c 100644 --- a/External/FEXCore/include/FEXCore/IR/IR.h +++ b/External/FEXCore/include/FEXCore/IR/IR.h @@ -89,7 +89,7 @@ static_assert(sizeof(OrderedNodeHeader) == sizeof(uint32_t) * 3); * This stores both the memory base and the provided NodeWrapper to be able to walk the list of nodes directly * Only the increment and decrement implementations of this class require understanding the implementation details of OrderedNode */ -class NodeWrapperIterator final { +class NodeWrapperIterator { public: using value_type = OrderedNodeWrapper; using size_type = std::size_t; @@ -108,8 +108,8 @@ public: using NodePtr = value_type*; using NodeRef = value_type&; - NodeWrapperIterator(uintptr_t Base) : BaseList {Base} {} - explicit NodeWrapperIterator(uintptr_t Base, NodeType Ptr) : BaseList {Base}, Node {Ptr} {} + NodeWrapperIterator(uintptr_t Base, uintptr_t IRBase) : BaseList {Base}, IRList{ IRBase } {} + explicit NodeWrapperIterator(uintptr_t Base, uintptr_t IRBase, NodeType Ptr) : BaseList {Base}, IRList{ IRBase }, Node {Ptr} {} bool operator==(const NodeWrapperIterator &rhs) const { return Node.NodeOffset == rhs.Node.NodeOffset; @@ -119,17 +119,17 @@ public: return !operator==(rhs); } - NodeWrapperIterator operator++() { + NodeWrapperIterator operator++() { OrderedNodeHeader *RealNode = reinterpret_cast(Node.GetNode(BaseList)); - Node = RealNode->Next; - return *this; - } + Node = RealNode->Next; + return *this; + } - NodeWrapperIterator operator--() { - OrderedNodeHeader *RealNode = reinterpret_cast(Node.GetNode(BaseList)); - Node = RealNode->Previous; - return *this; - } + NodeWrapperIterator operator--() { + OrderedNodeHeader *RealNode = reinterpret_cast(Node.GetNode(BaseList)); + Node = RealNode->Previous; + return *this; + } NodeRef operator*() { return Node; @@ -140,11 +140,12 @@ public: } static NodeWrapperIterator Invalid() { - return NodeWrapperIterator(0); + return NodeWrapperIterator(0, 0); } -private: +protected: uintptr_t BaseList{}; + uintptr_t IRList{}; NodeType Node{}; }; diff --git a/External/FEXCore/include/FEXCore/IR/IREmitter.h b/External/FEXCore/include/FEXCore/IR/IREmitter.h index 51da9b926..1d2f38bd6 100644 --- a/External/FEXCore/include/FEXCore/IR/IREmitter.h +++ b/External/FEXCore/include/FEXCore/IR/IREmitter.h @@ -454,23 +454,22 @@ friend class FEXCore::IR::PassManager; * @return OrderedNode */ IRPair CreateCodeNode() { - auto CodeNode = _CodeBlock(InvalidNode, InvalidNode, InvalidNode); + SetWriteCursor(nullptr); // Orphan from any previous nodes + + auto CodeNode = _CodeBlock(InvalidNode, InvalidNode); CodeBlocks.emplace_back(CodeNode); + + SetWriteCursor(nullptr);// Orphan from any future nodes + + auto Begin = _Dummy(); + CodeNode.first->Begin = Begin.Node->Wrapped(ListData.Begin()); + + auto EndBlock = _EndBlock(CodeNode); + CodeNode.first->Last = EndBlock.Node->Wrapped(ListData.Begin()); + return CodeNode; } - void SetCodeNodeBegin(OrderedNode *CodeNode, OrderedNode *Begin) { - FEXCore::IR::IROp_CodeBlock *IROp = CodeNode->Op(Data.Begin())->CW(); - LogMan::Throw::A(IROp->Header.Op == IROps::OP_CODEBLOCK, "Invalid"); - IROp->Begin = Begin->Wrapped(ListData.Begin()); - } - - void SetCodeNodeLast(OrderedNode *CodeNode, OrderedNode *Last) { - FEXCore::IR::IROp_CodeBlock *IROp = CodeNode->Op(Data.Begin())->CW(); - LogMan::Throw::A(IROp->Header.Op == IROps::OP_CODEBLOCK, "Invalid"); - IROp->Last = Last->Wrapped(ListData.Begin()); - } - /** * @name Links codeblocks together * Codeblocks are singly linked so we need to walk the list forward if the linked block isn't isn't the last @@ -483,22 +482,10 @@ friend class FEXCore::IR::PassManager; * @{ */ /** @} */ void LinkCodeBlocks(OrderedNode *CodeNode, OrderedNode *Next) { - FEXCore::IR::IROp_CodeBlock *CurrentIROp = CodeNode->Op(Data.Begin())->CW(); - LogMan::Throw::A(CurrentIROp->Header.Op == IROps::OP_CODEBLOCK, "Invalid"); + FEXCore::IR::IROp_CodeBlock *CurrentIROp = CodeNode->Op(Data.Begin())->CW(); + LogMan::Throw::A(CurrentIROp->Header.Op == IROps::OP_CODEBLOCK, "Invalid"); - OrderedNodeWrapper OldNext = CurrentIROp->Next; - // First thing is to assign CodeNode->Next to the incoming node - { - CurrentIROp->Next = Next->Wrapped(ListData.Begin()); - } - - // Second thing is to assign the incoming node's Next to what was in CodeNode->Next - { - FEXCore::IR::IROp_CodeBlock *NextIROp = Next->Op(Data.Begin())->CW(); - auto NewOldNext = NextIROp->Next; - NextIROp->Next = OldNext; - OldNext = NewOldNext; - } + CodeNode->append(ListData.Begin(), Next); } IRPair CreateNewCodeBlock(); diff --git a/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h b/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h index 85c8cb7fd..3749ea7e6 100644 --- a/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h +++ b/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h @@ -98,13 +98,53 @@ public: size_t GetListSize() const { return ListSize; } size_t GetSSACount() const { return ListSize / sizeof(OrderedNode); } + OrderedNode* GetHeaderNode() const { + OrderedNodeWrapper Wrapped; + Wrapped.NodeOffset = sizeof(OrderedNode); + return Wrapped.GetNode(GetListData()); + } + + const IROp_IRHeader *GetHeader() const { + auto Node = GetHeaderNode(); + FEXCore::IR::IROp_Header* Header = Node->Op(GetData()); + + return Header->C(); + } + +private: + struct Blocks { + const IRListView *view; + + Blocks(const IRListView *parent) : view(parent) {}; + + using iterator = NodeWrapperIterator; + + iterator begin() const noexcept { + auto Header = view->GetHeader(); + return iterator(reinterpret_cast(view->ListData), reinterpret_cast(view->IRData), Header->Blocks); + } + + iterator end() const noexcept + { + OrderedNodeWrapper Wrapped; + Wrapped.NodeOffset = 0; + return iterator(reinterpret_cast(view->ListData), reinterpret_cast(view->IRData), Wrapped); + } + }; + +public: + + Blocks getBlocks() const { + return Blocks(this); + } + using iterator = NodeWrapperIterator; iterator begin() const noexcept { OrderedNodeWrapper Wrapped; Wrapped.NodeOffset = sizeof(OrderedNode); - return iterator(reinterpret_cast(ListData), Wrapped); + return iterator(reinterpret_cast(ListData), reinterpret_cast(IRData), Wrapped); } /** @@ -116,7 +156,7 @@ public: { OrderedNodeWrapper Wrapped; Wrapped.NodeOffset = 0; - return iterator(reinterpret_cast(ListData), Wrapped); + return iterator(reinterpret_cast(ListData), reinterpret_cast(IRData), Wrapped); } /** @@ -124,7 +164,7 @@ public: * @return Iterator for this op */ iterator at(OrderedNodeWrapper Node) const noexcept { - return iterator(reinterpret_cast(ListData), Node); + return iterator(reinterpret_cast(ListData), reinterpret_cast(IRData), Node); } private: diff --git a/Source/Tests/IRLoader/Loader.cpp b/Source/Tests/IRLoader/Loader.cpp index e3458163d..3fc3c13cd 100644 --- a/Source/Tests/IRLoader/Loader.cpp +++ b/Source/Tests/IRLoader/Loader.cpp @@ -366,16 +366,13 @@ namespace FEX::IRLoader { IRHeader = _IRHeader(InvalidNode, Entry.second, CodeBlockCount.second, false); } + SetWriteCursor(nullptr); // isolate the header from everything following + // Spin through the blocks and generate basic block ops - IRPair PrevBlock{}; for(size_t i = 0; i < Defs.size(); ++i) { auto &Def = Defs[i]; if (Def.OpEnum == FEXCore::IR::IROps::OP_CODEBLOCK) { - auto CodeBlock = _CodeBlock(InvalidNode, InvalidNode, InvalidNode); - if (PrevBlock.first) { - PrevBlock.first->Next = CodeBlock.Node->Wrapped(ListData.Begin()); - } - PrevBlock = CodeBlock; + auto CodeBlock = _CodeBlock(InvalidNode, InvalidNode); SSANameMapper[Def.Definition] = CodeBlock.Node; Def.Node = CodeBlock.Node; @@ -386,6 +383,7 @@ namespace FEX::IRLoader { } } } + SetWriteCursor(nullptr); // isolate the block headers too // Spin through all the definitions and add the ops to the basic blocks OrderedNode *CurrentBlock{}; @@ -405,7 +403,6 @@ namespace FEX::IRLoader { CurrentBlock = DefTarget->second; CurrentBlockOp = CurrentBlock->Op(Data.Begin())->CW(); - SetWriteCursor(CurrentBlock); } if (Def.OpEnum == FEXCore::IR::IROps::OP_ENDBLOCK) { @@ -420,7 +417,7 @@ namespace FEX::IRLoader { if (!CheckPrintError(Def, Adjust.first)) return false; - Def.Node = _EndBlock(Adjust.second); + Def.Node = _EndBlock(CurrentBlock); CurrentBlockOp->Last = Def.Node->Wrapped(ListData.Begin()); CurrentBlock = nullptr; From 36afd5b1c677f5a124067b9ce57266d00e4e4069 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Fri, 4 Sep 2020 04:43:31 +1200 Subject: [PATCH 03/16] Block Iterator: Use structured bindings --- .../Core/Interpreter/InterpreterCore.cpp | 15 +- .../Source/Interface/Core/JIT/x86_64/JIT.cpp | 5 +- External/FEXCore/Source/Interface/IR/IR.cpp | 7 +- .../Source/Interface/IR/Passes/ConstProp.cpp | 4 +- .../IR/Passes/DeadCodeElimination.cpp | 4 +- .../IR/Passes/DeadContextStoreElimination.cpp | 9 +- .../Interface/IR/Passes/IRCompaction.cpp | 5 +- .../Interface/IR/Passes/IRValidation.cpp | 5 +- .../Interface/IR/Passes/PhiValidation.cpp | 4 +- .../RedundantFlagCalculationElimination.cpp | 4 +- .../IR/Passes/RegisterAllocationPass.cpp | 22 +- .../IR/Passes/SyscallOptimization.cpp | 4 +- .../IR/Passes/ValueDominanceValidation.cpp | 10 +- External/FEXCore/include/FEXCore/IR/IR.h | 209 +++++++++++++----- .../include/FEXCore/IR/IntrusiveIRList.h | 2 +- 15 files changed, 197 insertions(+), 112 deletions(-) diff --git a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp index 98e4a7cf1..59a85b488 100644 --- a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp +++ b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp @@ -119,8 +119,8 @@ void InterpreterCore::ExecuteCode(FEXCore::Core::InternalThreadState *Thread) { while (1) { using namespace FEXCore::IR; - IR::OrderedNode const *BlockNode = BlockIterator()->GetNode(ListBegin); - auto BlockIROp = BlockNode->Op(DataBegin)->C(); + auto [BlockNode, BlockHeader] = BlockIterator(); + auto BlockIROp = BlockHeader->CW(); LogMan::Throw::A(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block"); // We grab these nodes this way so we can iterate easily @@ -142,11 +142,8 @@ void InterpreterCore::ExecuteCode(FEXCore::Core::InternalThreadState *Thread) { switch (IROp->Op) { case IR::OP_DUMMY: case IR::OP_BEGINBLOCK: + case IR::OP_ENDBLOCK: break; - case IR::OP_ENDBLOCK: { - auto Op = IROp->C(); - break; - } case IR::OP_FENCE: { auto Op = IROp->C(); switch (Op->Fence) { @@ -171,10 +168,10 @@ void InterpreterCore::ExecuteCode(FEXCore::Core::InternalThreadState *Thread) { auto Op = IROp->C(); uint64_t Arg = *GetSrc(SSAData, Op->Header.Args[0]); if (!!Arg) { - BlockIterator = NodeWrapperIterator(ListBegin, DataBegin, Op->Header.Args[1]); + BlockIterator = NodeIterator(ListBegin, DataBegin, Op->Header.Args[1]); } else { - BlockIterator = NodeWrapperIterator(ListBegin, DataBegin, Op->Header.Args[2]); + BlockIterator = NodeIterator(ListBegin, DataBegin, Op->Header.Args[2]); } BlockResults.Redo = true; return; @@ -182,7 +179,7 @@ void InterpreterCore::ExecuteCode(FEXCore::Core::InternalThreadState *Thread) { } case IR::OP_JUMP: { auto Op = IROp->C(); - BlockIterator = NodeWrapperIterator(ListBegin, DataBegin, Op->Header.Args[0]); + BlockIterator = NodeIterator(ListBegin, DataBegin, Op->Header.Args[0]); BlockResults.Redo = true; return; break; diff --git a/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp b/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp index 0dbb09d9a..779027c25 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp @@ -511,10 +511,9 @@ void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const ret(); }; - for (auto Block : CurrentIR->getBlocks()) { + for (auto [BlockNode, BlockHeader] : CurrentIR->getBlocks()) { using namespace FEXCore::IR; - auto BlockNode = Block.GetNode(ListBegin); - auto BlockIROp = BlockNode->Op(DataBegin)->CW(); + auto BlockIROp = BlockHeader->CW(); LogMan::Throw::A(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block"); // We grab these nodes this way so we can iterate easily diff --git a/External/FEXCore/Source/Interface/IR/IR.cpp b/External/FEXCore/Source/Interface/IR/IR.cpp index 64c0557c7..b6741d2f4 100644 --- a/External/FEXCore/Source/Interface/IR/IR.cpp +++ b/External/FEXCore/Source/Interface/IR/IR.cpp @@ -132,10 +132,9 @@ void Dump(std::stringstream *out, IRListView const* IR, IR::RegisterAlloc *out << "%ssa" << HeaderOp->Blocks.ID() << ", "; *out << "#" << std::dec << HeaderOp->BlockCount << std::endl; - for (auto Block : IR->getBlocks()) { - auto BlockNode = Block.GetNode(ListBegin); - auto BlockIROp = BlockNode->Op(DataBegin)->CW(); - // LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); + for (auto [BlockNode, BlockHeader] : IR->getBlocks()) { + auto BlockIROp = BlockHeader->CW(); + // LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); // We grab these nodes this way so we can iterate easily auto CodeBegin = IR->at(BlockIROp->Begin); diff --git a/External/FEXCore/Source/Interface/IR/Passes/ConstProp.cpp b/External/FEXCore/Source/Interface/IR/Passes/ConstProp.cpp index bdefa5bc5..a13cc8e90 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/ConstProp.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/ConstProp.cpp @@ -22,8 +22,8 @@ bool ConstProp::Run(IREmitter *IREmit) { auto OriginalWriteCursor = IREmit->GetWriteCursor(); - for (auto Block : CurrentIR.getBlocks()) { - auto BlockIROp = Block.GetNode(ListBegin)->Op(DataBegin)->CW(); + for (auto [BlockNode, BlockHeader] : CurrentIR.getBlocks()) { + auto BlockIROp = BlockHeader->CW(); LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); // We grab these nodes this way so we can iterate easily diff --git a/External/FEXCore/Source/Interface/IR/Passes/DeadCodeElimination.cpp b/External/FEXCore/Source/Interface/IR/Passes/DeadCodeElimination.cpp index 439fe9c25..136adc73c 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/DeadCodeElimination.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/DeadCodeElimination.cpp @@ -22,8 +22,8 @@ bool DeadCodeElimination::Run(IREmitter *IREmit) { int NumRemoved = 0; - for (auto Block : CurrentIR.getBlocks()) { - auto BlockIROp = Block.GetNode(ListBegin)->Op(DataBegin)->CW(); + for (auto [BlockNode, BlockHeader] : CurrentIR.getBlocks()) { + auto BlockIROp = BlockHeader->CW(); LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); // We grab these nodes this way so we can iterate easily diff --git a/External/FEXCore/Source/Interface/IR/Passes/DeadContextStoreElimination.cpp b/External/FEXCore/Source/Interface/IR/Passes/DeadContextStoreElimination.cpp index 15efeab68..75ebe8b16 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/DeadContextStoreElimination.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/DeadContextStoreElimination.cpp @@ -317,9 +317,8 @@ void RCLSE::CalculateControlFlowInfo(FEXCore::IR::IREmitter *IREmit) { uintptr_t ListBegin = CurrentIR.GetListData(); uintptr_t DataBegin = CurrentIR.GetData(); - for (auto Block : CurrentIR.getBlocks()) { - auto BlockNode = Block.GetNode(ListBegin); - auto BlockIROp = BlockNode->Op(DataBegin)->CW(); + for (auto [BlockNode, BlockHeader] : CurrentIR.getBlocks()) { + auto BlockIROp = BlockHeader->CW(); LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); BlockInfo *CurrentBlock = &OffsetToBlockMap.try_emplace(BlockNode->Wrapped(ListBegin).ID()).first->second; @@ -435,8 +434,8 @@ bool RCLSE::RedundantStoreLoadElimination(FEXCore::IR::IREmitter *IREmit) { ContextInfo LocalInfo = ClassifiedStruct; - for (auto Block : CurrentIR.getBlocks()) { - auto BlockIROp = Block.GetNode(ListBegin)->Op(DataBegin)->CW(); + for (auto [BlockNode, BlockHeader] : CurrentIR.getBlocks()) { + auto BlockIROp = BlockHeader->CW(); LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); ResetClassificationAccesses(&LocalInfo); diff --git a/External/FEXCore/Source/Interface/IR/Passes/IRCompaction.cpp b/External/FEXCore/Source/Interface/IR/Passes/IRCompaction.cpp index 2551fa37f..3eb59d8b7 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/IRCompaction.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/IRCompaction.cpp @@ -74,9 +74,8 @@ bool IRCompaction::Run(IREmitter *IREmit) { { // Generate our codeblocks and link them together OrderedNode* PrevCodeBlock{}; - for (auto Block : CurrentIR.getBlocks()) { - auto BlockNode = Block.GetNode(ListBegin); - auto BlockIROp = BlockNode->Op(DataBegin)->CW(); + for (auto [BlockNode, BlockHeader] : CurrentIR.getBlocks()) { + auto BlockIROp = BlockHeader->CW(); LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); auto LocalBlockIRNode = LocalBuilder._CodeBlock(LocalHeaderOp, LocalHeaderOp); // Use LocalHeaderOp as a dummy arg for now diff --git a/External/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp b/External/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp index 61bd371b2..0397c164e 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp @@ -47,9 +47,8 @@ bool IRValidation::Run(IREmitter *IREmit) { RAPass = Manager->GetRAPass(); } - for (auto Block : CurrentIR.getBlocks()) { - auto BlockNode = Block.GetNode(ListBegin); - auto BlockIROp = BlockNode->Op(DataBegin)->CW(); + for (auto [BlockNode, BlockHeader] : CurrentIR.getBlocks()) { + auto BlockIROp = BlockHeader->CW(); LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); BlockInfo *CurrentBlock = &OffsetToBlockMap.try_emplace(BlockNode->Wrapped(ListBegin).ID()).first->second; diff --git a/External/FEXCore/Source/Interface/IR/Passes/PhiValidation.cpp b/External/FEXCore/Source/Interface/IR/Passes/PhiValidation.cpp index a819ca6c0..7112a4c22 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/PhiValidation.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/PhiValidation.cpp @@ -19,8 +19,8 @@ bool PhiValidation::Run(IREmitter *IREmit) { std::ostringstream Errors; // Walk the list and calculate the control flow - for (auto Block : CurrentIR.getBlocks()) { - auto BlockIROp = Block.GetNode(ListBegin)->Op(DataBegin)->CW(); + for (auto [BlockNode, BlockHeader] : CurrentIR.getBlocks()) { + auto BlockIROp = BlockHeader->CW(); LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); // We grab these nodes this way so we can iterate easily diff --git a/External/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp b/External/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp index d881124f7..546cffd36 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp @@ -27,8 +27,8 @@ bool DeadFlagCalculationEliminination::Run(IREmitter *IREmit) { uintptr_t ListBegin = CurrentIR.GetListData(); uintptr_t DataBegin = CurrentIR.GetData(); - for (auto Block : CurrentIR.getBlocks()) { - auto BlockIROp = Block.GetNode(ListBegin)->Op(DataBegin)->CW(); + for (auto [BlockNode, BlockHeader] : CurrentIR.getBlocks()) { + auto BlockIROp = BlockHeader->CW(); LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); // We grab these nodes this way so we can iterate easily diff --git a/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp b/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp index e5a4211f1..0cec8ddea 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp @@ -261,9 +261,8 @@ namespace { uintptr_t ListBegin = IR->GetListData(); uintptr_t DataBegin = IR->GetData(); - for (auto Block : IR->getBlocks()) { - auto BlockNode = Block.GetNode(ListBegin); - auto BlockIROp = BlockNode->Op(DataBegin)->CW(); + for (auto [BlockNode, BlockHeader] : IR->getBlocks()) { + auto BlockIROp = BlockHeader->CW(); LogMan::Throw::A(BlockIROp->Header.Op == FEXCore::IR::OP_CODEBLOCK, "IR type failed to be a code block"); // We grab these nodes this way so we can iterate easily @@ -385,9 +384,8 @@ namespace FEXCore::IR { uintptr_t DataBegin = IR->GetData(); constexpr uint32_t DEFAULT_REMAT_COST = 1000; - for (auto Block : IR->getBlocks()) { - auto BlockNode = Block.GetNode(ListBegin); - auto BlockIROp = BlockNode->Op(DataBegin)->CW(); + for (auto [BlockNode, BlockHeader] : IR->getBlocks()) { + auto BlockIROp = BlockHeader->CW(); LogMan::Throw::A(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block"); // We grab these nodes this way so we can iterate easily @@ -466,11 +464,9 @@ namespace FEXCore::IR { void ConstrainedRAPass::CalculateBlockInterferences(FEXCore::IR::IRListView *IR) { using namespace FEXCore; uintptr_t ListBegin = IR->GetListData(); - uintptr_t DataBegin = IR->GetData(); - for (auto Block : IR->getBlocks()) { - auto BlockNode = Block.GetNode(ListBegin); - auto BlockIROp = BlockNode->Op(DataBegin)->CW(); + for (auto [BlockNode, BlockHeader] : IR->getBlocks()) { + auto BlockIROp = BlockHeader->CW(); LogMan::Throw::A(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block"); BlockInterferences *BlockInterferenceVector = &LocalBlockInterferences.try_emplace(BlockNode->Wrapped(ListBegin).ID()).first->second; @@ -521,11 +517,9 @@ namespace FEXCore::IR { }; using namespace FEXCore; uintptr_t ListBegin = IR->GetListData(); - uintptr_t DataBegin = IR->GetData(); - for (auto Block : IR->getBlocks()) { - auto BlockNode = Block.GetNode(ListBegin); - auto BlockIROp = BlockNode->Op(DataBegin)->CW(); + for (auto [BlockNode, BlockHeader] : IR->getBlocks()) { + auto BlockIROp = BlockHeader->CW(); LogMan::Throw::A(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block"); BlockInterferences *BlockInterferenceVector = &LocalBlockInterferences.try_emplace(BlockNode->Wrapped(ListBegin).ID()).first->second; diff --git a/External/FEXCore/Source/Interface/IR/Passes/SyscallOptimization.cpp b/External/FEXCore/Source/Interface/IR/Passes/SyscallOptimization.cpp index b2b6a25ac..e9eb8dcd1 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/SyscallOptimization.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/SyscallOptimization.cpp @@ -18,8 +18,8 @@ bool SyscallOptimization::Run(IREmitter *IREmit) { uintptr_t DataBegin = CurrentIR.GetData(); - for (auto Block : CurrentIR.getBlocks()) { - auto BlockIROp = Block.GetNode(ListBegin)->Op(DataBegin)->CW(); + for (auto [BlockNode, BlockHeader] : CurrentIR.getBlocks()) { + auto BlockIROp = BlockHeader->CW(); LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); // We grab these nodes this way so we can iterate easily diff --git a/External/FEXCore/Source/Interface/IR/Passes/ValueDominanceValidation.cpp b/External/FEXCore/Source/Interface/IR/Passes/ValueDominanceValidation.cpp index a2f74aadf..2197465a7 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/ValueDominanceValidation.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/ValueDominanceValidation.cpp @@ -30,9 +30,8 @@ bool ValueDominanceValidation::Run(IREmitter *IREmit) { std::unordered_map OffsetToBlockMap; - for (auto Block : CurrentIR.getBlocks()) { - auto BlockNode = Block.GetNode(ListBegin); - auto BlockIROp = BlockNode->Op(DataBegin)->CW(); + for (auto [BlockNode, BlockHeader] : CurrentIR.getBlocks()) { + auto BlockIROp = BlockHeader->CW(); LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); BlockInfo *CurrentBlock = &OffsetToBlockMap.try_emplace(BlockNode->Wrapped(ListBegin).ID()).first->second; @@ -90,9 +89,8 @@ bool ValueDominanceValidation::Run(IREmitter *IREmit) { } } - for (auto Block : CurrentIR.getBlocks()) { - auto BlockNode = Block.GetNode(ListBegin); - auto BlockIROp = BlockNode->Op(DataBegin)->CW(); + for (auto [BlockNode, BlockHeader] : CurrentIR.getBlocks()) { + auto BlockIROp = BlockHeader->CW(); LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); // We grab these nodes this way so we can iterate easily diff --git a/External/FEXCore/include/FEXCore/IR/IR.h b/External/FEXCore/include/FEXCore/IR/IR.h index 3b8983c2c..c48a1a9e0 100644 --- a/External/FEXCore/include/FEXCore/IR/IR.h +++ b/External/FEXCore/include/FEXCore/IR/IR.h @@ -3,6 +3,7 @@ #include #include #include +#include namespace FEXCore::IR { class RegisterAllocationPass; @@ -84,70 +85,44 @@ struct OrderedNodeHeader { static_assert(sizeof(OrderedNodeHeader) == sizeof(uint32_t) * 3); -/** -* @brief This is our NodeWrapperIterator -* This stores both the memory base and the provided NodeWrapper to be able to walk the list of nodes directly -* Only the increment and decrement implementations of this class require understanding the implementation details of OrderedNode -*/ -class NodeWrapperIterator { -public: - using value_type = OrderedNodeWrapper; - using size_type = std::size_t; - using difference_type = std::ptrdiff_t; - using reference = value_type&; - using const_reference = const value_type&; - using pointer = value_type*; - using const_pointer = const value_type*; - using iterator = NodeWrapperIterator; - using const_iterator = const NodeWrapperIterator; - using reverse_iterator = iterator; - using const_reverse_iterator = const_iterator; - using iterator_category = std::bidirectional_iterator_tag; - using NodeType = value_type; - using NodePtr = value_type*; - using NodeRef = value_type&; - NodeWrapperIterator(uintptr_t Base, uintptr_t IRBase) : BaseList {Base}, IRList{ IRBase } {} - explicit NodeWrapperIterator(uintptr_t Base, uintptr_t IRBase, NodeType Ptr) : BaseList {Base}, IRList{ IRBase }, Node {Ptr} {} +// class AllNodesIterator : public NodeWrapperIterator { +// AllNodesIterator operator++() { +// OrderedNodeHeader *RealNode = reinterpret_cast(Node.GetNode(BaseList)); +// auto IROp = Node.GetNode(BaseList)->Op(IRList); - bool operator==(const NodeWrapperIterator &rhs) const { - return Node.NodeOffset == rhs.Node.NodeOffset; - } +// // If this is the last node of a codeblock, we need to continue to the next block +// if (IROp->Op == OP_ENDBLOCK) { +// auto EndBlock = IROp->C(); - bool operator!=(const NodeWrapperIterator &rhs) const { - return !operator==(rhs); - } +// OrderedNodeHeader *CurrentBlock = EndBlock->BlockHeader; - NodeWrapperIterator operator++() { - OrderedNodeHeader *RealNode = reinterpret_cast(Node.GetNode(BaseList)); - Node = RealNode->Next; - return *this; - } +// Node = CurrentBlock->Next; +// } else if (IROp->Op == OP_CODEBLOCK) { +// auto CodeBlock = IROp->C(); - NodeWrapperIterator operator--() { - OrderedNodeHeader *RealNode = reinterpret_cast(Node.GetNode(BaseList)); - Node = RealNode->Previous; - return *this; - } +// Node = CodeBlock->Begin; +// } else { +// Node = RealNode->Next; +// } - NodeRef operator*() { - return Node; - } +// return *this; +// } - NodePtr operator()() { - return &Node; - } +// AllNodesIterator operator--() { +// OrderedNodeHeader *RealNode = reinterpret_cast(Node.GetNode(BaseList)); +// auto IROp = Node.GetNode(BaseList)->Op(IRList); - static NodeWrapperIterator Invalid() { - return NodeWrapperIterator(0, 0); - } +// // Reverse iterator is a little harder +// if (IROp->Op == OP_CODEBLOCK) { -protected: - uintptr_t BaseList{}; - uintptr_t IRList{}; - NodeType Node{}; -}; +// } + +// Node = RealNode->Previous; +// return *this; +// } +// }; /** * @brief This is a node in our IR representation @@ -373,6 +348,132 @@ struct FenceType final { constexpr bool operator!=(FenceType const &rhs) const { return !operator==(rhs); } }; +/** +* @brief This is our NodeWrapperIterator +* This stores both the memory base and the provided NodeWrapper to be able to walk the list of nodes directly +* Only the increment and decrement implementations of this class require understanding the implementation details of OrderedNode +*/ +class NodeWrapperIterator { +public: + using value_type = OrderedNodeWrapper; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using reference = value_type&; + using const_reference = const value_type&; + using pointer = value_type*; + using const_pointer = const value_type*; + using iterator = NodeWrapperIterator; + using const_iterator = const NodeWrapperIterator; + using reverse_iterator = iterator; + using const_reverse_iterator = const_iterator; + using iterator_category = std::bidirectional_iterator_tag; + + using NodeType = value_type; + using NodePtr = value_type*; + using NodeRef = value_type&; + + NodeWrapperIterator(uintptr_t Base, uintptr_t IRBase) : BaseList {Base}, IRList{ IRBase } {} + explicit NodeWrapperIterator(uintptr_t Base, uintptr_t IRBase, NodeType Ptr) : BaseList {Base}, IRList{ IRBase }, Node {Ptr} {} + + bool operator==(const NodeWrapperIterator &rhs) const { + return Node.NodeOffset == rhs.Node.NodeOffset; + } + + bool operator!=(const NodeWrapperIterator &rhs) const { + return !operator==(rhs); + } + + NodeWrapperIterator operator++() { + OrderedNodeHeader *RealNode = reinterpret_cast(Node.GetNode(BaseList)); + Node = RealNode->Next; + return *this; + } + + NodeWrapperIterator operator--() { + OrderedNodeHeader *RealNode = reinterpret_cast(Node.GetNode(BaseList)); + Node = RealNode->Previous; + return *this; + } + + NodeRef operator*() { + return Node; + } + + NodePtr operator()() { + return &Node; + } + + static NodeWrapperIterator Invalid() { + return NodeWrapperIterator(0, 0); + } + +protected: + uintptr_t BaseList{}; + uintptr_t IRList{}; + NodeType Node{}; +}; + +class NodeIterator { +public: + using value_type = std::tuple; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using reference = value_type&; + using const_reference = const value_type&; + using pointer = value_type*; + using const_pointer = const value_type*; + using iterator = NodeWrapperIterator; + using const_iterator = const NodeWrapperIterator; + using reverse_iterator = iterator; + using const_reverse_iterator = const_iterator; + using iterator_category = std::bidirectional_iterator_tag; + + using NodePtr = value_type*; + using NodeRef = value_type&; + + NodeIterator(uintptr_t Base, uintptr_t IRBase) : BaseList {Base}, IRList{ IRBase } {} + explicit NodeIterator(uintptr_t Base, uintptr_t IRBase, OrderedNodeWrapper Ptr) : BaseList {Base}, IRList{ IRBase }, Node {Ptr} {} + + bool operator==(const NodeIterator &rhs) const { + return Node.NodeOffset == rhs.Node.NodeOffset; + } + + bool operator!=(const NodeIterator &rhs) const { + return !operator==(rhs); + } + + NodeIterator operator++() { + OrderedNodeHeader *RealNode = reinterpret_cast(Node.GetNode(BaseList)); + Node = RealNode->Next; + return *this; + } + + NodeIterator operator--() { + OrderedNodeHeader *RealNode = reinterpret_cast(Node.GetNode(BaseList)); + Node = RealNode->Previous; + return *this; + } + + value_type operator*() { + OrderedNode *RealNode = Node.GetNode(BaseList); + return { RealNode, RealNode->Op(IRList) }; + } + + value_type operator()() { + OrderedNode *RealNode = Node.GetNode(BaseList); + return { RealNode, RealNode->Op(IRList) }; + } + + static NodeIterator Invalid() { + return NodeIterator(0, 0); + } + +protected: + uintptr_t BaseList{}; + uintptr_t IRList{}; + OrderedNodeWrapper Node{}; +}; + #define IROP_ENUM #define IROP_STRUCTS #define IROP_SIZES diff --git a/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h b/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h index 3749ea7e6..355c4a7ab 100644 --- a/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h +++ b/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h @@ -117,7 +117,7 @@ private: Blocks(const IRListView *parent) : view(parent) {}; - using iterator = NodeWrapperIterator; + using iterator = NodeIterator; iterator begin() const noexcept { auto Header = view->GetHeader(); From 599231c18012c39d5f20c36e9db4a910fa881a10 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Fri, 4 Sep 2020 17:43:04 +1200 Subject: [PATCH 04/16] IRListView: Add GetOp --- External/FEXCore/Scripts/json_ir_generator.py | 49 +++++++++---------- .../include/FEXCore/IR/IntrusiveIRList.h | 25 ++++++++-- 2 files changed, 43 insertions(+), 31 deletions(-) diff --git a/External/FEXCore/Scripts/json_ir_generator.py b/External/FEXCore/Scripts/json_ir_generator.py index fedf36c15..5558a8ffd 100644 --- a/External/FEXCore/Scripts/json_ir_generator.py +++ b/External/FEXCore/Scripts/json_ir_generator.py @@ -40,10 +40,6 @@ def print_ir_structs(ops, defines): output_file.write("};\n\n"); - output_file.write("struct __attribute__((packed)) IROp_Empty {\n") - output_file.write("\tIROp_Header Header;\n") - output_file.write("};\n\n") - output_file.write("// User defined IR Op structs\n") for op_key, op_vals in ops.items(): SSAArgs = 0 @@ -59,34 +55,33 @@ def print_ir_structs(ops, defines): if ("SSANames" in op_vals and len(op_vals["SSANames"]) != 0): HasSSANames = True - if (HasArgs or SSAArgs != 0): - output_file.write("struct __attribute__((packed)) IROp_%s {\n" % op_key) - output_file.write("\tIROp_Header Header;\n\n") + output_file.write("struct __attribute__((packed)) IROp_%s {\n" % op_key) + output_file.write("\tIROp_Header Header;\n\n") - # SSA arguments have a hard requirement to appear after the header - if (SSAArgs != 0): - if (HasSSANames): - for i in range(0, SSAArgs): - output_file.write("\tOrderedNodeWrapper %s;\n" % (op_vals["SSANames"][i])); + # SSA arguments have a hard requirement to appear after the header + if (SSAArgs != 0): + if (HasSSANames): + for i in range(0, SSAArgs): + output_file.write("\tOrderedNodeWrapper %s;\n" % (op_vals["SSANames"][i])); - else: - output_file.write("private:\n") - for i in range(0, SSAArgs): - output_file.write("\tuint64_t : (sizeof(OrderedNodeWrapper) * 8);\n"); - output_file.write("public:\n") + else: + output_file.write("private:\n") + for i in range(0, SSAArgs): + output_file.write("\tuint64_t : (sizeof(OrderedNodeWrapper) * 8);\n"); + output_file.write("public:\n") - if (HasArgs): - output_file.write("\t// User defined data\n") + if (HasArgs): + output_file.write("\t// User defined data\n") - # Print out arguments in IR Op - for i in range(0, len(op_vals["Args"]), 2): - data_type = op_vals["Args"][i] - data_name = op_vals["Args"][i+1] - output_file.write("\t%s %s;\n" % (data_type, data_name)) + # Print out arguments in IR Op + for i in range(0, len(op_vals["Args"]), 2): + data_type = op_vals["Args"][i] + data_name = op_vals["Args"][i+1] + output_file.write("\t%s %s;\n" % (data_type, data_name)) - output_file.write("};\n") - else: - output_file.write("using IROp_%s = IROp_Empty;\n" % op_key) + output_file.write("\tstatic constexpr IROps OPCODE = OP_%s;\n" % op_key.upper()) + + output_file.write("};\n") # Add a static assert that the IR ops must be pod output_file.write("static_assert(std::is_pod::value);\n\n" % op_key) diff --git a/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h b/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h index 355c4a7ab..0258a20b2 100644 --- a/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h +++ b/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h @@ -1,6 +1,7 @@ #pragma once #include "FEXCore/IR/IR.h" +#include "LogManager.h" #include #include @@ -98,17 +99,33 @@ public: size_t GetListSize() const { return ListSize; } size_t GetSSACount() const { return ListSize / sizeof(OrderedNode); } + uint32_t GetID(OrderedNode *Node) const { + return Node->Wrapped(GetListData()).ID(); + } + OrderedNode* GetHeaderNode() const { OrderedNodeWrapper Wrapped; Wrapped.NodeOffset = sizeof(OrderedNode); return Wrapped.GetNode(GetListData()); } - const IROp_IRHeader *GetHeader() const { - auto Node = GetHeaderNode(); - FEXCore::IR::IROp_Header* Header = Node->Op(GetData()); + IROp_IRHeader *GetHeader() const { + return GetOp(GetHeaderNode()); + } - return Header->C(); + template + T *GetOp(OrderedNode *Node) const { + auto OpHeader = Node->Op(GetData()); + auto Op = OpHeader->template CW(); + LogMan::Throw::A(Op->OPCODE == Op->Header.Op, "Expected Node to be '%s'. Found '%s' instead", GetName(Op->OPCODE), GetName(Op->Header.Op)); + + return Op; + } + + template + T *GetOp(OrderedNodeWrapper Wrapper) const { + auto Node = Wrapper.GetNode(GetListData()); + return GetOp(Node); } private: From 4ad4f28a752435e6e786248caac150e42754c793 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Fri, 4 Sep 2020 22:24:18 +1200 Subject: [PATCH 05/16] Add Code and All Code iterators --- External/FEXCore/include/FEXCore/IR/IR.h | 72 ++++++++----------- .../include/FEXCore/IR/IntrusiveIRList.h | 66 +++++++++++++---- 2 files changed, 82 insertions(+), 56 deletions(-) diff --git a/External/FEXCore/include/FEXCore/IR/IR.h b/External/FEXCore/include/FEXCore/IR/IR.h index c48a1a9e0..13efd0585 100644 --- a/External/FEXCore/include/FEXCore/IR/IR.h +++ b/External/FEXCore/include/FEXCore/IR/IR.h @@ -85,45 +85,6 @@ struct OrderedNodeHeader { static_assert(sizeof(OrderedNodeHeader) == sizeof(uint32_t) * 3); - - -// class AllNodesIterator : public NodeWrapperIterator { -// AllNodesIterator operator++() { -// OrderedNodeHeader *RealNode = reinterpret_cast(Node.GetNode(BaseList)); -// auto IROp = Node.GetNode(BaseList)->Op(IRList); - -// // If this is the last node of a codeblock, we need to continue to the next block -// if (IROp->Op == OP_ENDBLOCK) { -// auto EndBlock = IROp->C(); - -// OrderedNodeHeader *CurrentBlock = EndBlock->BlockHeader; - -// Node = CurrentBlock->Next; -// } else if (IROp->Op == OP_CODEBLOCK) { -// auto CodeBlock = IROp->C(); - -// Node = CodeBlock->Begin; -// } else { -// Node = RealNode->Next; -// } - -// return *this; -// } - -// AllNodesIterator operator--() { -// OrderedNodeHeader *RealNode = reinterpret_cast(Node.GetNode(BaseList)); -// auto IROp = Node.GetNode(BaseList)->Op(IRList); - -// // Reverse iterator is a little harder -// if (IROp->Op == OP_CODEBLOCK) { - -// } - -// Node = RealNode->Previous; -// return *this; -// } -// }; - /** * @brief This is a node in our IR representation * Is a doubly linked list node that lives in a representation of a linearly allocated node list @@ -428,9 +389,6 @@ public: using const_reverse_iterator = const_iterator; using iterator_category = std::bidirectional_iterator_tag; - using NodePtr = value_type*; - using NodeRef = value_type&; - NodeIterator(uintptr_t Base, uintptr_t IRBase) : BaseList {Base}, IRList{ IRBase } {} explicit NodeIterator(uintptr_t Base, uintptr_t IRBase, OrderedNodeWrapper Ptr) : BaseList {Base}, IRList{ IRBase }, Node {Ptr} {} @@ -480,6 +438,36 @@ protected: #define IROP_REG_CLASSES #include +class AllNodesIterator : public NodeIterator { + using iterator_category = std::forward_iterator_tag; +public: + AllNodesIterator(uintptr_t Base, uintptr_t IRBase) : NodeIterator(Base, IRBase) {} + explicit AllNodesIterator(uintptr_t Base, uintptr_t IRBase, OrderedNodeWrapper Ptr) : NodeIterator(Base, IRBase, Ptr) {} + + AllNodesIterator operator++() { + OrderedNodeHeader *RealNode = reinterpret_cast(Node.GetNode(BaseList)); + auto IROp = Node.GetNode(BaseList)->Op(IRList); + + // If this is the last node of a codeblock, we need to continue to the next block + if (IROp->Op == OP_ENDBLOCK) { + auto EndBlock = IROp->C(); + + auto CurrentBlock = EndBlock->BlockHeader.GetNode(BaseList); + Node = CurrentBlock->Header.Next; + } else if (IROp->Op == OP_CODEBLOCK) { + auto CodeBlock = IROp->C(); + + Node = CodeBlock->Begin; + } else { + Node = RealNode->Next; + } + + return *this; + } + + AllNodesIterator operator--() = delete; +}; + template class IRListView; diff --git a/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h b/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h index 0258a20b2..674278f17 100644 --- a/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h +++ b/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h @@ -129,30 +129,68 @@ public: } private: - struct Blocks { - const IRListView *view; - - Blocks(const IRListView *parent) : view(parent) {}; - + struct BlockRange { using iterator = NodeIterator; + const IRListView *View; + + BlockRange(const IRListView *parent) : View(parent) {}; iterator begin() const noexcept { - auto Header = view->GetHeader(); - return iterator(reinterpret_cast(view->ListData), reinterpret_cast(view->IRData), Header->Blocks); + auto Header = View->GetHeader(); + return iterator(View->GetListData(), View->GetData(), Header->Blocks); } - iterator end() const noexcept - { - OrderedNodeWrapper Wrapped; - Wrapped.NodeOffset = 0; - return iterator(reinterpret_cast(view->ListData), reinterpret_cast(view->IRData), Wrapped); + iterator end() const noexcept { + return iterator(View->GetListData(), View->GetData()); } }; + struct CodeRange { + using iterator = NodeIterator; + const IRListView *View; + const OrderedNodeWrapper BlockWrapper; + + CodeRange(const IRListView *parent, OrderedNodeWrapper block) : View(parent), BlockWrapper(block) {}; + + iterator begin() const noexcept { + auto Block = View->GetOp(BlockWrapper); + return iterator(View->GetListData(), View->GetData(), Block->Begin); + } + + iterator end() const noexcept { + return iterator(View->GetListData(), View->GetData()); + } + }; + + struct AllCodeRange { + using iterator = AllNodesIterator; // Diffrent Iterator + const IRListView *View; + + AllCodeRange(const IRListView *parent) : View(parent) {}; + + iterator begin() const noexcept { + auto Header = View->GetHeader(); + return iterator(View->GetListData(), View->GetData(), Header->Blocks); + } + + iterator end() const noexcept { + return iterator(View->GetListData(), View->GetData()); + } + }; + + public: - Blocks getBlocks() const { - return Blocks(this); + BlockRange getBlocks() const { + return BlockRange(this); + } + + CodeRange getCode(OrderedNode *block) const { + return CodeRange(this, block->Wrapped(GetListData())); + } + + AllCodeRange GetAllCode() const { + return AllCodeRange(this); } using iterator = NodeWrapperIterator; From df6618a4d28f2f6d90ee25aca5a66d14d3e5c925 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Mon, 7 Sep 2020 09:58:42 +1200 Subject: [PATCH 06/16] New replace node functions Probally doesn't build --- .../FEXCore/Source/Interface/IR/IREmitter.cpp | 9 +++-- External/FEXCore/include/FEXCore/IR/IR.h | 5 +++ .../FEXCore/include/FEXCore/IR/IREmitter.h | 35 +++++++++++-------- .../include/FEXCore/IR/IntrusiveIRList.h | 14 ++++++-- 4 files changed, 40 insertions(+), 23 deletions(-) diff --git a/External/FEXCore/Source/Interface/IR/IREmitter.cpp b/External/FEXCore/Source/Interface/IR/IREmitter.cpp index bf74f01ba..61d3c1c5c 100644 --- a/External/FEXCore/Source/Interface/IR/IREmitter.cpp +++ b/External/FEXCore/Source/Interface/IR/IREmitter.cpp @@ -11,18 +11,17 @@ void IREmitter::ResetWorkingList() { CurrentCodeBlock = nullptr; } -void IREmitter::ReplaceAllUsesWithInclusive(OrderedNode *Node, OrderedNode *NewNode, IR::NodeWrapperIterator After, IR::NodeWrapperIterator End) { +void IREmitter::ReplaceAllUsesWithRange(OrderedNode *Node, OrderedNode *NewNode, AllNodesIterator After, AllNodesIterator End) { uintptr_t ListBegin = ListData.Begin(); uintptr_t DataBegin = Data.Begin(); + auto NodeId = Node->Wrapped(ListBegin).ID(); while (After != End) { - OrderedNodeWrapper *WrapperOp = After(); - OrderedNode *RealNode = WrapperOp->GetNode(ListBegin); - FEXCore::IR::IROp_Header *IROp = RealNode->Op(DataBegin); + auto [RealNode, IROp] = After(); uint8_t NumArgs = IR::GetArgs(IROp->Op); for (uint8_t i = 0; i < NumArgs; ++i) { - if (IROp->Args[i].ID() == Node->Wrapped(ListBegin).ID()) { + if (IROp->Args[i].ID() == NodeId) { Node->RemoveUse(); NewNode->AddUse(); IROp->Args[i].NodeOffset = NewNode->Wrapped(ListBegin).NodeOffset; diff --git a/External/FEXCore/include/FEXCore/IR/IR.h b/External/FEXCore/include/FEXCore/IR/IR.h index 13efd0585..0262568ae 100644 --- a/External/FEXCore/include/FEXCore/IR/IR.h +++ b/External/FEXCore/include/FEXCore/IR/IR.h @@ -443,6 +443,7 @@ class AllNodesIterator : public NodeIterator { public: AllNodesIterator(uintptr_t Base, uintptr_t IRBase) : NodeIterator(Base, IRBase) {} explicit AllNodesIterator(uintptr_t Base, uintptr_t IRBase, OrderedNodeWrapper Ptr) : NodeIterator(Base, IRBase, Ptr) {} + AllNodesIterator(NodeIterator other) : NodeIterator(other) {} // Allow NodeIterator to be upgraded AllNodesIterator operator++() { OrderedNodeHeader *RealNode = reinterpret_cast(Node.GetNode(BaseList)); @@ -466,6 +467,10 @@ public: } AllNodesIterator operator--() = delete; + + static AllNodesIterator Invalid() { + return AllNodesIterator(0, 0); + } }; template diff --git a/External/FEXCore/include/FEXCore/IR/IREmitter.h b/External/FEXCore/include/FEXCore/IR/IREmitter.h index 1d2f38bd6..28b821989 100644 --- a/External/FEXCore/include/FEXCore/IR/IREmitter.h +++ b/External/FEXCore/include/FEXCore/IR/IREmitter.h @@ -400,25 +400,30 @@ friend class FEXCore::IR::PassManager; return false; } - // This is fairly special in how it operates - // Since the node is decoupled from the backing op then we can swap out the backing op without much overhead - // This can potentially cause problems where multiple nodes are pointing to the same IROp - OrderedNode *ReplaceAllUsesWith(OrderedNode *Node, IROp_Header *Op) { - RemoveArgUses(Node); - Node->Header.Value.SetOffset(Data.Begin(), reinterpret_cast(Op)); - return Node; + void ReplaceAllUsesWithRange(OrderedNode *Node, OrderedNode *NewNode, AllNodesIterator After, AllNodesIterator End); + + void ReplaceUsesWithAfter(OrderedNode *Node, OrderedNode *NewNode, AllNodesIterator After) { + ReplaceAllUsesWithRange(Node, NewNode, After, AllNodesIterator(ListData.Begin(), Data.Begin())); } - // This is similar to the previous op except that we pass in a node - // This takes the op backing in the new node and replaces the node in the other node - // Again can cause problems where things are pointing to NewNode and haven't been decoupled - OrderedNode *ReplaceAllUsesWith(OrderedNode *Node, OrderedNode *NewNode) { - RemoveArgUses(Node); - Node->Header.Value.NodeOffset = NewNode->Header.Value.NodeOffset; - return Node; + void ReplaceUsesWithAfter(OrderedNode *Node, OrderedNode *NewNode, OrderedNode *After) { + auto Wrapped = Node->Wrapped(ListData.Begin()); + AllNodesIterator It = AllNodesIterator(ListData.Begin(), Data.Begin(), Wrapped); + + ReplaceUsesWithAfter(Node, NewNode, It); + } + + void ReplaceAllUsesWith(OrderedNode *Node, OrderedNode *NewNode) { + auto Start = AllNodesIterator(ListData.Begin(), Data.Begin(), Node->Wrapped(ListData.Begin())); + + ReplaceUsesWithAfter(Node, NewNode, Start); + + LogMan::Throw::A(Node->NumUses == 0, "Node still used"); + + // Since we have deleted ALL uses, we can safely delete the node. + Remove(Node); } - void ReplaceAllUsesWithInclusive(OrderedNode *Node, OrderedNode *NewNode, IR::NodeWrapperIterator After, IR::NodeWrapperIterator End); void ReplaceNodeArgument(OrderedNode *Node, uint8_t Arg, OrderedNode *NewArg); void Remove(OrderedNode *Node); diff --git a/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h b/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h index 674278f17..a4c561d70 100644 --- a/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h +++ b/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h @@ -117,7 +117,11 @@ public: T *GetOp(OrderedNode *Node) const { auto OpHeader = Node->Op(GetData()); auto Op = OpHeader->template CW(); - LogMan::Throw::A(Op->OPCODE == Op->Header.Op, "Expected Node to be '%s'. Found '%s' instead", GetName(Op->OPCODE), GetName(Op->Header.Op)); + + // If we are casting to something narrower than just the header, check the opcode. + if constexpr (!std::is_same::value) { + LogMan::Throw::A(Op->OPCODE == Op->Header.Op, "Expected Node to be '%s'. Found '%s' instead", GetName(Op->OPCODE), GetName(Op->Header.Op)); + } return Op; } @@ -128,6 +132,10 @@ public: return GetOp(Node); } + OrderedNode* GetNode(OrderedNodeWrapper Wrapper) const { + return Wrapper.GetNode(GetListData()); + } + private: struct BlockRange { using iterator = NodeIterator; @@ -181,11 +189,11 @@ private: public: - BlockRange getBlocks() const { + BlockRange GetBlocks() const { return BlockRange(this); } - CodeRange getCode(OrderedNode *block) const { + CodeRange GetCode(OrderedNode *block) const { return CodeRange(this, block->Wrapped(GetListData())); } From 6b26290b4275ff2ffff969404158361d438725f9 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Mon, 7 Sep 2020 10:27:22 +1200 Subject: [PATCH 07/16] Switch most passes to use the new interface. --- .../Core/Interpreter/InterpreterCore.cpp | 23 +- .../Source/Interface/Core/JIT/x86_64/JIT.cpp | 25 +- External/FEXCore/Source/Interface/IR/IR.cpp | 2 +- .../Source/Interface/IR/Passes/ConstProp.cpp | 362 +++++++++--------- .../IR/Passes/DeadCodeElimination.cpp | 35 +- .../IR/Passes/DeadContextStoreElimination.cpp | 86 +---- .../Interface/IR/Passes/IRCompaction.cpp | 42 +- .../Interface/IR/Passes/IRValidation.cpp | 2 +- .../Interface/IR/Passes/PhiValidation.cpp | 23 +- .../RedundantFlagCalculationElimination.cpp | 22 +- .../IR/Passes/RegisterAllocationPass.cpp | 8 +- .../IR/Passes/SyscallOptimization.cpp | 46 +-- .../IR/Passes/ValueDominanceValidation.cpp | 49 +-- 13 files changed, 252 insertions(+), 473 deletions(-) diff --git a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp index 59a85b488..e219fb7e8 100644 --- a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp +++ b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp @@ -93,15 +93,8 @@ void InterpreterCore::ExecuteCode(FEXCore::Core::InternalThreadState *Thread) { static_assert(sizeof(FEXCore::IR::IROp_Header) == 4); static_assert(sizeof(FEXCore::IR::OrderedNode) == 16); - auto HeaderIterator = CurrentIR->begin(); - IR::OrderedNodeWrapper *HeaderNodeWrapper = HeaderIterator(); - IR::OrderedNode *HeaderNode = HeaderNodeWrapper->GetNode(ListBegin); - auto HeaderOp = HeaderNode->Op(DataBegin)->CW(); - LogMan::Throw::A(HeaderOp->Header.Op == IR::OP_IRHEADER, "First op wasn't IRHeader"); - - auto BlockIterator = CurrentIR->getBlocks().begin(); - auto BlockEnd = CurrentIR->getBlocks().end(); - + auto BlockIterator = CurrentIR->GetBlocks().begin(); + auto BlockEnd = CurrentIR->GetBlocks().end(); // Allocate 16 bytes per SSA void *SSAData = alloca(ListSize * 16); @@ -131,13 +124,11 @@ void InterpreterCore::ExecuteCode(FEXCore::Core::InternalThreadState *Thread) { bool Redo; } BlockResults{}; - auto HandleBlock = [&]() { - while (1) { - OrderedNodeWrapper WrapperOp = *CodeBegin(); - OrderedNode *RealNode = WrapperOp.GetNode(ListBegin); - FEXCore::IR::IROp_Header *IROp = RealNode->Op(DataBegin); + auto HandleBlock = [&](OrderedNode *BlockNode) { + for (auto [CodeNode, IROp] : CurrentIR->GetCode(BlockNode)) { + OrderedNodeWrapper WrapperOp = CodeNode->Wrapped(ListBegin); uint8_t OpSize = IROp->Size; - uint32_t Node = WrapperOp.ID(); + uint32_t Node = CurrentIR->GetID(CodeNode); switch (IROp->Op) { case IR::OP_DUMMY: @@ -4223,7 +4214,7 @@ void InterpreterCore::ExecuteCode(FEXCore::Core::InternalThreadState *Thread) { } }; - HandleBlock(); + HandleBlock(BlockNode); if (BlockResults.Redo) { continue; diff --git a/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp b/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp index 779027c25..8a74de9e9 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp @@ -419,12 +419,8 @@ void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const JumpTargets.clear(); CurrentIR = IR; uint32_t SSACount = CurrentIR->GetSSACount(); - uintptr_t ListBegin = CurrentIR->GetListData(); - uintptr_t DataBegin = CurrentIR->GetData(); auto HeaderOp = CurrentIR->GetHeader(); - LogMan::Throw::A(HeaderOp->Header.Op == IR::OP_IRHEADER, "First op wasn't IRHeader"); - if (HeaderOp->ShouldInterpret) { return InterpreterFallbackHelperAddress; } @@ -511,17 +507,13 @@ void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const ret(); }; - for (auto [BlockNode, BlockHeader] : CurrentIR->getBlocks()) { + for (auto [BlockNode, BlockHeader] : CurrentIR->GetBlocks()) { using namespace FEXCore::IR; auto BlockIROp = BlockHeader->CW(); LogMan::Throw::A(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block"); - // We grab these nodes this way so we can iterate easily - auto CodeBegin = CurrentIR->at(BlockIROp->Begin); - auto CodeLast = CurrentIR->at(BlockIROp->Last); - { - uint32_t Node = BlockNode->Wrapped(ListBegin).ID(); + uint32_t Node = CurrentIR->GetID(BlockNode); auto IsTarget = JumpTargets.find(Node); if (IsTarget == JumpTargets.end()) { IsTarget = JumpTargets.try_emplace(Node).first; @@ -530,12 +522,9 @@ void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const L(IsTarget->second); } - while (1) { - OrderedNodeWrapper *WrapperOp = CodeBegin(); - OrderedNode *RealNode = WrapperOp->GetNode(ListBegin); - FEXCore::IR::IROp_Header *IROp = RealNode->Op(DataBegin); + for (auto [CodeNode, IROp] : CurrentIR->GetCode(BlockNode)) { uint8_t OpSize = IROp->Size; - uint32_t Node = WrapperOp->ID(); + uint32_t Node = CurrentIR->GetID(CodeNode); #ifdef DEBUG_RA if (IROp->Op != IR::OP_BEGINBLOCK && @@ -4819,12 +4808,6 @@ void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const LogMan::Msg::A("Unknown IR Op: %d(%s)", IROp->Op, FEXCore::IR::GetName(IROp->Op).data()); break; } - - // CodeLast is inclusive. So we still need to dump the CodeLast op as well - if (CodeBegin == CodeLast) { - break; - } - ++CodeBegin; } } diff --git a/External/FEXCore/Source/Interface/IR/IR.cpp b/External/FEXCore/Source/Interface/IR/IR.cpp index b6741d2f4..a4eb56f41 100644 --- a/External/FEXCore/Source/Interface/IR/IR.cpp +++ b/External/FEXCore/Source/Interface/IR/IR.cpp @@ -132,7 +132,7 @@ void Dump(std::stringstream *out, IRListView const* IR, IR::RegisterAlloc *out << "%ssa" << HeaderOp->Blocks.ID() << ", "; *out << "#" << std::dec << HeaderOp->BlockCount << std::endl; - for (auto [BlockNode, BlockHeader] : IR->getBlocks()) { + for (auto [BlockNode, BlockHeader] : IR->GetBlocks()) { auto BlockIROp = BlockHeader->CW(); // LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); diff --git a/External/FEXCore/Source/Interface/IR/Passes/ConstProp.cpp b/External/FEXCore/Source/Interface/IR/Passes/ConstProp.cpp index a13cc8e90..00df9da1f 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/ConstProp.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/ConstProp.cpp @@ -22,219 +22,201 @@ bool ConstProp::Run(IREmitter *IREmit) { auto OriginalWriteCursor = IREmit->GetWriteCursor(); - for (auto [BlockNode, BlockHeader] : CurrentIR.getBlocks()) { - auto BlockIROp = BlockHeader->CW(); - LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); + for (auto [CodeNode, IROp] : CurrentIR.GetAllCode()) { - // We grab these nodes this way so we can iterate easily - auto CodeBegin = CurrentIR.at(BlockIROp->Begin); - auto CodeLast = CurrentIR.at(BlockIROp->Last); - while (1) { - auto CodeOp = CodeBegin(); - OrderedNode *CodeNode = CodeOp->GetNode(ListBegin); - auto IROp = CodeNode->Op(DataBegin); - switch (IROp->Op) { + switch (IROp->Op) { /* - case OP_UMUL: - case OP_DIV: - case OP_UDIV: - case OP_REM: - case OP_UREM: - case OP_MULH: - case OP_UMULH: - case OP_LSHR: - case OP_ASHR: - case OP_ROL: - case OP_ROR: - case OP_LDIV: - case OP_LUDIV: - case OP_LREM: - case OP_LUREM: - case OP_BFI: - { - uint64_t Constant1; - uint64_t Constant2; + case OP_UMUL: + case OP_DIV: + case OP_UDIV: + case OP_REM: + case OP_UREM: + case OP_MULH: + case OP_UMULH: + case OP_LSHR: + case OP_ASHR: + case OP_ROL: + case OP_ROR: + case OP_LDIV: + case OP_LUDIV: + case OP_LREM: + case OP_LUREM: + case OP_BFI: + { + uint64_t Constant1; + uint64_t Constant2; - if (IREmit->IsValueConstant(IROp->Args[0], &Constant1) && - IREmit->IsValueConstant(IROp->Args[1], &Constant2)) { - LogMan::Msg::A("Could const prop op: %s", std::string(IR::GetName(IROp->Op)).c_str()); - } - break; + if (IREmit->IsValueConstant(IROp->Args[0], &Constant1) && + IREmit->IsValueConstant(IROp->Args[1], &Constant2)) { + LogMan::Msg::A("Could const prop op: %s", std::string(IR::GetName(IROp->Op)).c_str()); } + break; + } - case OP_SEXT: - case OP_NEG: - case OP_POPCOUNT: - case OP_FINDLSB: - case OP_FINDMSB: - case OP_REV: - case OP_SBFE: - { - uint64_t Constant1; + case OP_SEXT: + case OP_NEG: + case OP_POPCOUNT: + case OP_FINDLSB: + case OP_FINDMSB: + case OP_REV: + case OP_SBFE: + { + uint64_t Constant1; - if (IREmit->IsValueConstant(IROp->Args[0], &Constant1)) { - LogMan::Msg::A("Could const prop op: %s", std::string(IR::GetName(IROp->Op)).c_str()); - } - break; + if (IREmit->IsValueConstant(IROp->Args[0], &Constant1)) { + LogMan::Msg::A("Could const prop op: %s", std::string(IR::GetName(IROp->Op)).c_str()); } + break; + } */ - case OP_ADD: { - auto Op = IROp->C(); - uint64_t Constant1; - uint64_t Constant2; + case OP_ADD: { + auto Op = IROp->C(); + uint64_t Constant1; + uint64_t Constant2; - if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1) && - IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { - uint64_t NewConstant = (Constant1 + Constant2) & getMask(Op) ; - IREmit->SetWriteCursor(CodeNode); - auto ConstantVal = IREmit->_Constant(NewConstant); - IREmit->ReplaceAllUsesWithInclusive(CodeNode, ConstantVal, CodeBegin, CodeLast); - Changed = true; - } - break; + if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1) && + IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { + uint64_t NewConstant = (Constant1 + Constant2) & getMask(Op) ; + IREmit->SetWriteCursor(CodeNode); + auto ConstantVal = IREmit->_Constant(NewConstant); + IREmit->ReplaceAllUsesWith(CodeNode, ConstantVal); + Changed = true; } - case OP_SUB: { - auto Op = IROp->C(); - uint64_t Constant1; - uint64_t Constant2; + break; + } + case OP_SUB: { + auto Op = IROp->C(); + uint64_t Constant1; + uint64_t Constant2; - if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1) && - IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { - uint64_t NewConstant = (Constant1 - Constant2) & getMask(Op) ; - IREmit->SetWriteCursor(CodeNode); - auto ConstantVal = IREmit->_Constant(NewConstant); - IREmit->ReplaceAllUsesWithInclusive(CodeNode, ConstantVal, CodeBegin, CodeLast); - Changed = true; - } - break; + if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1) && + IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { + uint64_t NewConstant = (Constant1 - Constant2) & getMask(Op) ; + IREmit->SetWriteCursor(CodeNode); + auto ConstantVal = IREmit->_Constant(NewConstant); + IREmit->ReplaceAllUsesWith(CodeNode, ConstantVal); + Changed = true; } - case OP_AND: { - auto Op = IROp->CW(); - uint64_t Constant1; - uint64_t Constant2; + break; + } + case OP_AND: { + auto Op = IROp->CW(); + uint64_t Constant1; + uint64_t Constant2; - if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1) && - IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { - uint64_t NewConstant = (Constant1 & Constant2) & getMask(Op) ; - IREmit->SetWriteCursor(CodeNode); - auto ConstantVal = IREmit->_Constant(NewConstant); - IREmit->ReplaceAllUsesWithInclusive(CodeNode, ConstantVal, CodeBegin, CodeLast); - Changed = true; - } else if (Op->Header.Args[0].ID() == Op->Header.Args[1].ID()) { - // AND with same value results in original value - IREmit->ReplaceAllUsesWithInclusive(CodeNode, Op->Header.Args[0].GetNode(ListBegin), CodeBegin, CodeLast); - Changed = true; - } - break; + if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1) && + IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { + uint64_t NewConstant = (Constant1 & Constant2) & getMask(Op) ; + IREmit->SetWriteCursor(CodeNode); + auto ConstantVal = IREmit->_Constant(NewConstant); + IREmit->ReplaceAllUsesWith(CodeNode, ConstantVal); + Changed = true; + } else if (Op->Header.Args[0].ID() == Op->Header.Args[1].ID()) { + // AND with same value results in original value + IREmit->ReplaceAllUsesWith(CodeNode, Op->Header.Args[0].GetNode(ListBegin)); + Changed = true; } - case OP_OR: { - auto Op = IROp->CW(); - uint64_t Constant1; - uint64_t Constant2; + break; + } + case OP_OR: { + auto Op = IROp->CW(); + uint64_t Constant1; + uint64_t Constant2; - if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1) && - IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { - uint64_t NewConstant = Constant1 | Constant2; - IREmit->SetWriteCursor(CodeNode); - auto ConstantVal = IREmit->_Constant(NewConstant); - IREmit->ReplaceAllUsesWithInclusive(CodeNode, ConstantVal, CodeBegin, CodeLast); - Changed = true; - } else if (Op->Header.Args[0].ID() == Op->Header.Args[1].ID()) { - // OR with same value results in original value - IREmit->ReplaceAllUsesWithInclusive(CodeNode, Op->Header.Args[0].GetNode(ListBegin), CodeBegin, CodeLast); - Changed = true; - } - break; + if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1) && + IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { + uint64_t NewConstant = Constant1 | Constant2; + IREmit->SetWriteCursor(CodeNode); + auto ConstantVal = IREmit->_Constant(NewConstant); + IREmit->ReplaceAllUsesWith(CodeNode, ConstantVal); + Changed = true; + } else if (Op->Header.Args[0].ID() == Op->Header.Args[1].ID()) { + // OR with same value results in original value + IREmit->ReplaceAllUsesWith(CodeNode, Op->Header.Args[0].GetNode(ListBegin)); + Changed = true; } - case OP_XOR: { - auto Op = IROp->CW(); - uint64_t Constant1; - uint64_t Constant2; + break; + } + case OP_XOR: { + auto Op = IROp->C(); + uint64_t Constant1; + uint64_t Constant2; - if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1) && - IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { - uint64_t NewConstant = Constant1 ^ Constant2; - IREmit->SetWriteCursor(CodeNode); - auto ConstantVal = IREmit->_Constant(NewConstant); - IREmit->ReplaceAllUsesWithInclusive(CodeNode, ConstantVal, CodeBegin, CodeLast); - Changed = true; - } else if (Op->Header.Args[0].ID() == Op->Header.Args[1].ID()) { - // XOR with same value results to zero - IREmit->SetWriteCursor(CodeNode); - IREmit->ReplaceAllUsesWithInclusive(CodeNode, IREmit->_Constant(0), CodeBegin, CodeLast); - Changed = true; - } - break; + if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1) && + IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { + uint64_t NewConstant = Constant1 ^ Constant2; + IREmit->SetWriteCursor(CodeNode); + auto ConstantVal = IREmit->_Constant(NewConstant); + IREmit->ReplaceAllUsesWith(CodeNode, ConstantVal); + Changed = true; + } else if (Op->Header.Args[0].ID() == Op->Header.Args[1].ID()) { + // XOR with same value results to zero + IREmit->SetWriteCursor(CodeNode); + IREmit->ReplaceAllUsesWith(CodeNode, IREmit->_Constant(0)); + Changed = true; } - case OP_LSHL: { - auto Op = IROp->CW(); - uint64_t Constant1; - uint64_t Constant2; + break; + } + case OP_LSHL: { + auto Op = IROp->CW(); + uint64_t Constant1; + uint64_t Constant2; - if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1) && - IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { - uint64_t NewConstant = (Constant1 << Constant2) & getMask(Op); - IREmit->SetWriteCursor(CodeNode); - auto ConstantVal = IREmit->_Constant(NewConstant); - IREmit->ReplaceAllUsesWithInclusive(CodeNode, ConstantVal, CodeBegin, CodeLast); - Changed = true; - } - else if (IREmit->IsValueConstant(Op->Header.Args[1], &Constant2) && - Constant2 == 0) { - IREmit->SetWriteCursor(CodeNode); - OrderedNode *Arg = Op->Header.Args[0].GetNode(ListBegin); - IREmit->ReplaceAllUsesWithInclusive(CodeNode, Arg, CodeBegin, CodeLast); - Changed = true; - } - break; + if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1) && + IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { + uint64_t NewConstant = (Constant1 << Constant2) & getMask(Op); + IREmit->SetWriteCursor(CodeNode); + auto ConstantVal = IREmit->_Constant(NewConstant); + IREmit->ReplaceAllUsesWith(CodeNode, ConstantVal); + Changed = true; + } + else if (IREmit->IsValueConstant(Op->Header.Args[1], &Constant2) && + Constant2 == 0) { + IREmit->SetWriteCursor(CodeNode); + OrderedNode *Arg = Op->Header.Args[0].GetNode(ListBegin); + IREmit->ReplaceAllUsesWith(CodeNode, Arg); + Changed = true; + } + break; + } + case OP_BFE: { + auto Op = IROp->C(); + uint64_t Constant; + if (IROp->Size <= 8 && IREmit->IsValueConstant(Op->Header.Args[0], &Constant)) { + uint64_t SourceMask = (1ULL << Op->Width) - 1; + if (Op->Width == 64) + SourceMask = ~0ULL; + SourceMask <<= Op->lsb; + + uint64_t NewConstant = (Constant & SourceMask) >> Op->lsb; + IREmit->SetWriteCursor(CodeNode); + auto ConstantVal = IREmit->_Constant(NewConstant); + IREmit->ReplaceAllUsesWith(CodeNode, ConstantVal); + Changed = true; + } else if (IROp->Size == Op->Header.Args[0].GetNode(ListBegin)->Op(DataBegin)->Size && Op->Width == (IROp->Size * 8) && Op->lsb == 0 ) { + // A BFE that extracts all bits results in original value + // XXX - This is broken for now - see https://github.com/FEX-Emu/FEX/issues/351 + // IREmit->ReplaceAllUsesWith(CodeNode, Op->Header.Args[0].GetNode(ListBegin)); + // Changed = true; } + break; + } + case OP_MUL: { + auto Op = IROp->C(); + uint64_t Constant1; + uint64_t Constant2; - case OP_BFE: { - auto Op = IROp->CW(); - uint64_t Constant; - if (IROp->Size <= 8 && IREmit->IsValueConstant(Op->Header.Args[0], &Constant)) { - uint64_t SourceMask = (1ULL << Op->Width) - 1; - if (Op->Width == 64) - SourceMask = ~0ULL; - SourceMask <<= Op->lsb; - - uint64_t NewConstant = (Constant & SourceMask) >> Op->lsb; - IREmit->SetWriteCursor(CodeNode); - auto ConstantVal = IREmit->_Constant(NewConstant); - IREmit->ReplaceAllUsesWithInclusive(CodeNode, ConstantVal, CodeBegin, CodeLast); - Changed = true; - } else if (IROp->Size == Op->Header.Args[0].GetNode(ListBegin)->Op(DataBegin)->Size && Op->Width == (IROp->Size * 8) && Op->lsb == 0 ) { - // A BFE that extracts all bits results in original value - // XXX - This is broken for now - see https://github.com/FEX-Emu/FEX/issues/351 - // IREmit->ReplaceAllUsesWithInclusive(CodeNode, Op->Header.Args[0].GetNode(ListBegin), CodeBegin, CodeLast); - // Changed = true; - } - - break; + if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1) && + IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { + uint64_t NewConstant = (Constant1 * Constant2) & getMask(Op); + IREmit->SetWriteCursor(CodeNode); + auto ConstantVal = IREmit->_Constant(NewConstant); + IREmit->ReplaceAllUsesWith(CodeNode, ConstantVal); + Changed = true; } - case OP_MUL: { - auto Op = IROp->C(); - uint64_t Constant1; - uint64_t Constant2; - - if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1) && - IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { - uint64_t NewConstant = (Constant1 * Constant2) & getMask(Op); - IREmit->SetWriteCursor(CodeNode); - auto ConstantVal = IREmit->_Constant(NewConstant); - IREmit->ReplaceAllUsesWithInclusive(CodeNode, ConstantVal, CodeBegin, CodeLast); - Changed = true; - } - } - default: break; - } - - // CodeLast is inclusive. So we still need to dump the CodeLast op as well - if (CodeBegin == CodeLast) { - break; - } - ++CodeBegin; + } + default: break; } } diff --git a/External/FEXCore/Source/Interface/IR/Passes/DeadCodeElimination.cpp b/External/FEXCore/Source/Interface/IR/Passes/DeadCodeElimination.cpp index 136adc73c..1bb996fac 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/DeadCodeElimination.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/DeadCodeElimination.cpp @@ -16,38 +16,17 @@ private: bool DeadCodeElimination::Run(IREmitter *IREmit) { auto CurrentIR = IREmit->ViewIR(); - - uintptr_t ListBegin = CurrentIR.GetListData(); - uintptr_t DataBegin = CurrentIR.GetData(); - int NumRemoved = 0; - for (auto [BlockNode, BlockHeader] : CurrentIR.getBlocks()) { - auto BlockIROp = BlockHeader->CW(); - LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); + for (auto [CodeNode, IROp] : CurrentIR.GetAllCode()) { - // We grab these nodes this way so we can iterate easily - auto CodeBegin = CurrentIR.at(BlockIROp->Begin); - auto CodeLast = CurrentIR.at(BlockIROp->Last); - - while (1) { - auto CodeOp = CodeLast(); - OrderedNode *CodeNode = CodeOp->GetNode(ListBegin); - auto IROp = CodeNode->Op(DataBegin); - - // Skip over anything that has side effects - // Use count tracking can't safely remove anything with side effects - if (!IR::HasSideEffects(IROp->Op)) { - if (CodeNode->GetUses() == 0) { - NumRemoved++; - IREmit->Remove(CodeNode); - } + // Skip over anything that has side effects + // Use count tracking can't safely remove anything with side effects + if (!IR::HasSideEffects(IROp->Op)) { + if (CodeNode->GetUses() == 0) { + NumRemoved++; + IREmit->Remove(CodeNode); } - - if (CodeLast == CodeBegin) { - break; - } - --CodeLast; } } diff --git a/External/FEXCore/Source/Interface/IR/Passes/DeadContextStoreElimination.cpp b/External/FEXCore/Source/Interface/IR/Passes/DeadContextStoreElimination.cpp index 75ebe8b16..d043019a4 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/DeadContextStoreElimination.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/DeadContextStoreElimination.cpp @@ -314,30 +314,18 @@ void RCLSE::CalculateControlFlowInfo(FEXCore::IR::IREmitter *IREmit) { OffsetToBlockMap.clear(); auto CurrentIR = IREmit->ViewIR(); - uintptr_t ListBegin = CurrentIR.GetListData(); - uintptr_t DataBegin = CurrentIR.GetData(); - for (auto [BlockNode, BlockHeader] : CurrentIR.getBlocks()) { - auto BlockIROp = BlockHeader->CW(); - LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); + for (auto [BlockNode, BlockHeader] : CurrentIR.GetBlocks()) { + BlockInfo *CurrentBlock = &OffsetToBlockMap.try_emplace(CurrentIR.GetID(BlockNode)).first->second; - BlockInfo *CurrentBlock = &OffsetToBlockMap.try_emplace(BlockNode->Wrapped(ListBegin).ID()).first->second; - - // We grab these nodes this way so we can iterate easily - auto CodeBegin = CurrentIR.at(BlockIROp->Begin); - auto CodeLast = CurrentIR.at(BlockIROp->Last); - - while (1) { - auto CodeOp = CodeBegin(); - OrderedNode *CodeNode = CodeOp->GetNode(ListBegin); - auto IROp = CodeNode->Op(DataBegin); + for (auto [CodeNode, IROp] : CurrentIR.GetCode(BlockNode)) { switch (IROp->Op) { case IR::OP_CONDJUMP: { auto Op = IROp->CW(); - OrderedNode *TrueTargetNode = Op->Header.Args[1].GetNode(ListBegin); - OrderedNode *FalseTargetNode = Op->Header.Args[2].GetNode(ListBegin); + OrderedNode *TrueTargetNode = CurrentIR.GetNode(Op->Header.Args[1]); + OrderedNode *FalseTargetNode = CurrentIR.GetNode(Op->Header.Args[2]); CurrentBlock->Successors.emplace_back(TrueTargetNode); CurrentBlock->Successors.emplace_back(FalseTargetNode); @@ -356,7 +344,7 @@ void RCLSE::CalculateControlFlowInfo(FEXCore::IR::IREmitter *IREmit) { } case IR::OP_JUMP: { auto Op = IROp->CW(); - OrderedNode *TargetNode = Op->Header.Args[0].GetNode(ListBegin); + OrderedNode *TargetNode = CurrentIR.GetNode(Op->Header.Args[0]); CurrentBlock->Successors.emplace_back(TargetNode); { @@ -367,12 +355,6 @@ void RCLSE::CalculateControlFlowInfo(FEXCore::IR::IREmitter *IREmit) { } default: break; } - - // CodeLast is inclusive. So we still need to dump the CodeLast op as well - if (CodeBegin == CodeLast) { - break; - } - ++CodeBegin; } } } @@ -418,41 +400,17 @@ bool RCLSE::RedundantStoreLoadElimination(FEXCore::IR::IREmitter *IREmit) { bool Changed = false; auto CurrentIR = IREmit->ViewIR(); - uintptr_t ListBegin = CurrentIR.GetListData(); - uintptr_t DataBegin = CurrentIR.GetData(); auto OriginalWriteCursor = IREmit->GetWriteCursor(); - auto Begin = CurrentIR.begin(); - auto Op = Begin(); - - OrderedNode *RealNode = Op->GetNode(ListBegin); - auto HeaderOp = RealNode->Op(DataBegin)->CW(); - LogMan::Throw::A(HeaderOp->Header.Op == OP_IRHEADER, "First op wasn't IRHeader"); - - // Walk the list and calculate the control flow - OrderedNode *BlockNode = HeaderOp->Blocks.GetNode(ListBegin); + // XXX: Walk the list and calculate the control flow ContextInfo LocalInfo = ClassifiedStruct; - for (auto [BlockNode, BlockHeader] : CurrentIR.getBlocks()) { - auto BlockIROp = BlockHeader->CW(); - LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); + for (auto [BlockNode, BlockHeader] : CurrentIR.GetBlocks()) { ResetClassificationAccesses(&LocalInfo); - // We grab these nodes this way so we can iterate easily - auto CodeBegin = CurrentIR.at(BlockIROp->Begin); - auto CodeLast = CurrentIR.at(BlockIROp->Last); - - auto OpSize = [&](OrderedNode *node) { - return node->Op(DataBegin)->Size; - }; - - while (1) { - auto CodeOp = CodeBegin(); - OrderedNode *CodeNode = CodeOp->GetNode(ListBegin); - auto IROp = CodeNode->Op(DataBegin); - + for (auto [CodeNode, IROp] : CurrentIR.GetCode(BlockNode)) { if (IROp->Op == OP_STORECONTEXT) { auto Op = IROp->CW(); auto Info = FindMemberInfo(&LocalInfo, Op->Offset, IROp->Size); @@ -461,7 +419,7 @@ bool RCLSE::RedundantStoreLoadElimination(FEXCore::IR::IREmitter *IREmit) { uint8_t LastSize = Info->AccessSize; LastAccessType LastAccess = Info->Accessed; OrderedNode *LastStoreNode = Info->StoreNode; - RecordAccess(Info, Op->Class, Op->Offset, IROp->Size, ACCESS_WRITE, Op->Header.Args[0].GetNode(ListBegin), CodeNode); + RecordAccess(Info, Op->Class, Op->Offset, IROp->Size, ACCESS_WRITE, CurrentIR.GetNode(Op->Header.Args[0]), CodeNode); if (LastAccess == ACCESS_WRITE && LastClass == Op->Class && @@ -493,17 +451,17 @@ bool RCLSE::RedundantStoreLoadElimination(FEXCore::IR::IREmitter *IREmit) { IREmit->SetWriteCursor(CodeNode); - uint8_t TruncateSize = OpSize(LastNode); + uint8_t TruncateSize = IREmit->GetOpSize(LastNode); // Did store context do an implicit truncation? - if (OpSize(LastStoreNode) < TruncateSize) - TruncateSize = OpSize(LastStoreNode); + if (IREmit->GetOpSize(LastStoreNode) < TruncateSize) + TruncateSize = IREmit->GetOpSize(LastStoreNode); // Or are we doing a partial read if (IROp->Size < TruncateSize) TruncateSize = IROp->Size; - if (TruncateSize != OpSize(LastNode)) { + if (TruncateSize != IREmit->GetOpSize(LastNode)) { // We need to insert an explict truncation if (LastClass == FPRClass) { LastNode = IREmit->_VMov(LastNode, TruncateSize); // Vmov truncates and zexts when register width is smaller than source @@ -518,7 +476,7 @@ bool RCLSE::RedundantStoreLoadElimination(FEXCore::IR::IREmitter *IREmit) { } } - IREmit->ReplaceAllUsesWithInclusive(CodeNode, LastNode, CodeBegin, CodeLast); + IREmit->ReplaceAllUsesWith(CodeNode, LastNode); RecordAccess(Info, Op->Class, Op->Offset, IROp->Size, ACCESS_READ, LastNode); Changed = true; } @@ -528,7 +486,7 @@ bool RCLSE::RedundantStoreLoadElimination(FEXCore::IR::IREmitter *IREmit) { LastSize == IROp->Size && Info->Accessed == ACCESS_READ) { // Did we read and then read again? - IREmit->ReplaceAllUsesWithInclusive(CodeNode, LastNode, CodeBegin, CodeLast); + IREmit->ReplaceAllUsesWith(CodeNode, LastNode); RecordAccess(Info, Op->Class, Op->Offset, IROp->Size, ACCESS_READ, LastNode); Changed = true; } @@ -537,7 +495,7 @@ bool RCLSE::RedundantStoreLoadElimination(FEXCore::IR::IREmitter *IREmit) { auto Op = IROp->CW(); auto Info = FindMemberInfo(&LocalInfo, offsetof(FEXCore::Core::CPUState, flags[0]) + Op->Flag, 1); auto LastStoreNode = Info->StoreNode; - RecordAccess(&LocalInfo, FEXCore::IR::GPRClass, offsetof(FEXCore::Core::CPUState, flags[0]) + Op->Flag, 1, ACCESS_WRITE, Op->Header.Args[0].GetNode(ListBegin), CodeNode); + RecordAccess(&LocalInfo, FEXCore::IR::GPRClass, offsetof(FEXCore::Core::CPUState, flags[0]) + Op->Flag, 1, ACCESS_WRITE, CurrentIR.GetNode(Op->Header.Args[0]), CodeNode); // Flags don't alias, so we can take the simple route here. Kill any flags that have been overwritten if (LastStoreNode != nullptr) @@ -556,12 +514,12 @@ bool RCLSE::RedundantStoreLoadElimination(FEXCore::IR::IREmitter *IREmit) { // If the last store matches this load value then we can replace the loaded value with the previous valid one IREmit->SetWriteCursor(CodeNode); auto Res = IREmit->_Bfe(1, 0, LastNode); - IREmit->ReplaceAllUsesWithInclusive(CodeNode, Res, CodeBegin, CodeLast); + IREmit->ReplaceAllUsesWith(CodeNode, Res); RecordAccess(Info, FEXCore::IR::GPRClass, offsetof(FEXCore::Core::CPUState, flags[0]) + Op->Flag, 1, ACCESS_READ, LastNode); Changed = true; } else if (LastAccess == ACCESS_READ) { - IREmit->ReplaceAllUsesWithInclusive(CodeNode, LastNode, CodeBegin, CodeLast); + IREmit->ReplaceAllUsesWith(CodeNode, LastNode); RecordAccess(Info, FEXCore::IR::GPRClass, offsetof(FEXCore::Core::CPUState, flags[0]) + Op->Flag, 1, ACCESS_READ, LastNode); Changed = true; } @@ -573,12 +531,6 @@ bool RCLSE::RedundantStoreLoadElimination(FEXCore::IR::IREmitter *IREmit) { // We can't track through these ResetClassificationAccesses(&LocalInfo); } - - // CodeLast is inclusive. So we still need to dump the CodeLast op as well - if (CodeBegin == CodeLast) { - break; - } - ++CodeBegin; } } diff --git a/External/FEXCore/Source/Interface/IR/Passes/IRCompaction.cpp b/External/FEXCore/Source/Interface/IR/Passes/IRCompaction.cpp index 3eb59d8b7..61cdc1873 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/IRCompaction.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/IRCompaction.cpp @@ -74,9 +74,8 @@ bool IRCompaction::Run(IREmitter *IREmit) { { // Generate our codeblocks and link them together OrderedNode* PrevCodeBlock{}; - for (auto [BlockNode, BlockHeader] : CurrentIR.getBlocks()) { - auto BlockIROp = BlockHeader->CW(); - LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); + for (auto [BlockNode, BlockHeader] : CurrentIR.GetBlocks()) { + LogMan::Throw::A(BlockHeader->Op == OP_CODEBLOCK, "IR type failed to be a code block"); auto LocalBlockIRNode = LocalBuilder._CodeBlock(LocalHeaderOp, LocalHeaderOp); // Use LocalHeaderOp as a dummy arg for now OldToNewRemap[BlockNode->Wrapped(ListBegin).ID()] = LocalBlockIRNode.Node->Wrapped(LocalListBegin).ID(); @@ -93,22 +92,11 @@ bool IRCompaction::Run(IREmitter *IREmit) { { // Copy all of our IR ops over to the new location for (auto &Block : GeneratedCodeBlocks) { - auto BlockIROp = Block.OldNode->Op(DataBegin)->CW(); - LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); - - // We grab these nodes this way so we can iterate easily - auto CodeBegin = CurrentIR.at(BlockIROp->Begin); - auto CodeLast = CurrentIR.at(BlockIROp->Last); CodeBlockData FirstNode{}; CodeBlockData LastNode{}; uint32_t i {}; - while (1) { - auto CodeOp = CodeBegin(); - OrderedNode *CodeNode = CodeOp->GetNode(ListBegin); - auto IROp = CodeNode->Op(DataBegin); - LogMan::Throw::A(IROp->Op != OP_IRHEADER, "%%ssa%d ended up being IRHeader. Shouldn't have hit this", CodeOp->ID()); - + for (auto [CodeNode, IROp] : CurrentIR.GetCode(Block.OldNode)) { size_t OpSize = FEXCore::IR::GetSize(IROp->Op); // Allocate the ops locally for our local dispatch @@ -124,20 +112,18 @@ bool IRCompaction::Run(IREmitter *IREmit) { // Set our map remapper to map the new location // Even nodes that don't have a destination need to be in this map // Need to be able to remap branch targets any other bits - OldToNewRemap[CodeOp->ID()] = LocalNodeWrapper.ID(); + OldToNewRemap[CurrentIR.GetID(CodeNode)] = LocalNodeWrapper.ID(); if (i == 0) { FirstNode.OldNode = CodeNode; FirstNode.NewNode = LocalPair.Node; } - // CodeLast is inclusive. So we still need to dump the CodeLast op as well - if (CodeBegin == CodeLast) { + if (IROp->Op == OP_ENDBLOCK) { LastNode.OldNode = CodeNode; LastNode.NewNode = LocalPair.Node; - break; } - ++CodeBegin; + ++i; } @@ -154,15 +140,9 @@ bool IRCompaction::Run(IREmitter *IREmit) { auto BlockIROp = Block.OldNode->Op(DataBegin)->CW(); LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); - // We grab these nodes this way so we can iterate easily - auto CodeBegin = CurrentIR.at(BlockIROp->Begin); - auto CodeLast = CurrentIR.at(BlockIROp->Last); - while (1) { - auto CodeOp = CodeBegin(); - OrderedNode *CodeNode = CodeOp->GetNode(ListBegin); - auto IROp = CodeNode->Op(DataBegin); + for (auto [CodeNode, IROp] : CurrentIR.GetCode(Block.OldNode)) { - OrderedNodeWrapper LocalNodeWrapper = OrderedNodeWrapper::WrapOffset(OldToNewRemap[CodeOp->ID()] * sizeof(OrderedNode)); + OrderedNodeWrapper LocalNodeWrapper = OrderedNodeWrapper::WrapOffset(OldToNewRemap[CurrentIR.GetID(CodeNode)] * sizeof(OrderedNode)); OrderedNode *LocalNode = LocalNodeWrapper.GetNode(LocalListBegin); FEXCore::IR::IROp_Header *LocalIROp = LocalNode->Op(LocalDataBegin); @@ -175,12 +155,6 @@ bool IRCompaction::Run(IREmitter *IREmit) { LogMan::Throw::A(OldToNewRemap[OldArg] != ~0U, "Tried remapping unfound node %%ssa%d", OldArg); LocalIROp->Args[i].NodeOffset = OldToNewRemap[OldArg] * sizeof(OrderedNode); } - - // CodeLast is inclusive. So we still need to dump the CodeLast op as well - if (CodeBegin == CodeLast) { - break; - } - ++CodeBegin; } } } diff --git a/External/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp b/External/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp index 0397c164e..4b8307d38 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp @@ -47,7 +47,7 @@ bool IRValidation::Run(IREmitter *IREmit) { RAPass = Manager->GetRAPass(); } - for (auto [BlockNode, BlockHeader] : CurrentIR.getBlocks()) { + for (auto [BlockNode, BlockHeader] : CurrentIR.GetBlocks()) { auto BlockIROp = BlockHeader->CW(); LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); diff --git a/External/FEXCore/Source/Interface/IR/Passes/PhiValidation.cpp b/External/FEXCore/Source/Interface/IR/Passes/PhiValidation.cpp index 7112a4c22..ad57e71b6 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/PhiValidation.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/PhiValidation.cpp @@ -13,26 +13,15 @@ public: bool PhiValidation::Run(IREmitter *IREmit) { bool HadError = false; auto CurrentIR = IREmit->ViewIR(); - uintptr_t ListBegin = CurrentIR.GetListData(); - uintptr_t DataBegin = CurrentIR.GetData(); std::ostringstream Errors; // Walk the list and calculate the control flow - for (auto [BlockNode, BlockHeader] : CurrentIR.getBlocks()) { - auto BlockIROp = BlockHeader->CW(); - LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); - - // We grab these nodes this way so we can iterate easily - auto CodeBegin = CurrentIR.at(BlockIROp->Begin); - auto CodeLast = CurrentIR.at(BlockIROp->Last); + for (auto [BlockNode, BlockHeader] : CurrentIR.GetBlocks()) { bool FoundNonPhi{}; - while (1) { - auto CodeOp = CodeBegin(); - OrderedNode *CodeNode = CodeOp->GetNode(ListBegin); - auto IROp = CodeNode->Op(DataBegin); + for (auto [CodeNode, IROp] : CurrentIR.GetCode(BlockNode)) { switch (IROp->Op) { // DUMMY doesn't matter for us @@ -43,7 +32,7 @@ bool PhiValidation::Run(IREmitter *IREmit) { // If we have found a non-phi IR op and then had a Phi or PhiValue value then this is a programming mistake // PHI values MUST be defined at the top of the block only HadError |= true; - Errors << "Phi %ssa" << CodeOp->ID() << ": Was defined after non-phi operations. Which is invalid!" << std::endl; + Errors << "Phi %ssa" << CurrentIR.GetID(CodeNode) << ": Was defined after non-phi operations. Which is invalid!" << std::endl; } // Check all the phi values to ensure they have the same type @@ -53,12 +42,6 @@ bool PhiValidation::Run(IREmitter *IREmit) { FoundNonPhi = true; break; } - - // CodeLast is inclusive. So we still need to dump the CodeLast op as well - if (CodeBegin == CodeLast) { - break; - } - ++CodeBegin; } } diff --git a/External/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp b/External/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp index 546cffd36..1705c64a7 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp @@ -24,21 +24,9 @@ bool DeadFlagCalculationEliminination::Run(IREmitter *IREmit) { bool Changed = false; auto CurrentIR = IREmit->ViewIR(); - uintptr_t ListBegin = CurrentIR.GetListData(); - uintptr_t DataBegin = CurrentIR.GetData(); - - for (auto [BlockNode, BlockHeader] : CurrentIR.getBlocks()) { - auto BlockIROp = BlockHeader->CW(); - LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); - - // We grab these nodes this way so we can iterate easily - auto CodeBegin = CurrentIR.at(BlockIROp->Begin); - auto CodeLast = CurrentIR.at(BlockIROp->Last); - while (1) { - auto CodeOp = CodeBegin(); - OrderedNode *CodeNode = CodeOp->GetNode(ListBegin); - auto IROp = CodeNode->Op(DataBegin); + for (auto [BlockNode, BlockHeader] : CurrentIR.GetBlocks()) { + for (auto [CodeNode, IROp] : CurrentIR.GetCode(BlockNode)) { if (IROp->Op == OP_STOREFLAG) { auto Op = IROp->CW(); // Set this node as the last one valid for this flag @@ -48,12 +36,6 @@ bool DeadFlagCalculationEliminination::Run(IREmitter *IREmit) { auto Op = IROp->CW(); LastValidFlagStores[Op->Flag] = nullptr; } - - // CodeLast is inclusive. So we still need to dump the CodeLast op as well - if (CodeBegin == CodeLast) { - break; - } - ++CodeBegin; } // If any flags are stored but not loaded by the end of the block, then erase them diff --git a/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp b/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp index 0cec8ddea..c24089aaa 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp @@ -261,7 +261,7 @@ namespace { uintptr_t ListBegin = IR->GetListData(); uintptr_t DataBegin = IR->GetData(); - for (auto [BlockNode, BlockHeader] : IR->getBlocks()) { + for (auto [BlockNode, BlockHeader] : IR->GetBlocks()) { auto BlockIROp = BlockHeader->CW(); LogMan::Throw::A(BlockIROp->Header.Op == FEXCore::IR::OP_CODEBLOCK, "IR type failed to be a code block"); @@ -384,7 +384,7 @@ namespace FEXCore::IR { uintptr_t DataBegin = IR->GetData(); constexpr uint32_t DEFAULT_REMAT_COST = 1000; - for (auto [BlockNode, BlockHeader] : IR->getBlocks()) { + for (auto [BlockNode, BlockHeader] : IR->GetBlocks()) { auto BlockIROp = BlockHeader->CW(); LogMan::Throw::A(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block"); @@ -465,7 +465,7 @@ namespace FEXCore::IR { using namespace FEXCore; uintptr_t ListBegin = IR->GetListData(); - for (auto [BlockNode, BlockHeader] : IR->getBlocks()) { + for (auto [BlockNode, BlockHeader] : IR->GetBlocks()) { auto BlockIROp = BlockHeader->CW(); LogMan::Throw::A(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block"); @@ -518,7 +518,7 @@ namespace FEXCore::IR { using namespace FEXCore; uintptr_t ListBegin = IR->GetListData(); - for (auto [BlockNode, BlockHeader] : IR->getBlocks()) { + for (auto [BlockNode, BlockHeader] : IR->GetBlocks()) { auto BlockIROp = BlockHeader->CW(); LogMan::Throw::A(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block"); diff --git a/External/FEXCore/Source/Interface/IR/Passes/SyscallOptimization.cpp b/External/FEXCore/Source/Interface/IR/Passes/SyscallOptimization.cpp index e9eb8dcd1..27783fc24 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/SyscallOptimization.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/SyscallOptimization.cpp @@ -14,47 +14,29 @@ public: bool SyscallOptimization::Run(IREmitter *IREmit) { bool Changed = false; auto CurrentIR = IREmit->ViewIR(); - uintptr_t ListBegin = CurrentIR.GetListData(); - uintptr_t DataBegin = CurrentIR.GetData(); - for (auto [BlockNode, BlockHeader] : CurrentIR.getBlocks()) { - auto BlockIROp = BlockHeader->CW(); - LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); + for (auto [CodeNode, IROp] : CurrentIR.GetAllCode()) { - // We grab these nodes this way so we can iterate easily - auto CodeBegin = CurrentIR.at(BlockIROp->Begin); - auto CodeLast = CurrentIR.at(BlockIROp->Last); - while (1) { - auto CodeOp = CodeBegin(); - OrderedNode *CodeNode = CodeOp->GetNode(ListBegin); - auto IROp = CodeNode->Op(DataBegin); - - if (IROp->Op == FEXCore::IR::OP_SYSCALL) { - // Is the first argument a constant? - uint64_t Constant; - if (IREmit->IsValueConstant(IROp->Args[0], &Constant)) { - auto SyscallDef = Manager->SyscallHandler->GetDefinition(Constant); - // XXX: Once we have the ability to do real function calls then we can call directly in to the syscall handler - if (SyscallDef->NumArgs < FEXCore::HLE::SyscallArguments::MAX_ARGS) { - // If the number of args are less than what the IR op supports then we can remove arg usage - // We need +1 since we are still passing in syscall number here - for (uint8_t Arg = (SyscallDef->NumArgs + 1); Arg < FEXCore::HLE::SyscallArguments::MAX_ARGS; ++Arg) { - IREmit->ReplaceNodeArgument(CodeNode, Arg, IREmit->Invalid()); - } - Changed = true; + if (IROp->Op == FEXCore::IR::OP_SYSCALL) { + // Is the first argument a constant? + uint64_t Constant; + if (IREmit->IsValueConstant(IROp->Args[0], &Constant)) { + auto SyscallDef = Manager->SyscallHandler->GetDefinition(Constant); + // XXX: Once we have the ability to do real function calls then we can call directly in to the syscall handler + if (SyscallDef->NumArgs < FEXCore::HLE::SyscallArguments::MAX_ARGS) { + // If the number of args are less than what the IR op supports then we can remove arg usage + // We need +1 since we are still passing in syscall number here + for (uint8_t Arg = (SyscallDef->NumArgs + 1); Arg < FEXCore::HLE::SyscallArguments::MAX_ARGS; ++Arg) { + IREmit->ReplaceNodeArgument(CodeNode, Arg, IREmit->Invalid()); } + Changed = true; } } - - // CodeLast is inclusive. So we still need to dump the CodeLast op as well - if (CodeBegin == CodeLast) { - break; - } - ++CodeBegin; } } + return Changed; } diff --git a/External/FEXCore/Source/Interface/IR/Passes/ValueDominanceValidation.cpp b/External/FEXCore/Source/Interface/IR/Passes/ValueDominanceValidation.cpp index 2197465a7..957c3ee80 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/ValueDominanceValidation.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/ValueDominanceValidation.cpp @@ -30,21 +30,11 @@ bool ValueDominanceValidation::Run(IREmitter *IREmit) { std::unordered_map OffsetToBlockMap; - for (auto [BlockNode, BlockHeader] : CurrentIR.getBlocks()) { - auto BlockIROp = BlockHeader->CW(); - LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); + for (auto [BlockNode, BlockHeader] : CurrentIR.GetBlocks()) { - BlockInfo *CurrentBlock = &OffsetToBlockMap.try_emplace(BlockNode->Wrapped(ListBegin).ID()).first->second; - - // We grab these nodes this way so we can iterate easily - auto CodeBegin = CurrentIR.at(BlockIROp->Begin); - auto CodeLast = CurrentIR.at(BlockIROp->Last); - - while (1) { - auto CodeOp = CodeBegin(); - OrderedNode *CodeNode = CodeOp->GetNode(ListBegin); - auto IROp = CodeNode->Op(DataBegin); + BlockInfo *CurrentBlock = &OffsetToBlockMap.try_emplace(CurrentIR.GetID(BlockNode)).first->second; + for (auto [CodeNode, IROp] : CurrentIR.GetCode(BlockNode)) { switch (IROp->Op) { case IR::OP_CONDJUMP: { auto Op = IROp->CW(); @@ -80,27 +70,14 @@ bool ValueDominanceValidation::Run(IREmitter *IREmit) { } default: break; } - - // CodeLast is inclusive. So we still need to dump the CodeLast op as well - if (CodeBegin == CodeLast) { - break; - } - ++CodeBegin; } } - for (auto [BlockNode, BlockHeader] : CurrentIR.getBlocks()) { + for (auto [BlockNode, BlockHeader] : CurrentIR.GetBlocks()) { auto BlockIROp = BlockHeader->CW(); - LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); - // We grab these nodes this way so we can iterate easily - auto CodeBegin = CurrentIR.at(BlockIROp->Begin); - auto CodeLast = CurrentIR.at(BlockIROp->Last); - - while (1) { - auto CodeOp = CodeBegin(); - OrderedNode *CodeNode = CodeOp->GetNode(ListBegin); - auto IROp = CodeNode->Op(DataBegin); + for (auto [CodeNode, IROp] : CurrentIR.GetCode(BlockNode)) { + uint32_t CodeID = CurrentIR.GetID(CodeNode); uint8_t NumArgs = IR::GetArgs(IROp->Op); for (uint32_t i = 0; i < NumArgs; ++i) { @@ -123,9 +100,9 @@ bool ValueDominanceValidation::Run(IREmitter *IREmit) { // %ssa_1 = Load // %ssa_2 = %ssa_1, %ssa_3 // %ssa_3 = Load - if (Arg.ID() > CodeOp->ID()) { + if (Arg.ID() > CodeID) { HadError |= true; - Errors << "Inst %ssa" << CodeOp->ID() << ": Arg[" << i << "] %ssa" << Arg.ID() << " definition does not dominate this use!" << std::endl; + Errors << "Inst %ssa" << CodeID << ": Arg[" << i << "] %ssa" << Arg.ID() << " definition does not dominate this use!" << std::endl; } } else if (Arg.ID() < BlockIROp->Begin.ID()) { @@ -188,7 +165,7 @@ bool ValueDominanceValidation::Run(IREmitter *IREmit) { if (!FoundPredDefine) { HadError |= true; - Errors << "Inst %ssa" << CodeOp->ID() << ": Arg[" << i << "] %ssa" << Arg.ID() << " definition does not dominate this use! But was defined before this block!" << std::endl; + Errors << "Inst %ssa" << CodeID << ": Arg[" << i << "] %ssa" << Arg.ID() << " definition does not dominate this use! But was defined before this block!" << std::endl; } } else if (Arg.ID() > BlockIROp->Last.ID()) { @@ -202,15 +179,9 @@ bool ValueDominanceValidation::Run(IREmitter *IREmit) { // CodeBlock_2: // %ssa_3 = Load HadError |= true; - Errors << "Inst %ssa" << CodeOp->ID() << ": Arg[" << i << "] %ssa" << Arg.ID() << " definition does not dominate this use!" << std::endl; + Errors << "Inst %ssa" << CodeID << ": Arg[" << i << "] %ssa" << Arg.ID() << " definition does not dominate this use!" << std::endl; } } - - // CodeLast is inclusive. So we still need to dump the CodeLast op as well - if (CodeBegin == CodeLast) { - break; - } - ++CodeBegin; } } From 3c6dbd0ade576cb5bcc7792ba13e7935197275ff Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Mon, 7 Sep 2020 10:55:38 +1200 Subject: [PATCH 08/16] Change iterator type of IR.at And switch over more passes to use the new interfaces. --- External/FEXCore/Source/Interface/IR/IR.cpp | 54 +++++++----------- .../Interface/IR/Passes/IRValidation.cpp | 57 +++++++------------ External/FEXCore/include/FEXCore/IR/IR.h | 4 ++ .../FEXCore/include/FEXCore/IR/IREmitter.h | 2 +- .../include/FEXCore/IR/IntrusiveIRList.h | 17 +++++- 5 files changed, 58 insertions(+), 76 deletions(-) diff --git a/External/FEXCore/Source/Interface/IR/IR.cpp b/External/FEXCore/Source/Interface/IR/IR.cpp index a4eb56f41..986ea8397 100644 --- a/External/FEXCore/Source/Interface/IR/IR.cpp +++ b/External/FEXCore/Source/Interface/IR/IR.cpp @@ -112,11 +112,7 @@ static void PrintArg(std::stringstream *out, [[maybe_unused]] IRListView } void Dump(std::stringstream *out, IRListView const* IR, IR::RegisterAllocationPass *RAPass) { - uintptr_t ListBegin = IR->GetListData(); - uintptr_t DataBegin = IR->GetData(); - auto HeaderOp = IR->GetHeader(); - LogMan::Throw::A(HeaderOp->Header.Op == OP_IRHEADER, "First op wasn't IRHeader"); int8_t CurrentIndent = 0; auto AddIndent = [&out, &CurrentIndent]() { @@ -133,24 +129,19 @@ void Dump(std::stringstream *out, IRListView const* IR, IR::RegisterAlloc *out << "#" << std::dec << HeaderOp->BlockCount << std::endl; for (auto [BlockNode, BlockHeader] : IR->GetBlocks()) { - auto BlockIROp = BlockHeader->CW(); - // LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); + { + auto BlockIROp = BlockHeader->C(); - // We grab these nodes this way so we can iterate easily - auto CodeBegin = IR->at(BlockIROp->Begin); - auto CodeLast = IR->at(BlockIROp->Last); + AddIndent(); + *out << "(%ssa" << std::to_string(IR->GetID(BlockNode)) << ") " << "CodeBlock "; - AddIndent(); - *out << "(%ssa" << std::to_string(BlockNode->Wrapped(ListBegin).ID()) << ") " << "CodeBlock "; - - *out << "%ssa" << std::to_string(BlockIROp->Begin.ID()) << ", "; - *out << "%ssa" << std::to_string(BlockIROp->Last.ID()) << std::endl; + *out << "%ssa" << std::to_string(BlockIROp->Begin.ID()) << ", "; + *out << "%ssa" << std::to_string(BlockIROp->Last.ID()) << std::endl; + } ++CurrentIndent; - while (1) { - OrderedNodeWrapper *CodeOp = CodeBegin(); - OrderedNode *CodeNode = CodeOp->GetNode(ListBegin); - auto IROp = CodeNode->Op(DataBegin); + for (auto [CodeNode, IROp] : IR->GetCode(BlockNode)) { + uint32_t ID = IR->GetID(CodeNode); auto Name = FEXCore::IR::GetName(IROp->Op); bool Skip{}; @@ -171,10 +162,10 @@ void Dump(std::stringstream *out, IRListView const* IR, IR::RegisterAlloc } uint32_t NumElements = IROp->Size / ElementSize; - *out << "%ssa" << std::to_string(CodeOp->ID()); + *out << "%ssa" << std::to_string(ID); if (RAPass) { - uint64_t RegClass = RAPass->GetNodeRegister(CodeOp->ID()); + uint64_t RegClass = RAPass->GetNodeRegister(ID); FEXCore::IR::RegisterClassType Class {uint32_t(RegClass >> 32)}; uint32_t Reg = RegClass; switch (Class) { @@ -205,7 +196,7 @@ void Dump(std::stringstream *out, IRListView const* IR, IR::RegisterAlloc NumElements = IROp->Size / ElementSize; } - *out << "(%ssa" << std::to_string(CodeOp->ID()) << " "; + *out << "(%ssa" << std::to_string(ID) << " "; *out << "i" << std::dec << (ElementSize * 8); if (NumElements > 1) { *out << "v" << std::dec << NumElements; @@ -215,7 +206,7 @@ void Dump(std::stringstream *out, IRListView const* IR, IR::RegisterAlloc *out << Name; switch (IROp->Op) { case IR::OP_BEGINBLOCK: - *out << " %ssa" << std::to_string(CodeOp->ID()); + *out << " %ssa" << std::to_string(ID); break; case IR::OP_ENDBLOCK: break; @@ -230,19 +221,18 @@ void Dump(std::stringstream *out, IRListView const* IR, IR::RegisterAlloc *out << " "; while (NodeBegin != NodeBegin.Invalid()) { - OrderedNodeWrapper *NodeOp = NodeBegin(); - OrderedNode *NodeNode = NodeOp->GetNode(ListBegin); - auto IRNodeOp = NodeNode->Op(DataBegin)->C(); + auto [NodeNode, IROp] = NodeBegin(); + auto PhiOp = IROp->C(); *out << "[ "; - PrintArg(out, IR, IRNodeOp->Value, RAPass); + PrintArg(out, IR, PhiOp->Value, RAPass); *out << ", "; - PrintArg(out, IR, IRNodeOp->Block, RAPass); + PrintArg(out, IR, PhiOp->Block, RAPass); *out << " ]"; - if (IRNodeOp->Next.ID()) + if (PhiOp->Next.ID()) *out << ", "; - NodeBegin = IR->at(IRNodeOp->Next); + NodeBegin = IR->at(PhiOp->Next); } break; } @@ -253,12 +243,6 @@ void Dump(std::stringstream *out, IRListView const* IR, IR::RegisterAlloc *out << "\n"; } - - // CodeLast is inclusive. So we still need to dump the CodeLast op as well - if (CodeBegin == CodeLast) { - break; - } - ++CodeBegin; } CurrentIndent = std::max(0, CurrentIndent - 1); diff --git a/External/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp b/External/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp index 4b8307d38..0d1097bf0 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp @@ -51,19 +51,10 @@ bool IRValidation::Run(IREmitter *IREmit) { auto BlockIROp = BlockHeader->CW(); LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); - BlockInfo *CurrentBlock = &OffsetToBlockMap.try_emplace(BlockNode->Wrapped(ListBegin).ID()).first->second; + BlockInfo *CurrentBlock = &OffsetToBlockMap.try_emplace(CurrentIR.GetID(BlockNode)).first->second; - - - // We grab these nodes this way so we can iterate easily - auto CodeBegin = CurrentIR.at(BlockIROp->Begin); - auto CodeLast = CurrentIR.at(BlockIROp->Last); - - while (1) { - auto CodeOp = CodeBegin(); - OrderedNode *CodeNode = CodeOp->GetNode(ListBegin); - auto IROp = CodeNode->Op(DataBegin); - uint32_t Node = CodeOp->ID(); + for (auto [CodeNode, IROp] : CurrentIR.GetCode(BlockNode)) { + uint32_t ID = CurrentIR.GetID(CodeNode); uint8_t OpSize = IROp->Size; @@ -71,18 +62,18 @@ bool IRValidation::Run(IREmitter *IREmit) { HadError |= OpSize == 0; // Does the op have a destination of size 0? if (OpSize == 0) { - Errors << "%ssa" << CodeOp->ID() << ": Had destination but with no size" << std::endl; + Errors << "%ssa" << ID << ": Had destination but with no size" << std::endl; } // Does the node have zero uses? Should have been DCE'd if (CodeNode->GetUses() == 0) { HadWarning |= true; - Warnings << "%ssa" << CodeOp->ID() << ": Destination created but had no uses" << std::endl; + Warnings << "%ssa" << ID << ": Destination created but had no uses" << std::endl; } if (RAPass) { // If we have a register allocator then the destination needs to be assigned a register and class - uint64_t Reg = RAPass->GetNodeRegister(Node); + uint64_t Reg = RAPass->GetNodeRegister(ID); FEXCore::IR::RegisterClassType ExpectedClass = IR::GetRegClass(IROp->Op); FEXCore::IR::RegisterClassType AssignedClass = FEXCore::IR::RegisterClassType{uint32_t(Reg >> 32)}; @@ -90,20 +81,20 @@ bool IRValidation::Run(IREmitter *IREmit) { // If no register class was assigned if (AssignedClass == IR::InvalidClass) { HadError |= true; - Errors << "%ssa" << CodeOp->ID() << ": Had destination but with no register class assigned" << std::endl; + Errors << "%ssa" << ID << ": Had destination but with no register class assigned" << std::endl; } // If no physical register was assigned if ((uint32_t)Reg == ~0U) { HadError |= true; - Errors << "%ssa" << CodeOp->ID() << ": Had destination but with no register assigned" << std::endl; + Errors << "%ssa" << ID << ": Had destination but with no register assigned" << std::endl; } // Assigned class wasn't the expected class and it is a non-complex op if (AssignedClass != ExpectedClass && ExpectedClass != IR::ComplexClass) { HadWarning |= true; - Warnings << "%ssa" << CodeOp->ID() << ": Destination had register class " << AssignedClass.Val << " When register class " << ExpectedClass.Val << " Was expected" << std::endl; + Warnings << "%ssa" << ID << ": Destination had register class " << AssignedClass.Val << " When register class " << ExpectedClass.Val << " Was expected" << std::endl; } } } @@ -111,24 +102,24 @@ bool IRValidation::Run(IREmitter *IREmit) { uint8_t NumArgs = IR::GetArgs(IROp->Op); if (NumArgs != IROp->NumArgs) - Errors << "%ssa" << CodeOp->ID() << ": Has wrong number of Args" << std::endl; + Errors << "%ssa" << ID << ": Has wrong number of Args" << std::endl; for (uint32_t i = 0; i < NumArgs; ++i) { OrderedNodeWrapper Arg = IROp->Args[i]; // Was an argument defined after this node? - if (Arg.ID() >= CodeOp->ID()) { + if (Arg.ID() >= ID) { HadError |= true; - Errors << "%ssa" << CodeOp->ID() << ": Arg[" << i << "] has definition after use at %ssa" << Arg.ID() << std::endl; + Errors << "%ssa" << ID << ": Arg[" << i << "] has definition after use at %ssa" << Arg.ID() << std::endl; } if (!NodeIsLive.Get(Arg.ID())) { HadError |= true; - Errors << "%ssa" << CodeOp->ID() << ": Arg[" << i << "] refrences dead %ssa" << Arg.ID() << std::endl; + Errors << "%ssa" << ID << ": Arg[" << i << "] refrences dead %ssa" << Arg.ID() << std::endl; } Uses[Arg.ID()]++; } - NodeIsLive.Set(CodeOp->ID()); + NodeIsLive.Set(ID); switch (IROp->Op) { case IR::OP_EXITFUNCTION: { @@ -149,7 +140,7 @@ bool IRValidation::Run(IREmitter *IREmit) { if (TrueTargetOp->Op != OP_CODEBLOCK) { HadError |= true; - Errors << "CondJump %ssa" << CodeOp->ID() << ": True Target Jumps to Op that isn't the begining of a block" << std::endl; + Errors << "CondJump %ssa" << ID << ": True Target Jumps to Op that isn't the begining of a block" << std::endl; } else { auto Block = OffsetToBlockMap.try_emplace(Op->Header.Args[1].ID()).first; @@ -158,7 +149,7 @@ bool IRValidation::Run(IREmitter *IREmit) { if (FalseTargetOp->Op != OP_CODEBLOCK) { HadError |= true; - Errors << "CondJump %ssa" << CodeOp->ID() << ": False Target Jumps to Op that isn't the begining of a block" << std::endl; + Errors << "CondJump %ssa" << ID << ": False Target Jumps to Op that isn't the begining of a block" << std::endl; } else { auto Block = OffsetToBlockMap.try_emplace(Op->Header.Args[2].ID()).first; @@ -175,7 +166,7 @@ bool IRValidation::Run(IREmitter *IREmit) { FEXCore::IR::IROp_Header const *TargetOp = TargetNode->Op(DataBegin); if (TargetOp->Op != OP_CODEBLOCK) { HadError |= true; - Errors << "Jump %ssa" << CodeOp->ID() << ": Jump to Op that isn't the begining of a block" << std::endl; + Errors << "Jump %ssa" << ID << ": Jump to Op that isn't the begining of a block" << std::endl; } else { auto Block = OffsetToBlockMap.try_emplace(Op->Header.Args[0].ID()).first; @@ -187,12 +178,6 @@ bool IRValidation::Run(IREmitter *IREmit) { // LogMan::Msg::A("Unknown IR Op: %d(%s)", IROp->Op, FEXCore::IR::GetName(IROp->Op).data()); break; } - - // CodeLast is inclusive. So we still need to dump the CodeLast op as well - if (CodeBegin == CodeLast) { - break; - } - ++CodeBegin; } // Blocks can only have zero (Exit), 1 (Unconditional branch) or 2 (Conditional) successors @@ -203,14 +188,12 @@ bool IRValidation::Run(IREmitter *IREmit) { } { - auto GetOp = [&ListBegin, &DataBegin](auto Code) { - auto CodeOp = Code(); - OrderedNode *CodeNode = CodeOp->GetNode(ListBegin); - auto IROp = CodeNode->Op(DataBegin); + auto GetOp = [](auto Code) { + auto [CodeNode, IROp] = Code(); return IROp->Op; }; - auto CodeCurrent = CodeLast; + auto CodeCurrent = CurrentIR.at(BlockIROp->Last); // Last instruction in the block must be EndBlock { diff --git a/External/FEXCore/include/FEXCore/IR/IR.h b/External/FEXCore/include/FEXCore/IR/IR.h index 0262568ae..f70cb5b98 100644 --- a/External/FEXCore/include/FEXCore/IR/IR.h +++ b/External/FEXCore/include/FEXCore/IR/IR.h @@ -422,6 +422,10 @@ public: return { RealNode, RealNode->Op(IRList) }; } + uint32_t ID() { + return Node.ID(); + } + static NodeIterator Invalid() { return NodeIterator(0, 0); } diff --git a/External/FEXCore/include/FEXCore/IR/IREmitter.h b/External/FEXCore/include/FEXCore/IR/IREmitter.h index 28b821989..0a71fc597 100644 --- a/External/FEXCore/include/FEXCore/IR/IREmitter.h +++ b/External/FEXCore/include/FEXCore/IR/IREmitter.h @@ -466,7 +466,7 @@ friend class FEXCore::IR::PassManager; SetWriteCursor(nullptr);// Orphan from any future nodes - auto Begin = _Dummy(); + auto Begin = _BeginBlock(CodeNode); CodeNode.first->Begin = Begin.Node->Wrapped(ListData.Begin()); auto EndBlock = _EndBlock(CodeNode); diff --git a/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h b/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h index a4c561d70..3e94bd6c8 100644 --- a/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h +++ b/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h @@ -201,7 +201,7 @@ public: return AllCodeRange(this); } - using iterator = NodeWrapperIterator; + using iterator = NodeIterator; iterator begin() const noexcept { @@ -226,8 +226,19 @@ public: * @brief Convert a OrderedNodeWrapper to an interator that we can iterate over * @return Iterator for this op */ - iterator at(OrderedNodeWrapper Node) const noexcept { - return iterator(reinterpret_cast(ListData), reinterpret_cast(IRData), Node); + iterator at(OrderedNodeWrapper Wrapped) const noexcept { + return iterator(reinterpret_cast(ListData), reinterpret_cast(IRData), Wrapped); + } + + iterator at(uint32_t ID) const noexcept { + OrderedNodeWrapper Wrapped; + Wrapped.NodeOffset = ID * sizeof(OrderedNode); + return iterator(reinterpret_cast(ListData), reinterpret_cast(IRData), Wrapped); + } + + iterator at(OrderedNode *Node) const noexcept { + auto Wrapped = Node->Wrapped(reinterpret_cast(ListData)); + return iterator(reinterpret_cast(ListData), reinterpret_cast(IRData), Wrapped); } private: From e756b46189ddba9e6bc82c340825516d0de23779 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Fri, 11 Sep 2020 11:29:20 +1200 Subject: [PATCH 09/16] Allow AllNodes to iterate in reverse We replace Dummy with the old unused BeginBlock and pointing it at block header like EndBlock --- External/FEXCore/Scripts/json_ir_generator.py | 1 - .../Source/Interface/Core/JIT/x86_64/JIT.cpp | 22 ++++---------- External/FEXCore/Source/Interface/IR/IR.cpp | 8 ----- External/FEXCore/Source/Interface/IR/IR.json | 9 +++++- .../FEXCore/Source/Interface/IR/IREmitter.cpp | 1 - .../Interface/IR/Passes/PhiValidation.cpp | 4 +-- External/FEXCore/include/FEXCore/IR/IR.h | 30 +++++++++++++++++-- 7 files changed, 43 insertions(+), 32 deletions(-) diff --git a/External/FEXCore/Scripts/json_ir_generator.py b/External/FEXCore/Scripts/json_ir_generator.py index 5558a8ffd..3ef6fe3da 100644 --- a/External/FEXCore/Scripts/json_ir_generator.py +++ b/External/FEXCore/Scripts/json_ir_generator.py @@ -302,7 +302,6 @@ def print_ir_allocator_helpers(ops, defines): output_file.write("\tuint8_t GetOpSize(OrderedNode *Op) const {\n") output_file.write("\t\tauto HeaderOp = Op->Header.Value.GetNode(Data.Begin());\n") - output_file.write("\t\tLogMan::Throw::A(HeaderOp->HasDest, \"Op %s has no dest\\n\", GetName(HeaderOp->Op));\n") output_file.write("\t\treturn HeaderOp->Size;\n") output_file.write("\t}\n\n") diff --git a/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp b/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp index 8a74de9e9..9144a2221 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp @@ -509,10 +509,11 @@ void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const for (auto [BlockNode, BlockHeader] : CurrentIR->GetBlocks()) { using namespace FEXCore::IR; - auto BlockIROp = BlockHeader->CW(); - LogMan::Throw::A(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block"); { + auto BlockIROp = BlockHeader->CW(); + LogMan::Throw::A(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block"); + uint32_t Node = CurrentIR->GetID(BlockNode); auto IsTarget = JumpTargets.find(Node); if (IsTarget == JumpTargets.end()) { @@ -563,21 +564,6 @@ void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const #endif switch (IROp->Op) { - case IR::OP_BEGINBLOCK: { - auto IsTarget = JumpTargets.find(Node); - if (IsTarget == JumpTargets.end()) { - IsTarget = JumpTargets.try_emplace(Node).first; - } - else { - } - - L(IsTarget->second); - break; - } - case IR::OP_ENDBLOCK: { - auto Op = IROp->C(); - break; - } case IR::OP_EXITFUNCTION: { RegularExit(); break; @@ -4800,6 +4786,8 @@ void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const break; } case IR::OP_DUMMY: + case IR::OP_BEGINBLOCK: + case IR::OP_ENDBLOCK: case IR::OP_IRHEADER: case IR::OP_PHIVALUE: case IR::OP_PHI: diff --git a/External/FEXCore/Source/Interface/IR/IR.cpp b/External/FEXCore/Source/Interface/IR/IR.cpp index 986ea8397..ba56b4e45 100644 --- a/External/FEXCore/Source/Interface/IR/IR.cpp +++ b/External/FEXCore/Source/Interface/IR/IR.cpp @@ -204,14 +204,6 @@ void Dump(std::stringstream *out, IRListView const* IR, IR::RegisterAlloc *out << ") "; } *out << Name; - switch (IROp->Op) { - case IR::OP_BEGINBLOCK: - *out << " %ssa" << std::to_string(ID); - break; - case IR::OP_ENDBLOCK: - break; - default: break; - } #define IROP_ARGPRINTER_HELPER #include diff --git a/External/FEXCore/Source/Interface/IR/IR.json b/External/FEXCore/Source/Interface/IR/IR.json index 3acb3cb5d..6ba45ee48 100644 --- a/External/FEXCore/Source/Interface/IR/IR.json +++ b/External/FEXCore/Source/Interface/IR/IR.json @@ -73,7 +73,14 @@ ] }, "BeginBlock": { - "OpClass": "Misc" + "HasSideEffects": true, + "OpClass": "Misc", + "SwitchGen": false, + "SSAArgs": "1", + "RAOverride": "0", + "SSANames": [ + "BlockHeader" + ] }, "EndBlock": { diff --git a/External/FEXCore/Source/Interface/IR/IREmitter.cpp b/External/FEXCore/Source/Interface/IR/IREmitter.cpp index 61d3c1c5c..6dae5ee0a 100644 --- a/External/FEXCore/Source/Interface/IR/IREmitter.cpp +++ b/External/FEXCore/Source/Interface/IR/IREmitter.cpp @@ -13,7 +13,6 @@ void IREmitter::ResetWorkingList() { void IREmitter::ReplaceAllUsesWithRange(OrderedNode *Node, OrderedNode *NewNode, AllNodesIterator After, AllNodesIterator End) { uintptr_t ListBegin = ListData.Begin(); - uintptr_t DataBegin = Data.Begin(); auto NodeId = Node->Wrapped(ListBegin).ID(); while (After != End) { diff --git a/External/FEXCore/Source/Interface/IR/Passes/PhiValidation.cpp b/External/FEXCore/Source/Interface/IR/Passes/PhiValidation.cpp index ad57e71b6..8a0b3482a 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/PhiValidation.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/PhiValidation.cpp @@ -24,8 +24,8 @@ bool PhiValidation::Run(IREmitter *IREmit) { for (auto [CodeNode, IROp] : CurrentIR.GetCode(BlockNode)) { switch (IROp->Op) { - // DUMMY doesn't matter for us - case IR::OP_DUMMY: break; + // BEGINBLOCK doesn't matter for us + case IR::OP_BEGINBLOCK: break; case IR::OP_PHIVALUE: case IR::OP_PHI: { if (FoundNonPhi) { diff --git a/External/FEXCore/include/FEXCore/IR/IR.h b/External/FEXCore/include/FEXCore/IR/IR.h index f70cb5b98..91334195d 100644 --- a/External/FEXCore/include/FEXCore/IR/IR.h +++ b/External/FEXCore/include/FEXCore/IR/IR.h @@ -374,6 +374,10 @@ protected: NodeType Node{}; }; +/* This iterator can be used to step though nodes. + * Due to how our IR is laid out, this can be used to either step + * though the CodeBlocks or though the code within a single block. + */ class NodeIterator { public: using value_type = std::tuple; @@ -442,8 +446,13 @@ protected: #define IROP_REG_CLASSES #include +/* This iterator can be used to step though every single node in a multi-block in SSA order. + * + * Iterates in the order of: + * + * end <-- CodeBlockA <--> BlockAInst1 <--> BlockAInst2 <--> CodeBlockB <--> BlockBInst1 <--> BlockBInst2 --> end + */ class AllNodesIterator : public NodeIterator { - using iterator_category = std::forward_iterator_tag; public: AllNodesIterator(uintptr_t Base, uintptr_t IRBase) : NodeIterator(Base, IRBase) {} explicit AllNodesIterator(uintptr_t Base, uintptr_t IRBase, OrderedNodeWrapper Ptr) : NodeIterator(Base, IRBase, Ptr) {} @@ -470,7 +479,24 @@ public: return *this; } - AllNodesIterator operator--() = delete; + AllNodesIterator operator--() { + auto IROp = Node.GetNode(BaseList)->Op(IRList); + + if (IROp->Op == OP_BEGINBLOCK) { + auto BeginBlock = IROp->C(); + + Node = BeginBlock->BlockHeader; + } else if (IROp->Op == OP_CODEBLOCK) { + auto PrevBlockWrapper = Node.GetNode(BaseList)->Header.Previous; + auto PrevCodeBlock = PrevBlockWrapper.GetNode(BaseList)->Op(IRList)->C(); + + Node = PrevCodeBlock->Last; + } else { + Node = Node.GetNode(BaseList)->Header.Previous; + } + + return *this; + } static AllNodesIterator Invalid() { return AllNodesIterator(0, 0); From 70b34565366e4e6d9a2b89c42bde47e077680f28 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Fri, 11 Sep 2020 11:29:44 +1200 Subject: [PATCH 10/16] Swich register allocator to new scheme. --- .../Interface/IR/Passes/IRCompaction.cpp | 7 +- .../IR/Passes/RegisterAllocationPass.cpp | 246 +++++------------- 2 files changed, 69 insertions(+), 184 deletions(-) diff --git a/External/FEXCore/Source/Interface/IR/Passes/IRCompaction.cpp b/External/FEXCore/Source/Interface/IR/Passes/IRCompaction.cpp index 61cdc1873..2d602bcdb 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/IRCompaction.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/IRCompaction.cpp @@ -73,7 +73,6 @@ bool IRCompaction::Run(IREmitter *IREmit) { { // Generate our codeblocks and link them together - OrderedNode* PrevCodeBlock{}; for (auto [BlockNode, BlockHeader] : CurrentIR.GetBlocks()) { LogMan::Throw::A(BlockHeader->Op == OP_CODEBLOCK, "IR type failed to be a code block"); @@ -86,13 +85,15 @@ bool IRCompaction::Run(IREmitter *IREmit) { LocalHeaderOp.first->Blocks = GeneratedCodeBlocks[0].NewNode->Wrapped(LocalListBegin); } - // Isolate the nodes from the Block headers - LocalBuilder.SetWriteCursor(nullptr); + { // Copy all of our IR ops over to the new location for (auto &Block : GeneratedCodeBlocks) { + // Isolate block contents from any previous headers/blocks + LocalBuilder.SetWriteCursor(nullptr); + CodeBlockData FirstNode{}; CodeBlockData LastNode{}; uint32_t i {}; diff --git a/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp b/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp index c24089aaa..18c941c88 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp @@ -206,10 +206,8 @@ namespace { return false; } - FEXCore::IR::RegisterClassType GetRegClassFromNode(uintptr_t ListBegin, uintptr_t DataBegin, FEXCore::IR::OrderedNodeWrapper const WrapperOp) { + FEXCore::IR::RegisterClassType GetRegClassFromNode(FEXCore::IR::IRListView *IR, FEXCore::IR::IROp_Header *IROp) { using namespace FEXCore; - IR::OrderedNode const *RealNode = WrapperOp.GetNode(ListBegin); - IR::IROp_Header const *IROp = RealNode->Op(DataBegin); FEXCore::IR::RegisterClassType Class = IR::GetRegClass(IROp->Op); if (Class != FEXCore::IR::ComplexClass) @@ -241,13 +239,13 @@ namespace { case IR::OP_PHIVALUE: { // Unwrap the PHIValue to get the class auto Op = IROp->C(); - return GetRegClassFromNode(ListBegin, DataBegin, Op->Value); + return GetRegClassFromNode(IR, IR->GetOp(Op->Value)); } case IR::OP_PHI: { // Class is defined from the values passed in // All Phi nodes should have its class be the same (Validation should confirm this auto Op = IROp->C(); - return GetRegClassFromNode(ListBegin, DataBegin, Op->PhiBegin); + return GetRegClassFromNode(IR, IR->GetOp(Op->PhiBegin)); } default: break; } @@ -258,32 +256,10 @@ namespace { // Walk the IR and set the node classes void FindNodeClasses(RegisterGraph *Graph, FEXCore::IR::IRListView *IR) { - uintptr_t ListBegin = IR->GetListData(); - uintptr_t DataBegin = IR->GetData(); - - for (auto [BlockNode, BlockHeader] : IR->GetBlocks()) { - auto BlockIROp = BlockHeader->CW(); - LogMan::Throw::A(BlockIROp->Header.Op == FEXCore::IR::OP_CODEBLOCK, "IR type failed to be a code block"); - - // We grab these nodes this way so we can iterate easily - auto CodeBegin = IR->at(BlockIROp->Begin); - auto CodeLast = IR->at(BlockIROp->Last); - while (1) { - FEXCore::IR::OrderedNodeWrapper *CodeOp = CodeBegin(); - FEXCore::IR::OrderedNode *CodeNode = CodeOp->GetNode(ListBegin); - auto IROp = CodeNode->Op(DataBegin); - uint32_t Node = CodeOp->ID(); - - // If the destination hasn't yet been set then set it now - if (IROp->HasDest) { - SetNodeClass(Graph, Node, GetRegClassFromNode(ListBegin, DataBegin, *CodeOp)); - } - - // CodeLast is inclusive. So we still need to dump the CodeLast op as well - if (CodeBegin == CodeLast) { - break; - } - ++CodeBegin; + for (auto [CodeNode, IROp] : IR->GetAllCode()) { + // If the destination hasn't yet been set then set it now + if (IROp->HasDest) { + SetNodeClass(Graph, IR->GetID(CodeNode), GetRegClassFromNode(IR, IROp)); } } } @@ -329,8 +305,8 @@ namespace FEXCore::IR { void CalculateNodeInterference(FEXCore::IR::IRListView *IR); void AllocateVirtualRegisters(); - FEXCore::IR::NodeWrapperIterator FindFirstUse(FEXCore::IR::IREmitter *IREmit, FEXCore::IR::OrderedNode* Node, FEXCore::IR::NodeWrapperIterator Begin, FEXCore::IR::NodeWrapperIterator End); - FEXCore::IR::NodeWrapperIterator FindLastUseBefore(FEXCore::IR::IREmitter *IREmit, FEXCore::IR::OrderedNode* Node, FEXCore::IR::NodeWrapperIterator Begin, FEXCore::IR::NodeWrapperIterator End); + FEXCore::IR::AllNodesIterator FindFirstUse(FEXCore::IR::IREmitter *IREmit, FEXCore::IR::OrderedNode* Node, FEXCore::IR::AllNodesIterator Begin, FEXCore::IR::AllNodesIterator End); + FEXCore::IR::AllNodesIterator FindLastUseBefore(FEXCore::IR::IREmitter *IREmit, FEXCore::IR::OrderedNode* Node, FEXCore::IR::AllNodesIterator Begin, FEXCore::IR::AllNodesIterator End); uint32_t FindNodeToSpill(IREmitter *IREmit, RegisterNode *RegisterNode, uint32_t CurrentLocation, LiveRange const *OpLiveRange, int32_t RematCost = -1); uint32_t FindSpillSlot(uint32_t Node, FEXCore::IR::RegisterClassType RegisterClass); @@ -380,22 +356,10 @@ namespace FEXCore::IR { } LiveRanges.assign(Nodes * sizeof(LiveRange), {~0U, ~0U}); - uintptr_t ListBegin = IR->GetListData(); - uintptr_t DataBegin = IR->GetData(); - constexpr uint32_t DEFAULT_REMAT_COST = 1000; for (auto [BlockNode, BlockHeader] : IR->GetBlocks()) { - auto BlockIROp = BlockHeader->CW(); - LogMan::Throw::A(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block"); - - // We grab these nodes this way so we can iterate easily - auto CodeBegin = IR->at(BlockIROp->Begin); - auto CodeLast = IR->at(BlockIROp->Last); - while (1) { - auto CodeOp = CodeBegin(); - IR::OrderedNode *CodeNode = CodeOp->GetNode(ListBegin); - auto IROp = CodeNode->Op(DataBegin); - uint32_t Node = CodeOp->ID(); + for (auto [CodeNode, IROp] : IR->GetCode(BlockNode)) { + uint32_t Node = IR->GetID(CodeNode); // If the destination hasn't yet been set then set it now if (IROp->HasDest) { @@ -421,7 +385,7 @@ namespace FEXCore::IR { } // Set this node's block ID - Graph->Nodes[Node].Head.BlockID = BlockNode->Wrapped(ListBegin).ID(); + Graph->Nodes[Node].Head.BlockID = IR->GetID(BlockNode); uint8_t NumArgs = IR::GetArgs(IROp->Op); for (uint8_t i = 0; i < NumArgs; ++i) { @@ -440,23 +404,16 @@ namespace FEXCore::IR { uint32_t CurrentSourcePartner = Node; while (NodeBegin != NodeBegin.Invalid()) { - FEXCore::IR::OrderedNodeWrapper *NodeOp = NodeBegin(); - FEXCore::IR::OrderedNode *NodeNode = NodeOp->GetNode(ListBegin); - auto IRNodeOp = NodeNode->Op(DataBegin)->C(); + auto [ValueNode, ValueHeader] = NodeBegin(); + auto ValueOp = ValueHeader->CW(); // Set the node partner to the current one // This creates a singly linked list of node partners to follow - SetNodePartner(Graph, CurrentSourcePartner, IRNodeOp->Value.ID()); - CurrentSourcePartner = IRNodeOp->Value.ID(); - NodeBegin = IR->at(IRNodeOp->Next); + SetNodePartner(Graph, CurrentSourcePartner, ValueOp->Value.ID()); + CurrentSourcePartner = ValueOp->Value.ID(); + NodeBegin = IR->at(ValueOp->Next); } } - - // CodeLast is inclusive. So we still need to dump the CodeLast op as well - if (CodeBegin == CodeLast) { - break; - } - ++CodeBegin; } } } @@ -472,12 +429,8 @@ namespace FEXCore::IR { BlockInterferences *BlockInterferenceVector = &LocalBlockInterferences.try_emplace(BlockNode->Wrapped(ListBegin).ID()).first->second; BlockInterferenceVector->reserve(BlockIROp->Last.ID() - BlockIROp->Begin.ID()); - // We grab these nodes this way so we can iterate easily - auto CodeBegin = IR->at(BlockIROp->Begin); - auto CodeLast = IR->at(BlockIROp->Last); - while (1) { - auto CodeOp = CodeBegin(); - uint32_t Node = CodeOp->ID(); + for (auto [CodeNode, IROp] : IR->GetCode(BlockNode)) { + uint32_t Node = IR->GetID(CodeNode); LiveRange *NodeLiveRange = &LiveRanges[Node]; if (NodeLiveRange->Begin >= BlockIROp->Begin.ID() && @@ -490,12 +443,6 @@ namespace FEXCore::IR { // If the live range is not fully inside the block then add it to the global interference list GlobalBlockInterferences.emplace_back(Node); } - - // CodeLast is inclusive. So we still need to dump the CodeLast op as well - if (CodeBegin == CodeLast) { - break; - } - ++CodeBegin; } } } @@ -516,23 +463,15 @@ namespace FEXCore::IR { } }; using namespace FEXCore; - uintptr_t ListBegin = IR->GetListData(); for (auto [BlockNode, BlockHeader] : IR->GetBlocks()) { - auto BlockIROp = BlockHeader->CW(); - LogMan::Throw::A(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block"); - - BlockInterferences *BlockInterferenceVector = &LocalBlockInterferences.try_emplace(BlockNode->Wrapped(ListBegin).ID()).first->second; + BlockInterferences *BlockInterferenceVector = &LocalBlockInterferences.try_emplace(IR->GetID(BlockNode)).first->second; std::vector Interferences; Interferences.reserve(BlockInterferenceVector->size() + GlobalBlockInterferences.size()); - // We grab these nodes this way so we can iterate easily - auto CodeBegin = IR->at(BlockIROp->Begin); - auto CodeLast = IR->at(BlockIROp->Last); - while (1) { - auto CodeOp = CodeBegin(); - uint32_t Node = CodeOp->ID(); + for (auto [CodeNode, IROp] : IR->GetCode(BlockNode)) { + uint32_t Node = IR->GetID(CodeNode); // Check for every interference with the local block's interference for (auto RHSNode : *BlockInterferenceVector) { @@ -561,12 +500,6 @@ namespace FEXCore::IR { } Interferences.clear(); - - // CodeLast is inclusive. So we still need to dump the CodeLast op as well - if (CodeBegin == CodeLast) { - break; - } - ++CodeBegin; } } } @@ -657,18 +590,12 @@ namespace FEXCore::IR { } } - FEXCore::IR::NodeWrapperIterator ConstrainedRAPass::FindFirstUse(FEXCore::IR::IREmitter *IREmit, FEXCore::IR::OrderedNode* Node, FEXCore::IR::NodeWrapperIterator Begin, FEXCore::IR::NodeWrapperIterator End) { - auto CurrentIR = IREmit->ViewIR(); - uintptr_t ListBegin = CurrentIR.GetListData(); - uintptr_t DataBegin = CurrentIR.GetData(); + FEXCore::IR::AllNodesIterator ConstrainedRAPass::FindFirstUse(FEXCore::IR::IREmitter *IREmit, FEXCore::IR::OrderedNode* Node, FEXCore::IR::AllNodesIterator Begin, FEXCore::IR::AllNodesIterator End) { + using namespace FEXCore::IR; + uint32_t SearchID = IREmit->ViewIR().GetID(Node); - uint32_t SearchID = Node->Wrapped(ListBegin).ID(); - - while (1) { - using namespace FEXCore::IR; - OrderedNodeWrapper *WrapperOp = Begin(); - OrderedNode *RealNode = WrapperOp->GetNode(ListBegin); - FEXCore::IR::IROp_Header *IROp = RealNode->Op(DataBegin); + while(1) { + auto [RealNode, IROp] = Begin(); uint8_t NumArgs = FEXCore::IR::GetArgs(IROp->Op); for (uint8_t i = 0; i < NumArgs; ++i) { @@ -686,21 +613,16 @@ namespace FEXCore::IR { ++Begin; } - return FEXCore::IR::NodeWrapperIterator::Invalid(); + return AllNodesIterator::Invalid(); } - FEXCore::IR::NodeWrapperIterator ConstrainedRAPass::FindLastUseBefore(FEXCore::IR::IREmitter *IREmit, FEXCore::IR::OrderedNode* Node, FEXCore::IR::NodeWrapperIterator Begin, FEXCore::IR::NodeWrapperIterator End) { + FEXCore::IR::AllNodesIterator ConstrainedRAPass::FindLastUseBefore(FEXCore::IR::IREmitter *IREmit, FEXCore::IR::OrderedNode* Node, FEXCore::IR::AllNodesIterator Begin, FEXCore::IR::AllNodesIterator End) { auto CurrentIR = IREmit->ViewIR(); - uintptr_t ListBegin = CurrentIR.GetListData(); - uintptr_t DataBegin = CurrentIR.GetData(); - - uint32_t SearchID = Node->Wrapped(ListBegin).ID(); + uint32_t SearchID = CurrentIR.GetID(Node); while (1) { using namespace FEXCore::IR; - OrderedNodeWrapper *WrapperOp = End(); - OrderedNode *RealNode = WrapperOp->GetNode(ListBegin); - FEXCore::IR::IROp_Header *IROp = RealNode->Op(DataBegin); + auto [RealNode, IROp] = End(); if (Node == RealNode) { // We walked back all the way to the definition of the IR op @@ -723,7 +645,7 @@ namespace FEXCore::IR { --End; } - return FEXCore::IR::NodeWrapperIterator::Invalid(); + return FEXCore::IR::AllNodesIterator::Invalid(); } uint32_t ConstrainedRAPass::FindNodeToSpill(IREmitter *IREmit, RegisterNode *RegisterNode, uint32_t CurrentLocation, LiveRange const *OpLiveRange, int32_t RematCost) { @@ -795,7 +717,7 @@ namespace FEXCore::IR { // does NOT have a use inside of this this node's live range // Search only inside the source node's live range to see if there is a use auto FirstUseLocation = FindFirstUse(IREmit, InterferenceOrderedNode, NodeOpBeginIter, NodeOpEndIter); - if (FirstUseLocation == IR::NodeWrapperIterator::Invalid()) { + if (FirstUseLocation == IR::NodeIterator::Invalid()) { // Looks like there isn't a usage of this interference node inside our node's live range // This means it is safe to spill this node and it'll result in in lower RA // Proper calculation of cost to spill would be to calculate the two distances from @@ -803,11 +725,11 @@ namespace FEXCore::IR { // This would ensure something will spill earlier if its previous use and next use are farther away auto InterferenceNodeNextUse = FindFirstUse(IREmit, InterferenceOrderedNode, NodeOpBeginIter, InterferenceNodeOpEndIter); auto InterferenceNodePrevUse = FindLastUseBefore(IREmit, InterferenceOrderedNode, InterferenceNodeOpBeginIter, NodeOpBeginIter); - LogMan::Throw::A(InterferenceNodeNextUse != IR::NodeWrapperIterator::Invalid(), "Couldn't find next usage of op"); + LogMan::Throw::A(InterferenceNodeNextUse != IR::NodeIterator::Invalid(), "Couldn't find next usage of op"); // If there is no use of the interference op prior to our op then it only has initial definition - if (InterferenceNodePrevUse == IR::NodeWrapperIterator::Invalid()) InterferenceNodePrevUse = InterferenceNodeOpBeginIter; + if (InterferenceNodePrevUse == IR::NodeIterator::Invalid()) InterferenceNodePrevUse = InterferenceNodeOpBeginIter; - uint32_t NextUseDistance = InterferenceNodeNextUse()->ID() - CurrentLocation; + uint32_t NextUseDistance = InterferenceNodeNextUse.ID() - CurrentLocation; if (NextUseDistance >= InterferenceFarthestNextUse) { Found = true; InterferenceToSpill = j; @@ -870,11 +792,11 @@ namespace FEXCore::IR { OpLiveRange->End > InterferenceLiveRange->End) { auto FirstUseLocation = FindFirstUse(IREmit, InterferenceOrderedNode, NodeOpBeginIter, NodeOpBeginIter); - if (FirstUseLocation == IR::NodeWrapperIterator::Invalid()) { + if (FirstUseLocation == IR::NodeIterator::Invalid()) { // This means that the assignment of our register doesn't use this interference node // So we are safe to spill this interference node before assignment of our current node auto InterferenceNodeNextUse = FindFirstUse(IREmit, InterferenceOrderedNode, NodeOpBeginIter, InterferenceNodeOpEndIter); - uint32_t NextUseDistance = InterferenceNodeNextUse()->ID() - CurrentLocation; + uint32_t NextUseDistance = InterferenceNodeNextUse.ID() - CurrentLocation; if (NextUseDistance >= InterferenceFarthestNextUse) { Found = true; @@ -905,11 +827,11 @@ namespace FEXCore::IR { OpLiveRange->End <= InterferenceLiveRange->End) { auto FirstUseLocation = FindFirstUse(IREmit, InterferenceOrderedNode, NodeOpEndIter, NodeOpEndIter); - if (FirstUseLocation == IR::NodeWrapperIterator::Invalid()) { + if (FirstUseLocation == IR::NodeIterator::Invalid()) { // This means that the assignment of our the interference register doesn't overlap // with the final usage of our register, we can spill it and reduce usage auto InterferenceNodeNextUse = FindFirstUse(IREmit, InterferenceOrderedNode, NodeOpBeginIter, InterferenceNodeOpEndIter); - uint32_t NextUseDistance = InterferenceNodeNextUse()->ID() - CurrentLocation; + uint32_t NextUseDistance = InterferenceNodeNextUse.ID() - CurrentLocation; if (NextUseDistance >= InterferenceFarthestNextUse) { Found = true; @@ -969,36 +891,15 @@ namespace FEXCore::IR { using namespace FEXCore; auto IR = IREmit->ViewIR(); - uintptr_t ListBegin = IR.GetListData(); - uintptr_t DataBegin = IR.GetData(); - - auto Begin = IR.begin(); - auto Op = Begin(); auto LastCursor = IREmit->GetWriteCursor(); - IR::OrderedNode *RealNode = Op->GetNode(ListBegin); - auto HeaderOp = RealNode->Op(DataBegin)->CW(); - LogMan::Throw::A(HeaderOp->Header.Op == IR::OP_IRHEADER, "First op wasn't IRHeader"); + for (auto [BlockNode, BlockIRHeader] : IR.GetBlocks()) { + auto BlockIROp = BlockIRHeader->CW(); - IR::OrderedNode *BlockNode = HeaderOp->Blocks.GetNode(ListBegin); - - while (1) { - auto BlockIROp = BlockNode->Op(DataBegin)->CW(); - LogMan::Throw::A(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block"); - - // We grab these nodes this way so we can iterate easily - auto CodeBegin = IR.at(BlockIROp->Begin); - auto CodeLast = IR.at(BlockIROp->Last); - - auto BlockBegin = CodeBegin; - - while (1) { - auto CodeOp = CodeBegin(); - IR::OrderedNode *CodeNode = CodeOp->GetNode(ListBegin); - auto IROp = CodeNode->Op(DataBegin); + for (auto [CodeNode, IROp] : IR.GetCode(BlockNode)) { if (IROp->HasDest) { - uint32_t Node = CodeOp->ID(); + uint32_t Node = IR.GetID(CodeNode); RegisterNode *CurrentNode = &Graph->Nodes[Node]; LiveRange *OpLiveRange = &LiveRanges[Node]; @@ -1014,21 +915,19 @@ namespace FEXCore::IR { uint32_t InterferenceNode = FindNodeToSpill(IREmit, CurrentNode, Node, OpLiveRange, 1); if (InterferenceNode != ~0U) { // We want to end the live range of this value here and continue it on first use - IR::OrderedNodeWrapper ConstantOp = IR::OrderedNodeWrapper::WrapOffset(InterferenceNode * sizeof(IR::OrderedNode)); - IR::OrderedNode *ConstantNode = ConstantOp.GetNode(ListBegin); - FEXCore::IR::IROp_Constant const *ConstantIROp = ConstantNode->Op(DataBegin)->C(); - LogMan::Throw::A(ConstantIROp->Header.Op == IR::OP_CONSTANT, "This needs to be const"); + auto [ConstantNode, _] = IR.at(InterferenceNode)(); + auto ConstantIROp = IR.GetOp(ConstantNode); + // First op post Spill - auto NextIter = CodeBegin; - auto FirstUseLocation = FindFirstUse(IREmit, ConstantNode, NextIter, CodeLast); - LogMan::Throw::A(FirstUseLocation != IR::NodeWrapperIterator::Invalid(), "At %%ssa%d Spilling Op %%ssa%d but Failure to find op use", CodeOp->ID(), InterferenceNode); - if (FirstUseLocation != IR::NodeWrapperIterator::Invalid()) { + auto NextIter = IR.at(CodeNode); + auto FirstUseLocation = FindFirstUse(IREmit, ConstantNode, NextIter, NodeIterator::Invalid()); + LogMan::Throw::A(FirstUseLocation != IR::NodeIterator::Invalid(), "At %%ssa%d Spilling Op %%ssa%d but Failure to find op use", Node, InterferenceNode); + if (FirstUseLocation != IR::NodeIterator::Invalid()) { --FirstUseLocation; - IR::OrderedNodeWrapper *FirstUseOp = FirstUseLocation(); - IR::OrderedNode *FirstUseOrderedNode = FirstUseOp->GetNode(ListBegin); + auto [FirstUseOrderedNode, _] = FirstUseLocation(); IREmit->SetWriteCursor(FirstUseOrderedNode); auto FilledConstant = IREmit->_Constant(ConstantIROp->Constant); - IREmit->ReplaceAllUsesWithInclusive(ConstantNode, FilledConstant, FirstUseLocation, CodeLast); + IREmit->ReplaceUsesWithAfter(ConstantNode, FilledConstant, FirstUseLocation); Spilled = true; } } @@ -1046,17 +945,17 @@ namespace FEXCore::IR { LogMan::Throw::A(InterferenceRegisterNode->Head.PhiPartner == nullptr, "We don't support spilling PHI nodes currently"); // This is the op that we need to dump - FEXCore::IR::OrderedNodeWrapper InterferenceOp = IR::OrderedNodeWrapper::WrapOffset(InterferenceNode * sizeof(IR::OrderedNode)); - FEXCore::IR::OrderedNode *InterferenceOrderedNode = InterferenceOp.GetNode(ListBegin); - FEXCore::IR::IROp_Header *InterferenceIROp = InterferenceOrderedNode->Op(DataBegin); + auto [InterferenceOrderedNode, InterferenceIROp] = IR.at(InterferenceNode)(); + // This will find the last use of this definition // Walks from CodeBegin -> BlockBegin to find the last Use // Which this is walking backwards to find the first use - auto LastUseOp = FindLastUseBefore(IREmit, InterferenceOrderedNode, BlockBegin, CodeBegin); + auto LastUseIterator = FindLastUseBefore(IREmit, InterferenceOrderedNode, NodeIterator::Invalid(), IR.at(CodeNode)); + auto [LastUseNode, LastUseIROp] = LastUseIterator(); // Set the write cursor to point of last usage - IREmit->SetWriteCursor(LastUseOp()->GetNode(ListBegin)); + IREmit->SetWriteCursor(LastUseNode); // Actually spill the node now auto SpillOp = IREmit->_SpillRegister(InterferenceOrderedNode, SpillSlot, InterferenceRegClass); @@ -1066,24 +965,23 @@ namespace FEXCore::IR { { // Search from the point of spilling to find the first use // Set the write cursor to the first location found and fill at that point - auto FirstIter = IR.at(SpillOp.Node->Wrapped(ListBegin)); + auto FirstIter = IR.at(SpillOp.Node); // Just past the spill ++FirstIter; - auto FirstUseLocation = FindFirstUse(IREmit, InterferenceOrderedNode, FirstIter, CodeLast); + auto FirstUseLocation = FindFirstUse(IREmit, InterferenceOrderedNode, FirstIter, NodeIterator::Invalid()); - LogMan::Throw::A(FirstUseLocation != NodeWrapperIterator::Invalid(), "At %%ssa%d Spilling Op %%ssa%d but Failure to find op use", CodeOp->ID(), InterferenceNode); - if (FirstUseLocation != IR::NodeWrapperIterator::Invalid()) { + LogMan::Throw::A(FirstUseLocation != NodeIterator::Invalid(), "At %%ssa%d Spilling Op %%ssa%d but Failure to find op use", Node, InterferenceNode); + if (FirstUseLocation != IR::NodeIterator::Invalid()) { // We want to fill just before the first use --FirstUseLocation; - IR::OrderedNodeWrapper *FirstUseOp = FirstUseLocation(); - IR::OrderedNode *FirstUseOrderedNode = FirstUseOp->GetNode(ListBegin); + auto [FirstUseOrderedNode, _] = FirstUseLocation(); IREmit->SetWriteCursor(FirstUseOrderedNode); auto FilledInterference = IREmit->_FillRegister(SpillSlot, InterferenceRegClass); FilledInterference.first->Header.Size = InterferenceIROp->Size; FilledInterference.first->Header.ElementSize = InterferenceIROp->ElementSize; - IREmit->ReplaceAllUsesWithInclusive(InterferenceOrderedNode, FilledInterference, FirstUseLocation, CodeLast); + IREmit->ReplaceUsesWithAfter(InterferenceOrderedNode, FilledInterference, FirstUseLocation); Spilled = true; } } @@ -1097,12 +995,6 @@ namespace FEXCore::IR { } } } - - // CodeLast is inclusive. So we still need to dump the CodeLast op as well - if (CodeBegin == CodeLast) { - break; - } - ++CodeBegin; } } } @@ -1145,16 +1037,8 @@ namespace FEXCore::IR { bool Changed = false; auto IR = IREmit->ViewIR(); - uintptr_t ListBegin = IR.GetListData(); - uintptr_t DataBegin = IR.GetData(); - - auto Begin = IR.begin(); - auto Op = Begin(); - - IR::OrderedNode *RealNode = Op->GetNode(ListBegin); - auto HeaderOp = RealNode->Op(DataBegin)->CW(); - LogMan::Throw::A(HeaderOp->Header.Op == IR::OP_IRHEADER, "First op wasn't IRHeader"); + auto HeaderOp = IR.GetHeader(); if (HeaderOp->ShouldInterpret) { return false; } From d515753b388e2db25425200c3fe98c1659186c7f Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Fri, 11 Sep 2020 13:54:34 +1200 Subject: [PATCH 11/16] Remove remaing traces of NodeWrapperIterator --- External/FEXCore/include/FEXCore/IR/IR.h | 69 ++---------------------- 1 file changed, 3 insertions(+), 66 deletions(-) diff --git a/External/FEXCore/include/FEXCore/IR/IR.h b/External/FEXCore/include/FEXCore/IR/IR.h index 91334195d..fc4c0a675 100644 --- a/External/FEXCore/include/FEXCore/IR/IR.h +++ b/External/FEXCore/include/FEXCore/IR/IR.h @@ -309,70 +309,7 @@ struct FenceType final { constexpr bool operator!=(FenceType const &rhs) const { return !operator==(rhs); } }; -/** -* @brief This is our NodeWrapperIterator -* This stores both the memory base and the provided NodeWrapper to be able to walk the list of nodes directly -* Only the increment and decrement implementations of this class require understanding the implementation details of OrderedNode -*/ -class NodeWrapperIterator { -public: - using value_type = OrderedNodeWrapper; - using size_type = std::size_t; - using difference_type = std::ptrdiff_t; - using reference = value_type&; - using const_reference = const value_type&; - using pointer = value_type*; - using const_pointer = const value_type*; - using iterator = NodeWrapperIterator; - using const_iterator = const NodeWrapperIterator; - using reverse_iterator = iterator; - using const_reverse_iterator = const_iterator; - using iterator_category = std::bidirectional_iterator_tag; - - using NodeType = value_type; - using NodePtr = value_type*; - using NodeRef = value_type&; - - NodeWrapperIterator(uintptr_t Base, uintptr_t IRBase) : BaseList {Base}, IRList{ IRBase } {} - explicit NodeWrapperIterator(uintptr_t Base, uintptr_t IRBase, NodeType Ptr) : BaseList {Base}, IRList{ IRBase }, Node {Ptr} {} - - bool operator==(const NodeWrapperIterator &rhs) const { - return Node.NodeOffset == rhs.Node.NodeOffset; - } - - bool operator!=(const NodeWrapperIterator &rhs) const { - return !operator==(rhs); - } - - NodeWrapperIterator operator++() { - OrderedNodeHeader *RealNode = reinterpret_cast(Node.GetNode(BaseList)); - Node = RealNode->Next; - return *this; - } - - NodeWrapperIterator operator--() { - OrderedNodeHeader *RealNode = reinterpret_cast(Node.GetNode(BaseList)); - Node = RealNode->Previous; - return *this; - } - - NodeRef operator*() { - return Node; - } - - NodePtr operator()() { - return &Node; - } - - static NodeWrapperIterator Invalid() { - return NodeWrapperIterator(0, 0); - } - -protected: - uintptr_t BaseList{}; - uintptr_t IRList{}; - NodeType Node{}; -}; +class NodeIterator; /* This iterator can be used to step though nodes. * Due to how our IR is laid out, this can be used to either step @@ -387,8 +324,8 @@ public: using const_reference = const value_type&; using pointer = value_type*; using const_pointer = const value_type*; - using iterator = NodeWrapperIterator; - using const_iterator = const NodeWrapperIterator; + using iterator = NodeIterator; + using const_iterator = const NodeIterator; using reverse_iterator = iterator; using const_reverse_iterator = const_iterator; using iterator_category = std::bidirectional_iterator_tag; From 0a78651cce21987f80386b2909302091d38c5a3c Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Fri, 11 Sep 2020 14:46:20 +1200 Subject: [PATCH 12/16] Fix ListBegin usages that got missed. There are still a few in interpeter and IR compaction which are harder to fix. --- .../Core/Interpreter/InterpreterCore.cpp | 3 +- External/FEXCore/Source/Interface/IR/IR.cpp | 6 +--- .../Source/Interface/IR/Passes/ConstProp.cpp | 12 ++++---- .../Interface/IR/Passes/IRCompaction.cpp | 14 ++++----- .../Interface/IR/Passes/IRValidation.cpp | 30 ++++++++++--------- .../IR/Passes/RegisterAllocationPass.cpp | 23 ++++---------- .../IR/Passes/ValueDominanceValidation.cpp | 15 +++++----- 7 files changed, 41 insertions(+), 62 deletions(-) diff --git a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp index e219fb7e8..f3588bf2d 100644 --- a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp +++ b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp @@ -105,8 +105,7 @@ void InterpreterCore::ExecuteCode(FEXCore::Core::InternalThreadState *Thread) { #define GD *GetDest(SSAData, WrapperOp) #define GDP GetDest(SSAData, WrapperOp) auto GetOpSize = [&](IR::OrderedNodeWrapper Node) { - FEXCore::IR::OrderedNode const *RealNode = Node.GetNode(ListBegin); - FEXCore::IR::IROp_Header const *IROp = RealNode->Op(DataBegin); + auto IROp = CurrentIR->GetOp(Node); return IROp->Size; }; diff --git a/External/FEXCore/Source/Interface/IR/IR.cpp b/External/FEXCore/Source/Interface/IR/IR.cpp index ba56b4e45..8fffc6e0a 100644 --- a/External/FEXCore/Source/Interface/IR/IR.cpp +++ b/External/FEXCore/Source/Interface/IR/IR.cpp @@ -52,11 +52,7 @@ static void PrintArg(std::stringstream *out, [[maybe_unused]] IRListView } static void PrintArg(std::stringstream *out, IRListView const* IR, OrderedNodeWrapper Arg, IR::RegisterAllocationPass *RAPass) { - uintptr_t Data = IR->GetData(); - uintptr_t ListBegin = IR->GetListData(); - - OrderedNode *RealNode = Arg.GetNode(ListBegin); - auto IROp = RealNode->Op(Data); + auto [CodeNode, IROp] = IR->at(Arg)(); *out << "%ssa" << std::to_string(Arg.ID()); if (RAPass) { diff --git a/External/FEXCore/Source/Interface/IR/Passes/ConstProp.cpp b/External/FEXCore/Source/Interface/IR/Passes/ConstProp.cpp index 00df9da1f..a5620af5b 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/ConstProp.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/ConstProp.cpp @@ -17,8 +17,6 @@ static uint64_t getMask(T Op) { bool ConstProp::Run(IREmitter *IREmit) { bool Changed = false; auto CurrentIR = IREmit->ViewIR(); - uintptr_t ListBegin = CurrentIR.GetListData(); - uintptr_t DataBegin = CurrentIR.GetData(); auto OriginalWriteCursor = IREmit->GetWriteCursor(); @@ -113,7 +111,7 @@ bool ConstProp::Run(IREmitter *IREmit) { Changed = true; } else if (Op->Header.Args[0].ID() == Op->Header.Args[1].ID()) { // AND with same value results in original value - IREmit->ReplaceAllUsesWith(CodeNode, Op->Header.Args[0].GetNode(ListBegin)); + IREmit->ReplaceAllUsesWith(CodeNode, CurrentIR.GetNode(Op->Header.Args[0])); Changed = true; } break; @@ -132,7 +130,7 @@ bool ConstProp::Run(IREmitter *IREmit) { Changed = true; } else if (Op->Header.Args[0].ID() == Op->Header.Args[1].ID()) { // OR with same value results in original value - IREmit->ReplaceAllUsesWith(CodeNode, Op->Header.Args[0].GetNode(ListBegin)); + IREmit->ReplaceAllUsesWith(CodeNode, CurrentIR.GetNode(Op->Header.Args[0])); Changed = true; } break; @@ -173,7 +171,7 @@ bool ConstProp::Run(IREmitter *IREmit) { else if (IREmit->IsValueConstant(Op->Header.Args[1], &Constant2) && Constant2 == 0) { IREmit->SetWriteCursor(CodeNode); - OrderedNode *Arg = Op->Header.Args[0].GetNode(ListBegin); + OrderedNode *Arg = CurrentIR.GetNode(Op->Header.Args[0]); IREmit->ReplaceAllUsesWith(CodeNode, Arg); Changed = true; } @@ -193,10 +191,10 @@ bool ConstProp::Run(IREmitter *IREmit) { auto ConstantVal = IREmit->_Constant(NewConstant); IREmit->ReplaceAllUsesWith(CodeNode, ConstantVal); Changed = true; - } else if (IROp->Size == Op->Header.Args[0].GetNode(ListBegin)->Op(DataBegin)->Size && Op->Width == (IROp->Size * 8) && Op->lsb == 0 ) { + } else if (IROp->Size == CurrentIR.GetOp(Op->Header.Args[0])->Size && Op->Width == (IROp->Size * 8) && Op->lsb == 0 ) { // A BFE that extracts all bits results in original value // XXX - This is broken for now - see https://github.com/FEX-Emu/FEX/issues/351 - // IREmit->ReplaceAllUsesWith(CodeNode, Op->Header.Args[0].GetNode(ListBegin)); + // IREmit->ReplaceAllUsesWith(CodeNode, CurrentIR.GetNode(Op->Header.Args[0])); // Changed = true; } diff --git a/External/FEXCore/Source/Interface/IR/Passes/IRCompaction.cpp b/External/FEXCore/Source/Interface/IR/Passes/IRCompaction.cpp index 2d602bcdb..2b29d8733 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/IRCompaction.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/IRCompaction.cpp @@ -69,7 +69,7 @@ bool IRCompaction::Run(IREmitter *IREmit) { // Zero is always zero(invalid) OldToNewRemap[0] = 0; auto LocalHeaderOp = LocalBuilder._IRHeader(OrderedNodeWrapper::WrapOffset(0).GetNode(ListBegin), HeaderOp->Entry, HeaderOp->BlockCount, HeaderOp->ShouldInterpret); - OldToNewRemap[HeaderNode->Wrapped(ListBegin).ID()] = LocalHeaderOp.Node->Wrapped(LocalListBegin).ID(); + OldToNewRemap[CurrentIR.GetID(HeaderNode)] = LocalIR.GetID(LocalHeaderOp.Node); { // Generate our codeblocks and link them together @@ -77,7 +77,7 @@ bool IRCompaction::Run(IREmitter *IREmit) { LogMan::Throw::A(BlockHeader->Op == OP_CODEBLOCK, "IR type failed to be a code block"); auto LocalBlockIRNode = LocalBuilder._CodeBlock(LocalHeaderOp, LocalHeaderOp); // Use LocalHeaderOp as a dummy arg for now - OldToNewRemap[BlockNode->Wrapped(ListBegin).ID()] = LocalBlockIRNode.Node->Wrapped(LocalListBegin).ID(); + OldToNewRemap[CurrentIR.GetID(BlockNode)] = LocalIR.GetID(LocalBlockIRNode.Node); GeneratedCodeBlocks.emplace_back(CodeBlockData{BlockNode, LocalBlockIRNode}); } @@ -102,7 +102,6 @@ bool IRCompaction::Run(IREmitter *IREmit) { // Allocate the ops locally for our local dispatch auto LocalPair = LocalBuilder.AllocateRawOp(OpSize); - IR::OrderedNodeWrapper LocalNodeWrapper = LocalPair.Node->Wrapped(LocalListBegin); // Copy usage infomation LocalPair.Node->NumUses = CodeNode->GetUses(); @@ -113,7 +112,7 @@ bool IRCompaction::Run(IREmitter *IREmit) { // Set our map remapper to map the new location // Even nodes that don't have a destination need to be in this map // Need to be able to remap branch targets any other bits - OldToNewRemap[CurrentIR.GetID(CodeNode)] = LocalNodeWrapper.ID(); + OldToNewRemap[CurrentIR.GetID(CodeNode)] = LocalIR.GetID(LocalPair.Node); if (i == 0) { FirstNode.OldNode = CodeNode; @@ -138,14 +137,11 @@ bool IRCompaction::Run(IREmitter *IREmit) { { // Fixup the arguments of all the IROps for (auto &Block : GeneratedCodeBlocks) { - auto BlockIROp = Block.OldNode->Op(DataBegin)->CW(); + auto BlockIROp = CurrentIR.GetOp(Block.OldNode); LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); for (auto [CodeNode, IROp] : CurrentIR.GetCode(Block.OldNode)) { - - OrderedNodeWrapper LocalNodeWrapper = OrderedNodeWrapper::WrapOffset(OldToNewRemap[CurrentIR.GetID(CodeNode)] * sizeof(OrderedNode)); - OrderedNode *LocalNode = LocalNodeWrapper.GetNode(LocalListBegin); - FEXCore::IR::IROp_Header *LocalIROp = LocalNode->Op(LocalDataBegin); + auto [LocalNode, LocalIROp] = LocalIR.at(OldToNewRemap[CurrentIR.GetID(CodeNode)])(); // Now that we have the op copied over, we need to modify SSA values to point to the new correct locations // This doesn't use IR::GetArgs(Op) because we need to remap all SSA nodes diff --git a/External/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp b/External/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp index 0d1097bf0..568e2f03f 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp @@ -28,8 +28,6 @@ bool IRValidation::Run(IREmitter *IREmit) { std::unordered_map OffsetToBlockMap; auto CurrentIR = IREmit->ViewIR(); - uintptr_t ListBegin = CurrentIR.GetListData(); - uintptr_t DataBegin = CurrentIR.GetData(); std::ostringstream Errors; std::ostringstream Warnings; @@ -51,7 +49,9 @@ bool IRValidation::Run(IREmitter *IREmit) { auto BlockIROp = BlockHeader->CW(); LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); - BlockInfo *CurrentBlock = &OffsetToBlockMap.try_emplace(CurrentIR.GetID(BlockNode)).first->second; + uint32_t BlockID = CurrentIR.GetID(BlockNode); + + BlockInfo *CurrentBlock = &OffsetToBlockMap.try_emplace(BlockID).first->second; for (auto [CodeNode, IROp] : CurrentIR.GetCode(BlockNode)) { uint32_t ID = CurrentIR.GetID(CodeNode); @@ -129,14 +129,14 @@ bool IRValidation::Run(IREmitter *IREmit) { case IR::OP_CONDJUMP: { auto Op = IROp->C(); - OrderedNode const *TrueTargetNode = Op->Header.Args[1].GetNode(ListBegin); - OrderedNode const *FalseTargetNode = Op->Header.Args[2].GetNode(ListBegin); + OrderedNode *TrueTargetNode = CurrentIR.GetNode(Op->Header.Args[1]); + OrderedNode *FalseTargetNode = CurrentIR.GetNode(Op->Header.Args[2]); CurrentBlock->Successors.emplace_back(TrueTargetNode); CurrentBlock->Successors.emplace_back(FalseTargetNode); - FEXCore::IR::IROp_Header const *TrueTargetOp = TrueTargetNode->Op(DataBegin); - FEXCore::IR::IROp_Header const *FalseTargetOp = FalseTargetNode->Op(DataBegin); + FEXCore::IR::IROp_Header const *TrueTargetOp = CurrentIR.GetOp(TrueTargetNode); + FEXCore::IR::IROp_Header const *FalseTargetOp = CurrentIR.GetOp(FalseTargetNode); if (TrueTargetOp->Op != OP_CODEBLOCK) { HadError |= true; @@ -160,10 +160,10 @@ bool IRValidation::Run(IREmitter *IREmit) { } case IR::OP_JUMP: { auto Op = IROp->C(); - OrderedNode const *TargetNode = Op->Header.Args[0].GetNode(ListBegin); + OrderedNode *TargetNode = CurrentIR.GetNode(Op->Header.Args[0]); CurrentBlock->Successors.emplace_back(TargetNode); - FEXCore::IR::IROp_Header const *TargetOp = TargetNode->Op(DataBegin); + FEXCore::IR::IROp_Header const *TargetOp = CurrentIR.GetOp(TargetNode); if (TargetOp->Op != OP_CODEBLOCK) { HadError |= true; Errors << "Jump %ssa" << ID << ": Jump to Op that isn't the begining of a block" << std::endl; @@ -184,7 +184,7 @@ bool IRValidation::Run(IREmitter *IREmit) { size_t NumSuccessors = CurrentBlock->Successors.size(); if (NumSuccessors > 2) { HadError |= true; - Errors << "%ssa" << BlockNode->Wrapped(ListBegin).ID() << " Has " << NumSuccessors << " successors which is too many" << std::endl; + Errors << "%ssa" << BlockID << " Has " << NumSuccessors << " successors which is too many" << std::endl; } { @@ -200,7 +200,7 @@ bool IRValidation::Run(IREmitter *IREmit) { auto Op = GetOp(CodeCurrent); if (Op != IR::OP_ENDBLOCK) { HadError |= true; - Errors << "%ssa" << BlockNode->Wrapped(ListBegin).ID() << " Failed to end block with EndBlock" << std::endl; + Errors << "%ssa" << BlockID << " Failed to end block with EndBlock" << std::endl; } } @@ -217,16 +217,18 @@ bool IRValidation::Run(IREmitter *IREmit) { break; default: HadError |= true; - Errors << "%ssa" << BlockNode->Wrapped(ListBegin).ID() << " Didn't have an exit IR op as its last instruction" << std::endl; + Errors << "%ssa" << BlockID << " Didn't have an exit IR op as its last instruction" << std::endl; }; } } } for (int i = 0; i < CurrentIR.GetSSACount(); i++) { - auto Node = OrderedNodeWrapper::WrapOffset(i * sizeof(IR::OrderedNode)).GetNode(ListBegin); - if (Node->NumUses != Uses[i]) + auto [Node, IROp] = CurrentIR.at(i)(); + if (Node->NumUses != Uses[i] && IROp->Op != OP_CODEBLOCK && IROp->Op != OP_IRHEADER) { + HadError = true; Errors << "%ssa" << i << " Has " << Uses[i] << " Uses, but reports " << Node->NumUses << std::endl; + } } std::stringstream Out; diff --git a/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp b/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp index 18c941c88..55c1ef93e 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp @@ -420,13 +420,12 @@ namespace FEXCore::IR { void ConstrainedRAPass::CalculateBlockInterferences(FEXCore::IR::IRListView *IR) { using namespace FEXCore; - uintptr_t ListBegin = IR->GetListData(); for (auto [BlockNode, BlockHeader] : IR->GetBlocks()) { auto BlockIROp = BlockHeader->CW(); LogMan::Throw::A(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block"); - BlockInterferences *BlockInterferenceVector = &LocalBlockInterferences.try_emplace(BlockNode->Wrapped(ListBegin).ID()).first->second; + BlockInterferences *BlockInterferenceVector = &LocalBlockInterferences.try_emplace(IR->GetID(BlockNode)).first->second; BlockInterferenceVector->reserve(BlockIROp->Last.ID() - BlockIROp->Begin.ID()); for (auto [CodeNode, IROp] : IR->GetCode(BlockNode)) { @@ -650,7 +649,6 @@ namespace FEXCore::IR { uint32_t ConstrainedRAPass::FindNodeToSpill(IREmitter *IREmit, RegisterNode *RegisterNode, uint32_t CurrentLocation, LiveRange const *OpLiveRange, int32_t RematCost) { auto IR = IREmit->ViewIR(); - uintptr_t ListBegin = IR.GetListData(); uint32_t InterferenceToSpill = ~0U; uint32_t InterferenceFarthestNextUse = 0; @@ -687,13 +685,9 @@ namespace FEXCore::IR { continue; } - FEXCore::IR::OrderedNodeWrapper InterferenceOp = IR::OrderedNodeWrapper::WrapOffset(InterferenceNode * sizeof(IR::OrderedNode)); - FEXCore::IR::OrderedNode *InterferenceOrderedNode = InterferenceOp.GetNode(ListBegin); - - IR::OrderedNodeWrapper InterferenceNodeOpBegin = IR::OrderedNodeWrapper::WrapOffset(InterferenceLiveRange->Begin * sizeof(IR::OrderedNode)); - IR::OrderedNodeWrapper InterferenceNodeOpEnd = IR::OrderedNodeWrapper::WrapOffset(InterferenceLiveRange->End * sizeof(IR::OrderedNode)); - auto InterferenceNodeOpBeginIter = IR.at(InterferenceNodeOpBegin); - auto InterferenceNodeOpEndIter = IR.at(InterferenceNodeOpEnd); + auto [InterferenceOrderedNode, _] = IR.at(InterferenceNode)(); + auto InterferenceNodeOpBeginIter = IR.at(InterferenceLiveRange->Begin); + auto InterferenceNodeOpEndIter = IR.at(InterferenceLiveRange->End); bool Found{}; @@ -765,11 +759,8 @@ namespace FEXCore::IR { continue; } - FEXCore::IR::OrderedNodeWrapper InterferenceOp = IR::OrderedNodeWrapper::WrapOffset(InterferenceNode * sizeof(IR::OrderedNode)); - FEXCore::IR::OrderedNode *InterferenceOrderedNode = InterferenceOp.GetNode(ListBegin); - - IR::OrderedNodeWrapper InterferenceNodeOpEnd = IR::OrderedNodeWrapper::WrapOffset(InterferenceLiveRange->End * sizeof(IR::OrderedNode)); - auto InterferenceNodeOpEndIter = IR.at(InterferenceNodeOpEnd); + auto [InterferenceOrderedNode, _] = IR.at(InterferenceNode)(); + auto InterferenceNodeOpEndIter = IR.at(InterferenceLiveRange->End); bool Found{}; @@ -894,8 +885,6 @@ namespace FEXCore::IR { auto LastCursor = IREmit->GetWriteCursor(); for (auto [BlockNode, BlockIRHeader] : IR.GetBlocks()) { - auto BlockIROp = BlockIRHeader->CW(); - for (auto [CodeNode, IROp] : IR.GetCode(BlockNode)) { if (IROp->HasDest) { diff --git a/External/FEXCore/Source/Interface/IR/Passes/ValueDominanceValidation.cpp b/External/FEXCore/Source/Interface/IR/Passes/ValueDominanceValidation.cpp index 957c3ee80..dd6e95ee8 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/ValueDominanceValidation.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/ValueDominanceValidation.cpp @@ -23,8 +23,7 @@ bool ValueDominanceValidation::Run(IREmitter *IREmit) { bool HadError = false; bool HadWarning = false; auto CurrentIR = IREmit->ViewIR(); - uintptr_t ListBegin = CurrentIR.GetListData(); - uintptr_t DataBegin = CurrentIR.GetData(); + std::ostringstream Errors; std::ostringstream Warnings; @@ -39,8 +38,8 @@ bool ValueDominanceValidation::Run(IREmitter *IREmit) { case IR::OP_CONDJUMP: { auto Op = IROp->CW(); - OrderedNode *TrueTargetNode = Op->Header.Args[1].GetNode(ListBegin); - OrderedNode *FalseTargetNode = Op->Header.Args[2].GetNode(ListBegin); + OrderedNode *TrueTargetNode = CurrentIR.GetNode(Op->Header.Args[1]); + OrderedNode *FalseTargetNode = CurrentIR.GetNode(Op->Header.Args[2]); CurrentBlock->Successors.emplace_back(TrueTargetNode); CurrentBlock->Successors.emplace_back(FalseTargetNode); @@ -59,7 +58,7 @@ bool ValueDominanceValidation::Run(IREmitter *IREmit) { } case IR::OP_JUMP: { auto Op = IROp->CW(); - OrderedNode *TargetNode = Op->Header.Args[0].GetNode(ListBegin); + OrderedNode *TargetNode = CurrentIR.GetNode(Op->Header.Args[0]); CurrentBlock->Successors.emplace_back(TargetNode); { @@ -134,7 +133,7 @@ bool ValueDominanceValidation::Run(IREmitter *IREmit) { std::set Predecessors; std::function AddPredecessors = [&] (IR::OrderedNode *Node) { - auto PredBlock = &OffsetToBlockMap.try_emplace(Node->Wrapped(ListBegin).ID()).first->second; + auto PredBlock = &OffsetToBlockMap.try_emplace(CurrentIR.GetID(Node)).first->second; // Current Block will always be in set // Walk each predecessor, adding their predecessors @@ -153,14 +152,14 @@ bool ValueDominanceValidation::Run(IREmitter *IREmit) { for (auto it = Predecessors.begin(); it != Predecessors.end(); ++it) { IR::OrderedNode *Pred = *it; - auto PredIROp = Pred->Op(DataBegin)->CW(); + auto PredIROp = CurrentIR.GetOp(Pred); if (Arg.ID() >= PredIROp->Begin.ID() && Arg.ID() < PredIROp->Last.ID()) { FoundPredDefine = true; break; } - Errors << "\tChecking Pred %ssa" << Pred->Wrapped(ListBegin).ID() << std::endl; + Errors << "\tChecking Pred %ssa" << CurrentIR.GetID(Pred) << std::endl; } if (!FoundPredDefine) { From 92a64aad2e36b2f9130cbcccf494c87480296cc3 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Fri, 11 Sep 2020 15:17:57 +1200 Subject: [PATCH 13/16] Update DeadFlagStoreElimiateion pass --- .../IR/Passes/DeadFlagStoreElimination.cpp | 98 +++---------------- 1 file changed, 11 insertions(+), 87 deletions(-) diff --git a/External/FEXCore/Source/Interface/IR/Passes/DeadFlagStoreElimination.cpp b/External/FEXCore/Source/Interface/IR/Passes/DeadFlagStoreElimination.cpp index 55eae62e3..54a233ea5 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/DeadFlagStoreElimination.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/DeadFlagStoreElimination.cpp @@ -18,10 +18,10 @@ struct FlagInfo { * @brief This is a temporary pass to detect simple multiblock dead flag stores * * First pass computes which flags are read and written per block - * + * * Second pass computes which flags are stored, but overwritten by the next block(s). * It also propagates this information a few times to catch dead flags across multiple blocks. - * + * * Third pass removes the dead stores. * */ @@ -30,33 +30,13 @@ bool DeadFlagStoreElimination::Run(IREmitter *IREmit) { bool Changed = false; auto CurrentIR = IREmit->ViewIR(); - uintptr_t ListBegin = CurrentIR.GetListData(); - uintptr_t DataBegin = CurrentIR.GetData(); - - auto Begin = CurrentIR.begin(); - auto Op = Begin(); - - OrderedNode *RealNode = Op->GetNode(ListBegin); - auto HeaderOp = RealNode->Op(DataBegin)->CW(); - LogMan::Throw::A(HeaderOp->Header.Op == OP_IRHEADER, "First op wasn't IRHeader"); // Pass 1 // Compute flags read/writes per block // This is conservative and doesn't try to be smart about loads after writes { - OrderedNode *BlockNode = HeaderOp->Blocks.GetNode(ListBegin); - - while (1) { - auto BlockIROp = BlockNode->Op(DataBegin)->CW(); - LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); - - // We grab these nodes this way so we can iterate easily - auto CodeBegin = CurrentIR.at(BlockIROp->Begin); - auto CodeLast = CurrentIR.at(BlockIROp->Last); - while (1) { - auto CodeOp = CodeBegin(); - OrderedNode *CodeNode = CodeOp->GetNode(ListBegin); - auto IROp = CodeNode->Op(DataBegin); + for (auto [BlockNode, BlockIROp] : CurrentIR.GetBlocks()) { + for (auto [CodeNode, IROp] : CurrentIR.GetCode(BlockNode)) { if (IROp->Op == OP_STOREFLAG) { auto Op = IROp->CW(); @@ -67,17 +47,6 @@ bool DeadFlagStoreElimination::Run(IREmitter *IREmit) { FlagMap[BlockNode].reads |= 1 << Op->Flag; } - // CodeLast is inclusive. So we still need to dump the CodeLast op as well - if (CodeBegin == CodeLast) { - break; - } - ++CodeBegin; - } - - if (BlockIROp->Next.ID() == 0) { - break; - } else { - BlockNode = BlockIROp->Next.GetNode(ListBegin); } } } @@ -87,23 +56,12 @@ bool DeadFlagStoreElimination::Run(IREmitter *IREmit) { // Propagate the information a few times to eliminate more for (int i = 0; i < 5; i++) { - OrderedNode *BlockNode = HeaderOp->Blocks.GetNode(ListBegin); - - while (1) { - auto BlockIROp = BlockNode->Op(DataBegin)->CW(); - LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); - - // We grab these nodes this way so we can iterate easily - auto CodeBegin = CurrentIR.at(BlockIROp->Begin); - auto CodeLast = CurrentIR.at(BlockIROp->Last); - while (1) { - auto CodeOp = CodeBegin(); - OrderedNode *CodeNode = CodeOp->GetNode(ListBegin); - auto IROp = CodeNode->Op(DataBegin); + for (auto [BlockNode, BlockIROp] : CurrentIR.GetBlocks()) { + for (auto [CodeNode, IROp] : CurrentIR.GetCode(BlockNode)) { if (IROp->Op == OP_JUMP) { auto Op = IROp->CW(); - OrderedNode *TargetNode = Op->Header.Args[0].GetNode(ListBegin); + OrderedNode *TargetNode = CurrentIR.GetNode(Op->Header.Args[0]); // stores to remove are written by the next block but not read FlagMap[BlockNode].kill = FlagMap[TargetNode].writes & ~(FlagMap[TargetNode].reads); @@ -114,8 +72,8 @@ bool DeadFlagStoreElimination::Run(IREmitter *IREmit) { else if (IROp->Op == OP_CONDJUMP) { auto Op = IROp->CW(); - OrderedNode *TrueTargetNode = Op->Header.Args[1].GetNode(ListBegin); - OrderedNode *FalseTargetNode = Op->Header.Args[2].GetNode(ListBegin); + OrderedNode *TrueTargetNode = CurrentIR.GetNode(Op->Header.Args[1]); + OrderedNode *FalseTargetNode = CurrentIR.GetNode(Op->Header.Args[2]); // stores to remove are written by the next blocks but not read FlagMap[BlockNode].kill = FlagMap[TrueTargetNode].writes & ~(FlagMap[TrueTargetNode].reads); @@ -124,18 +82,6 @@ bool DeadFlagStoreElimination::Run(IREmitter *IREmit) { // Flags that are written by the next blocks can be considered as written by this block, if not read FlagMap[BlockNode].writes |= FlagMap[BlockNode].kill & ~FlagMap[BlockNode].reads; } - - // CodeLast is inclusive. So we still need to dump the CodeLast op as well - if (CodeBegin == CodeLast) { - break; - } - ++CodeBegin; - } - - if (BlockIROp->Next.ID() == 0) { - break; - } else { - BlockNode = BlockIROp->Next.GetNode(ListBegin); } } } @@ -143,19 +89,8 @@ bool DeadFlagStoreElimination::Run(IREmitter *IREmit) { // Pass 3 // Remove the dead stores { - OrderedNode *BlockNode = HeaderOp->Blocks.GetNode(ListBegin); - - while (1) { - auto BlockIROp = BlockNode->Op(DataBegin)->CW(); - LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); - - // We grab these nodes this way so we can iterate easily - auto CodeBegin = CurrentIR.at(BlockIROp->Begin); - auto CodeLast = CurrentIR.at(BlockIROp->Last); - while (1) { - auto CodeOp = CodeBegin(); - OrderedNode *CodeNode = CodeOp->GetNode(ListBegin); - auto IROp = CodeNode->Op(DataBegin); + for (auto [BlockNode, BlockIROp] : CurrentIR.GetBlocks()) { + for (auto [CodeNode, IROp] : CurrentIR.GetCode(BlockNode)) { if (IROp->Op == OP_STOREFLAG) { auto Op = IROp->CW(); @@ -166,17 +101,6 @@ bool DeadFlagStoreElimination::Run(IREmitter *IREmit) { } } - // CodeLast is inclusive. So we still need to dump the CodeLast op as well - if (CodeBegin == CodeLast) { - break; - } - ++CodeBegin; - } - - if (BlockIROp->Next.ID() == 0) { - break; - } else { - BlockNode = BlockIROp->Next.GetNode(ListBegin); } } } From 3102fb78e78135b99390bf47a98941465d95a9ee Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Fri, 11 Sep 2020 15:18:05 +1200 Subject: [PATCH 14/16] Minor IR validation fixes --- .../Interface/IR/Passes/IRValidation.cpp | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/External/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp b/External/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp index 568e2f03f..b6066d5af 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp @@ -101,8 +101,21 @@ bool IRValidation::Run(IREmitter *IREmit) { uint8_t NumArgs = IR::GetArgs(IROp->Op); - if (NumArgs != IROp->NumArgs) - Errors << "%ssa" << ID << ": Has wrong number of Args" << std::endl; + if (NumArgs != IROp->NumArgs) { + switch (IROp->Op) { + case OP_BEGINBLOCK: + case OP_ENDBLOCK: + case OP_PHI: + case OP_PHIVALUE: + case OP_CONDJUMP: + case OP_JUMP: + // These override the nubmer of args for RA, so ignore them. + break; + default: + HadError |= true; + Errors << "%ssa" << ID << ": Has wrong number of Args" << std::endl; + } + } for (uint32_t i = 0; i < NumArgs; ++i) { OrderedNodeWrapper Arg = IROp->Args[i]; // Was an argument defined after this node? @@ -111,12 +124,14 @@ bool IRValidation::Run(IREmitter *IREmit) { Errors << "%ssa" << ID << ": Arg[" << i << "] has definition after use at %ssa" << Arg.ID() << std::endl; } - if (!NodeIsLive.Get(Arg.ID())) { + if (Arg.ID() != 0 && !NodeIsLive.Get(Arg.ID())) { HadError |= true; Errors << "%ssa" << ID << ": Arg[" << i << "] refrences dead %ssa" << Arg.ID() << std::endl; } - Uses[Arg.ID()]++; + if (Arg.ID() != 0) { + Uses[Arg.ID()]++; + } } NodeIsLive.Set(ID); @@ -226,7 +241,7 @@ bool IRValidation::Run(IREmitter *IREmit) { for (int i = 0; i < CurrentIR.GetSSACount(); i++) { auto [Node, IROp] = CurrentIR.at(i)(); if (Node->NumUses != Uses[i] && IROp->Op != OP_CODEBLOCK && IROp->Op != OP_IRHEADER) { - HadError = true; + HadError |= true; Errors << "%ssa" << i << " Has " << Uses[i] << " Uses, but reports " << Node->NumUses << std::endl; } } From 7c5180645617ac5d2c7151472b620a4249fae524 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Fri, 11 Sep 2020 15:27:46 +1200 Subject: [PATCH 15/16] Fix arm64 JIT --- .../Source/Interface/Core/JIT/Arm64/JIT.cpp | 41 ++++--------------- .../Interface/Core/JIT/Arm64/MiscOps.cpp | 10 +---- 2 files changed, 8 insertions(+), 43 deletions(-) diff --git a/External/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp b/External/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp index 10e8e77ab..04c628987 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp @@ -578,15 +578,8 @@ void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const JumpTargets.clear(); CurrentIR = IR; uint32_t SSACount = CurrentIR->GetSSACount(); - uintptr_t ListBegin = CurrentIR->GetListData(); - uintptr_t DataBegin = CurrentIR->GetData(); - - auto HeaderIterator = CurrentIR->begin(); - IR::OrderedNodeWrapper *HeaderNodeWrapper = HeaderIterator(); - IR::OrderedNode *HeaderNode = HeaderNodeWrapper->GetNode(ListBegin); - auto HeaderOp = HeaderNode->Op(DataBegin)->CW(); - LogMan::Throw::A(HeaderOp->Header.Op == IR::OP_IRHEADER, "First op wasn't IRHeader"); + auto HeaderOp = CurrentIR->GetHeader(); if (HeaderOp->ShouldInterpret) { return reinterpret_cast(InterpreterFallbackHelperAddress); } @@ -634,19 +627,13 @@ void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const stp(TMP1, lr, MemOperand(sp, -16, PreIndex)); } - IR::OrderedNode *BlockNode = HeaderOp->Blocks.GetNode(ListBegin); - - while (1) { + for (auto [BlockNode, BlockHeader] : CurrentIR->GetBlocks()) { using namespace FEXCore::IR; - auto BlockIROp = BlockNode->Op(DataBegin)->CW(); + auto BlockIROp = BlockHeader->CW(); LogMan::Throw::A(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block"); - // We grab these nodes this way so we can iterate easily - auto CodeBegin = CurrentIR->at(BlockIROp->Begin); - auto CodeLast = CurrentIR->at(BlockIROp->Last); - { - uint32_t Node = BlockNode->Wrapped(ListBegin).ID(); + uint32_t Node = CurrentIR->GetID(BlockNode); auto IsTarget = JumpTargets.find(Node); if (IsTarget == JumpTargets.end()) { IsTarget = JumpTargets.try_emplace(Node).first; @@ -655,26 +642,12 @@ void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const bind(&IsTarget->second); } - while (1) { - OrderedNodeWrapper *WrapperOp = CodeBegin(); - FEXCore::IR::IROp_Header *IROp = WrapperOp->GetNode(ListBegin)->Op(DataBegin); - uint32_t Node = WrapperOp->ID(); + for (auto [CodeNode, IROp] : CurrentIR->GetCode(BlockNode)) { + uint32_t ID = CurrentIR->GetID(CodeNode); // Execute handler OpHandler Handler = OpHandlers[IROp->Op]; - (this->*Handler)(IROp, Node); - - // CodeLast is inclusive. So we still need to dump the CodeLast op as well - if (CodeBegin == CodeLast) { - break; - } - ++CodeBegin; - } - - if (BlockIROp->Next.ID() == 0) { - break; - } else { - BlockNode = BlockIROp->Next.GetNode(ListBegin); + (this->*Handler)(IROp, ID); } } diff --git a/External/FEXCore/Source/Interface/Core/JIT/Arm64/MiscOps.cpp b/External/FEXCore/Source/Interface/Core/JIT/Arm64/MiscOps.cpp index 486d5489a..ae0022195 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/Arm64/MiscOps.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/Arm64/MiscOps.cpp @@ -6,14 +6,6 @@ using namespace vixl; using namespace vixl::aarch64; #define DEF_OP(x) void JITCore::Op_##x(FEXCore::IR::IROp_Header *IROp, uint32_t Node) -DEF_OP(EndBlock) { - auto Op = IROp->C(); - if (Op->RIPIncrement) { - ldr(TMP1, MemOperand(STATE, offsetof(FEXCore::Core::CPUState, rip))); - str(TMP1, MemOperand(STATE, offsetof(FEXCore::Core::CPUState, rip))); - } -} - DEF_OP(Fence) { auto Op = IROp->C(); switch (Op->Fence) { @@ -67,7 +59,7 @@ void JITCore::RegisterMiscHandlers() { REGISTER_OP(IRHEADER, NoOp); REGISTER_OP(CODEBLOCK, NoOp); REGISTER_OP(BEGINBLOCK, NoOp); - REGISTER_OP(ENDBLOCK, EndBlock); + REGISTER_OP(ENDBLOCK, NoOp); REGISTER_OP(FENCE, Fence); REGISTER_OP(BREAK, Break); REGISTER_OP(PHI, NoOp); From b5fd0c9f6a8393c22e806b4b1a8b9a158f7666a0 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Fri, 11 Sep 2020 15:54:11 +1200 Subject: [PATCH 16/16] Update IR docs --- External/FEXCore/docs/IR.md | 72 ++++++++++++++++++++++++++++--------- 1 file changed, 55 insertions(+), 17 deletions(-) diff --git a/External/FEXCore/docs/IR.md b/External/FEXCore/docs/IR.md index 8d337664d..16c2b1bae 100644 --- a/External/FEXCore/docs/IR.md +++ b/External/FEXCore/docs/IR.md @@ -55,15 +55,15 @@ Additionally it also points to the first `CodeBlock` IROp ``` (%%ssa3) CodeBlock %%ssa169, %%ssa173, %%ssa4 - (%%ssa169) Dummy + (%%ssa169) BeginBlock %ssa3 %ssa170 i64 = Constant 0x41a9e1 (%%ssa171) StoreContext %ssa170 i64, 0x8, 0x0 (%%ssa172) ExitFunction - (%%ssa173) EndBlock 0x0 + (%%ssa173) EndBlock %ssa3 ``` -* Dummy op is just a sentinal op and may be removed in the future -* EndBlock the ending op of a CodeBlock and may be used to increment the RIP independently of just setting it +* BeginBlock points back to the CodeBlock SSA which helps with iterating across multiple blocks +* EndBlock the ending op of a CodeBlock and also points back to the CodeBlock SSA. * ExitFunction will leave the function immediately and return back to the dispatcher * Every IR Op has an SSA value associated with it used for tracking the op itself * If the IROp doesn't have a real destination then it is invalid to use it as an argument in most other ops @@ -121,23 +121,19 @@ This is a doubly linked list of all of our IR nodes. This allows us to walk forw * Then once you have the `OrderedNode*` from GetNode, Use the `Op(IRDataBegin)` function to get the IR data. * I do **NOT** recommend using `GetNode` directly from `OpNodeWrapper` as it is VERY easy to mess it up -### NodeWrapperIterator -Provides a fairly straightforward wrapper object that allows easily walking the IR nodes with C++ increment and decrement operations +### NodeIterator +Provides a fairly straightforward interface that allows easily walking the IR nodes with C++ increment and decrement operations. +Only iterates over a single block -### Example usage +#### Example usage ```cpp - IR::NodeWrapperIterator After = ...; - IR::NodeWrapperIterator End = ...; + IR::NodeIterator After = ...; + IR::NodeIterator End = ...; while (After != End) { - // NodeWrapperIterator() returns a pointer or a reference to an OrderedNodeWrapper object - OrderedNodeWrapper *WrapperOp = After(); - // OrderedNodeWrapper::GetNode(ListBegin) will return a pointer to our OrderedNode* object - OrderedNode *RealNode = WrapperOp->GetNode(ListBegin); - - // Now to get the IROp_Header - // We need to use OrderedNode::Op(DataBegin) to get the real data backing the object - FEXCore::IR::IROp_Header *IROp = RealNode->Op(DataBegin); + // NodeIterator() returns a pair of pointers to the OrderedNode and IROp data + // You can unpack the result with structured bindings + auto [CodeNode, IROp] = After(); // IROp_Header contains a bunch of information about the IR object // We can convert it with the object's C or CW functions @@ -157,6 +153,48 @@ Provides a fairly straightforward wrapper object that allows easily walking the ``` +### AllNodesIterator +This is like NodeIterator, except that it will cross block boundaries. + +### IRListView.GetBlocks() +Provides a range for easy iterating over all the blocks in a multi-block with NodeIterator + +#### Example usage +```c++ + for (auto [BlockNode, BlockHeader] : CurrentIR.GetBlocks()) { + // Do stuff for each block + } +``` + +### IRListView.GetCode(BlockNode) +Provides a range for easy iterating over all the code in a block + +#### Example usage +```c++ + for (auto [CodeNode, IROp] : CurrentIR.GetCode(BlockNode)) { + // Do stuff for each op + + switch(IROp->Op) { + case IR::OP_ADD: { + FEXCore::IR::IROp_Add const *Op = IROp->C(); + // Do stuff for each Add op. + + break; + } + } + } +``` + +### IRListView.GetAllCode() +Like GetCode, except it uses AllNodesIterator to allow easy iterating over every single op in the entire Multiblock + +#### Example usage +```c++ + for (auto [CodeNode, IROp] : CurrentIR.GetAllCode()) { + // Do stuff for each op + } +``` + ## JSON file An example of what the IR json looks like ```