Newer
Older
//= ValueState.cpp - Path-Sens. "State" for tracking valuues -----*- C++ -*--=//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This files defines SymbolID, ExprBindKey, and ValueState.
//
//===----------------------------------------------------------------------===//
#include "ValueState.h"
Ted Kremenek
committed
#include "llvm/ADT/SmallSet.h"
using namespace clang;
Ted Kremenek
committed
bool ValueState::isNotEqual(SymbolID sym, const llvm::APSInt& V) const {
// First, retrieve the NE-set associated with the given symbol.
ConstantNotEqTy::TreeTy* T = Data->ConstantNotEq.SlimFind(sym);
if (!T)
return false;
// Second, see if V is present in the NE-set.
return T->getValue().second.contains(&V);
}
const llvm::APSInt* ValueState::getSymVal(SymbolID sym) const {
ConstantEqTy::TreeTy* T = Data->ConstantEq.SlimFind(sym);
return T ? T->getValue().second : NULL;
}
ValueState
ValueStateManager::RemoveDeadBindings(ValueState St, Stmt* Loc,
const LiveVariables& Liveness) {
// This code essentially performs a "mark-and-sweep" of the VariableBindings.
// The roots are any Block-level exprs and Decls that our liveness algorithm
// tells us are live. We then see what Decls they may reference, and keep
// those around. This code more than likely can be made faster, and the
// frequency of which this method is called should be experimented with
// for optimum performance.
llvm::SmallVector<ValueDecl*, 10> WList;
Ted Kremenek
committed
llvm::SmallPtrSet<ValueDecl*, 10> Marked;
llvm::SmallSet<SymbolID, 20> MarkedSymbols;
ValueStateImpl NewSt = *St;
// Drop bindings for subexpressions.
NewSt.SubExprBindings = EXFactory.GetEmptyMap();
// Iterate over the block-expr bindings.
for (ValueState::beb_iterator I=St.beb_begin(), E=St.beb_end(); I!=E ; ++I) {
Expr* BlkExpr = I.getKey();
if (Liveness.isLive(Loc, BlkExpr)) {
Ted Kremenek
committed
RValue X = I.getData();
if (isa<lval::DeclVal>(X)) {
lval::DeclVal LV = cast<lval::DeclVal>(X);
WList.push_back(LV.getDecl());
Ted Kremenek
committed
for (RValue::symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end();
SI != SE; ++SI)
MarkedSymbols.insert(*SI);
NewSt.BlockExprBindings = Remove(NewSt, BlkExpr);
continue;
// Iterate over the variable bindings.
for (ValueState::vb_iterator I = St.vb_begin(), E = St.vb_end(); I!=E ; ++I)
if (Liveness.isLive(Loc, I.getKey()))
WList.push_back(I.getKey());
Ted Kremenek
committed
while (!WList.empty()) {
ValueDecl* V = WList.back();
WList.pop_back();
if (Marked.count(V))
continue;
Marked.insert(V);
if (V->getType()->isPointerType()) {
const LValue& LV =
cast<LValue>(GetValue(St, lval::DeclVal(cast<VarDecl>(V))));
Ted Kremenek
committed
for (RValue::symbol_iterator SI=LV.symbol_begin(), SE=LV.symbol_end();
SI != SE; ++SI)
MarkedSymbols.insert(*SI);
if (!isa<lval::DeclVal>(LV))
continue;
const lval::DeclVal& LVD = cast<lval::DeclVal>(LV);
WList.push_back(LVD.getDecl());
}
}
Ted Kremenek
committed
// Remove dead variable bindings.
for (ValueState::vb_iterator I = St.vb_begin(), E = St.vb_end(); I!=E ; ++I)
if (!Marked.count(I.getKey()))
NewSt.VarBindings = Remove(NewSt, I.getKey());
Ted Kremenek
committed
// Remove dead symbols.
for (ValueState::ce_iterator I = St.ce_begin(), E=St.ce_end(); I!=E; ++I)
if (!MarkedSymbols.count(I.getKey()))
NewSt.ConstantEq = CEFactory.Remove(NewSt.ConstantEq, I.getKey());
for (ValueState::cne_iterator I = St.cne_begin(), E=St.cne_end(); I!=E; ++I)
if (!MarkedSymbols.count(I.getKey()))
NewSt.ConstantNotEq = CNEFactory.Remove(NewSt.ConstantNotEq, I.getKey());
return getPersistentState(NewSt);
Ted Kremenek
committed
RValue ValueStateManager::GetValue(ValueState St, const LValue& LV,
QualType* T) {
if (isa<UnknownVal>(LV))
return UnknownVal();
assert (!isa<UninitializedVal>(LV));
switch (LV.getSubKind()) {
case lval::DeclValKind: {
ValueState::VarBindingsTy::TreeTy* T =
// FIXME: We should make lval::DeclVal only contain VarDecl
St->VarBindings.SlimFind(
cast<VarDecl>(cast<lval::DeclVal>(LV).getDecl()));
return T ? T->getValue().second : UnknownVal();
// FIXME: We should bind how far a "ContentsOf" will go...
case lval::SymbolValKind: {
const lval::SymbolVal& SV = cast<lval::SymbolVal>(LV);
assert (T);
if (T->getTypePtr()->isPointerType())
return lval::SymbolVal(SymMgr.getContentsOfSymbol(SV.getSymbol()));
else
return nonlval::SymbolVal(SymMgr.getContentsOfSymbol(SV.getSymbol()));
}
default:
assert (false && "Invalid LValue.");
break;
}
ValueState
ValueStateManager::AddNE(ValueState St, SymbolID sym, const llvm::APSInt& V) {
Ted Kremenek
committed
// First, retrieve the NE-set associated with the given symbol.
ValueState::ConstantNotEqTy::TreeTy* T = St->ConstantNotEq.SlimFind(sym);
Ted Kremenek
committed
ValueState::IntSetTy S = T ? T->getValue().second : ISetFactory.GetEmptySet();
// Now add V to the NE set.
S = ISetFactory.Add(S, &V);
// Create a new state with the old binding replaced.
ValueStateImpl NewSt = *St;
NewSt.ConstantNotEq = CNEFactory.Add(NewSt.ConstantNotEq,
Ted Kremenek
committed
sym, S);
// Get the persistent copy.
return getPersistentState(NewSt);
Ted Kremenek
committed
}
ValueState
ValueStateManager::AddEQ(ValueState St, SymbolID sym, const llvm::APSInt& V) {
Ted Kremenek
committed
// Create a new state with the old binding replaced.
ValueStateImpl NewSt = *St;
NewSt.ConstantEq = CEFactory.Add(NewSt.ConstantEq, sym, &V);
Ted Kremenek
committed
// Get the persistent copy.
return getPersistentState(NewSt);
Ted Kremenek
committed
}
RValue ValueStateManager::GetValue(ValueState St, Expr* E, bool* hasVal) {
case Stmt::AddrLabelExprClass:
return LValue::GetValue(cast<AddrLabelExpr>(E));
// ParenExprs are no-ops.
case Stmt::ParenExprClass:
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: {
ValueDecl* D = cast<DeclRefExpr>(E)->getDecl();
if (VarDecl* VD = dyn_cast<VarDecl>(D))
return GetValue(St, lval::DeclVal(VD));
else if (EnumConstantDecl* ED = dyn_cast<EnumConstantDecl>(D)) {
// FIXME: Do we need to cache a copy of this enum, since it
// already has persistent storage? We do this because we
// are comparing states using pointer equality. Perhaps there is
// a better way, since APInts are fairly lightweight.
return nonlval::ConcreteInt(ValMgr.getValue(ED->getInitVal()));
}
else if (FunctionDecl* FD = dyn_cast<FunctionDecl>(D))
return lval::FuncVal(FD);
assert (false &&
"ValueDecl support for this ValueDecl not implemented.");
return UnknownVal();
}
// Integer literals evaluate to an RValue. Simply retrieve the
// RValue for the literal.
#if 0
case Stmt::IntegerLiteralClass:
return NonLValue::GetValue(ValMgr, cast<IntegerLiteral>(E));
case Stmt::CharacterLiteralClass: {
CharacterLiteral* C = cast<CharacterLiteral>(E);
return NonLValue::GetValue(ValMgr, C->getValue(), C->getType(),
C->getLoc());
}
#endif
// 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: {
QualType CT = C->getType();
if (CT->isVoidType())
return UnknownVal();
QualType ST = C->getSubExpr()->getType();
if (CT == ST || (CT->isPointerType() && ST->isFunctionType())) {
continue;
}
break;
}
case Stmt::CastExprClass: {
QualType CT = C->getType();
QualType ST = C->getSubExpr()->getType();
if (CT->isVoidType())
return UnknownVal();
if (CT == ST || (CT->isPointerType() && ST->isFunctionType())) {
continue;
}
break;
}
// Handle all other Stmt* using a lookup.
default:
break;
};
break;
}
ValueState::ExprBindingsTy::TreeTy* T = St->SubExprBindings.SlimFind(E);
if (T) {
if (hasVal) *hasVal = true;
return T->getValue().second;
}
if (T) {
if (hasVal) *hasVal = true;
return T->getValue().second;
}
else {
if (hasVal) *hasVal = false;
LValue ValueStateManager::GetLValue(ValueState St, Expr* E) {
E = E->IgnoreParens();
if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E)) {
ValueDecl* VD = DR->getDecl();
if (FunctionDecl* FD = dyn_cast<FunctionDecl>(VD))
return lval::FuncVal(FD);
else
return lval::DeclVal(cast<VarDecl>(DR->getDecl()));
}
if (UnaryOperator* U = dyn_cast<UnaryOperator>(E))
if (U->getOpcode() == UnaryOperator::Deref) {
E = U->getSubExpr()->IgnoreParens();
if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E)) {
lval::DeclVal X(cast<VarDecl>(DR->getDecl()));
return cast<LValue>(GetValue(St, X));
}
else
return cast<LValue>(GetValue(St, E));
}
return cast<LValue>(GetValue(St, E));
ValueState
ValueStateManager::SetValue(ValueState St, Expr* E, bool isBlkExpr,
const RValue& V) {
assert (E);
if (V.isUnknown())
return St;
ValueStateImpl NewSt = *St;
if (isBlkExpr)
NewSt.BlockExprBindings = EXFactory.Add(NewSt.BlockExprBindings, E, V);
else
NewSt.SubExprBindings = EXFactory.Add(NewSt.SubExprBindings, E, V);
return getPersistentState(NewSt);
ValueState
ValueStateManager::SetValue(ValueState St, const LValue& LV, const RValue& V) {
if (isa<UnknownVal>(LV))
return St;
assert (!isa<UninitializedVal>(LV));
switch (LV.getSubKind()) {
case lval::DeclValKind:
return V.isKnown() // FIXME: Have DeclVal only contain VarDecl
? BindVar(St, cast<VarDecl>(cast<lval::DeclVal>(LV).getDecl()), V)
: UnbindVar(St, cast<VarDecl>(cast<lval::DeclVal>(LV).getDecl()));
default:
assert ("SetValue for given LValue type not yet implemented.");
return St;
}
}
ValueState
ValueStateManager::BindVar(ValueState St, VarDecl* D, const RValue& V) {
// Create a new state with the old binding removed.
ValueStateImpl NewSt = *St;
NewSt.VarBindings = VBFactory.Add(NewSt.VarBindings, D, V);
// Get the persistent copy.
return getPersistentState(NewSt);
ValueState
ValueStateManager::UnbindVar(ValueState St, VarDecl* D) {
// Create a new state with the old binding removed.
ValueStateImpl NewSt = *St;
NewSt.VarBindings = VBFactory.Remove(NewSt.VarBindings, D);
// Get the persistent copy.
return getPersistentState(NewSt);
}
ValueState
ValueStateManager::getInitialState() {
// Create a state with empty variable bindings.
ValueStateImpl StateImpl(EXFactory.GetEmptyMap(),
VBFactory.GetEmptyMap(),
Ted Kremenek
committed
CNEFactory.GetEmptyMap(),
CEFactory.GetEmptyMap());
return getPersistentState(StateImpl);
}
ValueState
ValueStateManager::getPersistentState(const ValueStateImpl &State) {
llvm::FoldingSetNodeID ID;
State.Profile(ID);
void* InsertPos;
if (ValueStateImpl* I = StateSet.FindNodeOrInsertPos(ID, InsertPos))
return I;
ValueStateImpl* I = (ValueStateImpl*) Alloc.Allocate<ValueStateImpl>();
new (I) ValueStateImpl(State);
StateSet.InsertNode(I, InsertPos);
return I;
}
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
void ValueState::printDOT(std::ostream& Out) const {
// Print Variable Bindings
Out << "Variables:\\l";
bool isFirst = true;
for (vb_iterator I=vb_begin(), E=vb_end(); I!=E; ++I) {
if (isFirst)
isFirst = false;
else
Out << "\\l";
Out << ' ' << I.getKey()->getName() << " : ";
I.getData().print(Out);
}
// Print Subexpression bindings.
isFirst = true;
for (seb_iterator I=seb_begin(), E=seb_end(); I != E;++I) {
if (isFirst) {
Out << "\\l\\lSub-Expressions:\\l";
isFirst = false;
}
else
Out << "\\l";
Out << " (" << (void*) I.getKey() << ") ";
I.getKey()->printPretty(Out);
Out << " : ";
I.getData().print(Out);
}
// Print block-expression bindings.
isFirst = true;
for (beb_iterator I=beb_begin(), E=beb_end(); I != E; ++I) {
if (isFirst) {
Out << "\\l\\lBlock-level Expressions:\\l";
isFirst = false;
}
else
Out << "\\l";
Out << " (" << (void*) I.getKey() << ") ";
I.getKey()->printPretty(Out);
Out << " : ";
I.getData().print(Out);
}
// Print equality constraints.
if (!Data->ConstantEq.isEmpty()) {
Out << "\\l\\|'==' constraints:";
for (ConstantEqTy::iterator I=Data->ConstantEq.begin(),
E=Data->ConstantEq.end(); I!=E;++I)
Out << "\\l $" << I.getKey() << " : " << I.getData()->toString();
}
// Print != constraints.
if (!Data->ConstantNotEq.isEmpty()) {
Out << "\\l\\|'!=' constraints:";
for (ConstantNotEqTy::iterator I=Data->ConstantNotEq.begin(),
EI=Data->ConstantNotEq.end(); I != EI; ++I) {
Out << "\\l $" << I.getKey() << " : ";
isFirst = true;
IntSetTy::iterator J=I.getData().begin(), EJ=I.getData().end();
for ( ; J != EJ; ++J) {
if (isFirst) isFirst = false;
else Out << ", ";
Out << (*J)->toString();
}
}
}
}