[cfe-commits] r46278 - /cfe/trunk/Analysis/GRConstants.cpp
Ted Kremenek
kremenek at apple.com
Wed Jan 23 11:59:45 PST 2008
Author: kremenek
Date: Wed Jan 23 13:59:44 2008
New Revision: 46278
URL: http://llvm.org/viewvc/llvm-project?rev=46278&view=rev
Log:
Major "architectural" changes to the GRConstants analysis. We now reason about
abstract "L-values" and "R-values" when doing value tracking, and expanding
constant tracking to encompass tracking disjunctive sets of possible constants.
Further, the tree-walking is more efficient, as we don't blindly recurse the
tree if we won't generate new states.
Modified:
cfe/trunk/Analysis/GRConstants.cpp
Modified: cfe/trunk/Analysis/GRConstants.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Analysis/GRConstants.cpp?rev=46278&r1=46277&r2=46278&view=diff
==============================================================================
--- cfe/trunk/Analysis/GRConstants.cpp (original)
+++ cfe/trunk/Analysis/GRConstants.cpp Wed Jan 23 13:59:44 2008
@@ -1,6 +1,6 @@
//===-- GRConstants.cpp - Simple, Path-Sens. Constant Prop. ------*- C++ -*-==//
//
-// The LLVM Compiler Infrastructure
+// The LLValM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
@@ -18,7 +18,6 @@
#include "clang/Analysis/PathSensitive/GREngine.h"
#include "clang/AST/Expr.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
-#include "clang/Analysis/Visitors/CFGStmtVisitor.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/DataTypes.h"
@@ -26,165 +25,429 @@
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Allocator.h"
#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Streams.h"
+
#ifndef NDEBUG
#include "llvm/Support/GraphWriter.h"
#include <sstream>
#endif
using namespace clang;
-using llvm::APInt;
-using llvm::APFloat;
using llvm::dyn_cast;
using llvm::cast;
//===----------------------------------------------------------------------===//
-/// DSPtr - A variant smart pointer that wraps either a ValueDecl* or a
+/// ValueKey - A variant smart pointer that wraps either a ValueDecl* or a
/// Stmt*. Use cast<> or dyn_cast<> to get actual pointer type
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN DSPtr {
+
+class VISIBILITY_HIDDEN ValueKey {
uintptr_t Raw;
public:
- enum VariantKind { IsSubExp=0x0, IsValueDecl=0x1, IsBlkLvl=0x2, Flags=0x3 };
+ enum Kind { IsSubExp=0x0, IsDecl=0x1, IsBlkExpr=0x2, Flags=0x3 };
inline void* getPtr() const { return reinterpret_cast<void*>(Raw & ~Flags); }
- inline VariantKind getKind() const { return (VariantKind) (Raw & Flags); }
+ inline Kind getKind() const { return (Kind) (Raw & Flags); }
- DSPtr(ValueDecl* D) : Raw(reinterpret_cast<uintptr_t>(D) | IsValueDecl) {}
- DSPtr(Stmt* S, bool isBlkLvl)
- : Raw(reinterpret_cast<uintptr_t>(S) | (isBlkLvl ? IsBlkLvl : IsSubExp)) {}
+ ValueKey(const ValueDecl* VD)
+ : Raw(reinterpret_cast<uintptr_t>(VD) | IsDecl) {}
+
+ ValueKey(Stmt* S, bool isBlkExpr)
+ : Raw(reinterpret_cast<uintptr_t>(S) | (isBlkExpr ? IsBlkExpr : IsSubExp)){}
bool isSubExpr() const { return getKind() == IsSubExp; }
+ bool isDecl() const { return getKind() == IsDecl; }
inline void Profile(llvm::FoldingSetNodeID& ID) const {
ID.AddPointer(getPtr());
ID.AddInteger((unsigned) getKind());
- }
- inline bool operator==(const DSPtr& X) const { return Raw == X.Raw; }
- inline bool operator!=(const DSPtr& X) const { return Raw != X.Raw; }
- inline bool operator<(const DSPtr& X) const {
- VariantKind k = getKind(), Xk = X.getKind();
- return k == Xk ? getPtr() < X.getPtr() : ((unsigned) k) < ((unsigned) Xk);
+ }
+
+ inline bool operator==(const ValueKey& X) const {
+ return Raw == X.Raw;
+ }
+
+ inline bool operator!=(const ValueKey& X) const {
+ return !operator==(X);
+ }
+
+ inline bool operator<(const ValueKey& X) const {
+ Kind k = getKind(), Xk = X.getKind();
+
+ return k == Xk ? getPtr() < X.getPtr()
+ : ((unsigned) k) < ((unsigned) Xk);
}
};
} // end anonymous namespace
-// Machinery to get cast<> and dyn_cast<> working with DSPtr.
+// Machinery to get cast<> and dyn_cast<> working with ValueKey.
namespace llvm {
- template<> inline bool isa<ValueDecl,DSPtr>(const DSPtr& V) {
- return V.getKind() == DSPtr::IsValueDecl;
+ template<> inline bool isa<ValueDecl,ValueKey>(const ValueKey& V) {
+ return V.getKind() == ValueKey::IsDecl;
}
- template<> inline bool isa<Stmt,DSPtr>(const DSPtr& V) {
- return ((unsigned) V.getKind()) != DSPtr::IsValueDecl;
+ template<> inline bool isa<Stmt,ValueKey>(const ValueKey& V) {
+ return ((unsigned) V.getKind()) != ValueKey::IsDecl;
}
- template<> struct VISIBILITY_HIDDEN cast_retty_impl<ValueDecl,DSPtr> {
+ template<> struct VISIBILITY_HIDDEN cast_retty_impl<ValueDecl,ValueKey> {
typedef const ValueDecl* ret_type;
};
- template<> struct VISIBILITY_HIDDEN cast_retty_impl<Stmt,DSPtr> {
+ template<> struct VISIBILITY_HIDDEN cast_retty_impl<Stmt,ValueKey> {
typedef const Stmt* ret_type;
};
- template<> struct VISIBILITY_HIDDEN simplify_type<DSPtr> {
+ template<> struct VISIBILITY_HIDDEN simplify_type<ValueKey> {
typedef void* SimpleType;
- static inline SimpleType getSimplifiedValue(const DSPtr &V) {
+ static inline SimpleType getSimplifiedValue(const ValueKey &V) {
return V.getPtr();
}
};
} // end llvm namespace
//===----------------------------------------------------------------------===//
-// DeclStmtMapTy - A ImmutableMap type from Decl*/Stmt* to integers.
-//
-// FIXME: We may eventually use APSInt, or a mixture of APSInt and
-// integer primitives to do this right; this will handle both
-// different bit-widths and allow us to detect integer overflows, etc.
-//
+// ValueManager.
//===----------------------------------------------------------------------===//
-typedef llvm::ImmutableMap<DSPtr,uint64_t> DeclStmtMapTy;
+namespace {
+
+typedef llvm::ImmutableSet<llvm::APSInt > APSIntSetTy;
+
+class VISIBILITY_HIDDEN ValueManager {
+
+
+ APSIntSetTy::Factory APSIntSetFactory;
+
+public:
+ ValueManager() {}
+ ~ValueManager() {}
+
+ APSIntSetTy GetEmptyAPSIntSet() {
+ return APSIntSetFactory.GetEmptySet();
+ }
+
+ APSIntSetTy AddToSet(const APSIntSetTy& Set, const llvm::APSInt& Val) {
+ return APSIntSetFactory.Add(Set, Val);
+ }
+};
+} // end anonymous namespace
-namespace clang {
-template<>
-struct VISIBILITY_HIDDEN GRTrait<DeclStmtMapTy> {
- static inline void* toPtr(DeclStmtMapTy M) {
- return reinterpret_cast<void*>(M.getRoot());
- }
- static inline DeclStmtMapTy toState(void* P) {
- return DeclStmtMapTy(static_cast<DeclStmtMapTy::TreeTy*>(P));
+//===----------------------------------------------------------------------===//
+// Expression Values.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class VISIBILITY_HIDDEN ExprValue {
+public:
+ enum Kind { // L-Values.
+ LValueDeclKind = 0x0,
+ // Special "Invalid" value.
+ InvalidValueKind = 0x1,
+ // R-Values.
+ RValueMayEqualSetKind = 0x2,
+ // Note that the Lvalue and RValue "kinds" overlap;
+ // the "InvalidValue" class can be used either as
+ // an LValue or RValue.
+ MinLValueKind = 0x0, MaxLValueKind = 0x1,
+ MinRValueKind = 0x1, MaxRValueKind = 0x2 };
+
+private:
+ enum Kind kind;
+ void* Data;
+
+protected:
+ ExprValue(Kind k, void* d) : kind(k), Data(d) {}
+
+ void* getRawPtr() const { return Data; }
+
+public:
+ ~ExprValue() {};
+
+ void Profile(llvm::FoldingSetNodeID& ID) const {
+ ID.AddInteger((unsigned) getKind());
+ ID.AddPointer(Data);
+ }
+
+ bool operator==(const ExprValue& RHS) const {
+ return kind == RHS.kind && Data == RHS.Data;
}
+
+ Kind getKind() const { return kind; }
+ bool isValid() const { return getKind() != InvalidValueKind; }
+
+ void print(std::ostream& OS) const;
+ void print() const { print(*llvm::cerr.stream()); }
+
+ // Implement isa<T> support.
+ static inline bool classof(const ExprValue*) { return true; }
};
-}
+
+class VISIBILITY_HIDDEN InvalidValue : public ExprValue {
+public:
+ InvalidValue() : ExprValue(InvalidValueKind, NULL) {}
+
+ static inline bool classof(const ExprValue* V) {
+ return V->getKind() == InvalidValueKind;
+ }
+};
+
+} // end anonymous namespace
//===----------------------------------------------------------------------===//
-// The Checker!
+// "R-Values": Interface.
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN ExprVariantTy {
- const uint64_t val;
- const bool isConstant;
+class VISIBILITY_HIDDEN RValue : public ExprValue {
+protected:
+ RValue(Kind k, void* d) : ExprValue(k,d) {}
+
public:
- ExprVariantTy() : val(0), isConstant(false) {}
- ExprVariantTy(uint64_t v) : val(v), isConstant(true) {}
+ RValue Add(ValueManager& ValMgr, const RValue& RHS) const;
+ RValue Sub(ValueManager& ValMgr, const RValue& RHS) const;
- operator bool() const { return isConstant; }
- uint64_t getVal() const { assert (isConstant); return val; }
+ static RValue GetRValue(ValueManager& ValMgr, IntegerLiteral* S);
- ExprVariantTy operator+(const ExprVariantTy& X) const {
- return (isConstant && X.isConstant) ? ExprVariantTy(val + X.val)
- : ExprVariantTy();
+ // Implement isa<T> support.
+ static inline bool classof(const ExprValue* V) {
+ return V->getKind() >= MinRValueKind;
}
+};
+
+class VISIBILITY_HIDDEN RValueMayEqualSet : public RValue {
+public:
+ RValueMayEqualSet(const APSIntSetTy& S)
+ : RValue(RValueMayEqualSetKind, S.getRoot()) {}
+
+ APSIntSetTy GetValues() const {
+ return APSIntSetTy(reinterpret_cast<APSIntSetTy::TreeTy*>(getRawPtr()));
+ }
+
+ RValueMayEqualSet Add(ValueManager& ValMgr, const RValueMayEqualSet& V) const;
+ RValueMayEqualSet Sub(ValueManager& ValMgr, const RValueMayEqualSet& V) const;
+
+ // Implement isa<T> support.
+ static inline bool classof(const ExprValue* V) {
+ return V->getKind() == RValueMayEqualSetKind;
+ }
+};
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// "R-Values": Implementation.
+//===----------------------------------------------------------------------===//
+
+#define RVALUE_DISPATCH_CASE(k1,k2,Op)\
+case ((k1##Kind+(MaxRValueKind-MinRValueKind))+(k2##Kind - MinRValueKind)):\
+ return cast<k1>(*this).Op(ValMgr,cast<k2>(RHS));
+
+#define RVALUE_DISPATCH(Op)\
+switch (getKind()+(MaxRValueKind-MinRValueKind)+(RHS.getKind()-MinRValueKind)){\
+ RVALUE_DISPATCH_CASE(RValueMayEqualSet,RValueMayEqualSet,Op)\
+ default:\
+ assert (!isValid() || !RHS.isValid() && "Missing case.");\
+ break;\
+}\
+return cast<RValue>(InvalidValue());
+
+RValue RValue::Add(ValueManager& ValMgr, const RValue& RHS) const {
+ RVALUE_DISPATCH(Add)
+}
+
+RValue RValue::Sub(ValueManager& ValMgr, const RValue& RHS) const {
+ RVALUE_DISPATCH(Sub)
+}
+
+#undef RVALUE_DISPATCH_CASE
+#undef RVALUE_DISPATCH
+
+RValueMayEqualSet
+RValueMayEqualSet::Add(ValueManager& ValMgr,
+ const RValueMayEqualSet& RHS) const {
+
+ APSIntSetTy S1 = GetValues();
+ APSIntSetTy S2 = RHS.GetValues();
- ExprVariantTy operator-(const ExprVariantTy& X) const {
- return (isConstant && X.isConstant) ? ExprVariantTy(val - X.val)
- : ExprVariantTy();
- }
+ APSIntSetTy M = ValMgr.GetEmptyAPSIntSet();
+
+ for (APSIntSetTy::iterator I1=S1.begin(), E1=S2.end(); I1!=E1; ++I1)
+ for (APSIntSetTy::iterator I2=S2.begin(), E2=S2.end(); I2!=E2; ++I2)
+ M = ValMgr.AddToSet(M, *I1 + *I2);
+
+ return M;
+}
+
+RValueMayEqualSet
+RValueMayEqualSet::Sub(ValueManager& ValMgr,
+ const RValueMayEqualSet& RHS) const {
+
+ APSIntSetTy S1 = GetValues();
+ APSIntSetTy S2 = RHS.GetValues();
+
+ APSIntSetTy M = ValMgr.GetEmptyAPSIntSet();
+
+ for (APSIntSetTy::iterator I1=S1.begin(), E1=S2.end(); I1!=E1; ++I1)
+ for (APSIntSetTy::iterator I2=S2.begin(), E2=S2.end(); I2!=E2; ++I2)
+ M = ValMgr.AddToSet(M, *I1 - *I2);
+
+ return M;
+}
+
+RValue RValue::GetRValue(ValueManager& ValMgr, IntegerLiteral* S) {
+ return RValueMayEqualSet(ValMgr.AddToSet(ValMgr.GetEmptyAPSIntSet(),
+ S->getValue()));
+}
+
+//===----------------------------------------------------------------------===//
+// "L-Values".
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class VISIBILITY_HIDDEN LValue : public ExprValue {
+protected:
+ LValue(Kind k, void* D) : ExprValue(k, D) {}
+
+public:
+ // Implement isa<T> support.
+ static inline bool classof(const ExprValue* V) {
+ return V->getKind() <= MaxLValueKind;
+ }
};
+
+class VISIBILITY_HIDDEN LValueDecl : public LValue {
+public:
+ LValueDecl(ValueDecl* vd) : LValue(LValueDeclKind,vd) {}
+
+ ValueDecl* getDecl() const {
+ return static_cast<ValueDecl*>(getRawPtr());
+ }
+
+ // Implement isa<T> support.
+ static inline bool classof(const ExprValue* V) {
+ return V->getKind() == LValueDeclKind;
+ }
+};
} // end anonymous namespace
//===----------------------------------------------------------------------===//
+// Pretty-Printing.
+//===----------------------------------------------------------------------===//
+
+void ExprValue::print(std::ostream& Out) const {
+ switch (getKind()) {
+ case InvalidValueKind:
+ Out << "Invalid"; break;
+
+ case RValueMayEqualSetKind: {
+ Out << "MayEqual{";
+ APSIntSetTy S = cast<RValueMayEqualSet>(this)->GetValues();
+
+ for (APSIntSetTy::iterator I=S.begin(), E=S.end(); I!=E; ++I)
+ Out << ' ' << (*I).toString();
+
+ Out << " }";
+ break;
+ }
+
+ default:
+ assert (false && "Pretty-printed not implemented for this ExprValue.");
+ break;
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// ValueMapTy - A ImmutableMap type Stmt*/Decl* to ExprValues.
+//===----------------------------------------------------------------------===//
+
+typedef llvm::ImmutableMap<ValueKey,ExprValue> ValueMapTy;
+
+namespace clang {
+ template<>
+ struct VISIBILITY_HIDDEN GRTrait<ValueMapTy> {
+ static inline void* toPtr(ValueMapTy M) {
+ return reinterpret_cast<void*>(M.getRoot());
+ }
+ static inline ValueMapTy toState(void* P) {
+ return ValueMapTy(static_cast<ValueMapTy::TreeTy*>(P));
+ }
+ };
+}
+
+//===----------------------------------------------------------------------===//
// The Checker!
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN GRConstants : public CFGStmtVisitor<GRConstants> {
+
+class VISIBILITY_HIDDEN GRConstants {
public:
- typedef DeclStmtMapTy StateTy;
+ typedef ValueMapTy StateTy;
typedef GRNodeBuilder<GRConstants> NodeBuilder;
typedef ExplodedNode<StateTy> NodeTy;
+
+ class NodeSet {
+ typedef llvm::SmallVector<NodeTy*,3> ImplTy;
+ ImplTy Impl;
+ public:
+
+ NodeSet() {}
+ NodeSet(NodeTy* N) { assert (N && !N->isInfeasible()); Impl.push_back(N); }
+
+ void Add(NodeTy* N) { if (N && !N->isInfeasible()) Impl.push_back(N); }
+
+ typedef ImplTy::iterator iterator;
+ typedef ImplTy::const_iterator const_iterator;
+
+ unsigned size() const { return Impl.size(); }
+
+ iterator begin() { return Impl.begin(); }
+ iterator end() { return Impl.end(); }
+
+ const_iterator begin() const { return Impl.begin(); }
+ const_iterator end() const { return Impl.end(); }
+ };
protected:
- // Liveness - live-variables information the ValueDecl* and Expr* (block-level)
- // in the CFG. Used to prune out dead state.
+ /// Liveness - live-variables information the ValueDecl* and block-level
+ /// Expr* in the CFG. Used to prune out dead state.
LiveVariables* Liveness;
- // Builder - The current GRNodeBuilder which is used when building the nodes
- // for a given statement.
+ /// Builder - The current GRNodeBuilder which is used when building the nodes
+ /// for a given statement.
NodeBuilder* Builder;
- DeclStmtMapTy::Factory StateMgr;
+ /// StateMgr - Object that manages the data for all created states.
+ ValueMapTy::Factory StateMgr;
+
+ /// ValueMgr - Object that manages the data for all created ExprValues.
+ ValueManager ValMgr;
- // cfg - the current CFG.
+ /// cfg - the current CFG.
CFG* cfg;
-
- typedef llvm::SmallVector<NodeTy*,8> NodeSetTy;
- NodeSetTy NodeSetA;
- NodeSetTy NodeSetB;
- NodeSetTy* Nodes;
- NodeSetTy* OldNodes;
- StateTy CurrentState;
- NodeTy* InitialPred;
+
+ /// StmtEntryNode - The immediate predecessor node.
+ NodeTy* StmtEntryNode;
+
+ /// CurrentStmt - The current block-level statement.
+ Stmt* CurrentStmt;
+
+ bool StateCleaned;
public:
- GRConstants() : Liveness(NULL), Builder(NULL), cfg(NULL),
- Nodes(&NodeSetA), OldNodes(&NodeSetB),
- CurrentState(StateMgr.GetEmptyMap()), InitialPred(NULL) {}
+ GRConstants() : Liveness(NULL), Builder(NULL), cfg(NULL),
+ StmtEntryNode(NULL), CurrentStmt(NULL) {}
~GRConstants() { delete Liveness; }
+ /// getCFG - Returns the CFG associated with this analysis.
CFG& getCFG() { assert (cfg); return *cfg; }
+ /// Initialize - Initialize the checker's state based on the specified
+ /// CFG. This results in liveness information being computed for
+ /// each block-level statement in the CFG.
void Initialize(CFG& c) {
cfg = &c;
Liveness = new LiveVariables(c);
@@ -192,191 +455,258 @@
Liveness->runOnAllBlocks(c, NULL, true);
}
+ /// getInitialState - Return the initial state used for the root vertex
+ /// in the ExplodedGraph.
StateTy getInitialState() {
return StateMgr.GetEmptyMap();
}
-
+
+ /// ProcessStmt - Called by GREngine. Used to generate new successor
+ /// nodes by processing the 'effects' of a block-level statement.
void ProcessStmt(Stmt* S, NodeBuilder& builder);
- void SwitchNodeSets();
- void DoStmt(Stmt* S);
-
- StateTy RemoveDescendantMappings(Stmt* S, StateTy M, unsigned Levels=2);
- StateTy RemoveDeadMappings(Stmt* S, StateTy M);
- void AddBinding(Expr* E, ExprVariantTy V, bool isBlkLvl = false);
- void AddBinding(ValueDecl* D, ExprVariantTy V);
+ /// RemoveDeadBindings - Return a new state that is the same as 'M' except
+ /// that all subexpression mappings are removed and that any
+ /// block-level expressions that are not live at 'S' also have their
+ /// mappings removed.
+ StateTy RemoveDeadBindings(Stmt* S, StateTy M);
+
+ StateTy SetValue(StateTy St, Stmt* S, const ExprValue& V,
+ bool isBlkExpr = false);
+
+ StateTy SetValue(StateTy St, const LValue& LV, const ExprValue& V);
- ExprVariantTy GetBinding(Expr* E);
+ ExprValue GetValue(const StateTy& St, Stmt* S);
+ ExprValue GetValue(const StateTy& St, const LValue& LV);
+ LValue GetLValue(const StateTy& St, Stmt* S);
- void BlockStmt_VisitStmt(Stmt* S) { DoStmt(S); }
+ void Nodify(NodeSet& Dst, Stmt* S, NodeTy* Pred, StateTy St);
- void VisitAssign(BinaryOperator* O);
- void VisitBinAdd(BinaryOperator* O);
- void VisitBinSub(BinaryOperator* O);
- void VisitBinAssign(BinaryOperator* D);
+ /// Visit - Transfer function logic for all statements. Dispatches to
+ /// other functions that handle specific kinds of statements.
+ void Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst);
+
+ /// VisitBinaryOperator - Transfer function logic for binary operators.
+ void VisitBinaryOperator(BinaryOperator* B, NodeTy* Pred, NodeSet& Dst);
};
} // end anonymous namespace
+
void GRConstants::ProcessStmt(Stmt* S, NodeBuilder& builder) {
Builder = &builder;
+
+ StmtEntryNode = builder.getLastNode();
+ CurrentStmt = S;
+ NodeSet Dst;
+ StateCleaned = false;
+
+ Visit(S, StmtEntryNode, Dst);
+
+ // If no nodes were generated, generate a new node that has all the
+ // dead mappings removed.
+ if (Dst.size() == 1 && *Dst.begin() == StmtEntryNode) {
+ StateTy St = RemoveDeadBindings(S, StmtEntryNode->getState());
+ builder.generateNode(S, St, StmtEntryNode);
+ }
- Nodes->clear();
- OldNodes->clear();
-
- InitialPred = Builder->getLastNode();
- assert (InitialPred);
- OldNodes->push_back(InitialPred);
-
- CurrentState = RemoveDeadMappings(S, InitialPred->getState());
-
- BlockStmt_Visit(S);
-
- Builder = NULL;
+ CurrentStmt = NULL;
+ StmtEntryNode = NULL;
+ Builder = NULL;
}
-ExprVariantTy GRConstants::GetBinding(Expr* E) {
- DSPtr P(NULL);
- E = E->IgnoreParens();
-
- switch (E->getStmtClass()) {
- case Stmt::DeclRefExprClass:
- P = DSPtr(cast<DeclRefExpr>(E)->getDecl());
- break;
- case Stmt::IntegerLiteralClass:
- return cast<IntegerLiteral>(E)->getValue().getZExtValue();
-
- default:
- P = DSPtr(E, getCFG().isBlkExpr(E));
+ExprValue GRConstants::GetValue(const StateTy& St, const LValue& LV) {
+ switch (LV.getKind()) {
+ case ExprValue::LValueDeclKind: {
+ StateTy::TreeTy* T = St.SlimFind(cast<LValueDecl>(LV).getDecl());
+ return T ? T->getValue().second : InvalidValue();
+ }
+ default:
+ assert (false && "Invalid LValue.");
break;
}
+
+ return InvalidValue();
+}
+
+ExprValue GRConstants::GetValue(const StateTy& St, Stmt* S) {
+ if (Expr* E = dyn_cast<Expr>(S))
+ S = E->IgnoreParens();
+
+ switch (S->getStmtClass()) {
+ case Stmt::DeclRefExprClass:
+ return GetValue(St, LValueDecl(cast<DeclRefExpr>(S)->getDecl()));
- StateTy::TreeTy* T = CurrentState.SlimFind(P);
+ case Stmt::IntegerLiteralClass:
+ return RValue::GetRValue(ValMgr, cast<IntegerLiteral>(S));
- if (!T)
- return ExprVariantTy();
+ default:
+ break;
+ };
- return T->getValue().second;
+ StateTy::TreeTy* T = St.SlimFind(ValueKey(S, getCFG().isBlkExpr(S)));
+ return T ? T->getValue().second : InvalidValue();
}
-void GRConstants::AddBinding(Expr* E, ExprVariantTy V, bool isBlkLvl) {
- if (V) CurrentState = StateMgr.Add(CurrentState, DSPtr(E,isBlkLvl), V.getVal());
+LValue GRConstants::GetLValue(const StateTy& St, Stmt* S) {
+ if (Expr* E = dyn_cast<Expr>(S))
+ S = E->IgnoreParens();
+
+ if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(S))
+ return LValueDecl(DR->getDecl());
+
+ return cast<LValue>(GetValue(St, S));
}
-void GRConstants::AddBinding(ValueDecl* D, ExprVariantTy V) {
- if (V) CurrentState = StateMgr.Add(CurrentState, DSPtr(D), V.getVal());
- else CurrentState = StateMgr.Remove(CurrentState, DSPtr(D));
+GRConstants::StateTy GRConstants::SetValue(StateTy St, Stmt* S,
+ const ExprValue& V, bool isBlkExpr) {
+
+ if (!StateCleaned) {
+ St = RemoveDeadBindings(CurrentStmt, St);
+ StateCleaned = true;
+ }
+
+ return V.isValid() ? StateMgr.Add(St, ValueKey(S,isBlkExpr), V)
+ : St;
}
-void GRConstants::SwitchNodeSets() {
- NodeSetTy* Tmp = OldNodes;
- OldNodes = Nodes;
- Nodes = Tmp;
- Nodes->clear();
+GRConstants::StateTy GRConstants::SetValue(StateTy St, const LValue& LV,
+ const ExprValue& V) {
+ if (!LV.isValid())
+ return St;
+
+ if (!StateCleaned) {
+ St = RemoveDeadBindings(CurrentStmt, St);
+ StateCleaned = true;
+ }
+
+ switch (LV.getKind()) {
+ case ExprValue::LValueDeclKind:
+ return V.isValid() ? StateMgr.Add(St, cast<LValueDecl>(LV).getDecl(), V)
+ : StateMgr.Remove(St, cast<LValueDecl>(LV).getDecl());
+
+ default:
+ assert ("SetValue for given LValue type not yet implemented.");
+ return St;
+ }
}
-GRConstants::StateTy GRConstants::RemoveDeadMappings(Stmt* Loc, StateTy M) {
-#if 0
- return M;
-#else
+GRConstants::StateTy GRConstants::RemoveDeadBindings(Stmt* Loc, StateTy M) {
// Note: in the code below, we can assign a new map to M since the
// iterators are iterating over the tree of the *original* map.
-
StateTy::iterator I = M.begin(), E = M.end();
- // First remove mappings for subexpressions, since they are not needed.
- for (; I!=E && I.getKey().getKind() == DSPtr::IsSubExp; ++I)
+ // Remove old bindings for subexpressions.
+ for (; I!=E && I.getKey().getKind() == ValueKey::IsSubExp; ++I)
M = StateMgr.Remove(M, I.getKey());
- // Next, remove any decls or block-level expressions whose mappings are dead.
- for (; I != E; ++I) {
- if (ValueDecl* VD = dyn_cast<ValueDecl>(I.getKey())) {
- if (VarDecl* V = dyn_cast<VarDecl>(VD)) {
- if (!Liveness->isLive(Loc, V)) M = StateMgr.Remove(M, I.getKey());
- }
- }
- else {
- Stmt* S = cast<Stmt>(I.getKey());
- assert (I.getKey().getKind() == DSPtr::IsBlkLvl);
- if (!Liveness->isLive(Loc, S)) M = StateMgr.Remove(M, I.getKey());
- }
- }
+ // Remove bindings for "dead" decls.
+ for (; I!=E && I.getKey().getKind() == ValueKey::IsDecl; ++I)
+ if (VarDecl* V = dyn_cast<VarDecl>(cast<ValueDecl>(I.getKey())))
+ if (!Liveness->isLive(Loc, V))
+ M = StateMgr.Remove(M, I.getKey());
+
+ // Remove bindings for "dead" block-level expressions.
+ for (; I!=E; ++I)
+ if (!Liveness->isLive(Loc, cast<Stmt>(I.getKey())))
+ M = StateMgr.Remove(M, I.getKey());
return M;
-#endif
}
-
-GRConstants::StateTy
-GRConstants::RemoveDescendantMappings(Stmt* S, GRConstants::StateTy State,
- unsigned Levels) {
- typedef Stmt::child_iterator iterator;
-
- for (iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I)
- if (Stmt* C = *I) {
- if (Levels == 1) {
- // Observe that this will only remove mappings to non-block level
- // expressions. This is valid even if *CI is a block-level expression,
- // since it simply won't be in the map in the first place.
- // Note: This should also work if 'C' is a block-level expression,
- // although ideally we would want to skip processing C's children.
- State = StateMgr.Remove(State, DSPtr(C,false));
+void GRConstants::Nodify(NodeSet& Dst, Stmt* S, GRConstants::NodeTy* Pred,
+ GRConstants::StateTy St) {
+
+ // If the state hasn't changed, don't generate a new node.
+ if (St == Pred->getState())
+ return;
+
+ Dst.Add(Builder->generateNode(S, St, Pred));
+}
+
+void GRConstants::VisitBinaryOperator(BinaryOperator* B,
+ GRConstants::NodeTy* Pred,
+ GRConstants::NodeSet& Dst) {
+ NodeSet S1;
+ Visit(B->getLHS(), Pred, S1);
+
+ for (NodeSet::iterator I1=S1.begin(), E1=S1.end(); I1 != E1; ++I1) {
+ NodeTy* N1 = *I1;
+
+ // When getting the value for the LHS, check if we are in an assignment.
+ // In such cases, we want to (initially) treat the LHS as an LValue,
+ // so we use GetLValue instead of GetValue so that DeclRefExpr's are
+ // evaluated to LValueDecl's instead of to an RValue.
+ const ExprValue& V1 =
+ B->isAssignmentOp() ? GetLValue(N1->getState(), B->getLHS())
+ : GetValue(N1->getState(), B->getLHS());
+
+ NodeSet S2;
+ Visit(B->getRHS(), N1, S2);
+
+ for (NodeSet::iterator I2=S2.begin(), E2=S2.end(); I2 != E2; ++I2) {
+ NodeTy* N2 = *I2;
+ StateTy St = N2->getState();
+ const ExprValue& V2 = GetValue(St, B->getRHS());
+
+ switch (B->getOpcode()) {
+ case BinaryOperator::Add: {
+ const RValue& R1 = cast<RValue>(V1);
+ const RValue& R2 = cast<RValue>(V2);
+
+ Nodify(Dst, B, N2, SetValue(St, B, R1.Add(ValMgr, R2)));
+ break;
+ }
+
+ case BinaryOperator::Sub: {
+ const RValue& R1 = cast<RValue>(V1);
+ const RValue& R2 = cast<RValue>(V2);
+
+ Nodify(Dst, B, N2, SetValue(St, B, R1.Sub(ValMgr, R2)));
+ break;
+ }
+
+ case BinaryOperator::Assign: {
+ const LValue& L1 = cast<LValue>(V1);
+ const RValue& R2 = cast<RValue>(V2);
+
+ Nodify(Dst, B, N2, SetValue(SetValue(St, B, R2), L1, R2));
+ break;
+ }
+
+ default:
+ Dst.Add(N2);
+ break;
}
- else {
- if (ParenExpr* P = dyn_cast<ParenExpr>(C))
- State = RemoveDescendantMappings(P, State, Levels);
- else
- State = RemoveDescendantMappings(C, State, Levels-1);
- }
- }
-
- return State;
-}
-
-void GRConstants::DoStmt(Stmt* S) {
- for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I)
- if (*I) DoStmt(*I);
-
- for (NodeSetTy::iterator I=OldNodes->begin(), E=OldNodes->end(); I!=E; ++I) {
- NodeTy* Pred = *I;
-
- if (Pred != InitialPred)
- CurrentState = Pred->getState();
-
- StateTy OldState = CurrentState;
-
- if (Pred != InitialPred)
- CurrentState = RemoveDescendantMappings(S, CurrentState);
-
- Visit(S);
-
- if (CurrentState != OldState) {
- NodeTy* N = Builder->generateNode(S, CurrentState, Pred);
- if (N) Nodes->push_back(N);
}
- else Nodes->push_back(Pred);
}
-
- SwitchNodeSets();
}
-void GRConstants::VisitBinAdd(BinaryOperator* B) {
- AddBinding(B, GetBinding(B->getLHS()) + GetBinding(B->getRHS()));
-}
-void GRConstants::VisitBinSub(BinaryOperator* B) {
- ExprVariantTy V1 = GetBinding(B->getLHS());
- ExprVariantTy V2 = GetBinding(B->getRHS());
-
- AddBinding(B, V1 - V2 );
-}
+void GRConstants::Visit(Stmt* S, GRConstants::NodeTy* Pred,
+ GRConstants::NodeSet& Dst) {
+ // FIXME: add metadata to the CFG so that we can disable
+ // this check when we KNOW that there is no block-level subexpression.
+ // The motivation is that this check requires a hashtable lookup.
-void GRConstants::VisitBinAssign(BinaryOperator* B) {
- if (DeclRefExpr* D = dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParens())) {
- ExprVariantTy V = GetBinding(B->getRHS());
- AddBinding(D->getDecl(), V);
- AddBinding(B, V);
+ if (S != CurrentStmt && getCFG().isBlkExpr(S)) {
+ Dst.Add(Pred);
+ return;
+ }
+
+ switch (S->getStmtClass()) {
+ case Stmt::BinaryOperatorClass:
+ VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst);
+ break;
+
+ case Stmt::ParenExprClass:
+ Visit(cast<ParenExpr>(S)->getSubExpr(), Pred, Dst);
+ break;
+
+ default:
+ Dst.Add(Pred); // No-op. Simply propagate the current state unchanged.
+ break;
}
}
@@ -439,7 +769,8 @@
Out << "Stmt: " << (void*) E;
}
- Out << " => " << I.getData();
+ Out << " => ";
+ I.getData().print(Out);
}
Out << " }";
@@ -458,4 +789,4 @@
llvm::ViewGraph(*Engine.getGraph().roots_begin(),"GRConstants");
#endif
}
-}
+} // end clang namespace
More information about the cfe-commits
mailing list