Skip to content

Commit c554433

Browse files
authored
Merge pull request #282 from correctcomputation/iss281
Major refactoring of array bounds code and some performance improvements
2 parents 0f8d6dc + 5d4d5ea commit c554433

15 files changed

+718
-321
lines changed

clang/include/clang/CConv/ABounds.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,13 @@ class ABounds {
4444
virtual ~ABounds() { }
4545

4646
virtual std::string mkString(AVarBoundsInfo *) = 0;
47-
virtual bool areSame(ABounds *) = 0;
47+
virtual bool areSame(ABounds *, AVarBoundsInfo *) = 0;
4848
virtual BoundsKey getBKey() = 0;
4949
virtual ABounds* makeCopy(BoundsKey NK) = 0;
5050

5151
// Set that maintains all the bound keys that are used inin
52+
// TODO: Is this still needed?
5253
static std::set<BoundsKey> KeysUsedInBounds;
53-
5454
static bool isKeyUsedInBounds(BoundsKey ToCheck);
5555

5656
static ABounds *getBoundsInfo(AVarBoundsInfo *AVBInfo,
@@ -66,7 +66,7 @@ class CountBound : public ABounds {
6666
virtual ~CountBound() { }
6767

6868
std::string mkString(AVarBoundsInfo *ABI) override ;
69-
bool areSame(ABounds *O) override;
69+
bool areSame(ABounds *O, AVarBoundsInfo *ABI) override;
7070
BoundsKey getBKey() override;
7171
ABounds* makeCopy(BoundsKey NK) override;
7272

@@ -88,7 +88,7 @@ class ByteBound : public ABounds {
8888
virtual ~ByteBound() { }
8989

9090
std::string mkString(AVarBoundsInfo *ABI) override ;
91-
bool areSame(ABounds *O) override;
91+
bool areSame(ABounds *O, AVarBoundsInfo *ABI) override;
9292
BoundsKey getBKey() override;
9393
ABounds* makeCopy(BoundsKey NK) override;
9494

@@ -111,7 +111,7 @@ class RangeBound : public ABounds {
111111
virtual ~RangeBound() { }
112112

113113
std::string mkString(AVarBoundsInfo *ABI) override ;
114-
bool areSame(ABounds *O) override;
114+
bool areSame(ABounds *O, AVarBoundsInfo *ABI) override;
115115

116116
BoundsKey getBKey() override {
117117
assert (false && "Not implemented.");

clang/include/clang/CConv/AVarBoundsInfo.h

Lines changed: 58 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -89,40 +89,69 @@ enum BoundsPriority {
8989
};
9090

9191
class AVarBoundsInfo;
92-
92+
typedef std::map<ABounds::BoundsKind, std::set<BoundsKey>> BndsKindMap;
9393
// The main class that handles figuring out bounds of arr variables.
9494
class AvarBoundsInference {
9595
public:
96-
AvarBoundsInference(AVarBoundsInfo *BoundsInfo) : BI(BoundsInfo) { }
96+
AvarBoundsInference(AVarBoundsInfo *BoundsInfo) : BI(BoundsInfo) {
97+
clearInferredBounds();
98+
}
99+
100+
// Clear all possible inferred bounds for all the BoundsKeys
101+
void clearInferredBounds() {
102+
CurrIterInferBounds.clear();
103+
BKsFailedFlowInference.clear();
104+
}
97105

98106
// Infer bounds for the given key from the set of given ARR atoms.
99107
// The flag FromPB requests the inference to use potential length variables.
100108
bool inferBounds(BoundsKey K, AVarGraph &BKGraph, bool FromPB = false);
109+
110+
// Get a consistent bound for all the arrays whose bounds have been
111+
// inferred.
112+
bool convergeInferredBounds();
101113
private:
102-
bool inferPossibleBounds(BoundsKey K, ABounds *SB,
103-
AVarGraph &BKGraph,
104-
std::set<ABounds *> &EB);
114+
// Find all the reachable variables form FromVarK that are visible
115+
// in DstScope
116+
bool getReachableBoundKeys(const ProgramVarScope *DstScope,
117+
BoundsKey FromVarK,
118+
std::set<BoundsKey> &PotK,
119+
AVarGraph &BKGraph,
120+
bool CheckImmediate = false);
105121

106122
bool intersectBounds(std::set<ProgramVar *> &ProgVars,
107123
ABounds::BoundsKind BK,
108124
std::set<ABounds *> &CurrB);
109125

110-
bool getRelevantBounds(std::set<BoundsKey> &RBKeys,
111-
std::set<ABounds *> &ResBounds);
126+
// Check if bounds specified by Bnds are declared bounds of K.
127+
bool areDeclaredBounds(BoundsKey K,
128+
const std::pair<ABounds::BoundsKind,
129+
std::set<BoundsKey>> &Bnds);
112130

113-
bool predictBounds(BoundsKey K, std::set<BoundsKey> &Neighbours,
114-
AVarGraph &BKGraph,
115-
ABounds **KB);
131+
// Get all the bounds of the given array i.e., BK
132+
bool getRelevantBounds(BoundsKey BK,
133+
BndsKindMap &ResBounds);
116134

135+
// Predict possible bounds for DstArrK from the bounds of Neighbours.
136+
// Return true if there is any change in the captured bounds information.
137+
bool predictBounds(BoundsKey DstArrK, std::set<BoundsKey> &Neighbours,
138+
AVarGraph &BKGraph);
117139

118-
void mergeReachableProgramVars(std::set<ProgramVar *> &AllVars);
140+
141+
void mergeReachableProgramVars(std::set<BoundsKey> &AllVars);
119142

120143
AVarBoundsInfo *BI;
144+
145+
// Potential Bounds for each bounds key inferred for the current iteration.
146+
std::map<BoundsKey, BndsKindMap> CurrIterInferBounds;
147+
// BoundsKey that failed the flow inference.
148+
std::set<BoundsKey> BKsFailedFlowInference;
121149
};
122150

123151
class AVarBoundsInfo {
124152
public:
125-
AVarBoundsInfo() : ProgVarGraph(this), CtxSensProgVarGraph(this) {
153+
AVarBoundsInfo() : ProgVarGraph(this), CtxSensProgVarGraph(this),
154+
RevCtxSensProgVarGraph(this) {
126155
BCount = 1;
127156
PVarInfo.clear();
128157
InProgramArrPtrBoundsKeys.clear();
@@ -163,6 +192,7 @@ class AVarBoundsInfo {
163192
BoundsKey getVariable(clang::FieldDecl *FD);
164193
BoundsKey getVariable(clang::FunctionDecl *FD);
165194
BoundsKey getConstKey(uint64_t value);
195+
bool fetchAllConstKeys(uint64_t value, std::set<BoundsKey> &AllKeys);
166196

167197
// Generate a random bounds key to be used for inference.
168198
BoundsKey getRandomBKey();
@@ -227,6 +257,8 @@ class AVarBoundsInfo {
227257
const CVarSet &SrcCVarSet,
228258
bool JsonFormat = false) const;
229259

260+
bool areSameProgramVar(BoundsKey B1, BoundsKey B2);
261+
230262
private:
231263
friend class AvarBoundsInference;
232264

@@ -238,8 +270,8 @@ class AVarBoundsInfo {
238270
BoundsKey BCount;
239271
// Map of VarKeys and corresponding program variables.
240272
std::map<BoundsKey, ProgramVar *> PVarInfo;
241-
// Map of APSInt (constants) and corresponding VarKeys.
242-
std::map<uint64_t, BoundsKey> ConstVarKeys;
273+
// Map of APSInt (constants) and set of BoundKeys that correspond to it.
274+
std::map<uint64_t, std::set<BoundsKey>> ConstVarKeys;
243275
// Map of BoundsKey and corresponding prioritized bounds information.
244276
// Note that although each PSL could have multiple ConstraintKeys Ex: **p.
245277
// Only the outer most pointer can have bounds.
@@ -272,9 +304,11 @@ class AVarBoundsInfo {
272304

273305
// Graph of all program variables.
274306
AVarGraph ProgVarGraph;
275-
// Graph that contains only edges between context-sensitive
276-
// BoundsKey and corresponding original BoundsKey.
307+
// Graph that contains only edges from normal BoundsKey to
308+
// context-sensitive BoundsKey.
277309
AVarGraph CtxSensProgVarGraph;
310+
// Same as above but in the reverse direction.
311+
AVarGraph RevCtxSensProgVarGraph;
278312
// Stats on techniques used to find length for various variables.
279313
AVarBoundsStats BoundsInferStats;
280314
// This is the map of pointer variable bounds key and set of bounds key
@@ -305,19 +339,22 @@ class AVarBoundsInfo {
305339
// Check if the provided bounds key corresponds to function return.
306340
bool isFunctionReturn(BoundsKey BK);
307341

308-
// Of all teh pointer bounds key, find arr pointers.
342+
// Of all the pointer bounds key, find arr pointers.
309343
void computerArrPointers(ProgramInfo *PI, std::set<BoundsKey> &Ret);
310344

345+
// Get all the array pointers that need bounds.
346+
void getBoundsNeededArrPointers(const std::set<BoundsKey> &ArrPtrs,
347+
std::set<BoundsKey> &AB);
348+
311349
// Keep only highest priority bounds for all the provided BoundsKeys
312350
// returns true if any thing changed, else false.
313351
bool keepHighestPriorityBounds(std::set<BoundsKey> &ArrPtrs);
314352

315353
// Perform worklist based inference on the requested array variables using
316-
// the provided graph.
317-
// The flag FromPB requests the algorithm to use potential length variables.
318-
bool performWorkListInference(std::set<BoundsKey> &ArrNeededBounds,
354+
// the provided graph and potential length variables.
355+
bool performWorkListInference(const std::set<BoundsKey> &ArrNeededBounds,
319356
AVarGraph &BKGraph,
320-
bool FromPB = false);
357+
AvarBoundsInference &BI);
321358

322359
void insertParamKey(ParamDeclType ParamDecl, BoundsKey NK);
323360
};

clang/include/clang/CConv/ArrayBoundsInferenceConsumer.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,15 @@
2222
class LocalVarABVisitor;
2323
class ConstraintResolver;
2424

25+
class AllocBasedBoundsInference : public ASTConsumer {
26+
public:
27+
explicit AllocBasedBoundsInference(ProgramInfo &I, clang::ASTContext *C) : Info(I) { }
28+
virtual void HandleTranslationUnit(ASTContext &Context);
29+
30+
private:
31+
ProgramInfo &Info;
32+
};
33+
2534
// This class handles determining bounds of global array variables.
2635
// i.e., function parameters, structure fields and global variables.
2736
class GlobalABVisitor: public clang::RecursiveASTVisitor<GlobalABVisitor> {
@@ -96,7 +105,8 @@ class LengthVarInference : public StmtVisitor<LengthVarInference> {
96105
std::unique_ptr<CFG> Cfg;
97106
};
98107

99-
void HandleArrayVariablesBoundsDetection(ASTContext *C, ProgramInfo &I);
108+
void HandleArrayVariablesBoundsDetection(ASTContext *C, ProgramInfo &I,
109+
bool UseHeuristics = true);
100110

101111
// Add constraints based on heuristics to the parameters of the
102112
// provided function.

clang/include/clang/CConv/ConstraintsGraph.h

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ class DataGraph :
114114
N = nullptr;
115115
}
116116
this->Nodes.clear();
117+
invalidateBFSCache();
117118
}
118119

119120
void removeEdge(Data Src, Data Dst) {
@@ -126,12 +127,14 @@ class DataGraph :
126127
(*NDst)->removeEdge(*E);
127128
delete E;
128129
}
130+
invalidateBFSCache();
129131
}
130132

131133
void addEdge(Data L, Data R) {
132134
NodeType *BL = this->findOrCreateNode(L);
133135
NodeType *BR = this->findOrCreateNode(R);
134136
BL->connectTo(*BR);
137+
invalidateBFSCache();
135138
}
136139

137140
bool getNeighbors(Data D, std::set<Data> &DataSet, bool Succ){
@@ -161,8 +164,16 @@ class DataGraph :
161164
auto *N = this->findNode(NodeType(Start));
162165
if (N == this->end())
163166
return;
164-
for (auto TNode : llvm::breadth_first(*N))
165-
Fn(TNode->getData());
167+
// Insert into BFS cache.
168+
if (BFSCache.find(Start) == BFSCache.end()) {
169+
std::set<Data> ReachableNodes;
170+
for (auto TNode : llvm::breadth_first(*N)) {
171+
ReachableNodes.insert(TNode->getData());
172+
}
173+
BFSCache[Start] = ReachableNodes;
174+
}
175+
for (auto SN : BFSCache[Start])
176+
Fn(SN);
166177
}
167178

168179
protected:
@@ -183,6 +194,11 @@ class DataGraph :
183194
template <typename G>
184195
friend struct llvm::GraphTraits;
185196
friend class GraphVizOutputGraph;
197+
std::map<Data, std::set<Data>> BFSCache;
198+
199+
void invalidateBFSCache() {
200+
BFSCache.clear();
201+
}
186202
};
187203

188204
// Specialize the graph for the checked and pointer type constraint graphs. This

clang/include/clang/CConv/ProgramVar.h

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#include "clang/AST/ASTContext.h"
2020
#include "clang/CConv/PersistentSourceLoc.h"
2121

22+
// Unique ID for a program variable or constant literal, both of
23+
// which could serve as bounds
2224
typedef uint32_t BoundsKey;
2325

2426
// Class representing scope of a program variable.
@@ -27,9 +29,9 @@ class ProgramVarScope {
2729
enum ScopeKind {
2830
// Function scope.
2931
FunctionScopeKind,
30-
// Function parameter scope.
32+
// Parameters of a particular function.
3133
FunctionParamScopeKind,
32-
// Context sensitive argument scope.
34+
// All arguments to a particular call
3335
CtxFunctionArgScopeKind,
3436
// Struct scope.
3537
StructScopeKind,
@@ -215,6 +217,17 @@ class CtxFunctionArgScope : public FunctionParamScope {
215217
const PersistentSourceLoc &CtxPSL) :
216218
FunctionParamScope(FN, IsSt) {
217219
PSL = CtxPSL;
220+
std::string FileName = PSL.getFileName();
221+
CtxIDStr = "";
222+
if (!FileName.empty()) {
223+
llvm::sys::fs::UniqueID UId;
224+
if (llvm::sys::fs::getUniqueID(FileName, UId)) {
225+
CtxIDStr = std::to_string(UId.getDevice()) + ":" +
226+
std::to_string(UId.getFile()) + ":";
227+
}
228+
}
229+
CtxIDStr += std::to_string(PSL.getLineNo()) + ":" +
230+
std::to_string(PSL.getColSNo());
218231
this->Kind = CtxFunctionArgScopeKind;
219232
}
220233

@@ -261,16 +274,16 @@ class CtxFunctionArgScope : public FunctionParamScope {
261274
}
262275

263276
std::string getStr() const {
264-
return "CtxFuncArg_" + FName;
277+
return FName + "_Ctx_" + CtxIDStr;
265278
}
266279

267280
static const CtxFunctionArgScope *
268281
getCtxFunctionParamScope(const FunctionParamScope *FPS,
269282
const PersistentSourceLoc &PSL);
270283

271284
private:
272-
PersistentSourceLoc PSL;
273-
285+
PersistentSourceLoc PSL; // source code location of this function call
286+
std::string CtxIDStr;
274287
static std::set<CtxFunctionArgScope, PVSComp> AllCtxFnArgScopes;
275288
};
276289

@@ -354,7 +367,7 @@ class ProgramVar {
354367
BoundsKey K;
355368
std::string VarName;
356369
const ProgramVarScope *VScope;
357-
bool IsConstant;
370+
bool IsConstant; // is a literal integer, not a variable
358371
// TODO: All the ProgramVars may not be used. We should try to figure out
359372
// a way to free unused program vars.
360373
static std::set<ProgramVar *> AllProgramVars;

clang/include/clang/CConv/Utils.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ bool isFunctionAllocator(std::string FuncName);
124124
// Is the given variable built in type?
125125
bool isPointerType(clang::ValueDecl *VD);
126126

127+
// Is this a pointer or array type?
128+
bool isPtrOrArrayType(const clang::QualType &QT);
129+
127130
// Check if provided type is a var arg type?
128131
bool isVarArgType(const std::string &TypeName);
129132

clang/lib/CConv/ABounds.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,10 @@ std::string CountBound::mkString(AVarBoundsInfo *ABI) {
6363
return "count(" + PV->mkString() + ")";
6464
}
6565

66-
bool CountBound::areSame(ABounds *O) {
66+
bool CountBound::areSame(ABounds *O, AVarBoundsInfo *ABI) {
6767
if (O != nullptr) {
68-
if (CountBound *OT = dyn_cast<CountBound>(O)) {
69-
return OT->CountVar == CountVar;
70-
}
68+
if (CountBound *OT = dyn_cast<CountBound>(O))
69+
return ABI->areSameProgramVar(this->CountVar, OT->CountVar);
7170
}
7271
return false;
7372
}
@@ -86,10 +85,10 @@ std::string ByteBound::mkString(AVarBoundsInfo *ABI) {
8685
return "byte_count(" + PV->mkString() + ")";
8786
}
8887

89-
bool ByteBound::areSame(ABounds *O) {
88+
bool ByteBound::areSame(ABounds *O, AVarBoundsInfo *ABI) {
9089
if (O != nullptr) {
9190
if (ByteBound *BB = dyn_cast<ByteBound>(O)) {
92-
return BB->ByteVar == ByteVar;
91+
return ABI->areSameProgramVar(this->ByteVar, BB->ByteVar);
9392
}
9493
}
9594
return false;
@@ -111,10 +110,11 @@ std::string RangeBound::mkString(AVarBoundsInfo *ABI) {
111110
return "bounds(" + LBVar->mkString() + ", " + UBVar->mkString() + ")";
112111
}
113112

114-
bool RangeBound::areSame(ABounds *O) {
113+
bool RangeBound::areSame(ABounds *O, AVarBoundsInfo *ABI) {
115114
if (O != nullptr) {
116115
if (RangeBound *RB = dyn_cast<RangeBound>(O)) {
117-
return RB->LB == LB && RB->UB == UB;
116+
return ABI->areSameProgramVar(this->LB, RB->LB) &&
117+
ABI->areSameProgramVar(this->UB, RB->UB);
118118
}
119119
}
120120
return false;

0 commit comments

Comments
 (0)