aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
diff options
context:
space:
mode:
authorYitzhak Mandelbaum <ymand@users.noreply.github.com>2024-02-06 15:38:56 -0500
committerGitHub <noreply@github.com>2024-02-06 15:38:56 -0500
commit672fb27b267edc5dec4939b0295c8eebcdc57467 (patch)
tree966861ace7eb0b01df91e51156130d2bf4a4720f /clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
parent90e8dc0f7cbd09cc653b497eb2dfc68edd800f48 (diff)
downloadllvm-672fb27b267edc5dec4939b0295c8eebcdc57467.zip
llvm-672fb27b267edc5dec4939b0295c8eebcdc57467.tar.gz
llvm-672fb27b267edc5dec4939b0295c8eebcdc57467.tar.bz2
[clang][dataflow] Add new `join` API and replace existing `merge` implementations. (#80361)
This patch adds a new interface for the join operation, now properly called `join`. Originally, the framework offered a single `merge` operation, which could serve either as a join or a widening. In practice, though we found this conflation didn't work for non-trivial anlyses, and split of the widening operation (`widen`). This change completes the transition by introducing a proper `join` with strict join semantics. In the process, it drops an odd (and often misused) aspect of `merge` wherein callees could implictly instruct the framework to drop the current entry by returning `false`. This features was never used correctly in analyses and doesn't belong in a join operation, so it is omitted. --------- Co-authored-by: Dmitri Gribenko <gribozavr@gmail.com> Co-authored-by: martinboehme <mboehme@google.com>
Diffstat (limited to 'clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp')
-rw-r--r--clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp59
1 files changed, 28 insertions, 31 deletions
diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index 01db658..24811de 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -86,15 +86,15 @@ static bool compareDistinctValues(QualType Type, Value &Val1,
llvm_unreachable("All cases covered in switch");
}
-/// Attempts to merge distinct values `Val1` and `Val2` in `Env1` and `Env2`,
-/// respectively, of the same type `Type`. Merging generally produces a single
+/// Attempts to join distinct values `Val1` and `Val2` in `Env1` and `Env2`,
+/// respectively, of the same type `Type`. Joining generally produces a single
/// value that (soundly) approximates the two inputs, although the actual
/// meaning depends on `Model`.
-static Value *mergeDistinctValues(QualType Type, Value &Val1,
- const Environment &Env1, Value &Val2,
- const Environment &Env2,
- Environment &MergedEnv,
- Environment::ValueModel &Model) {
+static Value *joinDistinctValues(QualType Type, Value &Val1,
+ const Environment &Env1, Value &Val2,
+ const Environment &Env2,
+ Environment &JoinedEnv,
+ Environment::ValueModel &Model) {
// Join distinct boolean values preserving information about the constraints
// in the respective path conditions.
if (isa<BoolValue>(&Val1) && isa<BoolValue>(&Val2)) {
@@ -113,17 +113,17 @@ static Value *mergeDistinctValues(QualType Type, Value &Val1,
// ```
auto &Expr1 = cast<BoolValue>(Val1).formula();
auto &Expr2 = cast<BoolValue>(Val2).formula();
- auto &A = MergedEnv.arena();
- auto &MergedVal = A.makeAtomRef(A.makeAtom());
- MergedEnv.assume(
+ auto &A = JoinedEnv.arena();
+ auto &JoinedVal = A.makeAtomRef(A.makeAtom());
+ JoinedEnv.assume(
A.makeOr(A.makeAnd(A.makeAtomRef(Env1.getFlowConditionToken()),
- A.makeEquals(MergedVal, Expr1)),
+ A.makeEquals(JoinedVal, Expr1)),
A.makeAnd(A.makeAtomRef(Env2.getFlowConditionToken()),
- A.makeEquals(MergedVal, Expr2))));
- return &A.makeBoolValue(MergedVal);
+ A.makeEquals(JoinedVal, Expr2))));
+ return &A.makeBoolValue(JoinedVal);
}
- Value *MergedVal = nullptr;
+ Value *JoinedVal = nullptr;
if (auto *RecordVal1 = dyn_cast<RecordValue>(&Val1)) {
auto *RecordVal2 = cast<RecordValue>(&Val2);
@@ -131,24 +131,21 @@ static Value *mergeDistinctValues(QualType Type, Value &Val1,
// `RecordVal1` and `RecordVal2` may have different properties associated
// with them. Create a new `RecordValue` with the same location but
// without any properties so that we soundly approximate both values. If a
- // particular analysis needs to merge properties, it should do so in
- // `DataflowAnalysis::merge()`.
- MergedVal = &MergedEnv.create<RecordValue>(RecordVal1->getLoc());
+ // particular analysis needs to join properties, it should do so in
+ // `DataflowAnalysis::join()`.
+ JoinedVal = &JoinedEnv.create<RecordValue>(RecordVal1->getLoc());
else
// If the locations for the two records are different, need to create a
// completely new value.
- MergedVal = MergedEnv.createValue(Type);
+ JoinedVal = JoinedEnv.createValue(Type);
} else {
- MergedVal = MergedEnv.createValue(Type);
+ JoinedVal = JoinedEnv.createValue(Type);
}
- // FIXME: Consider destroying `MergedValue` immediately if `ValueModel::merge`
- // returns false to avoid storing unneeded values in `DACtx`.
- if (MergedVal)
- if (Model.merge(Type, Val1, Env1, Val2, Env2, *MergedVal, MergedEnv))
- return MergedVal;
+ if (JoinedVal)
+ Model.join(Type, Val1, Env1, Val2, Env2, *JoinedVal, JoinedEnv);
- return nullptr;
+ return JoinedVal;
}
// When widening does not change `Current`, return value will equal `&Prev`.
@@ -240,9 +237,9 @@ joinLocToVal(const llvm::MapVector<const StorageLocation *, Value *> &LocToVal,
continue;
}
- if (Value *MergedVal = mergeDistinctValues(
+ if (Value *JoinedVal = joinDistinctValues(
Loc->getType(), *Val, Env1, *It->second, Env2, JoinedEnv, Model)) {
- Result.insert({Loc, MergedVal});
+ Result.insert({Loc, JoinedVal});
}
}
@@ -657,10 +654,10 @@ Environment Environment::join(const Environment &EnvA, const Environment &EnvB,
// cast.
auto *Func = dyn_cast<FunctionDecl>(EnvA.CallStack.back());
assert(Func != nullptr);
- if (Value *MergedVal =
- mergeDistinctValues(Func->getReturnType(), *EnvA.ReturnVal, EnvA,
- *EnvB.ReturnVal, EnvB, JoinedEnv, Model))
- JoinedEnv.ReturnVal = MergedVal;
+ if (Value *JoinedVal =
+ joinDistinctValues(Func->getReturnType(), *EnvA.ReturnVal, EnvA,
+ *EnvB.ReturnVal, EnvB, JoinedEnv, Model))
+ JoinedEnv.ReturnVal = JoinedVal;
}
if (EnvA.ReturnLoc == EnvB.ReturnLoc)