Skip to content

Commit 9a435ba

Browse files
committed
ICFG Optimizations -- graph merging and others.
The largest change performance wise is the change to the graph type to use a vector for edge storage. The merge function now mirrors the changes to the Points-To class to avoid re-building the FunctionVertexMap from scratch. Changes in constructionWalker avoid fetching the same data multiple times back-to-back. printAsDot was modified to allow the user to skip the edge labels, because those are quite expensive. Moved code out of the header that is only used internally to this function body. ProjectIRDB.h does not use the LLVMPointsToGraph.h, so it was removed which necessitated several other header changes.
1 parent 2938c39 commit 9a435ba

10 files changed

Lines changed: 101 additions & 90 deletions

File tree

include/phasar/DB/ProjectIRDB.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
#include <llvm/IR/LLVMContext.h>
2121
#include <llvm/IR/Module.h>
2222

23-
#include <phasar/PhasarLLVM/Pointer/LLVMPointsToGraph.h>
2423
#include <phasar/Utils/EnumFlags.h>
2524

2625
namespace llvm {

include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h

Lines changed: 3 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ class LLVMBasedICFG
8888
};
8989

9090
/// Specify the type of graph to be used.
91-
typedef boost::adjacency_list<boost::multisetS, boost::vecS,
91+
typedef boost::adjacency_list<boost::vecS, boost::vecS,
9292
boost::bidirectionalS, VertexProperties,
9393
EdgeProperties>
9494
bidigraph_t;
@@ -106,7 +106,7 @@ class LLVMBasedICFG
106106
/// Maps function names to the corresponding vertex id.
107107
std::unordered_map<const llvm::Function *, vertex_t> FunctionVertexMap;
108108

109-
void constructionWalker(const llvm::Function *F, Resolver *Res);
109+
void constructionWalker(const llvm::Function *F, Resolver &Resolver);
110110

111111
struct dependency_visitor;
112112

@@ -162,44 +162,7 @@ class LLVMBasedICFG
162162
using LLVMBasedCFG::print; // tell the compiler we wish to have both prints
163163
void print(std::ostream &OS = std::cout) const override;
164164

165-
// provide a VertexPropertyWrite to tell boost how to write a vertex
166-
class CallGraphVertexWriter {
167-
public:
168-
CallGraphVertexWriter(const bidigraph_t &CGraph) : CGraph(CGraph) {}
169-
template <class VertexOrEdge>
170-
void operator()(std::ostream &out, const VertexOrEdge &v) const {
171-
out << "[label=\"" << CGraph[v].getFunctionName() << "\"]";
172-
}
173-
174-
private:
175-
const bidigraph_t &CGraph;
176-
};
177-
178-
// a function to conveniently create the vertex writer
179-
CallGraphVertexWriter
180-
makeCallGraphVertexWriter(const bidigraph_t &CGraph) const {
181-
return CallGraphVertexWriter(CGraph);
182-
}
183-
184-
// provide a EdgePropertyWrite to tell boost how to write an edge
185-
class CallGraphEdgeWriter {
186-
public:
187-
CallGraphEdgeWriter(const bidigraph_t &CGraph) : CGraph(CGraph) {}
188-
template <class VertexOrEdge>
189-
void operator()(std::ostream &out, const VertexOrEdge &v) const {
190-
out << "[label=\"" << CGraph[v].getCallSiteAsString() << "\"]";
191-
}
192-
193-
private:
194-
const bidigraph_t &CGraph;
195-
};
196-
197-
// a function to conveniently create the edge writer
198-
CallGraphEdgeWriter makeCallGraphEdgeWriter(const bidigraph_t &CGraph) const {
199-
return CallGraphEdgeWriter(CGraph);
200-
}
201-
202-
void printAsDot(std::ostream &OS = std::cout) const;
165+
void printAsDot(std::ostream &OS = std::cout, bool printEdgeLabels = true) const;
203166

204167
void printInternalPTGAsDot(std::ostream &OS = std::cout) const;
205168

lib/DB/ProjectIRDB.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
#include <boost/filesystem.hpp>
3030

31+
#include <phasar/Config/Configuration.h>
3132
#include <phasar/DB/ProjectIRDB.h>
3233
#include <phasar/PhasarLLVM/DataFlowSolver/IfdsIde/LLVMZeroValue.h>
3334
#include <phasar/PhasarLLVM/Passes/GeneralStatisticsAnalysis.h>

lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp

