//===-- GRConstants.cpp - Simple, Path-Sens. Constant Prop. ------*- C++ -*-==// // // The LLValM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Constant Propagation via Graph Reachability // // This files defines a simple analysis that performs path-sensitive // constant propagation within a function. An example use of this analysis // is to perform simple checks for NULL dereferences. // //===----------------------------------------------------------------------===// #include "clang/Analysis/PathSensitive/GREngine.h" #include "clang/AST/Expr.h" #include "clang/AST/ASTContext.h" #include "clang/Analysis/Analyses/LiveVariables.h" #include "llvm/Support/Casting.h" #include "llvm/Support/DataTypes.h" #include "llvm/ADT/APSInt.h" #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" #include #ifndef NDEBUG #include "llvm/Support/GraphWriter.h" #include #endif using namespace clang; using llvm::dyn_cast; using llvm::cast; using llvm::APSInt; //===----------------------------------------------------------------------===// /// 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 SymbolID { unsigned Data; public: SymbolID() : Data(~0) {} SymbolID(unsigned x) : Data(x) {} bool isInitialized() const { return Data != (unsigned) ~0; } operator unsigned() const { assert (isInitialized()); return Data; } }; class VISIBILITY_HIDDEN ValueKey { uintptr_t Raw; void operator=(const ValueKey& RHS); // Do not implement. public: enum Kind { IsSubExpr=0x0, IsBlkExpr=0x1, IsDecl=0x2, // L-Value Bindings. IsSymbol=0x3, // Symbol Bindings. Flags=0x3 }; inline Kind getKind() const { return (Kind) (Raw & Flags); } inline void* getPtr() const { assert (getKind() != IsSymbol); return reinterpret_cast(Raw & ~Flags); } inline SymbolID getSymbolID() const { assert (getKind() == IsSymbol); return Raw >> 2; } ValueKey(const ValueDecl* VD) : Raw(reinterpret_cast(VD) | IsDecl) { assert(VD && "ValueDecl cannot be NULL."); } ValueKey(Stmt* S, bool isBlkExpr = false) : Raw(reinterpret_cast(S) | (isBlkExpr ? IsBlkExpr : IsSubExpr)){ assert(S && "Tracked statement cannot be NULL."); } ValueKey(SymbolID V) : Raw((V << 2) | IsSymbol) {} bool isSymbol() const { return getKind() == IsSymbol; } bool isSubExpr() const { return getKind() == IsSubExpr; } bool isBlkExpr() const { return getKind() == IsBlkExpr; } bool isDecl() const { return getKind() == IsDecl; } bool isStmt() const { return getKind() <= IsBlkExpr; } inline void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger(isSymbol() ? 1 : 0); if (isSymbol()) ID.AddInteger(getSymbolID()); else ID.AddPointer(getPtr()); } inline bool operator==(const ValueKey& X) const { return isSymbol() ? getSymbolID() == X.getSymbolID() : getPtr() == X.getPtr(); } inline bool operator!=(const ValueKey& X) const { return !operator==(X); } inline bool operator<(const ValueKey& X) const { if (isSymbol()) return X.isSymbol() ? getSymbolID() < X.getSymbolID() : false; return getPtr() < X.getPtr(); } }; } // end anonymous namespace // Machinery to get cast<> and dyn_cast<> working with ValueKey. namespace llvm { template<> inline bool isa(const ValueKey& V) { return V.getKind() == ValueKey::IsDecl; } template<> inline bool isa(const ValueKey& V) { return ((unsigned) V.getKind()) < ValueKey::IsDecl; } template<> struct VISIBILITY_HIDDEN cast_retty_impl { typedef const ValueDecl* ret_type; }; template<> struct VISIBILITY_HIDDEN cast_retty_impl { typedef const Stmt* ret_type; }; template<> struct VISIBILITY_HIDDEN simplify_type { typedef void* SimpleType; static inline SimpleType getSimplifiedValue(const ValueKey &V) { return V.getPtr(); } }; } // end llvm namespace //===----------------------------------------------------------------------===// // SymbolManager. //===----------------------------------------------------------------------===// namespace { class VISIBILITY_HIDDEN SymbolData { uintptr_t Data; public: enum Kind { ParmKind = 0x0, Mask = 0x3 }; SymbolData(ParmVarDecl* D) : Data(reinterpret_cast(D) | ParmKind) {} inline Kind getKind() const { return (Kind) (Data & Mask); } inline void* getPtr() const { return reinterpret_cast(Data & ~Mask); } inline bool operator==(const SymbolData& R) const { return Data == R.Data; } }; } // Machinery to get cast<> and dyn_cast<> working with SymbolData. namespace llvm { template<> inline bool isa(const SymbolData& V) { return V.getKind() == SymbolData::ParmKind; } template<> struct VISIBILITY_HIDDEN cast_retty_impl { typedef const ParmVarDecl* ret_type; }; template<> struct VISIBILITY_HIDDEN simplify_type { typedef void* SimpleType; static inline SimpleType getSimplifiedValue(const SymbolData &V) { return V.getPtr(); } }; } // end llvm namespace namespace { class VISIBILITY_HIDDEN SymbolManager { std::vector SymbolToData; typedef llvm::DenseMap MapTy; MapTy DataToSymbol; public: SymbolData getSymbolData(SymbolID id) const { assert (id < SymbolToData.size()); return SymbolToData[id]; } SymbolID getSymbol(ParmVarDecl* D); }; } // end anonymous namespace SymbolID SymbolManager::getSymbol(ParmVarDecl* D) { SymbolID& X = DataToSymbol[D]; if (!X.isInitialized()) { X = SymbolToData.size(); SymbolToData.push_back(D); } return X; } //===----------------------------------------------------------------------===// // ValueManager. //===----------------------------------------------------------------------===// namespace { typedef llvm::ImmutableSet APSIntSetTy; class VISIBILITY_HIDDEN ValueManager { ASTContext& Ctx; typedef llvm::FoldingSet > APSIntSetTy; APSIntSetTy APSIntSet; llvm::BumpPtrAllocator BPAlloc; public: ValueManager(ASTContext& ctx) : Ctx(ctx) {} ~ValueManager(); ASTContext& getContext() const { return Ctx; } APSInt& getValue(const APSInt& X); APSInt& getValue(uint64_t X, unsigned BitWidth, bool isUnsigned); APSInt& getValue(uint64_t X, QualType T, SourceLocation Loc = SourceLocation()); }; } // end anonymous namespace ValueManager::~ValueManager() { // Note that the dstor for the contents of APSIntSet will never be called, // so we iterate over the set and invoke the dstor for each APSInt. This // frees an aux. memory allocated to represent very large constants. for (APSIntSetTy::iterator I=APSIntSet.begin(), E=APSIntSet.end(); I!=E; ++I) I->getValue().~APSInt(); } APSInt& ValueManager::getValue(const APSInt& X) { llvm::FoldingSetNodeID ID; void* InsertPos; typedef llvm::FoldingSetNodeWrapper FoldNodeTy; X.Profile(ID); FoldNodeTy* P = APSIntSet.FindNodeOrInsertPos(ID, InsertPos); if (!P) { P = (FoldNodeTy*) BPAlloc.Allocate(); new (P) FoldNodeTy(X); APSIntSet.InsertNode(P, InsertPos); } return *P; } APSInt& ValueManager::getValue(uint64_t X, unsigned BitWidth, bool isUnsigned) { APSInt V(BitWidth, isUnsigned); V = X; return getValue(V); } APSInt& ValueManager::getValue(uint64_t X, QualType T, SourceLocation Loc) { unsigned bits = Ctx.getTypeSize(T, Loc); APSInt V(bits, T->isUnsignedIntegerType()); V = X; return getValue(V); } //===----------------------------------------------------------------------===// // Expression Values. //===----------------------------------------------------------------------===// namespace { class VISIBILITY_HIDDEN RValue { public: enum BaseKind { LValueKind=0x0, NonLValueKind=0x1, UninitializedKind=0x2, InvalidKind=0x3 }; enum { BaseBits = 2, BaseMask = 0x3 }; private: void* Data; unsigned Kind; protected: RValue(const void* d, bool isLValue, unsigned ValKind) : Data(const_cast(d)), Kind((isLValue ? LValueKind : NonLValueKind) | (ValKind << BaseBits)) {} explicit RValue(BaseKind k) : Data(0), Kind(k) {} void* getRawPtr() const { return reinterpret_cast(Data); } public: ~RValue() {}; RValue Cast(ValueManager& ValMgr, Expr* CastExpr) const; unsigned getRawKind() const { return Kind; } BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); } unsigned getSubKind() const { return (Kind & ~BaseMask) >> BaseBits; } void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger((unsigned) getRawKind()); ID.AddPointer(reinterpret_cast(Data)); } bool operator==(const RValue& RHS) const { return getRawKind() == RHS.getRawKind() && Data == RHS.Data; } inline bool isValid() const { return getRawKind() != InvalidKind; } inline bool isInvalid() const { return getRawKind() == InvalidKind; } void print(std::ostream& OS) const; void print() const { print(*llvm::cerr.stream()); } // Implement isa support. static inline bool classof(const RValue*) { return true; } }; class VISIBILITY_HIDDEN InvalidValue : public RValue { public: InvalidValue() : RValue(InvalidKind) {} static inline bool classof(const RValue* V) { return V->getBaseKind() == InvalidKind; } }; class VISIBILITY_HIDDEN UninitializedValue : public RValue { public: UninitializedValue() : RValue(UninitializedKind) {} static inline bool classof(const RValue* V) { return V->getBaseKind() == UninitializedKind; } }; class VISIBILITY_HIDDEN NonLValue : public RValue { protected: NonLValue(unsigned SubKind, const void* d) : RValue(d, false, SubKind) {} public: void print(std::ostream& Out) const; // Arithmetic operators. NonLValue Add(ValueManager& ValMgr, const NonLValue& RHS) const; NonLValue Sub(ValueManager& ValMgr, const NonLValue& RHS) const; NonLValue Mul(ValueManager& ValMgr, const NonLValue& RHS) const; NonLValue Div(ValueManager& ValMgr, const NonLValue& RHS) const; NonLValue Rem(ValueManager& ValMgr, const NonLValue& RHS) const; NonLValue UnaryMinus(ValueManager& ValMgr, UnaryOperator* U) const; // Equality operators. NonLValue EQ(ValueManager& ValMgr, const NonLValue& RHS) const; NonLValue NE(ValueManager& ValMgr, const NonLValue& RHS) const; // Utility methods to create NonLValues. static NonLValue GetValue(ValueManager& ValMgr, uint64_t X, QualType T, SourceLocation Loc = SourceLocation()); static NonLValue GetValue(ValueManager& ValMgr, IntegerLiteral* I); static NonLValue GetSymbolValue(SymbolManager& SymMgr, ParmVarDecl *D); static inline NonLValue GetIntTruthValue(ValueManager& ValMgr, bool X) { return GetValue(ValMgr, X ? 1U : 0U, ValMgr.getContext().IntTy); } // Implement isa support. static inline bool classof(const RValue* V) { return V->getBaseKind() >= NonLValueKind; } }; class VISIBILITY_HIDDEN LValue : public RValue { protected: LValue(unsigned SubKind, void* D) : RValue(D, true, SubKind) {} public: // Equality operators. NonLValue EQ(ValueManager& ValMgr, const LValue& RHS) const; NonLValue NE(ValueManager& ValMgr, const LValue& RHS) const; // Implement isa support. static inline bool classof(const RValue* V) { return V->getBaseKind() == LValueKind; } }; } // end anonymous namespace //===----------------------------------------------------------------------===// // LValues. //===----------------------------------------------------------------------===// namespace { enum { LValueDeclKind, NumLValueKind }; class VISIBILITY_HIDDEN LValueDecl : public LValue { public: LValueDecl(const ValueDecl* vd) : LValue(LValueDeclKind,const_cast(vd)) {} ValueDecl* getDecl() const { return static_cast(getRawPtr()); } inline bool operator==(const LValueDecl& R) const { return getDecl() == R.getDecl(); } inline bool operator!=(const LValueDecl& R) const { return getDecl() != R.getDecl(); } // Implement isa support. static inline bool classof(const RValue* V) { return V->getSubKind() == LValueDeclKind; } }; } // end anonymous namespace //===----------------------------------------------------------------------===// // Non-LValues. //===----------------------------------------------------------------------===// namespace { enum { SymbolicNonLValueKind, ConcreteIntKind, ConstrainedIntegerKind, NumNonLValueKind }; class VISIBILITY_HIDDEN SymbolicNonLValue : public NonLValue { public: SymbolicNonLValue(unsigned SymID) : NonLValue(SymbolicNonLValueKind, reinterpret_cast((uintptr_t) SymID)) {} SymbolID getSymbolID() const { return (SymbolID) reinterpret_cast(getRawPtr()); } static inline bool classof(const RValue* V) { return V->getSubKind() == SymbolicNonLValueKind; } }; class VISIBILITY_HIDDEN ConcreteInt : public NonLValue { public: ConcreteInt(const APSInt& V) : NonLValue(ConcreteIntKind, &V) {} const APSInt& getValue() const { return *static_cast(getRawPtr()); } // Arithmetic operators. ConcreteInt Add(ValueManager& ValMgr, const ConcreteInt& V) const { return ValMgr.getValue(getValue() + V.getValue()); } ConcreteInt Sub(ValueManager& ValMgr, const ConcreteInt& V) const { return ValMgr.getValue(getValue() - V.getValue()); } ConcreteInt Mul(ValueManager& ValMgr, const ConcreteInt& V) const { return ValMgr.getValue(getValue() * V.getValue()); } ConcreteInt Div(ValueManager& ValMgr, const ConcreteInt& V) const { return ValMgr.getValue(getValue() / V.getValue()); } ConcreteInt Rem(ValueManager& ValMgr, const ConcreteInt& V) const { return ValMgr.getValue(getValue() % V.getValue()); } ConcreteInt UnaryMinus(ValueManager& ValMgr, UnaryOperator* U) const { assert (U->getType() == U->getSubExpr()->getType()); assert (U->getType()->isIntegerType()); return ValMgr.getValue(-getValue()); } // Casting. ConcreteInt Cast(ValueManager& ValMgr, Expr* CastExpr) const { assert (CastExpr->getType()->isIntegerType()); APSInt X(getValue()); X.extOrTrunc(ValMgr.getContext().getTypeSize(CastExpr->getType(), CastExpr->getLocStart())); return ValMgr.getValue(X); } // Equality operators. ConcreteInt EQ(ValueManager& ValMgr, const ConcreteInt& V) const { const APSInt& Val = getValue(); return ValMgr.getValue(Val == V.getValue() ? 1U : 0U, Val.getBitWidth(), Val.isUnsigned()); } ConcreteInt NE(ValueManager& ValMgr, const ConcreteInt& V) const { const APSInt& Val = getValue(); return ValMgr.getValue(Val != V.getValue() ? 1U : 0U, Val.getBitWidth(), Val.isUnsigned()); } // Implement isa support. static inline bool classof(const RValue* V) { return V->getSubKind() == ConcreteIntKind; } }; } // end anonymous namespace //===----------------------------------------------------------------------===// // Transfer function dispatch for Non-LValues. //===----------------------------------------------------------------------===// RValue RValue::Cast(ValueManager& ValMgr, Expr* CastExpr) const { switch (getSubKind()) { case ConcreteIntKind: return cast(this)->Cast(ValMgr, CastExpr); default: return InvalidValue(); } } NonLValue NonLValue::UnaryMinus(ValueManager& ValMgr, UnaryOperator* U) const { switch (getSubKind()) { case ConcreteIntKind: return cast(this)->UnaryMinus(ValMgr, U); default: return cast(InvalidValue()); } } #define NONLVALUE_DISPATCH_CASE(k1,k2,Op)\ case (k1##Kind*NumNonLValueKind+k2##Kind):\ return cast(*this).Op(ValMgr,cast(RHS)); #define NONLVALUE_DISPATCH(Op)\ switch (getSubKind()*NumNonLValueKind+RHS.getSubKind()){\ NONLVALUE_DISPATCH_CASE(ConcreteInt,ConcreteInt,Op)\ default:\ if (getBaseKind() == UninitializedKind ||\ RHS.getBaseKind() == UninitializedKind)\ return cast(UninitializedValue());\ assert (!isValid() || !RHS.isValid() && "Missing case.");\ break;\ }\ return cast(InvalidValue()); NonLValue NonLValue::Add(ValueManager& ValMgr, const NonLValue& RHS) const { NONLVALUE_DISPATCH(Add) } NonLValue NonLValue::Sub(ValueManager& ValMgr, const NonLValue& RHS) const { NONLVALUE_DISPATCH(Sub) } NonLValue NonLValue::Mul(ValueManager& ValMgr, const NonLValue& RHS) const { NONLVALUE_DISPATCH(Mul) } NonLValue NonLValue::Div(ValueManager& ValMgr, const NonLValue& RHS) const { NONLVALUE_DISPATCH(Div) } NonLValue NonLValue::Rem(ValueManager& ValMgr, const NonLValue& RHS) const { NONLVALUE_DISPATCH(Rem) } NonLValue NonLValue::EQ(ValueManager& ValMgr, const NonLValue& RHS) const { NONLVALUE_DISPATCH(EQ) } NonLValue NonLValue::NE(ValueManager& ValMgr, const NonLValue& RHS) const { NONLVALUE_DISPATCH(NE) } #undef NONLVALUE_DISPATCH_CASE #undef NONLVALUE_DISPATCH //===----------------------------------------------------------------------===// // Transfer function dispatch for LValues. //===----------------------------------------------------------------------===// NonLValue LValue::EQ(ValueManager& ValMgr, const LValue& RHS) const { if (getSubKind() != RHS.getSubKind()) return NonLValue::GetIntTruthValue(ValMgr, false); switch (getSubKind()) { default: assert(false && "EQ not implemented for this LValue."); return cast(InvalidValue()); case LValueDeclKind: { bool b = cast(*this) == cast(RHS); return NonLValue::GetIntTruthValue(ValMgr, b); } } } NonLValue LValue::NE(ValueManager& ValMgr, const LValue& RHS) const { if (getSubKind() != RHS.getSubKind()) return NonLValue::GetIntTruthValue(ValMgr, true); switch (getSubKind()) { default: assert(false && "EQ not implemented for this LValue."); return cast(InvalidValue()); case LValueDeclKind: { bool b = cast(*this) != cast(RHS); return NonLValue::GetIntTruthValue(ValMgr, b); } } } //===----------------------------------------------------------------------===// // Utility methods for constructing Non-LValues. //===----------------------------------------------------------------------===// NonLValue NonLValue::GetValue(ValueManager& ValMgr, uint64_t X, QualType T, SourceLocation Loc) { return ConcreteInt(ValMgr.getValue(X, T, Loc)); } NonLValue NonLValue::GetValue(ValueManager& ValMgr, IntegerLiteral* I) { return ConcreteInt(ValMgr.getValue(APSInt(I->getValue(), I->getType()->isUnsignedIntegerType()))); } NonLValue NonLValue::GetSymbolValue(SymbolManager& SymMgr, ParmVarDecl* D) { return SymbolicNonLValue(SymMgr.getSymbol(D)); } //===----------------------------------------------------------------------===// // Pretty-Printing. //===----------------------------------------------------------------------===// void RValue::print(std::ostream& Out) const { switch (getBaseKind()) { case InvalidKind: Out << "Invalid"; break; case NonLValueKind: cast(this)->print(Out); break; case LValueKind: assert (false && "FIXME: LValue printing not implemented."); break; case UninitializedKind: Out << "Uninitialized"; break; default: assert (false && "Invalid RValue."); } } void NonLValue::print(std::ostream& Out) const { switch (getSubKind()) { case ConcreteIntKind: Out << cast(this)->getValue().toString(); break; case SymbolicNonLValueKind: Out << '$' << cast(this)->getSymbolID(); break; default: assert (false && "Pretty-printed not implemented for this NonLValue."); break; } } //===----------------------------------------------------------------------===// // ValueMapTy - A ImmutableMap type Stmt*/Decl*/Symbols to RValues. //===----------------------------------------------------------------------===// typedef llvm::ImmutableMap ValueMapTy; namespace clang { template<> struct VISIBILITY_HIDDEN GRTrait { static inline void* toPtr(ValueMapTy M) { return reinterpret_cast(M.getRoot()); } static inline ValueMapTy toState(void* P) { return ValueMapTy(static_cast(P)); } }; } //===----------------------------------------------------------------------===// // The Checker. //===----------------------------------------------------------------------===// namespace { class VISIBILITY_HIDDEN GRConstants { public: typedef ValueMapTy StateTy; typedef GRStmtNodeBuilder StmtNodeBuilder; typedef GRBranchNodeBuilder BranchNodeBuilder; typedef ExplodedGraph GraphTy; typedef GraphTy::NodeTy NodeTy; class NodeSet { typedef llvm::SmallVector 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(); } bool empty() const { return Impl.empty(); } 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: /// G - the simulation graph. GraphTy& G; /// Liveness - live-variables information the ValueDecl* and block-level /// Expr* in the CFG. Used to prune out dead state. LiveVariables Liveness; /// Builder - The current GRStmtNodeBuilder which is used when building the nodes /// for a given statement. StmtNodeBuilder* Builder; /// StateMgr - Object that manages the data for all created states. ValueMapTy::Factory StateMgr; /// ValueMgr - Object that manages the data for all created RValues. ValueManager ValMgr; /// SymMgr - Object that manages the symbol information. SymbolManager SymMgr; /// StmtEntryNode - The immediate predecessor node. NodeTy* StmtEntryNode; /// CurrentStmt - The current block-level statement. Stmt* CurrentStmt; bool StateCleaned; ASTContext& getContext() const { return G.getContext(); } public: GRConstants(GraphTy& g) : G(g), Liveness(G.getCFG(), G.getFunctionDecl()), Builder(NULL), ValMgr(G.getContext()), StmtEntryNode(NULL), CurrentStmt(NULL) { // Compute liveness information. Liveness.runOnCFG(G.getCFG()); Liveness.runOnAllBlocks(G.getCFG(), NULL, true); } /// getCFG - Returns the CFG associated with this analysis. CFG& getCFG() { return G.getCFG(); } /// getInitialState - Return the initial state used for the root vertex /// in the ExplodedGraph. StateTy getInitialState() { StateTy St = StateMgr.GetEmptyMap(); // Iterate the parameters. FunctionDecl& F = G.getFunctionDecl(); for (FunctionDecl::param_iterator I=F.param_begin(), E=F.param_end(); I!=E; ++I) { // For now we only support symbolic values for non-pointer types. if ((*I)->getType()->isPointerType() || (*I)->getType()->isReferenceType()) continue; // FIXME: Set these values to a symbol, not Uninitialized. St = SetValue(St, LValueDecl(*I), NonLValue::GetSymbolValue(SymMgr, *I)); } return St; } /// ProcessStmt - Called by GREngine. Used to generate new successor /// nodes by processing the 'effects' of a block-level statement. void ProcessStmt(Stmt* S, StmtNodeBuilder& builder); /// ProcessBranch - Called by GREngine. Used to generate successor /// nodes by processing the 'effects' of a branch condition. void ProcessBranch(Stmt* Condition, Stmt* Term, BranchNodeBuilder& builder); /// 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 RValue& V); StateTy SetValue(StateTy St, const Stmt* S, const RValue& V) { return SetValue(St, const_cast(S), V); } StateTy SetValue(StateTy St, const LValue& LV, const RValue& V); RValue GetValue(const StateTy& St, Stmt* S); inline RValue GetValue(const StateTy& St, const Stmt* S) { return GetValue(St, const_cast(S)); } RValue GetValue(const StateTy& St, const LValue& LV); LValue GetLValue(const StateTy& St, Stmt* S); void Nodify(NodeSet& Dst, Stmt* S, NodeTy* Pred, StateTy St); /// 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); /// VisitCast - Transfer function logic for all casts (implicit and explicit). void VisitCast(Expr* CastE, Expr* E, NodeTy* Pred, NodeSet& Dst); /// VisitUnaryOperator - Transfer function logic for unary operators. void VisitUnaryOperator(UnaryOperator* B, NodeTy* Pred, NodeSet& Dst); /// VisitBinaryOperator - Transfer function logic for binary operators. void VisitBinaryOperator(BinaryOperator* B, NodeTy* Pred, NodeSet& Dst); /// VisitDeclStmt - Transfer function logic for DeclStmts. void VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst); }; } // end anonymous namespace void GRConstants::ProcessBranch(Stmt* Condition, Stmt* Term, BranchNodeBuilder& builder) { } void GRConstants::ProcessStmt(Stmt* S, StmtNodeBuilder& 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); } CurrentStmt = NULL; StmtEntryNode = NULL; Builder = NULL; } RValue GRConstants::GetValue(const StateTy& St, const LValue& LV) { switch (LV.getSubKind()) { case LValueDeclKind: { StateTy::TreeTy* T = St.SlimFind(cast(LV).getDecl()); return T ? T->getValue().second : InvalidValue(); } default: assert (false && "Invalid LValue."); break; } return InvalidValue(); } RValue GRConstants::GetValue(const StateTy& St, Stmt* S) { for (;;) { switch (S->getStmtClass()) { // ParenExprs are no-ops. case Stmt::ParenExprClass: S = cast(S)->getSubExpr(); continue; // DeclRefExprs can either evaluate to an LValue or a Non-LValue // (assuming an implicit "load") depending on the context. In this // context we assume that we are retrieving the value contained // within the referenced variables. case Stmt::DeclRefExprClass: return GetValue(St, LValueDecl(cast(S)->getDecl())); // Integer literals evaluate to an RValue. Simply retrieve the // RValue for the literal. case Stmt::IntegerLiteralClass: return NonLValue::GetValue(ValMgr, cast(S)); // Casts where the source and target type are the same // are no-ops. We blast through these to get the descendant // subexpression that has a value. case Stmt::ImplicitCastExprClass: { ImplicitCastExpr* C = cast(S); if (C->getType() == C->getSubExpr()->getType()) { S = C->getSubExpr(); continue; } break; } case Stmt::CastExprClass: { CastExpr* C = cast(S); if (C->getType() == C->getSubExpr()->getType()) { S = C->getSubExpr(); continue; } break; } // Handle all other Stmt* using a lookup. default: break; }; break; } StateTy::TreeTy* T = St.SlimFind(S); return T ? T->getValue().second : InvalidValue(); } LValue GRConstants::GetLValue(const StateTy& St, Stmt* S) { while (ParenExpr* P = dyn_cast(S)) S = P->getSubExpr(); if (DeclRefExpr* DR = dyn_cast(S)) return LValueDecl(DR->getDecl()); return cast(GetValue(St, S)); } GRConstants::StateTy GRConstants::SetValue(StateTy St, Stmt* S, const RValue& V) { assert (S); if (!StateCleaned) { St = RemoveDeadBindings(CurrentStmt, St); StateCleaned = true; } bool isBlkExpr = false; if (S == CurrentStmt) { isBlkExpr = getCFG().isBlkExpr(S); if (!isBlkExpr) return St; } return V.isValid() ? StateMgr.Add(St, ValueKey(S,isBlkExpr), V) : St; } GRConstants::StateTy GRConstants::SetValue(StateTy St, const LValue& LV, const RValue& V) { if (!LV.isValid()) return St; if (!StateCleaned) { St = RemoveDeadBindings(CurrentStmt, St); StateCleaned = true; } switch (LV.getSubKind()) { case LValueDeclKind: return V.isValid() ? StateMgr.Add(St, cast(LV).getDecl(), V) : StateMgr.Remove(St, cast(LV).getDecl()); default: assert ("SetValue for given LValue type not yet implemented."); return St; } } 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(); for (; I!=E && !I.getKey().isSymbol(); ++I) { // Remove old bindings for subexpressions and "dead" // block-level expressions. if (I.getKey().isSubExpr() || I.getKey().isBlkExpr() && !Liveness.isLive(Loc,cast(I.getKey()))){ M = StateMgr.Remove(M, I.getKey()); } else if (I.getKey().isDecl()) { // Remove bindings for "dead" decls. if (VarDecl* V = dyn_cast(cast(I.getKey()))) if (!Liveness.isLive(Loc, V)) M = StateMgr.Remove(M, I.getKey()); } } return M; } 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::VisitCast(Expr* CastE, Expr* E, GRConstants::NodeTy* Pred, GRConstants::NodeSet& Dst) { QualType T = CastE->getType(); // Check for redundant casts. if (E->getType() == T) { Dst.Add(Pred); return; } NodeSet S1; Visit(E, Pred, S1); for (NodeSet::iterator I1=S1.begin(), E1=S1.end(); I1 != E1; ++I1) { NodeTy* N = *I1; StateTy St = N->getState(); const RValue& V = GetValue(St, E); Nodify(Dst, CastE, N, SetValue(St, CastE, V.Cast(ValMgr, CastE))); } } void GRConstants::VisitDeclStmt(DeclStmt* DS, GRConstants::NodeTy* Pred, GRConstants::NodeSet& Dst) { StateTy St = Pred->getState(); for (const ScopedDecl* D = DS->getDecl(); D; D = D->getNextDeclarator()) if (const VarDecl* VD = dyn_cast(D)) { const Expr* E = VD->getInit(); St = SetValue(St, LValueDecl(VD), E ? GetValue(St, E) : UninitializedValue()); } Nodify(Dst, DS, Pred, St); if (Dst.empty()) Dst.Add(Pred); } void GRConstants::VisitUnaryOperator(UnaryOperator* U, GRConstants::NodeTy* Pred, GRConstants::NodeSet& Dst) { NodeSet S1; Visit(U->getSubExpr(), Pred, S1); for (NodeSet::iterator I1=S1.begin(), E1=S1.end(); I1 != E1; ++I1) { NodeTy* N1 = *I1; StateTy St = N1->getState(); switch (U->getOpcode()) { case UnaryOperator::PostInc: { const LValue& L1 = GetLValue(St, U->getSubExpr()); NonLValue R1 = cast(GetValue(St, L1)); NonLValue R2 = NonLValue::GetValue(ValMgr, 1U, U->getType(), U->getLocStart()); NonLValue Result = R1.Add(ValMgr, R2); Nodify(Dst, U, N1, SetValue(SetValue(St, U, R1), L1, Result)); break; } case UnaryOperator::PostDec: { const LValue& L1 = GetLValue(St, U->getSubExpr()); NonLValue R1 = cast(GetValue(St, L1)); NonLValue R2 = NonLValue::GetValue(ValMgr, 1U, U->getType(), U->getLocStart()); NonLValue Result = R1.Sub(ValMgr, R2); Nodify(Dst, U, N1, SetValue(SetValue(St, U, R1), L1, Result)); break; } case UnaryOperator::PreInc: { const LValue& L1 = GetLValue(St, U->getSubExpr()); NonLValue R1 = cast(GetValue(St, L1)); NonLValue R2 = NonLValue::GetValue(ValMgr, 1U, U->getType(), U->getLocStart()); NonLValue Result = R1.Add(ValMgr, R2); Nodify(Dst, U, N1, SetValue(SetValue(St, U, Result), L1, Result)); break; } case UnaryOperator::PreDec: { const LValue& L1 = GetLValue(St, U->getSubExpr()); NonLValue R1 = cast(GetValue(St, L1)); NonLValue R2 = NonLValue::GetValue(ValMgr, 1U, U->getType(), U->getLocStart()); NonLValue Result = R1.Sub(ValMgr, R2); Nodify(Dst, U, N1, SetValue(SetValue(St, U, Result), L1, Result)); break; } case UnaryOperator::Minus: { const NonLValue& R1 = cast(GetValue(St, U->getSubExpr())); Nodify(Dst, U, N1, SetValue(St, U, R1.UnaryMinus(ValMgr, U))); break; } default: ; assert (false && "Not implemented."); } } } 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 NonLValue. const RValue& 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 RValue& V2 = GetValue(St, B->getRHS()); switch (B->getOpcode()) { default: Dst.Add(N2); break; // Arithmetic opreators. case BinaryOperator::Add: { const NonLValue& R1 = cast(V1); const NonLValue& R2 = cast(V2); Nodify(Dst, B, N2, SetValue(St, B, R1.Add(ValMgr, R2))); break; } case BinaryOperator::Sub: { const NonLValue& R1 = cast(V1); const NonLValue& R2 = cast(V2); Nodify(Dst, B, N2, SetValue(St, B, R1.Sub(ValMgr, R2))); break; } case BinaryOperator::Mul: { const NonLValue& R1 = cast(V1); const NonLValue& R2 = cast(V2); Nodify(Dst, B, N2, SetValue(St, B, R1.Mul(ValMgr, R2))); break; } case BinaryOperator::Div: { const NonLValue& R1 = cast(V1); const NonLValue& R2 = cast(V2); Nodify(Dst, B, N2, SetValue(St, B, R1.Div(ValMgr, R2))); break; } case BinaryOperator::Rem: { const NonLValue& R1 = cast(V1); const NonLValue& R2 = cast(V2); Nodify(Dst, B, N2, SetValue(St, B, R1.Rem(ValMgr, R2))); break; } // Assignment operators. case BinaryOperator::Assign: { const LValue& L1 = cast(V1); const NonLValue& R2 = cast(V2); Nodify(Dst, B, N2, SetValue(SetValue(St, B, R2), L1, R2)); break; } case BinaryOperator::AddAssign: { const LValue& L1 = cast(V1); NonLValue R1 = cast(GetValue(N1->getState(), L1)); NonLValue Result = R1.Add(ValMgr, cast(V2)); Nodify(Dst, B, N2, SetValue(SetValue(St, B, Result), L1, Result)); break; } case BinaryOperator::SubAssign: { const LValue& L1 = cast(V1); NonLValue R1 = cast(GetValue(N1->getState(), L1)); NonLValue Result = R1.Sub(ValMgr, cast(V2)); Nodify(Dst, B, N2, SetValue(SetValue(St, B, Result), L1, Result)); break; } case BinaryOperator::MulAssign: { const LValue& L1 = cast(V1); NonLValue R1 = cast(GetValue(N1->getState(), L1)); NonLValue Result = R1.Mul(ValMgr, cast(V2)); Nodify(Dst, B, N2, SetValue(SetValue(St, B, Result), L1, Result)); break; } case BinaryOperator::DivAssign: { const LValue& L1 = cast(V1); NonLValue R1 = cast(GetValue(N1->getState(), L1)); NonLValue Result = R1.Div(ValMgr, cast(V2)); Nodify(Dst, B, N2, SetValue(SetValue(St, B, Result), L1, Result)); break; } case BinaryOperator::RemAssign: { const LValue& L1 = cast(V1); NonLValue R1 = cast(GetValue(N1->getState(), L1)); NonLValue Result = R1.Rem(ValMgr, cast(V2)); Nodify(Dst, B, N2, SetValue(SetValue(St, B, Result), L1, Result)); break; } // Equality operators. case BinaryOperator::EQ: // FIXME: should we allow XX.EQ() to return a set of values, // allowing state bifurcation? In such cases, they will also // modify the state (meaning that a new state will be returned // as well). assert (B->getType() == getContext().IntTy); if (isa(V1)) { const LValue& L1 = cast(V1); const LValue& L2 = cast(V2); St = SetValue(St, B, L1.EQ(ValMgr, L2)); } else { const NonLValue& R1 = cast(V1); const NonLValue& R2 = cast(V2); St = SetValue(St, B, R1.EQ(ValMgr, R2)); } Nodify(Dst, B, N2, St); break; } } } } 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. if (S != CurrentStmt && getCFG().isBlkExpr(S)) { Dst.Add(Pred); return; } switch (S->getStmtClass()) { case Stmt::BinaryOperatorClass: case Stmt::CompoundAssignOperatorClass: VisitBinaryOperator(cast(S), Pred, Dst); break; case Stmt::UnaryOperatorClass: VisitUnaryOperator(cast(S), Pred, Dst); break; case Stmt::ParenExprClass: Visit(cast(S)->getSubExpr(), Pred, Dst); break; case Stmt::ImplicitCastExprClass: { ImplicitCastExpr* C = cast(S); VisitCast(C, C->getSubExpr(), Pred, Dst); break; } case Stmt::CastExprClass: { CastExpr* C = cast(S); VisitCast(C, C->getSubExpr(), Pred, Dst); break; } case Stmt::DeclStmtClass: VisitDeclStmt(cast(S), Pred, Dst); break; default: Dst.Add(Pred); // No-op. Simply propagate the current state unchanged. break; } } //===----------------------------------------------------------------------===// // Driver. //===----------------------------------------------------------------------===// #ifndef NDEBUG namespace llvm { template<> struct VISIBILITY_HIDDEN DOTGraphTraits : public DefaultDOTGraphTraits { static void PrintKindLabel(std::ostream& Out, ValueKey::Kind kind) { switch (kind) { case ValueKey::IsSubExpr: Out << "Sub-Expressions:\\l"; break; case ValueKey::IsDecl: Out << "Variables:\\l"; break; case ValueKey::IsBlkExpr: Out << "Block-level Expressions:\\l"; break; default: assert (false && "Unknown ValueKey type."); } } static void PrintKind(std::ostream& Out, GRConstants::StateTy M, ValueKey::Kind kind, bool isFirstGroup = false) { bool isFirst = true; for (GRConstants::StateTy::iterator I=M.begin(), E=M.end();I!=E;++I) { if (I.getKey().getKind() != kind) continue; if (isFirst) { if (!isFirstGroup) Out << "\\l\\l"; PrintKindLabel(Out, kind); isFirst = false; } else Out << "\\l"; Out << ' '; if (ValueDecl* V = dyn_cast(I.getKey())) Out << V->getName(); else { Stmt* E = cast(I.getKey()); Out << " (" << (void*) E << ") "; E->printPretty(Out); } Out << " : "; I.getData().print(Out); } } static std::string getNodeLabel(const GRConstants::NodeTy* N, void*) { std::ostringstream Out; // Program Location. ProgramPoint Loc = N->getLocation(); switch (Loc.getKind()) { case ProgramPoint::BlockEntranceKind: Out << "Block Entrance: B" << cast(Loc).getBlock()->getBlockID(); break; case ProgramPoint::BlockExitKind: assert (false); break; case ProgramPoint::PostStmtKind: { const PostStmt& L = cast(Loc); Out << L.getStmt()->getStmtClassName() << ':' << (void*) L.getStmt() << ' '; L.getStmt()->printPretty(Out); break; } default: { const BlockEdge& E = cast(Loc); Out << "Edge: (B" << E.getSrc()->getBlockID() << ", B" << E.getDst()->getBlockID() << ')'; } } Out << "\\|"; PrintKind(Out, N->getState(), ValueKey::IsDecl, true); PrintKind(Out, N->getState(), ValueKey::IsBlkExpr); PrintKind(Out, N->getState(), ValueKey::IsSubExpr); Out << "\\l"; return Out.str(); } }; } // end llvm namespace #endif namespace clang { void RunGRConstants(CFG& cfg, FunctionDecl& FD, ASTContext& Ctx) { GREngine Engine(cfg, FD, Ctx); Engine.ExecuteWorkList(); #ifndef NDEBUG llvm::ViewGraph(*Engine.getGraph().roots_begin(),"GRConstants"); #endif } } // end clang namespace