From b148afef4b3b26a01e59bf2fc7a90510264c01db Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Mon, 21 Oct 2019 14:53:47 +1300 Subject: [PATCH] Add Dead Code Elimitation pass Refactor the previous WIP to use NumUses --- Source/Interface/IR/PassManager.cpp | 1 + Source/Interface/IR/Passes.h | 1 + .../IR/Passes/DeadCodeElimination.cpp | 141 +++++------------- 3 files changed, 38 insertions(+), 105 deletions(-) diff --git a/Source/Interface/IR/PassManager.cpp b/Source/Interface/IR/PassManager.cpp index 268d2ce37..7167f8966 100644 --- a/Source/Interface/IR/PassManager.cpp +++ b/Source/Interface/IR/PassManager.cpp @@ -10,6 +10,7 @@ void PassManager::AddDefaultPasses() { Passes.emplace_back(std::unique_ptr(CreateRedundantFlagCalculationEliminination())); Passes.emplace_back(std::unique_ptr(CreateSyscallOptimization())); Passes.emplace_back(std::unique_ptr(CreatePassDeadContextStoreElimination())); + Passes.emplace_back(std::unique_ptr(CreatePassDeadCodeElimination())); // If the IR is compacted post-RA then the node indexing gets messed up and the backend isn't able to find the register assigned to a node // Compact before IR, don't worry about RA generating spills/fills diff --git a/Source/Interface/IR/Passes.h b/Source/Interface/IR/Passes.h index 01c96aff0..851528b4f 100644 --- a/Source/Interface/IR/Passes.h +++ b/Source/Interface/IR/Passes.h @@ -8,6 +8,7 @@ FEXCore::IR::Pass* CreateRedundantContextLoadElimination(); FEXCore::IR::Pass* CreatePassDeadContextStoreElimination(); FEXCore::IR::Pass* CreateSyscallOptimization(); FEXCore::IR::Pass* CreateRedundantFlagCalculationEliminination(); +FEXCore::IR::Pass* CreatePassDeadCodeElimination(); FEXCore::IR::Pass* CreateIRCompaction(); namespace Validation { diff --git a/Source/Interface/IR/Passes/DeadCodeElimination.cpp b/Source/Interface/IR/Passes/DeadCodeElimination.cpp index 0d4d01fa5..b1f96390c 100644 --- a/Source/Interface/IR/Passes/DeadCodeElimination.cpp +++ b/Source/Interface/IR/Passes/DeadCodeElimination.cpp @@ -9,42 +9,15 @@ class DeadCodeElimination final : public FEXCore::IR::Pass { bool Run(OpDispatchBuilder *Disp) override; private: - std::vector SSAStatus; void markUsed(OrderedNodeWrapper *CodeOp, IROp_Header *IROp); }; -enum { - UNKNOWN, - UNUSED, - USED, -}; - - bool DeadCodeElimination::Run(OpDispatchBuilder *Disp) { - bool Changed = false; auto CurrentIR = Disp->ViewIR(); - uint32_t SSACount = CurrentIR.GetSSACount(); - - SSAStatus = std::vector(SSACount, UNKNOWN); - uintptr_t ListBegin = CurrentIR.GetListData(); uintptr_t DataBegin = CurrentIR.GetData(); - std::function MarkUsed = [&] (OrderedNodeWrapper CodeOp) { - if (SSAStatus[CodeOp.ID()] == USED) - return; - SSAStatus[CodeOp.ID()] = USED; - - OrderedNode *CodeNode = CodeOp.GetNode(ListBegin); - auto IROp = CodeNode->Op(DataBegin); - - uint8_t NumArgs = IR::GetArgs(IROp->Op); - for (uint8_t i = 0; i < NumArgs; ++i) { - MarkUsed(IROp->Args[i]); - } - }; - auto Begin = CurrentIR.begin(); auto Op = Begin(); @@ -54,7 +27,7 @@ bool DeadCodeElimination::Run(OpDispatchBuilder *Disp) { OrderedNode *BlockNode = HeaderOp->Blocks.GetNode(ListBegin); - // First, iterate over IR nodes in all blocks, marking them as used or unused + int NumRemoved = 0; while (1) { auto BlockIROp = BlockNode->Op(DataBegin)->CW(); @@ -64,58 +37,47 @@ bool DeadCodeElimination::Run(OpDispatchBuilder *Disp) { auto CodeBegin = CurrentIR.at(BlockIROp->Begin); auto CodeLast = CurrentIR.at(BlockIROp->Last); - bool controlFlowEnded = false; while (1) { - auto CodeOp = CodeBegin(); + auto CodeOp = CodeLast(); OrderedNode *CodeNode = CodeOp->GetNode(ListBegin); auto IROp = CodeNode->Op(DataBegin); - auto ssa = CodeOp->ID(); - if (SSAStatus[ssa] == UNKNOWN) { - SSAStatus[ssa] = UNUSED; - } - - if (!controlFlowEnded) { - switch (IROp->Op) { - // State storage - case OP_STORECONTEXT: - case OP_STOREFLAG: - case OP_STOREMEM: - case OP_CAS: - MarkUsed(*CodeOp); - break; - // IO - case OP_SYSCALL: - MarkUsed(*CodeOp); - break; - // Control flow - case OP_BREAK: - case OP_JUMP: - case OP_EXITFUNCTION: - SSAStatus[ssa] = USED; - controlFlowEnded = true; // Kill any IR instructions after this - break; - case OP_CONDJUMP: - SSAStatus[ssa] = USED; - MarkUsed(IROp->Args[0]); // Mark the condition as used - break; - case OP_ENDBLOCK: - // Only keep this when incrementing - auto Op = IROp->C(); - if (Op->RIPIncrement) { - SSAStatus[ssa] = USED; - } - break; - default: - // leave everything else marked as unused - break; + switch (IROp->Op) { + // State/memory storage + case OP_STORECONTEXT: + case OP_STOREFLAG: + case OP_STOREMEM: + case OP_CAS: + // Keep + break; + // IO + case OP_SYSCALL: + // Keep + break; + // Control flow + case OP_BREAK: + case OP_JUMP: + case OP_ENDFUNCTION: + case OP_EXITFUNCTION: + case OP_CONDJUMP: + // Keep + break; + case OP_DUMMY: + case OP_ENDBLOCK: + // Keep, so we don't have to update block first/last + break; + default: + if (CodeNode->GetUses() == 0) { + NumRemoved++; + Disp->Remove(CodeNode); } - } - - if (CodeBegin == CodeLast) { break; } - ++CodeBegin; + + if (CodeLast == CodeBegin) { + break; + } + --CodeLast; } if (BlockIROp->Next.ID() == 0) { @@ -125,38 +87,7 @@ bool DeadCodeElimination::Run(OpDispatchBuilder *Disp) { } } - // Loop over blocks - 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 (SSAStatus[CodeBegin()->ID()] != USED) { - if (CodeBegin == CodeLast) { - - } - ++CodeBegin; - - - } - - auto &prev = BlockIROp->Begin; - - while (1) { - auto CodeOp = CodeBegin(); - - if (SSAStatus[CodeOp->ID()] == USED) { - prev = CodeOp->WrapOffset(); - - } - } - - } - - return Changed; + return NumRemoved != 0; } void DeadCodeElimination::markUsed(OrderedNodeWrapper *CodeOp, IROp_Header *IROp) {