Skip to content

Commit f9d1cbb

Browse files
Collection of code cleanup changes made to bounds inference (#650)
* Cleanup ScopeVisitor: - Better naming for fields - Make references to AVarBoundsInfo fields constant - Expose result of visitor through constant set reference instead of by mutating sets passed as arguments. - Remove loop of singleton set. * Cleanup getReachableBoundKeys - Rename SBVar -> FromProgramVar - Get rid of unnecessary set in constant finding loop * Cleanup StructAccessVisitor - Make two fields private. One of these was never used publicly, the other is exposed through a getter. - Slightly simpler logic for handling variable declarations. `isLocalVarDecl` returns false for ParmVarDecls, so it's OK to update IsGlobal with the result of this function for ParmVarDecl and VarDecl. - Added note about a bug on structure access such as `( 0 ? global_struct_var : local_struct_var).array`. * Cleanup CollectDeclsVisitor - Make set fields private and expose through const reference. - Update comments * Make some methods of ConstraintsGraph const - getNeighbors, getSuccessors, getPredecessors, and findNode are trivially const. - visitBreadthFirst mutates the BFSCache map, but this acceptable because it is cache for the actual graph data, and the underlying data is not mutated. To let this method be checked `BFSCache` is explicitly qualified with mutable. * Cleanup performFlowAnalysis - Avoid re-using AvarBoundsInference instance. - Avoid re-using set in inner most inference loop - Move some code into performWorkListInference since it was always called before/after this function. * Cleanup performWorkListInference - Remove `Changed` loop variable and instead terminate outer loop when `WorkList` is empty. - Replace inner while loop with a for loop to make it clearer that it the loop is just iterating over each element of `WorkList`. * Cleanup predictBounds - Move variable declarations closer to use. - Declare variables with explicit types where this helps me understand the code. - Add some comments. * Cleanup inferFromPotentialBounds - rename Handled to HasInferredBound - Use llvm::any_of instead of loop * Cleanup computeArrPointers - Avoid duplicating code in main for loop - Add comment expressing concern about special-casing on return-type null terminated arrays. - Delete some intermediate sets that didn't need to exist. * Delete commented out method tryGetBoundsKeyVar - A nearly identical un-commented version of this method still exists. The only difference is that getVariable is used to get a ConstraintVariable instead of getExprConstraintVars. * Cleanup handleAllocatorCall - remove unused Fname parameter from isAllocatorCall - getCalledFunctionName can only be called on CallExprs, so the type of its parameter can be changed from Expr to CallExpr. - Introduce function hasValidBoundsKey that can be used instead of calling tryGetValidBoundsKey with unused BoundsKey reference. * Cleanup LocalVarABVisitor - Rename addUsedParmVarDecl -> addNonLengthParameter - Delete some unused local variables - Add a comment about some odd code * Cleanup ComparisonVisitor - Fix typo in class name - Remove unused field - Expose result through const reference to field instead of mutating constructor argument. * Cleanup LengthVarInference - Remove unused fields - Avoid needing to `new` and `delete` some fields. * Add some array bounds debugging utilities - Dump context sensitive and reverse context sensitive graphs in addition to standard graph. - Add dumpBounds method to write current bounds solution state to standard error. This can be called from the debugger while stepping through execution. * ProgramVar cleanup - Store constant value of variable explicitly - Assertions to check that non-constant variable is not used as constant
1 parent 50e0a25 commit f9d1cbb

14 files changed

+550
-602
lines changed

clang/include/clang/3C/AVarBoundsInfo.h

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -106,31 +106,31 @@ class AvarBoundsInference {
106106

107107
// Infer bounds for the given key from the set of given ARR atoms.
108108
// The flag FromPB requests the inference to use potential length variables.
109-
bool inferBounds(BoundsKey K, AVarGraph &BKGraph, bool FromPB = false);
109+
bool inferBounds(BoundsKey K, const AVarGraph &BKGraph, bool FromPB = false);
110110

111-
// Get a consistent bound for all the arrays whose bounds have been
112-
// inferred.
113-
bool convergeInferredBounds();
111+
// Get a consistent bound for all the arrays whose bounds have been inferred.
112+
void convergeInferredBounds();
114113

115114
private:
116115
// Find all the reachable variables form FromVarK that are visible
117116
// in DstScope
118117
bool getReachableBoundKeys(const ProgramVarScope *DstScope,
119118
BoundsKey FromVarK, std::set<BoundsKey> &PotK,
120-
AVarGraph &BKGraph, bool CheckImmediate = false);
119+
const AVarGraph &BKGraph,
120+
bool CheckImmediate = false);
121121

122122
// Check if bounds specified by Bnds are declared bounds of K.
123123
bool areDeclaredBounds(
124124
BoundsKey K,
125125
const std::pair<ABounds::BoundsKind, std::set<BoundsKey>> &Bnds);
126126

127127
// Get all the bounds of the given array i.e., BK
128-
bool getRelevantBounds(BoundsKey BK, BndsKindMap &ResBounds);
128+
void getRelevantBounds(BoundsKey BK, BndsKindMap &ResBounds);
129129

130130
// Predict possible bounds for DstArrK from the bounds of Neighbours.
131131
// Return true if there is any change in the captured bounds information.
132-
bool predictBounds(BoundsKey DstArrK, std::set<BoundsKey> &Neighbours,
133-
AVarGraph &BKGraph);
132+
bool predictBounds(BoundsKey DstArrK, const std::set<BoundsKey> &Neighbours,
133+
const AVarGraph &BKGraph);
134134

135135
void mergeReachableProgramVars(BoundsKey TarBK, std::set<BoundsKey> &AllVars);
136136

@@ -139,14 +139,16 @@ class AvarBoundsInference {
139139
// Set the given pointer to have impossible bounds.
140140
void setImpossibleBounds(BoundsKey BK);
141141
// Infer bounds of the given pointer key from potential bounds.
142-
bool inferFromPotentialBounds(BoundsKey BK, AVarGraph &BKGraph);
142+
bool inferFromPotentialBounds(BoundsKey BK, const AVarGraph &BKGraph);
143143

144144
AVarBoundsInfo *BI;
145145

146146
// Potential Bounds for each bounds key inferred for the current iteration.
147147
std::map<BoundsKey, BndsKindMap> CurrIterInferBounds;
148148
// BoundsKey that failed the flow inference.
149149
std::set<BoundsKey> BKsFailedFlowInference;
150+
151+
static ABounds *getPreferredBound(const BndsKindMap &BKindMap);
150152
};
151153

152154
// Class that maintains information about potential bounds for
@@ -255,7 +257,7 @@ class AVarBoundsInfo {
255257
ProgramVar *getProgramVar(BoundsKey VK);
256258

257259
// Propagate the array bounds information for all array ptrs.
258-
bool performFlowAnalysis(ProgramInfo *PI);
260+
void performFlowAnalysis(ProgramInfo *PI);
259261

260262
// Get the context sensitive BoundsKey for the given key at CallSite
261263
// located at PSL.
@@ -366,23 +368,23 @@ class AVarBoundsInfo {
366368
bool isFunctionReturn(BoundsKey BK);
367369

368370
// Of all the pointer bounds key, find arr pointers.
369-
void computerArrPointers(ProgramInfo *PI, std::set<BoundsKey> &Ret);
371+
void computeArrPointers(const ProgramInfo *PI);
370372

371373
// Get all the array pointers that need bounds.
372-
void getBoundsNeededArrPointers(const std::set<BoundsKey> &ArrPtrs,
373-
std::set<BoundsKey> &AB);
374+
void getBoundsNeededArrPointers(std::set<BoundsKey> &AB) const;
374375

375376
// Keep only highest priority bounds for all the provided BoundsKeys
376377
// returns true if any thing changed, else false.
377-
bool keepHighestPriorityBounds(std::set<BoundsKey> &ArrPtrs);
378+
bool keepHighestPriorityBounds();
378379

379380
// Perform worklist based inference on the requested array variables using
380381
// the provided graph and potential length variables.
381-
bool performWorkListInference(const std::set<BoundsKey> &ArrNeededBounds,
382-
AVarGraph &BKGraph, AvarBoundsInference &BI,
383-
bool FromPB);
382+
void performWorkListInference(const AVarGraph &BKGraph,
383+
AvarBoundsInference &BI, bool FromPB);
384384

385385
void insertParamKey(ParamDeclType ParamDecl, BoundsKey NK);
386+
387+
void dumpBounds();
386388
};
387389

388390
#endif // LLVM_CLANG_3C_AVARBOUNDSINFO_H

clang/include/clang/3C/ArrayBoundsInferenceConsumer.h

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,11 @@ class LocalVarABVisitor : public clang::RecursiveASTVisitor<LocalVarABVisitor> {
6969
bool VisitSwitchStmt(SwitchStmt *S);
7070
bool VisitBinaryOperator(BinaryOperator *O);
7171
bool VisitArraySubscriptExpr(ArraySubscriptExpr *E);
72-
bool isNonLengthParameter(ParmVarDecl *PVD);
72+
bool isNonLengthParameter(ParmVarDecl *PVD) const;
7373

7474
private:
7575
void handleAssignment(BoundsKey LK, QualType LHSType, Expr *RHS);
76-
void addUsedParmVarDecl(Expr *CE);
76+
void addNonLengthParameter(Expr *CE);
7777
std::set<ParmVarDecl *> NonLengthParameters;
7878
ASTContext *Context;
7979
ProgramInfo &Info;
@@ -88,8 +88,6 @@ class LengthVarInference : public StmtVisitor<LengthVarInference> {
8888
public:
8989
LengthVarInference(ProgramInfo &In, ASTContext *AC, FunctionDecl *F);
9090

91-
virtual ~LengthVarInference();
92-
9391
void VisitStmt(Stmt *St);
9492

9593
void VisitArraySubscriptExpr(ArraySubscriptExpr *ASE);
@@ -98,11 +96,9 @@ class LengthVarInference : public StmtVisitor<LengthVarInference> {
9896
std::map<const Stmt *, CFGBlock *> StMap;
9997
ProgramInfo &I;
10098
ASTContext *C;
101-
FunctionDecl *FD;
10299
CFGBlock *CurBB;
103-
ControlDependencyCalculator *CDG;
104-
ConstraintResolver *CR;
105100
std::unique_ptr<CFG> Cfg;
101+
ControlDependencyCalculator CDG;
106102
};
107103

108104
void handleArrayVariablesBoundsDetection(ASTContext *C, ProgramInfo &I,

clang/include/clang/3C/ConstraintVariables.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ class PointerVariableConstraint : public ConstraintVariable {
412412
std::string getTy() const { return BaseType; }
413413
bool getArrPresent() const;
414414
// Check if the outermost pointer is an unsized array.
415-
bool isTopCvarUnsizedArr() const;
415+
bool isTopAtomUnsizedArr() const;
416416
// Check if any of the pointers is either a sized or unsized arr.
417417
bool hasSomeSizedArr() const;
418418

clang/include/clang/3C/Constraints.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -488,8 +488,8 @@ class Constraints {
488488
NTArrAtom *getNTArr() const;
489489
WildAtom *getWild() const;
490490
ConstAtom *getAssignment(Atom *A);
491-
ConstraintsGraph &getChkCG();
492-
ConstraintsGraph &getPtrTypCG();
491+
const ConstraintsGraph &getChkCG() const;
492+
const ConstraintsGraph &getPtrTypCG() const;
493493

494494
void resetEnvironment();
495495
bool checkInitialEnvSanity();

clang/include/clang/3C/ConstraintsGraph.h

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ class DataGraph
153153
}
154154

155155
bool getNeighbors(Data D, std::set<Data> &DataSet, bool Succ,
156-
bool Append = false, bool IgnoreSoftEdges = false) {
156+
bool Append = false, bool IgnoreSoftEdges = false) const {
157157
NodeType *N = this->findNode(D);
158158
if (N == nullptr)
159159
return false;
@@ -170,21 +170,23 @@ class DataGraph
170170
return !DataSet.empty();
171171
}
172172

173-
bool getSuccessors(Data D, std::set<Data> &DataSet, bool Append = false) {
173+
bool
174+
getSuccessors(Data D, std::set<Data> &DataSet, bool Append = false) const {
174175
return getNeighbors(D, DataSet, true, Append);
175176
}
176177

177-
bool getPredecessors(Data D, std::set<Data> &DataSet, bool Append = false) {
178+
bool
179+
getPredecessors(Data D, std::set<Data> &DataSet, bool Append = false) const {
178180
return getNeighbors(D, DataSet, false, Append);
179181
}
180182

181-
NodeType *findNode(Data D) {
183+
NodeType *findNode(Data D) const {
182184
if (NodeSet.find(D) != NodeSet.end())
183-
return NodeSet[D];
185+
return NodeSet.at(D);
184186
return nullptr;
185187
}
186188

187-
void visitBreadthFirst(Data Start, llvm::function_ref<void(Data)> Fn) {
189+
void visitBreadthFirst(Data Start, llvm::function_ref<void(Data)> Fn) const {
188190
NodeType *N = this->findNode(Start);
189191
if (N == nullptr)
190192
return;
@@ -217,7 +219,7 @@ class DataGraph
217219
private:
218220
template <typename G> friend struct llvm::GraphTraits;
219221
friend class GraphVizOutputGraph;
220-
std::map<Data, std::set<Data>> BFSCache;
222+
mutable std::map<Data, std::set<Data>> BFSCache;
221223
std::map<Data, NodeType *> NodeSet;
222224

223225
void invalidateBFSCache() { BFSCache.clear(); }

clang/include/clang/3C/ProgramInfo.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ class ProgramInfo : public ProgramVariableAdder {
134134

135135
const VariableMap &getVarMap() const { return Variables; }
136136
Constraints &getConstraints() { return CS; }
137+
const Constraints &getConstraints() const { return CS; }
137138
AVarBoundsInfo &getABoundsInfo() override { return ArrBInfo; }
138139

139140
PerformanceStats &getPerfStats() { return PerfS; }

clang/include/clang/3C/ProgramVar.h

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -406,35 +406,55 @@ class FunctionScope : public ProgramVarScope {
406406
// Class that represents a program variable along with its scope.
407407
class ProgramVar {
408408
public:
409-
const ProgramVarScope *getScope() { return VScope; }
409+
const ProgramVarScope *getScope() const { return VScope; }
410410
void setScope(const ProgramVarScope *PVS) { this->VScope = PVS; }
411-
BoundsKey getKey() { return K; }
412-
bool isNumConstant() { return IsConstant; }
413-
std::string mkString(bool GetKey = false);
414-
std::string getVarName() { return VarName; }
415-
std::string verboseStr();
416-
ProgramVar *makeCopy(BoundsKey NK);
417-
virtual ~ProgramVar() {}
411+
BoundsKey getKey() const { return K; }
412+
const std::string &getVarName() const { return VarName; }
413+
std::string verboseStr() const;
414+
ProgramVar *makeCopy(BoundsKey NK) const;
415+
416+
bool isNumConstant() const {return IsConstant; }
417+
uint64_t getConstantVal() const {
418+
assert("Can't get constant value for non-constant var." && IsConstant);
419+
return ConstantVal;
420+
}
418421

419422
static ProgramVar *createNewProgramVar(BoundsKey VK, std::string VName,
420-
const ProgramVarScope *PVS,
421-
bool IsCons = false);
423+
const ProgramVarScope *PVS);
424+
425+
static ProgramVar *createNewConstantVar(BoundsKey VK, uint64_t Value);
422426

423427
private:
424428
BoundsKey K;
425429
std::string VarName;
426430
const ProgramVarScope *VScope;
427-
bool IsConstant; // is a literal integer, not a variable
431+
432+
// Is a literal integer, not a variable.
433+
bool IsConstant;
434+
uint64_t ConstantVal;
435+
428436
// TODO: All the ProgramVars may not be used. We should try to figure out
429437
// a way to free unused program vars.
430-
static std::set<ProgramVar *> AllProgramVars;
431-
432-
ProgramVar(BoundsKey VK, std::string VName, const ProgramVarScope *PVS,
433-
bool IsCons)
434-
: K(VK), VarName(VName), VScope(PVS), IsConstant(IsCons) {}
438+
static std::set<const ProgramVar *> AllProgramVars;
439+
440+
ProgramVar(BoundsKey K, const std::string &VarName,
441+
const ProgramVarScope *VScope, bool IsConstant,
442+
uint32_t ConstantVal)
443+
: K(K), VarName(VarName), VScope(VScope), IsConstant(IsConstant),
444+
ConstantVal(ConstantVal) {
445+
// Constant variables should be a subclass of ProgramVariable. Until that
446+
// change happens this should sanity check how ProgramVars are constructed.
447+
assert("Constant value should not be set for non-constant variables." &&
448+
(IsConstant || ConstantVal == 0));
449+
AllProgramVars.insert(this);
450+
}
435451

436452
ProgramVar(BoundsKey VK, std::string VName, const ProgramVarScope *PVS)
437-
: ProgramVar(VK, VName, PVS, false) {}
453+
: ProgramVar(VK, VName, PVS, false, 0) {}
454+
455+
ProgramVar(BoundsKey VK, uint32_t CVal)
456+
: ProgramVar(VK, std::to_string(CVal), GlobalScope::getGlobalScope(), true,
457+
CVal) {}
438458
};
439459

440460
#endif // LLVM_CLANG_3C_PROGRAMVAR_H

clang/lib/3C/ABounds.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ ABounds *ABounds::getBoundsInfo(AVarBoundsInfo *ABInfo, BoundsExpr *BExpr,
3030
if (ABInfo->tryGetVariable(CBE->getCountExpr()->IgnoreParenCasts(), C,
3131
VK)) {
3232
ProgramVar *PV = ABInfo->getProgramVar(VK);
33-
if (PV->isNumConstant() && PV->getVarName() == "0") {
33+
if (PV->isNumConstant() && PV->getConstantVal() == 0) {
3434
// Invalid bounds. This is for functions like free.
3535
// Where the bounds is 0.
3636
Ret = nullptr;
@@ -60,7 +60,7 @@ std::string ABounds::getBoundsKeyStr(BoundsKey BK, AVarBoundsInfo *ABI,
6060
Decl *D) {
6161
ProgramVar *PV = ABI->getProgramVar(BK);
6262
assert(PV != nullptr && "No Valid program var");
63-
std::string BKStr = PV->mkString();
63+
std::string BKStr = PV->getVarName();
6464
unsigned PIdx = 0;
6565
auto *PVD = dyn_cast_or_null<ParmVarDecl>(D);
6666
// Does this belong to a function parameter?
@@ -74,7 +74,7 @@ std::string ABounds::getBoundsKeyStr(BoundsKey BK, AVarBoundsInfo *ABI,
7474
// If the parameter in the new declaration does not have a name?
7575
// then use the old name.
7676
if (BKStr.empty())
77-
BKStr = PV->mkString();
77+
BKStr = PV->getVarName();
7878
}
7979
}
8080
return BKStr;

0 commit comments

Comments
 (0)