aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
diff options
context:
space:
mode:
authorSam McCall <sam.mccall@gmail.com>2023-06-22 21:54:52 +0200
committerSam McCall <sam.mccall@gmail.com>2023-06-26 21:16:25 +0200
commitd85c233e4b05497a6d8c6e3f2a5fd63d9eeb200d (patch)
tree1d15f29816f0478e3d56c6d1d30baebf0fdcab01 /clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
parentc32c0e14d6944d6a0e36191d7b5bf6943f96092e (diff)
downloadllvm-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.cpp30
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 *