Lines changed: 85 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ LLVMBasedICFG::LLVMBasedICFG(ProjectIRDB &IRDB, CallGraphAnalysisType CGType,
143143
PointsToGraph *PTG = PT->getPointsToGraph(F);
144144
WholeModulePTG.mergeWith(PTG, F);
145145
}
146-
constructionWalker(F, Res.get());
146+
constructionWalker(F, *Res.get());
147147
}
148148
REG_COUNTER("WM-PTG Vertices", WholeModulePTG.getNumOfVertices(),
149149
PAMM_SEVERITY_LEVEL::Full);
@@ -166,29 +166,33 @@ LLVMBasedICFG::~LLVMBasedICFG() {
166166
}
167167

168168
void LLVMBasedICFG::constructionWalker(const llvm::Function *F,
169-
Resolver *Resolver) {
169+
Resolver &Resolver) {
170170
PAMM_GET_INSTANCE;
171171
auto &lg = lg::get();
172172
LOG_IF_ENABLE(BOOST_LOG_SEV(lg, DEBUG)
173173
<< "Walking in function: " << F->getName().str());
174-
if (VisitedFunctions.count(F) || F->isDeclaration()) {
174+
if (F->isDeclaration() || !VisitedFunctions.insert(F).second ) {
175175
LOG_IF_ENABLE(BOOST_LOG_SEV(lg, DEBUG)
176176
<< "Function already visited or only declaration: "
177177
<< F->getName().str());
178178
return;
179179
}
180-
VisitedFunctions.insert(F);
181180

182181
// add a node for function F to the call graph (if not present already)
183-
if (!FunctionVertexMap.count(F)) {
184-
FunctionVertexMap[F] = boost::add_vertex(CallGraph);
185-
CallGraph[FunctionVertexMap[F]] = VertexProperties(F);
182+
vertex_t thisFunctionVertexDescriptor;
183+
auto fvmItr = FunctionVertexMap.find(F);
184+
if (fvmItr != FunctionVertexMap.end())
185+
thisFunctionVertexDescriptor = fvmItr->second;
186+
else {
187+
thisFunctionVertexDescriptor = boost::add_vertex(VertexProperties(F), CallGraph);
188+
FunctionVertexMap[F] = thisFunctionVertexDescriptor;
186189
}
190+
187191
// iterate all instructions of the current function
188192
for (auto &BB : *F) {
189193
for (auto &I : BB) {
190194
if (llvm::isa<llvm::CallInst>(I) || llvm::isa<llvm::InvokeInst>(I)) {
191-
Resolver->preCall(&I);
195+
Resolver.preCall(&I);
192196

193197
llvm::ImmutableCallSite cs(&I);
194198
set<const llvm::Function *> possible_targets;
@@ -200,10 +204,11 @@ void LLVMBasedICFG::constructionWalker(const llvm::Function *F,
200204
<< " " << llvmIRToString(cs.getInstruction()));
201205
} else {
202206
// still try to resolve the called function statically
203-
const llvm::Value *v = cs.getCalledValue();
204-
const llvm::Value *sv = v->stripPointerCasts();
205-
if (sv->hasName() && IRDB.getFunction(sv->getName())) {
206-
possible_targets.insert(IRDB.getFunction(sv->getName()));
207+
const llvm::Value *sv = cs.getCalledValue()->stripPointerCasts();
208+
const llvm::Function *valueFunction =
209+
!sv->hasName() ? nullptr : IRDB.getFunction(sv->getName());
210+
if (valueFunction) {
211+
possible_targets.insert(valueFunction);
207212
LOG_IF_ENABLE(BOOST_LOG_SEV(lg, DEBUG)
208213
<< "Found static call-site: "
209214
<< llvmIRToString(cs.getInstruction()));
@@ -215,9 +220,9 @@ void LLVMBasedICFG::constructionWalker(const llvm::Function *F,
215220
<< " " << llvmIRToString(cs.getInstruction()));
216221
// call the resolve routine
217222
if (isVirtualFunctionCall(cs.getInstruction())) {
218-
possible_targets = Resolver->resolveVirtualCall(cs);
223+
possible_targets = Resolver.resolveVirtualCall(cs);
219224
} else {
220-
possible_targets = Resolver->resolveFunctionPointer(cs);
225+
possible_targets = Resolver.resolveFunctionPointer(cs);
221226
}
222227
}
223228
}
@@ -226,18 +231,19 @@ void LLVMBasedICFG::constructionWalker(const llvm::Function *F,
226231
<< "Found " << possible_targets.size()
227232
<< " possible target(s)");
228233

229-
Resolver->handlePossibleTargets(cs, possible_targets);
234+
Resolver.handlePossibleTargets(cs, possible_targets);
230235
// Insert possible target inside the graph and add the link with
231236
// the current function
232237
for (auto &possible_target : possible_targets) {
233-
auto target = possible_target;
234-
if (!FunctionVertexMap.count(target)) {
235-
FunctionVertexMap[target] = boost::add_vertex(CallGraph);
236-
CallGraph[FunctionVertexMap[target]] =
237-
VertexProperties(possible_target);
238+
vertex_t targetVertex;
239+
auto targetFvmItr = FunctionVertexMap.find(possible_target);
240+
if (targetFvmItr != FunctionVertexMap.end())
241+
targetVertex = targetFvmItr->second;
242+
else {
243+
targetVertex = boost::add_vertex(VertexProperties(possible_target), CallGraph);
244+
FunctionVertexMap[possible_target] = targetVertex;
238245
}
239-
240-
boost::add_edge(FunctionVertexMap[F], FunctionVertexMap[target],
246+
boost::add_edge(thisFunctionVertexDescriptor, targetVertex,
241247
EdgeProperties(cs.getInstruction()), CallGraph);
242248
}
243249

@@ -246,9 +252,9 @@ void LLVMBasedICFG::constructionWalker(const llvm::Function *F,
246252
constructionWalker(possible_target, Resolver);
247253
}
248254

249-
Resolver->postCall(&I);
255+
Resolver.postCall(&I);
250256
} else {
251-
Resolver->otherInst(&I);
257+
Resolver.otherInst(&I);
252258
}
253259
}
254260
}
@@ -446,23 +452,14 @@ LLVMBasedICFG::getLastInstructionOf(const string &name) {
446452
}
447453

448454
void LLVMBasedICFG::mergeWith(const LLVMBasedICFG &other) {
449-
// Copy other graph into this graph
450-
typedef typename boost::property_map<bidigraph_t, boost::vertex_index_t>::type
451-
index_map_t;
452-
// For simple adjacency_list<> this type would be more efficient:
453-
typedef typename boost::iterator_property_map<
454-
typename std::vector<LLVMBasedICFG::vertex_t>::iterator, index_map_t,
455-
LLVMBasedICFG::vertex_t, LLVMBasedICFG::vertex_t &>
456-
IsoMap;
457-
// For more generic graphs, one can try typedef std::map<vertex_t, vertex_t>
458-
// IsoMap;
459-
vector<LLVMBasedICFG::vertex_t> orig2copy_data(
460-
boost::num_vertices(other.CallGraph));
461-
IsoMap mapV = boost::make_iterator_property_map(
462-
orig2copy_data.begin(), get(boost::vertex_index, other.CallGraph));
463-
boost::copy_graph(other.CallGraph, CallGraph,
464-
boost::orig_to_copy(mapV)); // means g1 += g2
465-
// This vector hols the call-sites that are used to merge the whole-module
455+
typedef bidigraph_t::vertex_descriptor vertex_t;
456+
typedef std::map<vertex_t, vertex_t> vertex_map_t;
457+
vertex_map_t oldToNewVertexMapping;
458+
boost::associative_property_map<vertex_map_t> vertexMapWrapper(
459+
oldToNewVertexMapping);
460+
boost::copy_graph(other.CallGraph, CallGraph, boost::orig_to_copy(vertexMapWrapper));
461+
462+
// This vector holds the call-sites that are used to merge the whole-module
466463
// points-to graphs
467464
vector<pair<llvm::ImmutableCallSite, const llvm::Function *>> Calls;
468465
vertex_iterator vi_v, vi_v_end, vi_u, vi_u_end;
@@ -494,12 +491,16 @@ void LLVMBasedICFG::mergeWith(const LLVMBasedICFG &other) {
494491
}
495492
}
496493
}
497-
// Update the FunctionVertexMap
498-
FunctionVertexMap.clear();
499-
for (boost::tie(vi_v, vi_v_end) = boost::vertices(CallGraph);
500-
vi_v != vi_v_end; ++vi_v) {
501-
FunctionVertexMap.insert(make_pair(CallGraph[*vi_v].F, *vi_v));
494+
495+
// Update the FunctionVertexMap:
496+
for (const auto &otherValues : other.FunctionVertexMap) {
497+
auto mappingIter = oldToNewVertexMapping.find(otherValues.second);
498+
if (mappingIter != oldToNewVertexMapping.end()) {
499+
FunctionVertexMap.insert(
500+
make_pair(otherValues.first, mappingIter->second));
501+
}
502502
}
503+
503504
// Merge the already visited functions
504505
VisitedFunctions.insert(other.VisitedFunctions.begin(),
505506
other.VisitedFunctions.end());
@@ -535,9 +536,44 @@ void LLVMBasedICFG::print(ostream &OS) const {
535536
}
536537
}
537538

538-
void LLVMBasedICFG::printAsDot(std::ostream &OS) const {
539-
boost::write_graphviz(OS, CallGraph, makeCallGraphVertexWriter(CallGraph),
540-
makeCallGraphEdgeWriter(CallGraph));
539+
namespace {
540+
template <class graphType>
541+
class VertexWriter {
542+
public:
543+
VertexWriter(const graphType &CGraph) : CGraph(CGraph) {}
544+
template <class VertexOrEdge>
545+
void operator()(std::ostream &out, const VertexOrEdge &v) const {
546+
out << "[label=\"" << CGraph[v].getFunctionName() << "\"]";
547+
}
548+
549+
private:
550+
const graphType &CGraph;
551+
};
552+
553+
template <class graphType>
554+
class EdgeLabelWriter {
555+
public:
556+
EdgeLabelWriter(const graphType &CGraph) : CGraph(CGraph) {}
557+
template <class VertexOrEdge>
558+
void operator()(std::ostream &out, const VertexOrEdge &v) const {
559+
out << "[label=\"" << CGraph[v].getCallSiteAsString() << "\"]";
560+
}
561+
562+
private:
563+
const graphType &CGraph;
564+
};
565+
}
566+
567+
void LLVMBasedICFG::printAsDot(std::ostream &OS, bool printEdgeLabels) const {
568+
if (printEdgeLabels) {
569+
boost::write_graphviz(OS, CallGraph,
570+
VertexWriter<bidigraph_t>(CallGraph),
571+
EdgeLabelWriter<bidigraph_t>(CallGraph));
572+
} else {
573+
boost::write_graphviz(OS, CallGraph,
574+
VertexWriter<bidigraph_t>(CallGraph));
575+
576+
}
541577
}
542578

543579
void LLVMBasedICFG::printInternalPTGAsDot(std::ostream &OS) const {

lib/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include <llvm/IR/Instructions.h>
3636
#include <llvm/IR/Module.h>
3737

38+
#include <phasar/Config/Configuration.h>
3839
#include <phasar/DB/ProjectIRDB.h>
3940
#include <phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h>
4041
#include <phasar/Utils/GraphExtensions.h>

unittests/PhasarLLVM/ControlFlow/LLVMBasedBackwardCFGTest.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
#include <gtest/gtest.h>
22
#include <llvm/IR/InstIterator.h>
3+
#include <llvm/IR/Function.h>
4+
#include <llvm/IR/Instructions.h>
5+
#include <phasar/Config/Configuration.h>
36
#include <phasar/DB/ProjectIRDB.h>
47
#include <phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardCFG.h>
58
#include <phasar/Utils/LLVMShorthands.h>

unittests/PhasarLLVM/ControlFlow/LLVMBasedCFGTest.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
#include <gtest/gtest.h>
22
#include <llvm/IR/InstIterator.h>
3+
#include <llvm/IR/Function.h>
4+
#include <llvm/IR/Instructions.h>
5+
#include <phasar/Config/Configuration.h>
36
#include <phasar/DB/ProjectIRDB.h>
47
#include <phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h>
58
#include <phasar/Utils/LLVMShorthands.h>

unittests/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchyTest.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <gtest/gtest.h>
88

9+
#include <phasar/Config/Configuration.h>
910
#include <phasar/DB/ProjectIRDB.h>
1011
#include <phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h>
1112
#include <phasar/Utils/LLVMShorthands.h>

unittests/PhasarLLVM/TypeHierarchy/TypeGraphTest.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <phasar/PhasarLLVM/Pointer/TypeGraphs/LazyTypeGraph.h>
55

66
#include <boost/graph/isomorphism.hpp>
7+
#include <phasar/Config/Configuration.h>
78
#include <phasar/Utils/LLVMShorthands.h>
89
#include <phasar/Utils/Utilities.h>
910

unittests/Utils/LLVMShorthandsTest.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
#include <gtest/gtest.h>
2+
#include <llvm/IR/Function.h>
3+
#include <llvm/IR/Instructions.h>
4+
#include <phasar/Config/Configuration.h>
25
#include <phasar/DB/ProjectIRDB.h>
36
#include <phasar/Utils/LLVMShorthands.h>
47
#include <phasar/Utils/Utilities.h>

0 commit comments

Comments
 (0)