First Prototype of EnforceCFGCombingPass

This commit is contained in:
Pietro Fezzardi
2019-01-18 17:39:28 +01:00
parent 05a5660de2
commit d5f2bc7750
9 changed files with 193 additions and 153 deletions
-1
View File
@@ -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 -2
View File
@@ -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>();
}
-30
View File
@@ -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)
-62
View File
@@ -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
-20
View File
@@ -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");