diff options
author | Sam McCall <sam.mccall@gmail.com> | 2023-06-22 21:54:52 +0200 |
---|---|---|
committer | Sam McCall <sam.mccall@gmail.com> | 2023-06-26 21:16:25 +0200 |
commit | d85c233e4b05497a6d8c6e3f2a5fd63d9eeb200d (patch) | |
tree | 1d15f29816f0478e3d56c6d1d30baebf0fdcab01 /clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp | |
parent | c32c0e14d6944d6a0e36191d7b5bf6943f96092e (diff) | |
download | llvm-d85c233e4b05497a6d8c6e3f2a5fd63d9eeb200d.zip llvm-d85c233e4b05497a6d8c6e3f2a5fd63d9eeb200d.tar.gz llvm-d85c233e4b05497a6d8c6e3f2a5fd63d9eeb200d.tar.bz2 |
[dataflow] Make SAT solver deterministic
The SAT solver imported its constraints by iterating over an unordered DenseSet.
The path taken, and ultimately the runtime, the specific solution found, and
whether it would time out or complete could depend on the iteration order.
Instead, have the caller specify an ordered collection of constraints.
If this is built in a deterministic way, the system can have deterministic
behavior.
(The main alternative is to sort the constraints by value, but this option
is simpler today).
A lot of nondeterminism still appears to be remain in the framework, so today
the solver's inputs themselves are not deterministic yet.
Differential Revision: https://reviews.llvm.org/D153584
Diffstat (limited to 'clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp')
-rw-r--r-- | clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp | 30 |
1 files changed, 16 insertions, 14 deletions
diff --git a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp index 27ec15a..37bcc8b 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp @@ -18,6 +18,7 @@ #include "clang/Analysis/FlowSensitive/Logger.h" #include "clang/Analysis/FlowSensitive/Value.h" #include "llvm/ADT/SetOperations.h" +#include "llvm/ADT/SetVector.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FileSystem.h" @@ -125,11 +126,10 @@ DataflowAnalysisContext::joinFlowConditions(AtomicBoolValue &FirstToken, } Solver::Result -DataflowAnalysisContext::querySolver(llvm::DenseSet<BoolValue *> Constraints) { +DataflowAnalysisContext::querySolver(llvm::SetVector<BoolValue *> Constraints) { Constraints.insert(&arena().makeLiteral(true)); - Constraints.insert( - &arena().makeNot(arena().makeLiteral(false))); - return S->solve(std::move(Constraints)); + Constraints.insert(&arena().makeNot(arena().makeLiteral(false))); + return S->solve(Constraints.getArrayRef()); } bool DataflowAnalysisContext::flowConditionImplies(AtomicBoolValue &Token, @@ -139,8 +139,9 @@ bool DataflowAnalysisContext::flowConditionImplies(AtomicBoolValue &Token, // reducing the problem to satisfiability checking. In other words, we attempt // to show that assuming `Val` is false makes the constraints induced by the // flow condition unsatisfiable. - llvm::DenseSet<BoolValue *> Constraints = {&Token, - &arena().makeNot(Val)}; + llvm::SetVector<BoolValue *> Constraints; + Constraints.insert(&Token); + Constraints.insert(&arena().makeNot(Val)); llvm::DenseSet<AtomicBoolValue *> VisitedTokens; addTransitiveFlowConditionConstraints(Token, Constraints, VisitedTokens); return isUnsatisfiable(std::move(Constraints)); @@ -149,8 +150,8 @@ bool DataflowAnalysisContext::flowConditionImplies(AtomicBoolValue &Token, bool DataflowAnalysisContext::flowConditionIsTautology(AtomicBoolValue &Token) { // Returns true if and only if we cannot prove that the flow condition can // ever be false. - llvm::DenseSet<BoolValue *> Constraints = { - &arena().makeNot(Token)}; + llvm::SetVector<BoolValue *> Constraints; + Constraints.insert(&arena().makeNot(Token)); llvm::DenseSet<AtomicBoolValue *> VisitedTokens; addTransitiveFlowConditionConstraints(Token, Constraints, VisitedTokens); return isUnsatisfiable(std::move(Constraints)); @@ -158,13 +159,13 @@ bool DataflowAnalysisContext::flowConditionIsTautology(AtomicBoolValue &Token) { bool DataflowAnalysisContext::equivalentBoolValues(BoolValue &Val1, BoolValue &Val2) { - llvm::DenseSet<BoolValue *> Constraints = { - &arena().makeNot(arena().makeEquals(Val1, Val2))}; - return isUnsatisfiable(Constraints); + llvm::SetVector<BoolValue*> Constraints; + Constraints.insert(&arena().makeNot(arena().makeEquals(Val1, Val2))); + return isUnsatisfiable(std::move(Constraints)); } void DataflowAnalysisContext::addTransitiveFlowConditionConstraints( - AtomicBoolValue &Token, llvm::DenseSet<BoolValue *> &Constraints, + AtomicBoolValue &Token, llvm::SetVector<BoolValue *> &Constraints, llvm::DenseSet<AtomicBoolValue *> &VisitedTokens) { auto Res = VisitedTokens.insert(&Token); if (!Res.second) @@ -190,14 +191,15 @@ void DataflowAnalysisContext::addTransitiveFlowConditionConstraints( void DataflowAnalysisContext::dumpFlowCondition(AtomicBoolValue &Token, llvm::raw_ostream &OS) { - llvm::DenseSet<BoolValue *> Constraints = {&Token}; + llvm::SetVector<BoolValue *> Constraints; + Constraints.insert(&Token); llvm::DenseSet<AtomicBoolValue *> VisitedTokens; addTransitiveFlowConditionConstraints(Token, Constraints, VisitedTokens); llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames = { {&arena().makeLiteral(false), "False"}, {&arena().makeLiteral(true), "True"}}; - OS << debugString(Constraints, AtomNames); + OS << debugString(Constraints.getArrayRef(), AtomNames); } const ControlFlowContext * |