mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
First Prototype of EnforceCFGCombingPass
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
add_subdirectory(EnforceCFGCombingPass)
|
||||
add_subdirectory(ExamplePass)
|
||||
add_subdirectory(Liveness)
|
||||
add_subdirectory(RestructureCFGPass)
|
||||
add_subdirectory(RemovePCStoresPass)
|
||||
add_subdirectory(revng-c)
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -19,17 +19,23 @@ class BasicBlockNode;
|
||||
|
||||
namespace BasicBlockViewAnalysis {
|
||||
|
||||
class BasicBlockViewMap {
|
||||
using BBMap = std::map<llvm::BasicBlock *, llvm::BasicBlock *>;
|
||||
using BBViewMap = std::map<llvm::BasicBlock *, BBMap>;
|
||||
|
||||
protected:
|
||||
using BBMap = std::map<llvm::BasicBlock *, BasicBlockNode *>;
|
||||
BBMap Map;
|
||||
bool IsBottom;
|
||||
using BBNodeToBBMap = std::map<BasicBlockNode *, llvm::BasicBlock *>;
|
||||
|
||||
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<BasicBlockNode *, BasicBlockViewMap>;
|
||||
|
||||
class Analysis
|
||||
: public MonotoneFramework<Analysis,
|
||||
@@ -97,8 +114,8 @@ class Analysis
|
||||
llvm::SmallVector<BasicBlockNode *, 2>> {
|
||||
private:
|
||||
CFG &RegionCFGTree;
|
||||
const llvm::Function &OriginalFunction;
|
||||
BBNodeBBViewMap BBViewMap;
|
||||
const BBNodeToBBMap &EnforcedBBMap;
|
||||
BBViewMap ViewMap;
|
||||
|
||||
public:
|
||||
using Base = MonotoneFramework<Analysis,
|
||||
@@ -107,11 +124,10 @@ public:
|
||||
VisitType::PostOrder,
|
||||
llvm::SmallVector<BasicBlockNode *, 2>>;
|
||||
|
||||
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.
|
||||
|
||||
@@ -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}
|
||||
)
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
// LLVM includes
|
||||
#include <llvm/Pass.h>
|
||||
#include <llvm/Transforms/Utils/Cloning.h>
|
||||
#include <llvm/Transforms/Utils/ValueMapper.h>
|
||||
|
||||
// local librariesincludes
|
||||
#include "revng-c/RestructureCFGPass/RegionCFGTree.h"
|
||||
@@ -15,17 +17,20 @@
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
bool EnforceCFGCombingPass::runOnFunction(Function &F) {
|
||||
auto &LA = getAnalysis<LivenessAnalysisPass>();
|
||||
const LivenessAnalysis::LivenessMap &LiveIn = LA.getLiveIn();
|
||||
|
||||
using BBMap = BasicBlockViewAnalysis::BBMap;
|
||||
using BBNodeToBBMap = BasicBlockViewAnalysis::BBNodeToBBMap;
|
||||
using BBToBBNodeMap = std::map<BasicBlock *, BasicBlockNode *>;
|
||||
using BBViewMap = BasicBlockViewAnalysis::BBViewMap;
|
||||
|
||||
bool EnforceCFGCombingPass::runOnFunction(Function &F) {
|
||||
auto &RestructurePass = getAnalysis<RestructureCFG>();
|
||||
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<EdgeDescriptor> 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<BasicBlock *, std::vector<BasicBlock *>> EnforcedBBMap;
|
||||
|
||||
using InstrMap = std::map<const Instruction *, Instruction *>;
|
||||
std::map<BasicBlock *, std::vector<InstrMap>> 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<Instruction>(I.first);
|
||||
auto *EnforcedInstr = cast<Instruction>(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<BasicBlock::phi_iterator> 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<BasicBlock *> &BBClones = BBMapIt->second;
|
||||
const std::vector<InstrMap> &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<Instruction>(Op)) {
|
||||
Op.set(InstrMapCloneIt->at(OriginalInstrOp));
|
||||
} else if (auto *ArgOp = dyn_cast<Argument>(Op)) {
|
||||
ValueToValueMapTy::iterator It = ArgMap.find(ArgOp);
|
||||
revng_assert(It != ArgMap.end());
|
||||
Op.set(It->second);
|
||||
} else if (auto *BBOp = dyn_cast<BasicBlock>(Op)) {
|
||||
Op.set(BasicBlockViewMap.at(EnforcedBB).at(BBOp));
|
||||
} else if (auto *ConstOp = dyn_cast<Constant>(Op)) {
|
||||
revng_assert(not isa<BlockAddress>(ConstOp));
|
||||
} else {
|
||||
revng_abort();
|
||||
}
|
||||
}
|
||||
if (auto *PHI = dyn_cast<PHINode>(&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;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include <llvm/Pass.h>
|
||||
|
||||
// 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<LivenessAnalysisPass>();
|
||||
AU.addRequired<RestructureCFG>();
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -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<LiveSet>
|
||||
Analysis::handleEdge(const LiveSet &Original,
|
||||
llvm::BasicBlock *Source,
|
||||
llvm::BasicBlock *Destination) const {
|
||||
llvm::Optional<LiveSet> Result;
|
||||
|
||||
auto SrcIt = PHIEdges.find(Source);
|
||||
if (SrcIt == PHIEdges.end())
|
||||
return Result;
|
||||
|
||||
const std::set<Use *> &Pred = SrcIt->second.at(Destination);
|
||||
for (Use *P : Pred) {
|
||||
auto *ThePHI = cast<PHINode>(P->getUser());
|
||||
auto *LiveI = dyn_cast<Instruction>(P->get());
|
||||
for (Value *V : ThePHI->incoming_values()) {
|
||||
if (auto *VInstr = dyn_cast<Instruction>(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<PHINode>(&I))
|
||||
for (Use &U : PHI->incoming_values())
|
||||
PHIEdges[BB][PHI->getIncomingBlock(U)].insert(&U);
|
||||
|
||||
for (Use &U : I.operands())
|
||||
if (auto *OpInst = dyn_cast<Instruction>(U))
|
||||
LiveInResult.insert(OpInst);
|
||||
|
||||
LiveInResult.erase(&I);
|
||||
}
|
||||
LiveIn[BB] = LiveInResult.copy();
|
||||
return InterruptType::createInterrupt(std::move(LiveInResult));
|
||||
}
|
||||
|
||||
} // end namespace LivenessAnalysis
|
||||
@@ -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<LivenessAnalysisPass> X("liveness", "Liveness Analysis");
|
||||
Reference in New Issue
Block a user