aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
diff options
context:
space:
mode:
authorYitzhak Mandelbaum <ymand@users.noreply.github.com>2025-08-18 11:55:12 -0400
committerGitHub <noreply@github.com>2025-08-18 11:55:12 -0400
commit3ecfc0330d93a6c3a3f3d3e427390b01cb52a88d (patch)
tree44ee278359ea2f7d58920b031deb30221cf42b2d /clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
parentc67d27dad02ab7debfff6c7f7fc3ea8abf064b6a (diff)
downloadllvm-3ecfc0330d93a6c3a3f3d3e427390b01cb52a88d.zip
llvm-3ecfc0330d93a6c3a3f3d3e427390b01cb52a88d.tar.gz
llvm-3ecfc0330d93a6c3a3f3d3e427390b01cb52a88d.tar.bz2
[clang][dataflow] Add support for serialization and deserialization. (#152487)
Adds support for compact serialization of Formulas, and a corresponding parse function. Extends Environment and AnalysisContext with necessary functions for serializing and deserializing all formula-related parts of the environment.
Diffstat (limited to 'clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp')
-rw-r--r--clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp79
1 files changed, 79 insertions, 0 deletions
diff --git a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
index 6421ad3..06a8878 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
@@ -208,6 +208,24 @@ bool DataflowAnalysisContext::equivalentFormulas(const Formula &Val1,
return isUnsatisfiable(std::move(Constraints));
}
+llvm::DenseSet<Atom> DataflowAnalysisContext::collectDependencies(
+ llvm::DenseSet<Atom> Tokens) const {
+ // Use a worklist algorithm, with `Remaining` holding the worklist and
+ // `Tokens` tracking which atoms have already been added to the worklist.
+ std::vector<Atom> Remaining(Tokens.begin(), Tokens.end());
+ while (!Remaining.empty()) {
+ Atom CurrentToken = Remaining.back();
+ Remaining.pop_back();
+ if (auto DepsIt = FlowConditionDeps.find(CurrentToken);
+ DepsIt != FlowConditionDeps.end())
+ for (Atom A : DepsIt->second)
+ if (Tokens.insert(A).second)
+ Remaining.push_back(A);
+ }
+
+ return Tokens;
+}
+
void DataflowAnalysisContext::addTransitiveFlowConditionConstraints(
Atom Token, llvm::SetVector<const Formula *> &Constraints) {
llvm::DenseSet<Atom> AddedTokens;
@@ -224,6 +242,8 @@ void DataflowAnalysisContext::addTransitiveFlowConditionConstraints(
auto ConstraintsIt = FlowConditionConstraints.find(Token);
if (ConstraintsIt == FlowConditionConstraints.end()) {
+ // The flow condition is unconstrained. Just add the atom directly, which
+ // is equivalent to asserting it is true.
Constraints.insert(&arena().makeAtomRef(Token));
} else {
// Bind flow condition token via `iff` to its set of constraints:
@@ -239,6 +259,65 @@ void DataflowAnalysisContext::addTransitiveFlowConditionConstraints(
}
}
+static void getReferencedAtoms(const Formula &F,
+ llvm::DenseSet<dataflow::Atom> &Refs) {
+ switch (F.kind()) {
+ case Formula::AtomRef:
+ Refs.insert(F.getAtom());
+ break;
+ case Formula::Literal:
+ break;
+ case Formula::Not:
+ getReferencedAtoms(*F.operands()[0], Refs);
+ break;
+ case Formula::And:
+ case Formula::Or:
+ case Formula::Implies:
+ case Formula::Equal:
+ ArrayRef<const Formula *> Operands = F.operands();
+ getReferencedAtoms(*Operands[0], Refs);
+ getReferencedAtoms(*Operands[1], Refs);
+ break;
+ }
+}
+
+SimpleLogicalContext DataflowAnalysisContext::exportLogicalContext(
+ llvm::DenseSet<dataflow::Atom> TargetTokens) const {
+ SimpleLogicalContext LC;
+
+ if (Invariant != nullptr) {
+ LC.Invariant = Invariant;
+ getReferencedAtoms(*Invariant, TargetTokens);
+ }
+
+ llvm::DenseSet<dataflow::Atom> Dependencies =
+ collectDependencies(std::move(TargetTokens));
+
+ for (dataflow::Atom Token : Dependencies) {
+ // Only process the token if it is constrained. Unconstrained tokens don't
+ // have dependencies.
+ const Formula *Constraints = FlowConditionConstraints.lookup(Token);
+ if (Constraints == nullptr)
+ continue;
+ LC.TokenDefs[Token] = Constraints;
+
+ if (auto DepsIt = FlowConditionDeps.find(Token);
+ DepsIt != FlowConditionDeps.end())
+ LC.TokenDeps[Token] = DepsIt->second;
+ }
+
+ return LC;
+}
+
+void DataflowAnalysisContext::initLogicalContext(SimpleLogicalContext LC) {
+ Invariant = LC.Invariant;
+ FlowConditionConstraints = std::move(LC.TokenDefs);
+ // TODO: The dependencies in `LC.TokenDeps` can be reconstructed from
+ // `LC.TokenDefs`. Give the caller the option to reconstruct, rather than
+ // providing them directly, to save caller space (memory/disk).
+ FlowConditionDeps = std::move(LC.TokenDeps);
+}
+
static void printAtomList(const llvm::SmallVector<Atom> &Atoms,
llvm::raw_ostream &OS) {
OS << "(";