diff options
author | Yitzhak Mandelbaum <ymand@users.noreply.github.com> | 2024-02-06 15:38:56 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-06 15:38:56 -0500 |
commit | 672fb27b267edc5dec4939b0295c8eebcdc57467 (patch) | |
tree | 966861ace7eb0b01df91e51156130d2bf4a4720f /clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp | |
parent | 90e8dc0f7cbd09cc653b497eb2dfc68edd800f48 (diff) | |
download | llvm-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.cpp | 59 |
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) |