Skip to content

Commit 978431e

Browse files
author
Gabor Marton
committed
[Analyzer] SValBuilder: Simlify a SymExpr to the absolute simplest form
Move the SymExpr simplification fixpoint logic into SValBuilder. Differential Revision: https://reviews.llvm.org/D114938
1 parent fc3a260 commit 978431e

File tree

2 files changed

+43
-40
lines changed

2 files changed

+43
-40
lines changed

clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2191,42 +2191,6 @@ LLVM_NODISCARD ProgramStateRef reAssume(ProgramStateRef State,
21912191
Constraint->getMaxValue(), true);
21922192
}
21932193

2194-
// Simplify the given symbol with the help of the SValBuilder. In
2195-
// SValBuilder::symplifySval, we traverse the symbol tree and query the
2196-
// constraint values for the sub-trees and if a value is a constant we do the
2197-
// constant folding. Compound symbols might collapse to simpler symbol tree
2198-
// that is still possible to further simplify. Thus, we do the simplification on
2199-
// a new symbol tree until we reach the simplest form, i.e. the fixpoint.
2200-
//
2201-
// Consider the following symbol `(b * b) * b * b` which has this tree:
2202-
// *
2203-
// / \
2204-
// * b
2205-
// / \
2206-
// / b
2207-
// (b * b)
2208-
// Now, if the `b * b == 1` new constraint is added then during the first
2209-
// iteration we have the following transformations:
2210-
// * *
2211-
// / \ / \
2212-
// * b --> b b
2213-
// / \
2214-
// / b
2215-
// 1
2216-
// We need another iteration to reach the final result `1`.
2217-
LLVM_NODISCARD
2218-
static SVal simplifyUntilFixpoint(SValBuilder &SVB, ProgramStateRef State,
2219-
const SymbolRef Sym) {
2220-
SVal Val = SVB.makeSymbolVal(Sym);
2221-
SVal SimplifiedVal = SVB.simplifySVal(State, Val);
2222-
// Do the simplification until we can.
2223-
while (SimplifiedVal != Val) {
2224-
Val = SimplifiedVal;
2225-
SimplifiedVal = SVB.simplifySVal(State, Val);
2226-
}
2227-
return SimplifiedVal;
2228-
}
2229-
22302194
// Iterate over all symbols and try to simplify them. Once a symbol is
22312195
// simplified then we check if we can merge the simplified symbol's equivalence
22322196
// class to this class. This way, we simplify not just the symbols but the
@@ -2238,8 +2202,7 @@ EquivalenceClass::simplify(SValBuilder &SVB, RangeSet::Factory &F,
22382202
SymbolSet ClassMembers = Class.getClassMembers(State);
22392203
for (const SymbolRef &MemberSym : ClassMembers) {
22402204

2241-
const SVal SimplifiedMemberVal =
2242-
simplifyUntilFixpoint(SVB, State, MemberSym);
2205+
const SVal SimplifiedMemberVal = simplifyToSVal(State, MemberSym);
22432206
const SymbolRef SimplifiedMemberSym = SimplifiedMemberVal.getAsSymbol();
22442207

22452208
// The symbol is collapsed to a constant, check if the current State is

clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,35 @@ using namespace ento;
2121

2222
namespace {
2323
class SimpleSValBuilder : public SValBuilder {
24+
25+
// With one `simplifySValOnce` call, a compound symbols might collapse to
26+
// simpler symbol tree that is still possible to further simplify. Thus, we
27+
// do the simplification on a new symbol tree until we reach the simplest
28+
// form, i.e. the fixpoint.
29+
// Consider the following symbol `(b * b) * b * b` which has this tree:
30+
// *
31+
// / \
32+
// * b
33+
// / \
34+
// / b
35+
// (b * b)
36+
// Now, if the `b * b == 1` new constraint is added then during the first
37+
// iteration we have the following transformations:
38+
// * *
39+
// / \ / \
40+
// * b --> b b
41+
// / \
42+
// / b
43+
// 1
44+
// We need another iteration to reach the final result `1`.
45+
SVal simplifyUntilFixpoint(ProgramStateRef State, SVal Val);
46+
47+
// Recursively descends into symbolic expressions and replaces symbols
48+
// with their known values (in the sense of the getKnownValue() method).
49+
// We traverse the symbol tree and query the constraint values for the
50+
// sub-trees and if a value is a constant we do the constant folding.
51+
SVal simplifySValOnce(ProgramStateRef State, SVal V);
52+
2453
public:
2554
SimpleSValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context,
2655
ProgramStateManager &stateMgr)
@@ -40,8 +69,6 @@ class SimpleSValBuilder : public SValBuilder {
4069
/// (integer) value, that value is returned. Otherwise, returns NULL.
4170
const llvm::APSInt *getKnownValue(ProgramStateRef state, SVal V) override;
4271

43-
/// Recursively descends into symbolic expressions and replaces symbols
44-
/// with their known values (in the sense of the getKnownValue() method).
4572
SVal simplifySVal(ProgramStateRef State, SVal V) override;
4673

4774
SVal MakeSymIntVal(const SymExpr *LHS, BinaryOperator::Opcode op,
@@ -1105,7 +1132,20 @@ const llvm::APSInt *SimpleSValBuilder::getKnownValue(ProgramStateRef state,
11051132
return nullptr;
11061133
}
11071134

1135+
SVal SimpleSValBuilder::simplifyUntilFixpoint(ProgramStateRef State, SVal Val) {
1136+
SVal SimplifiedVal = simplifySValOnce(State, Val);
1137+
while (SimplifiedVal != Val) {
1138+
Val = SimplifiedVal;
1139+
SimplifiedVal = simplifySValOnce(State, Val);
1140+
}
1141+
return SimplifiedVal;
1142+
}
1143+
11081144
SVal SimpleSValBuilder::simplifySVal(ProgramStateRef State, SVal V) {
1145+
return simplifyUntilFixpoint(State, V);
1146+
}
1147+
1148+
SVal SimpleSValBuilder::simplifySValOnce(ProgramStateRef State, SVal V) {
11091149
// For now, this function tries to constant-fold symbols inside a
11101150
// nonloc::SymbolVal, and does nothing else. More simplifications should
11111151
// be possible, such as constant-folding an index in an ElementRegion.

0 commit comments

Comments
 (0)