svf-tools 1.0.1257 → 1.0.1259
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svf-tools",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1259",
|
|
4
4
|
"description": "* <b>[TypeClone](https://github.com/SVF-tools/SVF/wiki/TypeClone) published in our [ECOOP paper](https://yuleisui.github.io/publications/ecoop20.pdf) is now available in SVF </b> * <b>SVF now uses a single script for its build. Just type [`source ./build.sh`](https://github.com/SVF-tools/SVF/blob/master/build.sh) in your terminal, that's it!</b> * <b>SVF now supports LLVM-10.0.0! </b> * <b>We thank [bsauce](https://github.com/bsauce) for writing a user manual of SVF ([link1](https://www.jianshu.com/p/068a08ec749c) and [link2](https://www.jianshu.com/p/777c30d4240e)) in Chinese </b> * <b>SVF now supports LLVM-9.0.0 (Thank [Byoungyoung Lee](https://github.com/SVF-tools/SVF/issues/142) for his help!). </b> * <b>SVF now supports a set of [field-sensitive pointer analyses](https://yuleisui.github.io/publications/sas2019a.pdf). </b> * <b>[Use SVF as an external lib](https://github.com/SVF-tools/SVF/wiki/Using-SVF-as-a-lib-in-your-own-tool) for your own project (Contributed by [Hongxu Chen](https://github.com/HongxuChen)). </b> * <b>SVF now supports LLVM-7.0.0. </b> * <b>SVF now supports Docker. [Try SVF in Docker](https://github.com/SVF-tools/SVF/wiki/Try-SVF-in-Docker)! </b> * <b>SVF now supports [LLVM-6.0.0](https://github.com/svf-tools/SVF/pull/38) (Contributed by [Jack Anthony](https://github.com/jackanth)). </b> * <b>SVF now supports [LLVM-4.0.0](https://github.com/svf-tools/SVF/pull/23) (Contributed by Jared Carlson. Thank [Jared](https://github.com/jcarlson23) and [Will](https://github.com/dtzWill) for their in-depth [discussions](https://github.com/svf-tools/SVF/pull/18) about updating SVF!) </b> * <b>SVF now supports analysis for C++ programs.</b> <br />",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -37,9 +37,9 @@
|
|
|
37
37
|
#include "AE/Svfexe/AEStat.h"
|
|
38
38
|
#include "SVFIR/SVFIR.h"
|
|
39
39
|
#include "Util/SVFBugReport.h"
|
|
40
|
+
#include "Util/WorkList.h"
|
|
40
41
|
#include "Graphs/SCC.h"
|
|
41
42
|
#include "Graphs/CallGraph.h"
|
|
42
|
-
#include <deque>
|
|
43
43
|
|
|
44
44
|
namespace SVF
|
|
45
45
|
{
|
|
@@ -94,6 +94,12 @@ public:
|
|
|
94
94
|
WIDEN_NARROW
|
|
95
95
|
};
|
|
96
96
|
|
|
97
|
+
enum AEFunEntryMode
|
|
98
|
+
{
|
|
99
|
+
MAIN,
|
|
100
|
+
NO_MAIN
|
|
101
|
+
};
|
|
102
|
+
|
|
97
103
|
virtual void runOnModule();
|
|
98
104
|
|
|
99
105
|
/// Destructor
|
|
@@ -106,7 +112,7 @@ public:
|
|
|
106
112
|
void analyzeFromAllProgEntries();
|
|
107
113
|
|
|
108
114
|
/// Get all entry point functions (functions without callers)
|
|
109
|
-
|
|
115
|
+
FIFOWorkList<const FunObjVar*> collectProgEntryFuns();
|
|
110
116
|
|
|
111
117
|
/// Factory: returns the singleton instance. The concrete class is
|
|
112
118
|
/// chosen once, on first call, from `Options::AESparsity()`:
|
|
@@ -254,10 +260,10 @@ private:
|
|
|
254
260
|
virtual void handleCallSite(const ICFGNode* node);
|
|
255
261
|
|
|
256
262
|
/// Handle a WTO cycle (loop or recursive function) using widening/narrowing iteration
|
|
257
|
-
virtual void handleLoopOrRecursion(const ICFGCycleWTO* cycle, const CallICFGNode* caller
|
|
263
|
+
virtual void handleLoopOrRecursion(const ICFGCycleWTO* cycle, const CallICFGNode* caller);
|
|
258
264
|
|
|
259
265
|
/// Handle a function body via worklist-driven WTO traversal starting from funEntry
|
|
260
|
-
void handleFunction(const ICFGNode* funEntry, const CallICFGNode* caller
|
|
266
|
+
void handleFunction(const ICFGNode* funEntry, const CallICFGNode* caller);
|
|
261
267
|
|
|
262
268
|
/// Handle an ICFG node: execute statements; return true if state changed
|
|
263
269
|
bool handleICFGNode(const ICFGNode* node);
|
|
@@ -241,6 +241,7 @@ public:
|
|
|
241
241
|
|
|
242
242
|
// Abstract Execution
|
|
243
243
|
static const OptionMap<u32_t> AESparsity;
|
|
244
|
+
static const OptionMap<u32_t> AEFunEntry;
|
|
244
245
|
static const Option<u32_t> WidenDelay;
|
|
245
246
|
/// recursion handling mode, Default: TOP
|
|
246
247
|
static const OptionMap<u32_t> HandleRecur;
|
|
@@ -35,7 +35,6 @@
|
|
|
35
35
|
#include "Graphs/CallGraph.h"
|
|
36
36
|
#include "WPA/Andersen.h"
|
|
37
37
|
#include <cmath>
|
|
38
|
-
#include <deque>
|
|
39
38
|
#include <memory>
|
|
40
39
|
|
|
41
40
|
using namespace SVF;
|
|
@@ -118,11 +117,14 @@ AbstractInterpretation::~AbstractInterpretation()
|
|
|
118
117
|
}
|
|
119
118
|
|
|
120
119
|
/// Collect entry point functions for analysis.
|
|
121
|
-
///
|
|
122
|
-
///
|
|
123
|
-
|
|
120
|
+
/// In main mode, entry is main/svf.main. In no-main mode,
|
|
121
|
+
/// entries are SCCs with no external caller in the Andersen-resolved CallGraph.
|
|
122
|
+
FIFOWorkList<const FunObjVar*> AbstractInterpretation::collectProgEntryFuns()
|
|
124
123
|
{
|
|
125
|
-
|
|
124
|
+
FIFOWorkList<const FunObjVar*> entryFunctions;
|
|
125
|
+
const bool mainEntry = Options::AEFunEntry() == AEFunEntryMode::MAIN;
|
|
126
|
+
Set<NodeID> visitedEntrySCCs;
|
|
127
|
+
auto* callGraphSCC = preAnalysis->getCallGraphSCC();
|
|
126
128
|
|
|
127
129
|
for (auto it = callGraph->begin(); it != callGraph->end(); ++it)
|
|
128
130
|
{
|
|
@@ -133,39 +135,80 @@ std::deque<const FunObjVar*> AbstractInterpretation::collectProgEntryFuns()
|
|
|
133
135
|
if (fun->isDeclaration())
|
|
134
136
|
continue;
|
|
135
137
|
|
|
136
|
-
|
|
137
|
-
if (cgNode->getInEdges().empty())
|
|
138
|
+
if (mainEntry)
|
|
138
139
|
{
|
|
139
|
-
// If main exists, put it first for priority using deque's push_front
|
|
140
140
|
if (SVFUtil::isProgEntryFunction(fun))
|
|
141
141
|
{
|
|
142
|
-
entryFunctions.
|
|
142
|
+
entryFunctions.push(fun);
|
|
143
|
+
break;
|
|
143
144
|
}
|
|
144
|
-
|
|
145
|
+
}
|
|
146
|
+
else
|
|
147
|
+
{
|
|
148
|
+
NodeID repNodeId = callGraphSCC->repNode(cgNode->getId());
|
|
149
|
+
if (visitedEntrySCCs.count(repNodeId))
|
|
150
|
+
continue;
|
|
151
|
+
|
|
152
|
+
const NodeBS& cgSCCNodes = callGraphSCC->subNodes(repNodeId);
|
|
153
|
+
bool hasExternalCaller = false;
|
|
154
|
+
for (NodeID nodeId : cgSCCNodes)
|
|
145
155
|
{
|
|
146
|
-
|
|
156
|
+
const CallGraphNode* sccNode = callGraph->getGNode(nodeId);
|
|
157
|
+
for (auto inEdge : sccNode->getInEdges())
|
|
158
|
+
{
|
|
159
|
+
if (!cgSCCNodes.test(inEdge->getSrcID()))
|
|
160
|
+
{
|
|
161
|
+
hasExternalCaller = true;
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (hasExternalCaller)
|
|
166
|
+
break;
|
|
147
167
|
}
|
|
168
|
+
|
|
169
|
+
if (hasExternalCaller)
|
|
170
|
+
continue;
|
|
171
|
+
|
|
172
|
+
visitedEntrySCCs.insert(repNodeId);
|
|
173
|
+
const FunObjVar* entryFun = fun;
|
|
174
|
+
for (NodeID nodeId : cgSCCNodes)
|
|
175
|
+
{
|
|
176
|
+
const FunObjVar* sccFun = callGraph->getGNode(nodeId)->getFunction();
|
|
177
|
+
if (SVFUtil::isProgEntryFunction(sccFun))
|
|
178
|
+
{
|
|
179
|
+
entryFun = sccFun;
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
entryFunctions.push(entryFun);
|
|
148
184
|
}
|
|
149
185
|
}
|
|
150
186
|
|
|
187
|
+
if (mainEntry && entryFunctions.empty())
|
|
188
|
+
{
|
|
189
|
+
SVFUtil::errs() << SVFUtil::errMsg(
|
|
190
|
+
"AE -ae-fun-entry=main requires a program entry function, but main/svf.main was not found.\n");
|
|
191
|
+
assert(false && "No program entry function found for -ae-fun-entry=main");
|
|
192
|
+
abort();
|
|
193
|
+
}
|
|
194
|
+
|
|
151
195
|
return entryFunctions;
|
|
152
196
|
}
|
|
153
197
|
|
|
154
198
|
|
|
155
|
-
/// Program entry -
|
|
199
|
+
/// Program entry - entry policy is selected by -ae-fun-entry.
|
|
156
200
|
void AbstractInterpretation::analyse()
|
|
157
201
|
{
|
|
158
|
-
// Always use multi-entry analysis from all entry points
|
|
159
202
|
analyzeFromAllProgEntries();
|
|
160
203
|
}
|
|
161
204
|
|
|
162
|
-
/// Analyze
|
|
205
|
+
/// Analyze the entry functions selected by collectProgEntryFuns().
|
|
163
206
|
/// Abstract state is shared across entry points so that functions analyzed from
|
|
164
207
|
/// earlier entries are not re-analyzed from scratch.
|
|
165
208
|
void AbstractInterpretation::analyzeFromAllProgEntries()
|
|
166
209
|
{
|
|
167
210
|
// Collect all entry point functions
|
|
168
|
-
|
|
211
|
+
FIFOWorkList<const FunObjVar*> entryFunctions = collectProgEntryFuns();
|
|
169
212
|
|
|
170
213
|
if (entryFunctions.empty())
|
|
171
214
|
{
|
|
@@ -174,10 +217,13 @@ void AbstractInterpretation::analyzeFromAllProgEntries()
|
|
|
174
217
|
}
|
|
175
218
|
// handle Global ICFGNode of SVFModule
|
|
176
219
|
handleGlobalNode();
|
|
177
|
-
|
|
220
|
+
const ICFGNode* globalNode = icfg->getGlobalICFGNode();
|
|
221
|
+
while (!entryFunctions.empty())
|
|
178
222
|
{
|
|
223
|
+
const FunObjVar* entryFun = entryFunctions.pop();
|
|
179
224
|
const ICFGNode* funEntry = icfg->getFunEntryICFGNode(entryFun);
|
|
180
|
-
|
|
225
|
+
updateAbsState(funEntry, getAbsState(globalNode));
|
|
226
|
+
handleFunction(funEntry, nullptr);
|
|
181
227
|
}
|
|
182
228
|
}
|
|
183
229
|
|
|
@@ -443,7 +489,7 @@ static IntervalValue computeCmpConstraint(s32_t predicate, s64_t succ,
|
|
|
443
489
|
}
|
|
444
490
|
|
|
445
491
|
bool AbstractInterpretation::isCmpBranchEdgeFeasible(const IntraCFGEdge* edge,
|
|
446
|
-
|
|
492
|
+
AbstractState& as)
|
|
447
493
|
{
|
|
448
494
|
const ICFGNode* pred = edge->getSrcNode();
|
|
449
495
|
s64_t succ = edge->getSuccessorCondValue();
|
|
@@ -489,7 +535,7 @@ bool AbstractInterpretation::isSwitchBranchEdgeFeasible(
|
|
|
489
535
|
}
|
|
490
536
|
|
|
491
537
|
void AbstractInterpretation::collectBranchRefinement(const IntraCFGEdge* edge,
|
|
492
|
-
|
|
538
|
+
AbstractState& as)
|
|
493
539
|
{
|
|
494
540
|
const SVFVar* cond = edge->getCondition();
|
|
495
541
|
const ICFGNode* pred = edge->getSrcNode();
|
|
@@ -505,14 +551,15 @@ void AbstractInterpretation::collectBranchRefinement(const IntraCFGEdge* edge,
|
|
|
505
551
|
s32_t predicate = cmpStmt->getPredicate();
|
|
506
552
|
|
|
507
553
|
if (cmpStmt->getOpVarID(0) == IRGraph::NullPtr ||
|
|
508
|
-
|
|
554
|
+
cmpStmt->getOpVarID(1) == IRGraph::NullPtr)
|
|
509
555
|
{
|
|
510
556
|
// p == NULL / p != NULL: no interval obj to refine.
|
|
511
557
|
}
|
|
512
558
|
else
|
|
513
559
|
{
|
|
514
560
|
AbstractValue opVal[2] = {getAbsValue(cmpStmt->getOpVar(0), pred),
|
|
515
|
-
getAbsValue(cmpStmt->getOpVar(1), pred)
|
|
561
|
+
getAbsValue(cmpStmt->getOpVar(1), pred)
|
|
562
|
+
};
|
|
516
563
|
|
|
517
564
|
const bool hasIntervalCmp =
|
|
518
565
|
opVal[0].isInterval() && opVal[1].isInterval();
|
|
@@ -543,8 +590,8 @@ void AbstractInterpretation::collectBranchRefinement(const IntraCFGEdge* edge,
|
|
|
543
590
|
else
|
|
544
591
|
{
|
|
545
592
|
IntervalValue narrowed = computeCmpConstraint(
|
|
546
|
-
|
|
547
|
-
|
|
593
|
+
predicate, succ, i == 0, opVal[i].getInterval(),
|
|
594
|
+
opVal[other].getInterval());
|
|
548
595
|
|
|
549
596
|
if (narrowed.isTop())
|
|
550
597
|
{
|
|
@@ -658,7 +705,7 @@ void AbstractInterpretation::recordBranchRefinement(
|
|
|
658
705
|
}
|
|
659
706
|
|
|
660
707
|
bool AbstractInterpretation::isBranchEdgeFeasible(const IntraCFGEdge* edge,
|
|
661
|
-
|
|
708
|
+
AbstractState& as)
|
|
662
709
|
{
|
|
663
710
|
const SVFVar* cmpVar = edge->getCondition();
|
|
664
711
|
assert(!cmpVar->getInEdges().empty() && "branch condition has no defining edge?");
|
|
@@ -735,8 +782,7 @@ bool AbstractInterpretation::handleICFGNode(const ICFGNode* node)
|
|
|
735
782
|
void AbstractInterpretation::handleFunction(const ICFGNode* funEntry, const CallICFGNode* caller)
|
|
736
783
|
{
|
|
737
784
|
auto it = preAnalysis->getFuncToWTO().find(funEntry->getFun());
|
|
738
|
-
|
|
739
|
-
return;
|
|
785
|
+
assert(it != preAnalysis->getFuncToWTO().end() && "Missing WTO for function");
|
|
740
786
|
|
|
741
787
|
// Push all top-level WTO components into the worklist in WTO order
|
|
742
788
|
FIFOWorkList<const ICFGWTOComp*> worklist(it->second->getWTOComponents());
|
|
@@ -62,7 +62,7 @@ void FullSparseAbstractInterpretation::buildSVFG()
|
|
|
62
62
|
// =====================================================================
|
|
63
63
|
|
|
64
64
|
void FullSparseAbstractInterpretation::joinStates(AbstractState& dst,
|
|
65
|
-
|
|
65
|
+
const AbstractState& src)
|
|
66
66
|
{
|
|
67
67
|
// Propagate GepObjVar entries along ICFG edges. Kill semantics
|
|
68
68
|
// come from handleNode's as.store(addr, val) overwriting trace at
|
|
@@ -88,8 +88,8 @@ void FullSparseAbstractInterpretation::joinStates(AbstractState& dst,
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
void FullSparseAbstractInterpretation::storeValue(const ValVar* pointer,
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
const AbstractValue& val,
|
|
92
|
+
const ICFGNode* node)
|
|
93
93
|
{
|
|
94
94
|
// Clear branch refinement for every ObjVar this store overwrites.
|
|
95
95
|
// A store redefines the ObjVar; the pre-store branch constraint
|
|
@@ -206,20 +206,20 @@ void FullSparseAbstractInterpretation::pullObjValueFlows(const ICFGNode* node)
|
|
|
206
206
|
continue;
|
|
207
207
|
}
|
|
208
208
|
if (obj &&
|
|
209
|
-
|
|
210
|
-
|
|
209
|
+
SemiSparseAbstractInterpretation::hasAbsValue(
|
|
210
|
+
obj, srcICFG))
|
|
211
211
|
{
|
|
212
212
|
AbstractValue cur;
|
|
213
213
|
if (SemiSparseAbstractInterpretation::
|
|
214
214
|
hasAbsValue(obj, node))
|
|
215
215
|
{
|
|
216
216
|
cur = SemiSparseAbstractInterpretation::
|
|
217
|
-
|
|
217
|
+
getAbsValue(obj, node);
|
|
218
218
|
}
|
|
219
219
|
cur.join_with(SemiSparseAbstractInterpretation::
|
|
220
|
-
|
|
220
|
+
getAbsValue(obj, srcICFG));
|
|
221
221
|
SemiSparseAbstractInterpretation::
|
|
222
|
-
|
|
222
|
+
updateAbsValue(obj, cur, node);
|
|
223
223
|
}
|
|
224
224
|
}
|
|
225
225
|
}
|
|
@@ -243,7 +243,7 @@ static bool hasRedefineToSameObj(const ICFGNode* node,
|
|
|
243
243
|
for (const VFGNode* vfgNode : node->getVFGNodes())
|
|
244
244
|
{
|
|
245
245
|
if (SVFUtil::isa<StoreVFGNode>(vfgNode) &&
|
|
246
|
-
|
|
246
|
+
vfgNode->getDefSVFVars().intersects(edge->getPointsTo()))
|
|
247
247
|
return true;
|
|
248
248
|
}
|
|
249
249
|
|
|
@@ -298,7 +298,7 @@ bool FullSparseAbstractInterpretation::isIndirectSVFGEdgeFeasible(
|
|
|
298
298
|
// normal analysis; here we only need caller-side reachability,
|
|
299
299
|
// e.g. entry -> ret-site.
|
|
300
300
|
if (const CallICFGNode* call =
|
|
301
|
-
|
|
301
|
+
SVFUtil::dyn_cast<CallICFGNode>(cur))
|
|
302
302
|
{
|
|
303
303
|
const ICFGNode* succ = call->getRetICFGNode();
|
|
304
304
|
if (!succ || succ->getFun() != fun)
|
|
@@ -361,7 +361,7 @@ bool FullSparseAbstractInterpretation::isIndirectSVFGEdgeFeasible(
|
|
|
361
361
|
}
|
|
362
362
|
|
|
363
363
|
bool FullSparseAbstractInterpretation::isICFGPathFeasible(const ICFGNode* src,
|
|
364
|
-
|
|
364
|
+
const ICFGNode* dst)
|
|
365
365
|
{
|
|
366
366
|
bool feasible = true;
|
|
367
367
|
if (!src || !dst)
|
|
@@ -397,7 +397,7 @@ bool FullSparseAbstractInterpretation::isICFGPathFeasible(const ICFGNode* src,
|
|
|
397
397
|
// normal analysis; here we only need caller-side reachability,
|
|
398
398
|
// e.g. entry -> ret-site.
|
|
399
399
|
if (const CallICFGNode* call =
|
|
400
|
-
|
|
400
|
+
SVFUtil::dyn_cast<CallICFGNode>(cur))
|
|
401
401
|
{
|
|
402
402
|
const ICFGNode* succ = call->getRetICFGNode();
|
|
403
403
|
if (!succ || succ->getFun() != fun)
|
|
@@ -665,7 +665,7 @@ void SemiSparseAbstractInterpretation::updateAbsState(
|
|
|
665
665
|
}
|
|
666
666
|
|
|
667
667
|
void SemiSparseAbstractInterpretation::joinStates(AbstractState& dst,
|
|
668
|
-
|
|
668
|
+
const AbstractState& src)
|
|
669
669
|
{
|
|
670
670
|
// ValVars live at def-sites in semi-sparse mode; they don't flow
|
|
671
671
|
// through state merges. Iterate src's ObjVar (_addrToAbsVal) entries
|
|
@@ -697,7 +697,7 @@ const ICFGNode* SemiSparseAbstractInterpretation::getICFGNode(
|
|
|
697
697
|
SVFUtil::isa<RetValPN>(var))
|
|
698
698
|
{
|
|
699
699
|
return SVFUtil::dyn_cast<CallICFGNode>(var->getICFGNode())
|
|
700
|
-
|
|
700
|
+
->getRetICFGNode();
|
|
701
701
|
}
|
|
702
702
|
// for other ValVars, use their def-site as the node to query abstract
|
|
703
703
|
// value.
|
|
@@ -708,8 +708,8 @@ const ICFGNode* SemiSparseAbstractInterpretation::getICFGNode(
|
|
|
708
708
|
}
|
|
709
709
|
|
|
710
710
|
void SemiSparseAbstractInterpretation::updateAbsValue(const ValVar* var,
|
|
711
|
-
|
|
712
|
-
|
|
711
|
+
const AbstractValue& val,
|
|
712
|
+
const ICFGNode* node)
|
|
713
713
|
{
|
|
714
714
|
// Write to the var's def-site so getAbsValue stays consistent.
|
|
715
715
|
const ICFGNode* defNode = var->getICFGNode();
|
|
@@ -724,7 +724,7 @@ const AbstractValue& SemiSparseAbstractInterpretation::getAbsValue(
|
|
|
724
724
|
}
|
|
725
725
|
|
|
726
726
|
bool SemiSparseAbstractInterpretation::hasAbsValue(const ValVar* var,
|
|
727
|
-
|
|
727
|
+
const ICFGNode* node) const
|
|
728
728
|
{
|
|
729
729
|
return AbstractInterpretation::hasAbsValue(var, getICFGNode(var));
|
|
730
730
|
}
|
package/svf/lib/Util/Options.cpp
CHANGED
|
@@ -799,6 +799,20 @@ const OptionMap<u32_t> Options::AESparsity(
|
|
|
799
799
|
"Sparse abstract execution via SVFG."
|
|
800
800
|
}
|
|
801
801
|
});
|
|
802
|
+
const OptionMap<u32_t> Options::AEFunEntry(
|
|
803
|
+
"ae-fun-entry",
|
|
804
|
+
"Abstract execution function entry mode (Default: main)",
|
|
805
|
+
AbstractInterpretation::AEFunEntryMode::MAIN,
|
|
806
|
+
{
|
|
807
|
+
{
|
|
808
|
+
AbstractInterpretation::AEFunEntryMode::MAIN, "main",
|
|
809
|
+
"Analyze from the program entry function only."
|
|
810
|
+
},
|
|
811
|
+
{
|
|
812
|
+
AbstractInterpretation::AEFunEntryMode::NO_MAIN, "no-main",
|
|
813
|
+
"Analyze from every no-external-caller SCC after Andersen resolves the call graph."
|
|
814
|
+
}
|
|
815
|
+
});
|
|
802
816
|
const Option<u32_t> Options::WidenDelay(
|
|
803
817
|
"widen-delay", "Loop Widen Delay", 3);
|
|
804
818
|
const OptionMap<u32_t> Options::HandleRecur(
|