From d85c233e4b05497a6d8c6e3f2a5fd63d9eeb200d Mon Sep 17 00:00:00 2001 From: Sam McCall Date: Thu, 22 Jun 2023 21:54:52 +0200 Subject: [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 --- .../FlowSensitive/DataflowAnalysisContext.cpp | 30 ++++++++++++---------- 1 file changed, 16 insertions(+), 14 deletions(-) (limited to 'clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp') 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 Constraints) { +DataflowAnalysisContext::querySolver(llvm::SetVector 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 Constraints = {&Token, - &arena().makeNot(Val)}; + llvm::SetVector Constraints; + Constraints.insert(&Token); + Constraints.insert(&arena().makeNot(Val)); llvm::DenseSet 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 Constraints = { - &arena().makeNot(Token)}; + llvm::SetVector Constraints; + Constraints.insert(&arena().makeNot(Token)); llvm::DenseSet 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 Constraints = { - &arena().makeNot(arena().makeEquals(Val1, Val2))}; - return isUnsatisfiable(Constraints); + llvm::SetVector Constraints; + Constraints.insert(&arena().makeNot(arena().makeEquals(Val1, Val2))); + return isUnsatisfiable(std::move(Constraints)); } void DataflowAnalysisContext::addTransitiveFlowConditionConstraints( - AtomicBoolValue &Token, llvm::DenseSet &Constraints, + AtomicBoolValue &Token, llvm::SetVector &Constraints, llvm::DenseSet &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 Constraints = {&Token}; + llvm::SetVector Constraints; + Constraints.insert(&Token); llvm::DenseSet VisitedTokens; addTransitiveFlowConditionConstraints(Token, Constraints, VisitedTokens); llvm::DenseMap AtomNames = { {&arena().makeLiteral(false), "False"}, {&arena().makeLiteral(true), "True"}}; - OS << debugString(Constraints, AtomNames); + OS << debugString(Constraints.getArrayRef(), AtomNames); } const ControlFlowContext * -- cgit v1.1