Migrate the rest symbolic analysis stuff to BasicConstraintManager.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55536 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Analysis/BasicConstraintManager.cpp b/lib/Analysis/BasicConstraintManager.cpp
index efe5b93..7298d35 100644
--- a/lib/Analysis/BasicConstraintManager.cpp
+++ b/lib/Analysis/BasicConstraintManager.cpp
@@ -1,17 +1,19 @@
#include "clang/Analysis/PathSensitive/ConstraintManager.h"
#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Analysis/PathSensitive/GRStateTrait.h"
#include "llvm/Support/Compiler.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
namespace {
+typedef llvm::ImmutableMap<SymbolID,GRState::IntSetTy> ConstNotEqTy;
+typedef llvm::ImmutableMap<SymbolID,const llvm::APSInt*> ConstEqTy;
+
// BasicConstraintManager only tracks equality and inequality constraints of
// constants and integer variables.
class VISIBILITY_HIDDEN BasicConstraintManager : public ConstraintManager {
- typedef llvm::ImmutableMap<SymbolID, GRState::IntSetTy> ConstNotEqTy;
- typedef llvm::ImmutableMap<SymbolID, const llvm::APSInt*> ConstEqTy;
-
GRStateManager& StateMgr;
public:
@@ -52,7 +54,22 @@
const GRState* AssumeSymLE(const GRState* St, SymbolID sym,
const llvm::APSInt& V, bool& isFeasible);
- };
+
+ const GRState* AddEQ(const GRState* St, SymbolID sym, const llvm::APSInt& V);
+
+ const GRState* AddNE(const GRState* St, SymbolID sym, const llvm::APSInt& V);
+
+ const llvm::APSInt* getSymVal(const GRState* St, SymbolID sym);
+ bool isNotEqual(const GRState* St, SymbolID sym, const llvm::APSInt& V) const;
+ bool isEqual(const GRState* St, SymbolID sym, const llvm::APSInt& V) const;
+
+ const GRState* RemoveDeadBindings(const GRState* St,
+ StoreManager::LiveSymbolsTy& LSymbols,
+ StoreManager::DeadSymbolsTy& DSymbols);
+
+ void print(const GRState* St, std::ostream& Out,
+ const char* nl, const char *sep);
+};
} // end anonymous namespace
@@ -205,17 +222,19 @@
} // end switch
}
+
+
const GRState*
BasicConstraintManager::AssumeSymNE(const GRState* St, SymbolID sym,
const llvm::APSInt& V, bool& isFeasible) {
// First, determine if sym == X, where X != V.
- if (const llvm::APSInt* X = St->getSymVal(sym)) {
+ if (const llvm::APSInt* X = getSymVal(St, sym)) {
isFeasible = (*X != V);
return St;
}
// Second, determine if sym != V.
- if (St->isNotEqual(sym, V)) {
+ if (isNotEqual(St, sym, V)) {
isFeasible = true;
return St;
}
@@ -223,20 +242,20 @@
// If we reach here, sym is not a constant and we don't know if it is != V.
// Make that assumption.
isFeasible = true;
- return StateMgr.AddNE(St, sym, V);
+ return AddNE(St, sym, V);
}
const GRState*
BasicConstraintManager::AssumeSymEQ(const GRState* St, SymbolID sym,
const llvm::APSInt& V, bool& isFeasible) {
// First, determine if sym == X, where X != V.
- if (const llvm::APSInt* X = St->getSymVal(sym)) {
+ if (const llvm::APSInt* X = getSymVal(St, sym)) {
isFeasible = *X == V;
return St;
}
// Second, determine if sym != V.
- if (St->isNotEqual(sym, V)) {
+ if (isNotEqual(St, sym, V)) {
isFeasible = false;
return St;
}
@@ -245,7 +264,7 @@
// Make that assumption.
isFeasible = true;
- return StateMgr.AddEQ(St, sym, V);
+ return AddEQ(St, sym, V);
}
// These logic will be handled in another ConstraintManager.
@@ -272,7 +291,7 @@
// FIXME: Primitive logic for now. Only reject a path if the value of
// sym is a constant X and !(X >= V).
- if (const llvm::APSInt* X = St->getSymVal(sym)) {
+ if (const llvm::APSInt* X = getSymVal(St, sym)) {
isFeasible = *X >= V;
return St;
}
@@ -288,7 +307,7 @@
// FIXME: Primitive logic for now. Only reject a path if the value of
// sym is a constant X and !(X <= V).
- if (const llvm::APSInt* X = St->getSymVal(sym)) {
+ if (const llvm::APSInt* X = getSymVal(St, sym)) {
isFeasible = *X <= V;
return St;
}
@@ -296,3 +315,136 @@
isFeasible = true;
return St;
}
+
+static int ConstEqTyIndex = 0;
+static int ConstNotEqTyIndex = 0;
+
+namespace clang {
+ template<>
+ struct GRStateTrait<ConstNotEqTy> : public GRStatePartialTrait<ConstNotEqTy> {
+ static inline void* GDMIndex() { return &ConstNotEqTyIndex; }
+ };
+
+ template<>
+ struct GRStateTrait<ConstEqTy> : public GRStatePartialTrait<ConstEqTy> {
+ static inline void* GDMIndex() { return &ConstEqTyIndex; }
+ };
+}
+
+const GRState* BasicConstraintManager::AddEQ(const GRState* St, SymbolID sym,
+ const llvm::APSInt& V) {
+ // Create a new state with the old binding replaced.
+ GRStateRef state(St, StateMgr);
+ return state.set<ConstEqTy>(sym, &V);
+}
+
+const GRState* BasicConstraintManager::AddNE(const GRState* St, SymbolID sym,
+ const llvm::APSInt& V) {
+ GRState::IntSetTy::Factory ISetFactory(StateMgr.getAllocator());
+ GRStateRef state(St, StateMgr);
+
+ // First, retrieve the NE-set associated with the given symbol.
+ ConstNotEqTy::data_type* T = state.get<ConstNotEqTy>(sym);
+ GRState::IntSetTy S = T ? *T : ISetFactory.GetEmptySet();
+
+
+ // Now add V to the NE set.
+ S = ISetFactory.Add(S, &V);
+
+ // Create a new state with the old binding replaced.
+ return state.set<ConstNotEqTy>(sym, S);
+}
+
+const llvm::APSInt* BasicConstraintManager::getSymVal(const GRState* St,
+ SymbolID sym) {
+ const ConstEqTy::data_type* T = St->get<ConstEqTy>(sym);
+ return T ? *T : NULL;
+}
+
+bool BasicConstraintManager::isNotEqual(const GRState* St, SymbolID sym,
+ const llvm::APSInt& V) const {
+
+ // Retrieve the NE-set associated with the given symbol.
+ const ConstNotEqTy::data_type* T = St->get<ConstNotEqTy>(sym);
+
+ // See if V is present in the NE-set.
+ return T ? T->contains(&V) : false;
+}
+
+bool BasicConstraintManager::isEqual(const GRState* St, SymbolID sym,
+ const llvm::APSInt& V) const {
+ // Retrieve the EQ-set associated with the given symbol.
+ const ConstEqTy::data_type* T = St->get<ConstEqTy>(sym);
+ // See if V is present in the EQ-set.
+ return T ? **T == V : false;
+}
+
+const GRState* BasicConstraintManager::RemoveDeadBindings(const GRState* St,
+ StoreManager::LiveSymbolsTy& LSymbols,
+ StoreManager::DeadSymbolsTy& DSymbols) {
+ GRStateRef state(St, StateMgr);
+ ConstEqTy CE = state.get<ConstEqTy>();
+ ConstEqTy::Factory& CEFactory = state.get_context<ConstEqTy>();
+
+ for (ConstEqTy::iterator I = CE.begin(), E = CE.end(); I!=E; ++I) {
+ SymbolID sym = I.getKey();
+ if (!LSymbols.count(sym)) {
+ DSymbols.insert(sym);
+ CE = CEFactory.Remove(CE, sym);
+ }
+ }
+ state = state.set<ConstEqTy>(CE);
+
+ ConstNotEqTy CNE = state.get<ConstNotEqTy>();
+ ConstNotEqTy::Factory& CNEFactory = state.get_context<ConstNotEqTy>();
+
+ for (ConstNotEqTy::iterator I = CNE.begin(), E = CNE.end(); I != E; ++I) {
+ SymbolID sym = I.getKey();
+ if (!LSymbols.count(sym)) {
+ DSymbols.insert(sym);
+ CNE = CNEFactory.Remove(CNE, sym);
+ }
+ }
+
+ return state.set<ConstNotEqTy>(CNE);
+}
+
+void BasicConstraintManager::print(const GRState* St, std::ostream& Out,
+ const char* nl, const char *sep) {
+ // Print equality constraints.
+
+ ConstEqTy CE = St->get<ConstEqTy>();
+
+ if (!CE.isEmpty()) {
+ Out << nl << sep << "'==' constraints:";
+
+ for (ConstEqTy::iterator I = CE.begin(), E = CE.end(); I!=E; ++I) {
+ Out << nl << " $" << I.getKey();
+ llvm::raw_os_ostream OS(Out);
+ OS << " : " << *I.getData();
+ }
+ }
+
+ // Print != constraints.
+
+ ConstNotEqTy CNE = St->get<ConstNotEqTy>();
+
+ if (!CNE.isEmpty()) {
+ Out << nl << sep << "'!=' constraints:";
+
+ for (ConstNotEqTy::iterator I = CNE.begin(), EI = CNE.end(); I!=EI; ++I) {
+ Out << nl << " $" << I.getKey() << " : ";
+ bool isFirst = true;
+
+ GRState::IntSetTy::iterator J = I.getData().begin(),
+ EJ = I.getData().end();
+
+ for ( ; J != EJ; ++J) {
+ if (isFirst) isFirst = false;
+ else Out << ", ";
+
+ Out << *J;
+ }
+ }
+ }
+}
\ No newline at end of file