Newer
Older
//= RValues.cpp - Abstract RValues for Path-Sens. Value Tracking -*- 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 RValue, LValue, and NonLValue, classes that represent
// abstract r-values for use with path-sensitive value tracking.
//
//===----------------------------------------------------------------------===//
#include "RValues.h"
using namespace clang;
using llvm::dyn_cast;
using llvm::cast;
using llvm::APSInt;
//===----------------------------------------------------------------------===//
// SymbolManager.
//===----------------------------------------------------------------------===//
SymbolID SymbolManager::getSymbol(ParmVarDecl* D) {
SymbolID& X = DataToSymbol[getKey(D)];
if (!X.isInitialized()) {
X = SymbolToData.size();
SymbolToData.push_back(SymbolDataParmVar(D));
}
return X;
}
SymbolID SymbolManager::getContentsOfSymbol(SymbolID sym) {
SymbolID& X = DataToSymbol[getKey(sym)];
if (!X.isInitialized()) {
X = SymbolToData.size();
SymbolToData.push_back(SymbolDataContentsOf(sym));
}
return X;
}
Ted Kremenek
committed
QualType SymbolData::getType() const {
switch (getKind()) {
default:
assert (false && "getType() not implemented for this symbol.");
case ParmKind:
return cast<SymbolDataParmVar>(this)->getDecl()->getType();
Ted Kremenek
committed
}
}
SymbolManager::SymbolManager() {}
SymbolManager::~SymbolManager() {}
//===----------------------------------------------------------------------===//
Ted Kremenek
committed
// Values and ValueManager.
//===----------------------------------------------------------------------===//
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();
}
Ted Kremenek
committed
const APSInt& ValueManager::getValue(const APSInt& X) {
llvm::FoldingSetNodeID ID;
void* InsertPos;
typedef llvm::FoldingSetNodeWrapper<APSInt> FoldNodeTy;
X.Profile(ID);
FoldNodeTy* P = APSIntSet.FindNodeOrInsertPos(ID, InsertPos);
if (!P) {
P = (FoldNodeTy*) BPAlloc.Allocate<FoldNodeTy>();
new (P) FoldNodeTy(X);
APSIntSet.InsertNode(P, InsertPos);
}
return *P;
}
Ted Kremenek
committed
const APSInt& ValueManager::getValue(uint64_t X, unsigned BitWidth,
bool isUnsigned) {
APSInt V(BitWidth, isUnsigned);
V = X;
return getValue(V);
}
Ted Kremenek
committed
const 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);
}
Ted Kremenek
committed
const SymIntConstraint&
ValueManager::getConstraint(SymbolID sym, BinaryOperator::Opcode Op,
const llvm::APSInt& V) {
llvm::FoldingSetNodeID ID;
SymIntConstraint::Profile(ID, sym, Op, V);
void* InsertPos;
SymIntConstraint* C = SymIntCSet.FindNodeOrInsertPos(ID, InsertPos);
if (!C) {
C = (SymIntConstraint*) BPAlloc.Allocate<SymIntConstraint>();
new (C) SymIntConstraint(sym, Op, V);
SymIntCSet.InsertNode(C, InsertPos);
}
return *C;
}
//===----------------------------------------------------------------------===//
// Transfer function for Casts.
//===----------------------------------------------------------------------===//
RValue RValue::EvalCast(ValueManager& ValMgr, Expr* CastExpr) const {
switch (getBaseKind()) {
default: assert(false && "Invalid RValue."); break;
case LValueKind: return cast<LValue>(this)->EvalCast(ValMgr, CastExpr);
case NonLValueKind: return cast<NonLValue>(this)->EvalCast(ValMgr, CastExpr);
case UninitializedKind: case UnknownKind: break;
return *this;
}
//===----------------------------------------------------------------------===//
// Transfer function dispatch for Non-LValues.
//===----------------------------------------------------------------------===//
// Binary Operators (except assignments and comma).
NonLValue NonLValue::EvalBinaryOp(ValueManager& ValMgr,
BinaryOperator::Opcode Op,
const NonLValue& RHS) const {
if (isa<UnknownVal>(this) || isa<UnknownVal>(RHS))
return cast<NonLValue>(UnknownVal());
if (isa<UninitializedVal>(this) || isa<UninitializedVal>(RHS))
return cast<NonLValue>(UninitializedVal());
switch (getSubKind()) {
default:
assert (false && "Binary Operators not implemented for this NonLValue");
case nonlval::ConcreteIntKind:
if (isa<nonlval::ConcreteInt>(RHS)) {
nonlval::ConcreteInt& self = cast<nonlval::ConcreteInt>(*this);
return self.EvalBinaryOp(ValMgr, Op,
cast<nonlval::ConcreteInt>(RHS));
}
else if(isa<UnknownVal>(RHS))
return cast<NonLValue>(UnknownVal());
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
else
return RHS.EvalBinaryOp(ValMgr, Op, *this);
case nonlval::SymbolValKind: {
const nonlval::SymbolVal& self = cast<nonlval::SymbolVal>(*this);
switch (RHS.getSubKind()) {
default: assert ("Not Implemented." && false);
case nonlval::ConcreteIntKind: {
const SymIntConstraint& C =
ValMgr.getConstraint(self.getSymbol(), Op,
cast<nonlval::ConcreteInt>(RHS).getValue());
return nonlval::SymIntConstraintVal(C);
}
}
}
}
}
static const
llvm::APSInt& EvaluateAPSInt(ValueManager& ValMgr, BinaryOperator::Opcode Op,
const llvm::APSInt& V1, const llvm::APSInt& V2) {
switch (Op) {
default:
assert (false && "Invalid Opcode.");
case BinaryOperator::Mul:
return ValMgr.getValue( V1 * V2 );
case BinaryOperator::Div:
return ValMgr.getValue( V1 / V2 );
case BinaryOperator::Rem:
return ValMgr.getValue( V1 % V2 );
case BinaryOperator::Add:
return ValMgr.getValue( V1 + V2 );
case BinaryOperator::Sub:
return ValMgr.getValue( V1 - V2 );
case BinaryOperator::Shl:
return ValMgr.getValue( V1.operator<<( (unsigned) V2.getZExtValue() ));
case BinaryOperator::Shr:
return ValMgr.getValue( V1.operator>>( (unsigned) V2.getZExtValue() ));
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
case BinaryOperator::LT:
return ValMgr.getTruthValue( V1 < V2 );
case BinaryOperator::GT:
return ValMgr.getTruthValue( V1 > V2 );
case BinaryOperator::LE:
return ValMgr.getTruthValue( V1 <= V2 );
case BinaryOperator::GE:
return ValMgr.getTruthValue( V1 >= V2 );
case BinaryOperator::EQ:
return ValMgr.getTruthValue( V1 == V2 );
case BinaryOperator::NE:
return ValMgr.getTruthValue( V1 != V2 );
// Note: LAnd, LOr, Comma are handled specially by higher-level logic.
case BinaryOperator::And:
return ValMgr.getValue( V1 & V2 );
case BinaryOperator::Or:
return ValMgr.getValue( V1 | V2 );
}
}
nonlval::ConcreteInt
nonlval::ConcreteInt::EvalBinaryOp(ValueManager& ValMgr,
BinaryOperator::Opcode Op,
const nonlval::ConcreteInt& RHS) const {
return EvaluateAPSInt(ValMgr, Op, getValue(), RHS.getValue());
}
// Bitwise-Complement.
NonLValue NonLValue::EvalComplement(ValueManager& ValMgr) const {
switch (getSubKind()) {
case nonlval::ConcreteIntKind:
return cast<nonlval::ConcreteInt>(this)->EvalComplement(ValMgr);
default:
return cast<NonLValue>(UnknownVal());
nonlval::ConcreteInt
nonlval::ConcreteInt::EvalComplement(ValueManager& ValMgr) const {
return ValMgr.getValue(~getValue());
}
// Casts.
RValue NonLValue::EvalCast(ValueManager& ValMgr, Expr* CastExpr) const {
if (!isa<nonlval::ConcreteInt>(this))
APSInt V = cast<nonlval::ConcreteInt>(this)->getValue();
QualType T = CastExpr->getType();
Ted Kremenek
committed
V.setIsUnsigned(T->isUnsignedIntegerType() || T->isPointerType());
V.extOrTrunc(ValMgr.getContext().getTypeSize(T, CastExpr->getLocStart()));
if (CastExpr->getType()->isPointerType())
return lval::ConcreteInt(ValMgr.getValue(V));
return nonlval::ConcreteInt(ValMgr.getValue(V));
// Unary Minus.
NonLValue NonLValue::EvalMinus(ValueManager& ValMgr, UnaryOperator* U) const {
switch (getSubKind()) {
case nonlval::ConcreteIntKind:
return cast<nonlval::ConcreteInt>(this)->EvalMinus(ValMgr, U);
return cast<NonLValue>(UnknownVal());
nonlval::ConcreteInt
nonlval::ConcreteInt::EvalMinus(ValueManager& ValMgr, UnaryOperator* U) const {
assert (U->getType() == U->getSubExpr()->getType());
assert (U->getType()->isIntegerType());
return ValMgr.getValue(-getValue());
//===----------------------------------------------------------------------===//
// Transfer function dispatch for LValues.
//===----------------------------------------------------------------------===//
// Binary Operators (except assignments and comma).
RValue LValue::EvalBinaryOp(ValueManager& ValMgr,
BinaryOperator::Opcode Op,
const LValue& RHS) const {
switch (Op) {
default:
assert (false && "Not yet implemented.");
case BinaryOperator::EQ:
return EQ(ValMgr, RHS);
case BinaryOperator::NE:
return NE(ValMgr, RHS);
}
lval::ConcreteInt
lval::ConcreteInt::EvalBinaryOp(ValueManager& ValMgr,
BinaryOperator::Opcode Op,
const lval::ConcreteInt& RHS) const {
assert (Op == BinaryOperator::Add || Op == BinaryOperator::Sub ||
(Op >= BinaryOperator::LT && Op <= BinaryOperator::NE));
return EvaluateAPSInt(ValMgr, Op, getValue(), RHS.getValue());
}
NonLValue LValue::EQ(ValueManager& ValMgr, const LValue& RHS) const {
switch (getSubKind()) {
default:
assert(false && "EQ not implemented for this LValue.");
return cast<NonLValue>(UnknownVal());
case lval::ConcreteIntKind:
if (isa<lval::ConcreteInt>(RHS)) {
bool b = cast<lval::ConcreteInt>(this)->getValue() ==
cast<lval::ConcreteInt>(RHS).getValue();
return NonLValue::GetIntTruthValue(ValMgr, b);
}
else if (isa<lval::SymbolVal>(RHS)) {
const SymIntConstraint& C =
ValMgr.getConstraint(cast<lval::SymbolVal>(RHS).getSymbol(),
BinaryOperator::EQ,
cast<lval::ConcreteInt>(this)->getValue());
return nonlval::SymIntConstraintVal(C);
}
break;
case lval::SymbolValKind: {
if (isa<lval::ConcreteInt>(RHS)) {
const SymIntConstraint& C =
ValMgr.getConstraint(cast<lval::SymbolVal>(this)->getSymbol(),
BinaryOperator::EQ,
cast<lval::ConcreteInt>(RHS).getValue());
return nonlval::SymIntConstraintVal(C);
}
assert (!isa<lval::SymbolVal>(RHS) && "FIXME: Implement unification.");
break;
case lval::DeclValKind:
if (isa<lval::DeclVal>(RHS)) {
bool b = cast<lval::DeclVal>(*this) == cast<lval::DeclVal>(RHS);
return NonLValue::GetIntTruthValue(ValMgr, b);
}
break;
return NonLValue::GetIntTruthValue(ValMgr, false);
}
NonLValue LValue::NE(ValueManager& ValMgr, const LValue& RHS) const {
switch (getSubKind()) {
default:
assert(false && "NE not implemented for this LValue.");
return cast<NonLValue>(UnknownVal());
case lval::ConcreteIntKind:
if (isa<lval::ConcreteInt>(RHS)) {
bool b = cast<lval::ConcreteInt>(this)->getValue() !=
cast<lval::ConcreteInt>(RHS).getValue();
return NonLValue::GetIntTruthValue(ValMgr, b);
}
else if (isa<lval::SymbolVal>(RHS)) {
const SymIntConstraint& C =
ValMgr.getConstraint(cast<lval::SymbolVal>(RHS).getSymbol(),
BinaryOperator::NE,
cast<lval::ConcreteInt>(this)->getValue());
return nonlval::SymIntConstraintVal(C);
}
case lval::SymbolValKind: {
if (isa<lval::ConcreteInt>(RHS)) {
const SymIntConstraint& C =
ValMgr.getConstraint(cast<lval::SymbolVal>(this)->getSymbol(),
BinaryOperator::NE,
cast<lval::ConcreteInt>(RHS).getValue());
return nonlval::SymIntConstraintVal(C);
}
assert (!isa<lval::SymbolVal>(RHS) && "FIXME: Implement sym !=.");
break;
}
case lval::DeclValKind:
if (isa<lval::DeclVal>(RHS)) {
bool b = cast<lval::DeclVal>(*this) == cast<lval::DeclVal>(RHS);
return NonLValue::GetIntTruthValue(ValMgr, b);
}
break;
return NonLValue::GetIntTruthValue(ValMgr, true);
// Casts.
RValue LValue::EvalCast(ValueManager& ValMgr, Expr* CastExpr) const {
if (CastExpr->getType()->isPointerType())
return *this;
assert (CastExpr->getType()->isIntegerType());
if (!isa<lval::ConcreteInt>(*this))
APSInt V = cast<lval::ConcreteInt>(this)->getValue();
QualType T = CastExpr->getType();
V.setIsUnsigned(T->isUnsignedIntegerType() || T->isPointerType());
V.extOrTrunc(ValMgr.getContext().getTypeSize(T, CastExpr->getLocStart()));
return nonlval::ConcreteInt(ValMgr.getValue(V));
}
//===----------------------------------------------------------------------===//
// Utility methods for constructing Non-LValues.
//===----------------------------------------------------------------------===//
NonLValue NonLValue::GetValue(ValueManager& ValMgr, uint64_t X, QualType T,
SourceLocation Loc) {
return nonlval::ConcreteInt(ValMgr.getValue(X, T, Loc));
}
NonLValue NonLValue::GetValue(ValueManager& ValMgr, IntegerLiteral* I) {
return nonlval::ConcreteInt(ValMgr.getValue(APSInt(I->getValue(),
I->getType()->isUnsignedIntegerType())));
NonLValue NonLValue::GetIntTruthValue(ValueManager& ValMgr, bool b) {
return nonlval::ConcreteInt(ValMgr.getTruthValue(b));
}
RValue RValue::GetSymbolValue(SymbolManager& SymMgr, ParmVarDecl* D) {
QualType T = D->getType();
if (T->isPointerType() || T->isReferenceType())
return lval::SymbolVal(SymMgr.getSymbol(D));
return nonlval::SymbolVal(SymMgr.getSymbol(D));
void RValue::print() const {
print(*llvm::cerr.stream());
}
//===----------------------------------------------------------------------===//
// Pretty-Printing.
//===----------------------------------------------------------------------===//
void RValue::print(std::ostream& Out) const {
switch (getBaseKind()) {
Out << "Invalid";
break;
case NonLValueKind:
cast<NonLValue>(this)->print(Out);
break;
case LValueKind:
cast<LValue>(this)->print(Out);
break;
case UninitializedKind:
Out << "Uninitialized";
break;
default:
assert (false && "Invalid RValue.");
}
}
static void printOpcode(std::ostream& Out, BinaryOperator::Opcode Op) {
switch (Op) {
case BinaryOperator::Add: Out << "+" ; break;
case BinaryOperator::Sub: Out << "-" ; break;
case BinaryOperator::EQ: Out << "=="; break;
case BinaryOperator::NE: Out << "!="; break;
default: assert(false && "Not yet implemented.");
}
}
void NonLValue::print(std::ostream& Out) const {
switch (getSubKind()) {
case nonlval::ConcreteIntKind:
Out << cast<nonlval::ConcreteInt>(this)->getValue().toString();
if (cast<nonlval::ConcreteInt>(this)->getValue().isUnsigned())
Out << 'U';
case nonlval::SymbolValKind:
Out << '$' << cast<nonlval::SymbolVal>(this)->getSymbol();
case nonlval::SymIntConstraintValKind: {
const nonlval::SymIntConstraintVal& C =
*cast<nonlval::SymIntConstraintVal>(this);
Out << '$' << C.getConstraint().getSymbol() << ' ';
printOpcode(Out, C.getConstraint().getOpcode());
Out << ' ' << C.getConstraint().getInt().toString();
if (C.getConstraint().getInt().isUnsigned())
Out << 'U';
break;
}
default:
assert (false && "Pretty-printed not implemented for this NonLValue.");
break;
}
}
void LValue::print(std::ostream& Out) const {
switch (getSubKind()) {
case lval::ConcreteIntKind:
Out << cast<lval::ConcreteInt>(this)->getValue().toString()
<< " (LValue)";
break;
case lval::SymbolValKind:
Out << '$' << cast<lval::SymbolVal>(this)->getSymbol();
Ted Kremenek
committed
case lval::DeclValKind:
<< cast<lval::DeclVal>(this)->getDecl()->getIdentifier()->getName();
break;
default:
assert (false && "Pretty-printed not implemented for this LValue.");
break;
}
}