From d5f2bc77507da089fe4e57e14fcb3754d45694b4 Mon Sep 17 00:00:00 2001 From: Pietro Fezzardi Date: Fri, 18 Jan 2019 17:39:28 +0100 Subject: [PATCH] First Prototype of EnforceCFGCombingPass --- lib/CMakeLists.txt | 1 - .../BasicBlockViewAnalysis.cpp | 31 ++-- .../BasicBlockViewAnalysis.h | 50 ++++-- lib/EnforceCFGCombingPass/CMakeLists.txt | 4 +- .../EnforceCFGCombingPass.cpp | 146 +++++++++++++++++- .../EnforceCFGCombingPass.h | 2 - lib/Liveness/CMakeLists.txt | 30 ---- lib/Liveness/LivenessAnalysis.cpp | 62 -------- lib/Liveness/LivenessAnalysisPass.cpp | 20 --- 9 files changed, 193 insertions(+), 153 deletions(-) delete mode 100644 lib/Liveness/CMakeLists.txt delete mode 100644 lib/Liveness/LivenessAnalysis.cpp delete mode 100644 lib/Liveness/LivenessAnalysisPass.cpp diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 9f516f9bf..7c9532ee8 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -1,6 +1,5 @@ add_subdirectory(EnforceCFGCombingPass) add_subdirectory(ExamplePass) -add_subdirectory(Liveness) add_subdirectory(RestructureCFGPass) add_subdirectory(RemovePCStoresPass) add_subdirectory(revng-c) diff --git a/lib/EnforceCFGCombingPass/BasicBlockViewAnalysis.cpp b/lib/EnforceCFGCombingPass/BasicBlockViewAnalysis.cpp index e2f5fdbeb..fd0522977 100644 --- a/lib/EnforceCFGCombingPass/BasicBlockViewAnalysis.cpp +++ b/lib/EnforceCFGCombingPass/BasicBlockViewAnalysis.cpp @@ -8,19 +8,26 @@ using namespace llvm; namespace BasicBlockViewAnalysis { -Analysis::InterruptType Analysis::transfer(BasicBlockNode *InputBB) { - BasicBlockViewMap VisibleBB = State[InputBB].copy(); - BasicBlockNode *BB = InputBB; - while (BB->isDummy()) { - revng_assert(BB->basicBlock() == nullptr); - revng_assert(BB->successor_size() == 1); - BB = *BB->successors().begin(); +Analysis::InterruptType Analysis::transfer(BasicBlockNode *InputBBNode) { + BasicBlockViewMap VisibleBB = State[InputBBNode].copy(); + BasicBlock *EnforcedBB = EnforcedBBMap.at(InputBBNode); + + if (InputBBNode->isDummy()) { + while (InputBBNode->isDummy()) { + revng_assert(InputBBNode->basicBlock() == nullptr); + revng_assert(InputBBNode->successor_size() == 1); + InputBBNode = *InputBBNode->successors().begin(); + } + BasicBlock *OriginalBB = InputBBNode->basicBlock(); + revng_assert(OriginalBB != nullptr); + VisibleBB.at(OriginalBB) = EnforcedBB; + } else { + BasicBlock *OriginalBB = InputBBNode->basicBlock(); + revng_assert(OriginalBB != nullptr); + bool New = VisibleBB.insert(std::make_pair(OriginalBB, EnforcedBB)).second; + revng_assert(New); + ViewMap[EnforcedBB] = VisibleBB.copyMap(); } - BasicBlock *OriginalBB = BB->basicBlock(); - revng_assert(OriginalBB); - bool New = VisibleBB.insert(std::make_pair(OriginalBB, InputBB)).second; - revng_assert(New); - BBViewMap[InputBB] = VisibleBB.copy(); return InterruptType::createInterrupt(std::move(VisibleBB)); } diff --git a/lib/EnforceCFGCombingPass/BasicBlockViewAnalysis.h b/lib/EnforceCFGCombingPass/BasicBlockViewAnalysis.h index e8a06b2e7..0d866780d 100644 --- a/lib/EnforceCFGCombingPass/BasicBlockViewAnalysis.h +++ b/lib/EnforceCFGCombingPass/BasicBlockViewAnalysis.h @@ -19,17 +19,23 @@ class BasicBlockNode; namespace BasicBlockViewAnalysis { -class BasicBlockViewMap { +using BBMap = std::map; +using BBViewMap = std::map; -protected: - using BBMap = std::map; - BBMap Map; - bool IsBottom; +using BBNodeToBBMap = std::map; + +class BasicBlockViewMap { public: using iterator = BBMap::iterator; using const_iterator = BBMap::const_iterator; using value_type = BBMap::value_type; + using key_type = BBMap::key_type; + using mapped_type = BBMap::mapped_type; + +protected: + BBMap Map; + bool IsBottom; protected: BasicBlockViewMap(const BasicBlockViewMap &) = default; @@ -43,6 +49,8 @@ public: BasicBlockViewMap(BasicBlockViewMap &&) = default; BasicBlockViewMap &operator=(BasicBlockViewMap &&) = default; + BBMap copyMap() const { return Map; } + static BasicBlockViewMap bottom() { return BasicBlockViewMap(); } public: @@ -83,11 +91,20 @@ public: // map methods IsBottom = false; return Map.insert(V); } - - + mapped_type &operator[](const key_type& Key) { + return Map[Key]; + } + mapped_type &operator[](key_type&& Key) { + return Map[Key]; + } + mapped_type &at(const key_type& Key) { + return Map.at(Key); + } + const mapped_type &at(const key_type& Key) const { + return Map.at(Key); + } }; -using BBNodeBBViewMap = std::map; class Analysis : public MonotoneFramework> { private: CFG &RegionCFGTree; - const llvm::Function &OriginalFunction; - BBNodeBBViewMap BBViewMap; + const BBNodeToBBMap &EnforcedBBMap; + BBViewMap ViewMap; public: using Base = MonotoneFramework>; - Analysis(CFG &RegionCFGTree, - const llvm::Function &OriginalFunction) : + Analysis(CFG &RegionCFGTree, const BBNodeToBBMap &EnforcedBBMap) : Base(&RegionCFGTree.getEntryNode()), RegionCFGTree(RegionCFGTree), - OriginalFunction(OriginalFunction) { + EnforcedBBMap(EnforcedBBMap) { for (BasicBlockNode *BB : RegionCFGTree) { if (BB->successor_size() == 0) Base::registerExtremal(BB); @@ -120,7 +136,7 @@ public: void initialize() { Base::initialize(); - BBViewMap.clear(); + ViewMap.clear(); } void assertLowerThanOrEqual(const BasicBlockViewMap &A, @@ -128,9 +144,9 @@ public: revng_assert(A.lowerThanOrEqual(B)); } - const BBNodeBBViewMap &getBBNodeBBViewMap() const { - return BBViewMap; - } + const BBViewMap &getBBViewMap() const { return ViewMap; } + + BBViewMap &getBBViewMap() { return ViewMap; } /// This Analysis uses DefaultInterrupt, hence it is never supposed to dump /// the final state. diff --git a/lib/EnforceCFGCombingPass/CMakeLists.txt b/lib/EnforceCFGCombingPass/CMakeLists.txt index 1f822eb54..5d8d51e84 100644 --- a/lib/EnforceCFGCombingPass/CMakeLists.txt +++ b/lib/EnforceCFGCombingPass/CMakeLists.txt @@ -2,11 +2,11 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") add_library(EnforceCFGCombingPass SHARED EnforceCFGCombingPass.cpp - BasicBlockViewAnalysis.cpp + BasicBlockViewAnalysis.cpp ) target_link_libraries(EnforceCFGCombingPass - LivenessAnalysisPass + RestructureCFGPass ${REVNG_SUPPORT_LIBRARY} ${LLVM_LIBRARIES} ) diff --git a/lib/EnforceCFGCombingPass/EnforceCFGCombingPass.cpp b/lib/EnforceCFGCombingPass/EnforceCFGCombingPass.cpp index f1afd788a..f82ab1000 100644 --- a/lib/EnforceCFGCombingPass/EnforceCFGCombingPass.cpp +++ b/lib/EnforceCFGCombingPass/EnforceCFGCombingPass.cpp @@ -4,6 +4,8 @@ // LLVM includes #include +#include +#include // local librariesincludes #include "revng-c/RestructureCFGPass/RegionCFGTree.h" @@ -15,17 +17,20 @@ using namespace llvm; -bool EnforceCFGCombingPass::runOnFunction(Function &F) { - auto &LA = getAnalysis(); - const LivenessAnalysis::LivenessMap &LiveIn = LA.getLiveIn(); +using BBMap = BasicBlockViewAnalysis::BBMap; +using BBNodeToBBMap = BasicBlockViewAnalysis::BBNodeToBBMap; +using BBToBBNodeMap = std::map; +using BBViewMap = BasicBlockViewAnalysis::BBViewMap; + +bool EnforceCFGCombingPass::runOnFunction(Function &F) { auto &RestructurePass = getAnalysis(); CFG &RCFGT = RestructurePass.getRCT(); + // Perform preprocessing on RCFGT to ensure that each node with more + // than one successor only has dummy successors. If that's not true, + // inject dummy successors when necessary. { - // Perform preprocessing on RCFGT to ensure that each node with more - // than one successor only has dummy successors. If that's not true, - // inject dummy successors when necessary. std::vector NeedDummy; for (BasicBlockNode *Node : RCFGT.nodes()) if (not Node->isDummy() and Node->successor_size() > 1) @@ -40,9 +45,136 @@ bool EnforceCFGCombingPass::runOnFunction(Function &F) { } } - BasicBlockViewAnalysis::Analysis BBViewAnalysis(RCFGT, F); + // Clone Function, with all BasicBlocks and their Instructions. + // The clone will be all messed up at this point, becasue all the operands of + // the cloned instruction will refer to the original function, not to the + // cloned version. We will fix this later. + + Function *EnforcedF = Function::Create(F.getFunctionType(), F.getLinkage(), + F.getName(), F.getParent()); + + // Create a Map of the arguments, used later to fix operands of the cloned + // Instructions + ValueToValueMapTy ArgMap; + Function::arg_iterator DestArg = EnforcedF->arg_begin(); + for (const Argument &A : F.args()) { + DestArg->setName(A.getName()); + ArgMap[&A] = &*DestArg; + } + + BBNodeToBBMap EnforcedBBNodeToBBMap; + BBToBBNodeMap EnforcedBBToNodeBBMap; + + std::map> EnforcedBBMap; + + using InstrMap = std::map; + std::map> EnforcedInstrMap; + + for (BasicBlockNode *Node : RCFGT.nodes()) { + BasicBlock *BB = nullptr; + if (BasicBlock *OriginalBB = Node->basicBlock()) { + ValueToValueMapTy VMap{}; + BB = CloneBasicBlock(OriginalBB, VMap, "", EnforcedF); + EnforcedBBMap[OriginalBB].push_back(BB); + InstrMap IMap; + for (const auto &I : VMap) { + auto *OriginalInstr = cast(I.first); + auto *EnforcedInstr = cast(I.second); + IMap[OriginalInstr] = EnforcedInstr; + } + EnforcedInstrMap[OriginalBB].push_back(std::move(IMap)); + } else { + BB = BasicBlock::Create(F.getContext(), "", EnforcedF); + } + revng_assert(BB != nullptr); + EnforcedBBNodeToBBMap[Node] = BB; + EnforcedBBToNodeBBMap[BB] = Node; + } + + // BasicBlockViewAnalysis + BasicBlockViewAnalysis::Analysis BBViewAnalysis(RCFGT, EnforcedBBNodeToBBMap); BBViewAnalysis.initialize(); BBViewAnalysis.run(); + BBViewMap &BasicBlockViewMap = BBViewAnalysis.getBBViewMap(); + // Adjust BasicBlockViewMap with information on incoming blocks for PHINodes + for (auto &BBViewMapPair : BasicBlockViewMap) { + BasicBlock *EnforcedBB = BBViewMapPair.first; + llvm::iterator_range PHIS = EnforcedBB->phis(); + if (PHIS.begin() == PHIS.end()) + continue; + + BBMap &EnforcedIncomingBBMap = BasicBlockViewMap.at(EnforcedBB); + + for (PHINode &PHI : PHIS) { + unsigned NIncoming = PHI.getNumIncomingValues(); + for (unsigned I = 0; I < NIncoming; ++I) { + BasicBlock *OriginalIncomingBB = PHI.getIncomingBlock(I); + BasicBlockNode *Tmp = EnforcedBBToNodeBBMap.at(EnforcedBB); + BasicBlock *EnforcedIncomingBB = nullptr; + for (BasicBlockNode *PredIt : Tmp->predecessors()) { + BasicBlockNode *Pred = PredIt; + while (Pred->isDummy()) { + revng_assert(Pred->basicBlock() == nullptr); + revng_assert(Pred->predecessor_size() == 1); + Pred = *Pred->predecessors().begin(); + } + BasicBlock *PredOriginalBB = Pred->basicBlock(); + revng_assert(PredOriginalBB != nullptr); + if (PredOriginalBB == OriginalIncomingBB) { + EnforcedIncomingBB = EnforcedBBNodeToBBMap.at(PredIt); + break; + } + } + revng_assert(EnforcedIncomingBB != nullptr); + BBMap::iterator It; + bool New; + std::tie(It, New) = EnforcedIncomingBBMap.insert({OriginalIncomingBB, + EnforcedIncomingBB}); + revng_assert(New or It->second == EnforcedIncomingBB); + } + } + } + + revng_assert(EnforcedBBMap.size() == EnforcedInstrMap.size()); + auto BBMapIt = EnforcedBBMap.begin(); + auto BBMapEnd = EnforcedBBMap.end(); + auto InstrMapIt = EnforcedInstrMap.begin(); + for (; BBMapIt != BBMapEnd; ++BBMapIt, ++BBMapEnd) { + const std::vector &BBClones = BBMapIt->second; + const std::vector &InstrMapClones = InstrMapIt->second; + revng_assert(BBClones.size() == InstrMapClones.size()); + auto BBCloneIt = BBClones.begin(); + auto BBCloneEnd = BBClones.end(); + auto InstrMapCloneIt = InstrMapClones.begin(); + for (; BBCloneIt != BBCloneEnd; ++BBCloneIt, ++BBCloneEnd) { + BasicBlock *EnforcedBB = *BBCloneIt; + for (Instruction &EnforcedInstr : *EnforcedBB) { + for (Use &Op : EnforcedInstr.operands()) { + if (auto *OriginalInstrOp = dyn_cast(Op)) { + Op.set(InstrMapCloneIt->at(OriginalInstrOp)); + } else if (auto *ArgOp = dyn_cast(Op)) { + ValueToValueMapTy::iterator It = ArgMap.find(ArgOp); + revng_assert(It != ArgMap.end()); + Op.set(It->second); + } else if (auto *BBOp = dyn_cast(Op)) { + Op.set(BasicBlockViewMap.at(EnforcedBB).at(BBOp)); + } else if (auto *ConstOp = dyn_cast(Op)) { + revng_assert(not isa(ConstOp)); + } else { + revng_abort(); + } + } + if (auto *PHI = dyn_cast(&EnforcedInstr)) { + unsigned NIncoming = PHI->getNumIncomingValues(); + for (unsigned I = 0; I < NIncoming; ++I) { + BasicBlock *OrigIncomingBB = PHI->getIncomingBlock(I); + PHI->setIncomingBlock(I, BasicBlockViewMap.at(EnforcedBB).at(OrigIncomingBB)); + } + } + } + } + } + return true; } diff --git a/lib/EnforceCFGCombingPass/EnforceCFGCombingPass.h b/lib/EnforceCFGCombingPass/EnforceCFGCombingPass.h index 8a9514eba..91663504b 100644 --- a/lib/EnforceCFGCombingPass/EnforceCFGCombingPass.h +++ b/lib/EnforceCFGCombingPass/EnforceCFGCombingPass.h @@ -6,7 +6,6 @@ #include // revng-c includes -#include "revng-c/Liveness/LivenessAnalysisPass.h" #include "revng-c/RestructureCFGPass/RestructureCFG.h" struct EnforceCFGCombingPass : public llvm::FunctionPass { @@ -17,7 +16,6 @@ struct EnforceCFGCombingPass : public llvm::FunctionPass { bool runOnFunction(llvm::Function &F) override; void getAnalysisUsage(llvm::AnalysisUsage &AU) const override { - AU.addRequired(); AU.addRequired(); } diff --git a/lib/Liveness/CMakeLists.txt b/lib/Liveness/CMakeLists.txt deleted file mode 100644 index f175536cf..000000000 --- a/lib/Liveness/CMakeLists.txt +++ /dev/null @@ -1,30 +0,0 @@ -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") - -# The library with the LivenessAnalysis -add_library(LivenessAnalysis SHARED - LivenessAnalysis.cpp - ) - -target_link_libraries(LivenessAnalysis - ${REVNG_SUPPORT_LIBRARY} - ${LLVM_LIBRARIES} - ) - -# The shared library with the LivenessAnalysisPass FunctionPass. -# It can be loaded by opt with the -load option to run the analysis. -add_library(LivenessAnalysisPass SHARED - LivenessAnalysisPass.cpp - ) - -target_link_libraries(LivenessAnalysisPass - LivenessAnalysis - ${LLVM_LIBRARIES} - ) - -install(TARGETS LivenessAnalysis - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib) - -install(TARGETS LivenessAnalysisPass - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib) diff --git a/lib/Liveness/LivenessAnalysis.cpp b/lib/Liveness/LivenessAnalysis.cpp deleted file mode 100644 index 53b2eee9c..000000000 --- a/lib/Liveness/LivenessAnalysis.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// -// This file is distributed under the MIT License. See LICENSE.md for details. -// - -// local includes -#include "revng-c/Liveness/LivenessAnalysis.h" - -using namespace llvm; - -namespace LivenessAnalysis { - -llvm::Optional -Analysis::handleEdge(const LiveSet &Original, - llvm::BasicBlock *Source, - llvm::BasicBlock *Destination) const { - llvm::Optional Result; - - auto SrcIt = PHIEdges.find(Source); - if (SrcIt == PHIEdges.end()) - return Result; - - const std::set &Pred = SrcIt->second.at(Destination); - for (Use *P : Pred) { - auto *ThePHI = cast(P->getUser()); - auto *LiveI = dyn_cast(P->get()); - for (Value *V : ThePHI->incoming_values()) { - if (auto *VInstr = dyn_cast(V)) { - if (VInstr != LiveI) { - // lazily copy the Original only if necessary - if (not Result.hasValue()) - Result = Original.copy(); - Result->erase(VInstr); - } - } - } - } - - return Result; -} - -Analysis::InterruptType Analysis::transfer(llvm::BasicBlock *BB) { - LiveSet LiveInResult = State[BB].copy(); - auto RIt = BB->rbegin(); - auto REnd= BB->rend(); - for (; RIt != REnd; ++RIt) { - Instruction &I = *RIt; - - if (auto *PHI = dyn_cast(&I)) - for (Use &U : PHI->incoming_values()) - PHIEdges[BB][PHI->getIncomingBlock(U)].insert(&U); - - for (Use &U : I.operands()) - if (auto *OpInst = dyn_cast(U)) - LiveInResult.insert(OpInst); - - LiveInResult.erase(&I); - } - LiveIn[BB] = LiveInResult.copy(); - return InterruptType::createInterrupt(std::move(LiveInResult)); -} - -} // end namespace LivenessAnalysis diff --git a/lib/Liveness/LivenessAnalysisPass.cpp b/lib/Liveness/LivenessAnalysisPass.cpp deleted file mode 100644 index ad0443611..000000000 --- a/lib/Liveness/LivenessAnalysisPass.cpp +++ /dev/null @@ -1,20 +0,0 @@ -// -// This file is distributed under the MIT License. See LICENSE.md for details. -// - -// local includes -#include "revng-c/Liveness/LivenessAnalysisPass.h" - -using namespace llvm; - -bool LivenessAnalysisPass::runOnFunction(Function &F) { - LivenessAnalysis::Analysis LA(F); - LA.initialize(); - LA.run(); - LiveIn = LA.extractLiveIn(); - return false; - } - -char LivenessAnalysisPass::ID = 0; - -static RegisterPass X("liveness", "Liveness Analysis");