Major code refactoring/cleanup with transfer function logic. Now the

code structure is more suitable for additional symbolic analysis.

llvm-svn: 46831
This commit is contained in:
Ted Kremenek 2008-02-06 22:50:25 +00:00
parent 1242fff6ec
commit cdd0be1dc1
3 changed files with 337 additions and 306 deletions

View File

@ -537,7 +537,7 @@ void GRConstants::VisitCast(Expr* CastE, Expr* E, NodeTy* Pred, NodeSet& Dst) {
NodeTy* N = *I1;
StateTy St = N->getState();
const RValue& V = GetValue(St, E);
Nodify(Dst, CastE, N, SetValue(St, CastE, V.Cast(ValMgr, CastE)));
Nodify(Dst, CastE, N, SetValue(St, CastE, V.EvalCast(ValMgr, CastE)));
}
}
@ -585,7 +585,10 @@ void GRConstants::VisitUnaryOperator(UnaryOperator* U,
case UnaryOperator::PostInc: {
const LValue& L1 = GetLValue(St, U->getSubExpr());
NonLValue R1 = cast<NonLValue>(GetValue(St, L1));
NonLValue Result = R1.Add(ValMgr, GetRValueConstant(1U, U));
NonLValue Result = R1.EvalBinaryOp(ValMgr, BinaryOperator::Add,
GetRValueConstant(1U, U));
Nodify(Dst, U, N1, SetValue(SetValue(St, U, R1), L1, Result));
break;
}
@ -593,7 +596,10 @@ void GRConstants::VisitUnaryOperator(UnaryOperator* U,
case UnaryOperator::PostDec: {
const LValue& L1 = GetLValue(St, U->getSubExpr());
NonLValue R1 = cast<NonLValue>(GetValue(St, L1));
NonLValue Result = R1.Sub(ValMgr, GetRValueConstant(1U, U));
NonLValue Result = R1.EvalBinaryOp(ValMgr, BinaryOperator::Sub,
GetRValueConstant(1U, U));
Nodify(Dst, U, N1, SetValue(SetValue(St, U, R1), L1, Result));
break;
}
@ -601,7 +607,10 @@ void GRConstants::VisitUnaryOperator(UnaryOperator* U,
case UnaryOperator::PreInc: {
const LValue& L1 = GetLValue(St, U->getSubExpr());
NonLValue R1 = cast<NonLValue>(GetValue(St, L1));
NonLValue Result = R1.Add(ValMgr, GetRValueConstant(1U, U));
NonLValue Result = R1.EvalBinaryOp(ValMgr, BinaryOperator::Add,
GetRValueConstant(1U, U));
Nodify(Dst, U, N1, SetValue(SetValue(St, U, Result), L1, Result));
break;
}
@ -609,20 +618,23 @@ void GRConstants::VisitUnaryOperator(UnaryOperator* U,
case UnaryOperator::PreDec: {
const LValue& L1 = GetLValue(St, U->getSubExpr());
NonLValue R1 = cast<NonLValue>(GetValue(St, L1));
NonLValue Result = R1.Sub(ValMgr, GetRValueConstant(1U, U));
NonLValue Result = R1.EvalBinaryOp(ValMgr, BinaryOperator::Sub,
GetRValueConstant(1U, U));
Nodify(Dst, U, N1, SetValue(SetValue(St, U, Result), L1, Result));
break;
}
case UnaryOperator::Minus: {
const NonLValue& R1 = cast<NonLValue>(GetValue(St, U->getSubExpr()));
Nodify(Dst, U, N1, SetValue(St, U, R1.UnaryMinus(ValMgr, U)));
Nodify(Dst, U, N1, SetValue(St, U, R1.EvalMinus(ValMgr, U)));
break;
}
case UnaryOperator::Not: {
const NonLValue& R1 = cast<NonLValue>(GetValue(St, U->getSubExpr()));
Nodify(Dst, U, N1, SetValue(St, U, R1.BitwiseComplement(ValMgr)));
Nodify(Dst, U, N1, SetValue(St, U, R1.EvalComplement(ValMgr)));
break;
}
@ -635,14 +647,18 @@ void GRConstants::VisitUnaryOperator(UnaryOperator* U,
RValue V1 = GetValue(St, U->getSubExpr());
if (isa<LValue>(V1)) {
lval::ConcreteInt V2(ValMgr.getValue(0, U->getSubExpr()->getType()));
Nodify(Dst, U, N1, SetValue(St, U,
cast<LValue>(V1).EQ(ValMgr, V2)));
const LValue& L1 = cast<LValue>(V1);
lval::ConcreteInt V2(ValMgr.getZeroWithPtrWidth());
Nodify(Dst, U, N1,
SetValue(St, U, L1.EvalBinaryOp(ValMgr, BinaryOperator::EQ,
V2)));
}
else {
const NonLValue& R1 = cast<NonLValue>(V1);
nonlval::ConcreteInt V2(ValMgr.getZeroWithPtrWidth());
Nodify(Dst, U, N1, SetValue(St, U,
cast<NonLValue>(V1).EQ(ValMgr, V2)));
Nodify(Dst, U, N1,
SetValue(St, U, R1.EvalBinaryOp(ValMgr, BinaryOperator::EQ,
V2)));
}
break;
@ -687,122 +703,63 @@ void GRConstants::VisitBinaryOperator(BinaryOperator* B,
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;
BinaryOperator::Opcode Op = B->getOpcode();
if (Op <= BinaryOperator::Or) {
if (isa<LValue>(V1)) {
// FIXME: Add support for RHS being a non-lvalue.
const LValue& L1 = cast<LValue>(V1);
const LValue& L2 = cast<LValue>(V2);
// Arithmetic operators.
case BinaryOperator::Add: {
Nodify(Dst, B, N2, SetValue(St, B, L1.EvalBinaryOp(ValMgr, Op, L2)));
}
else {
const NonLValue& R1 = cast<NonLValue>(V1);
const NonLValue& R2 = cast<NonLValue>(V2);
Nodify(Dst, B, N2, SetValue(St, B, R1.Add(ValMgr, R2)));
break;
Nodify(Dst, B, N2, SetValue(St, B, R1.EvalBinaryOp(ValMgr, Op, R2)));
}
case BinaryOperator::Sub: {
const NonLValue& R1 = cast<NonLValue>(V1);
const NonLValue& R2 = cast<NonLValue>(V2);
Nodify(Dst, B, N2, SetValue(St, B, R1.Sub(ValMgr, R2)));
break;
}
case BinaryOperator::Mul: {
const NonLValue& R1 = cast<NonLValue>(V1);
const NonLValue& R2 = cast<NonLValue>(V2);
Nodify(Dst, B, N2, SetValue(St, B, R1.Mul(ValMgr, R2)));
break;
}
case BinaryOperator::Div: {
const NonLValue& R1 = cast<NonLValue>(V1);
const NonLValue& R2 = cast<NonLValue>(V2);
Nodify(Dst, B, N2, SetValue(St, B, R1.Div(ValMgr, R2)));
break;
}
case BinaryOperator::Rem: {
const NonLValue& R1 = cast<NonLValue>(V1);
const NonLValue& R2 = cast<NonLValue>(V2);
Nodify(Dst, B, N2, SetValue(St, B, R1.Rem(ValMgr, R2)));
break;
}
// Assignment operators.
continue;
}
switch (Op) {
case BinaryOperator::Assign: {
const LValue& L1 = cast<LValue>(V1);
Nodify(Dst, B, N2, SetValue(SetValue(St, B, V2), L1, V2));
break;
}
case BinaryOperator::AddAssign: {
const LValue& L1 = cast<LValue>(V1);
NonLValue R1 = cast<NonLValue>(GetValue(N1->getState(), L1));
NonLValue Result = R1.Add(ValMgr, cast<NonLValue>(V2));
Nodify(Dst, B, N2, SetValue(SetValue(St, B, Result), L1, Result));
break;
}
case BinaryOperator::SubAssign: {
const LValue& L1 = cast<LValue>(V1);
NonLValue R1 = cast<NonLValue>(GetValue(N1->getState(), L1));
NonLValue Result = R1.Sub(ValMgr, cast<NonLValue>(V2));
Nodify(Dst, B, N2, SetValue(SetValue(St, B, Result), L1, Result));
break;
}
case BinaryOperator::MulAssign: {
const LValue& L1 = cast<LValue>(V1);
NonLValue R1 = cast<NonLValue>(GetValue(N1->getState(), L1));
NonLValue Result = R1.Mul(ValMgr, cast<NonLValue>(V2));
Nodify(Dst, B, N2, SetValue(SetValue(St, B, Result), L1, Result));
break;
}
case BinaryOperator::DivAssign: {
const LValue& L1 = cast<LValue>(V1);
NonLValue R1 = cast<NonLValue>(GetValue(N1->getState(), L1));
NonLValue Result = R1.Div(ValMgr, cast<NonLValue>(V2));
Nodify(Dst, B, N2, SetValue(SetValue(St, B, Result), L1, Result));
break;
}
case BinaryOperator::RemAssign: {
const LValue& L1 = cast<LValue>(V1);
NonLValue R1 = cast<NonLValue>(GetValue(N1->getState(), L1));
NonLValue Result = R1.Rem(ValMgr, cast<NonLValue>(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);
default: { // Compound assignment operators.
if (isa<LValue>(V1)) {
const LValue& L1 = cast<LValue>(V1);
assert (B->isCompoundAssignmentOp());
const LValue& L1 = cast<LValue>(V1);
RValue Result = cast<NonLValue>(InvalidValue());
Op = (BinaryOperator::Opcode)
(((unsigned) Op) - ((unsigned) BinaryOperator::MulAssign));
if (isa<LValue>(V2)) {
// FIXME: Add support for Non-LValues on RHS.
const LValue& L2 = cast<LValue>(V2);
Nodify(Dst, B, N2, SetValue(St, B, L1.EQ(ValMgr, L2)));
Result = L1.EvalBinaryOp(ValMgr, Op, L2);
}
else {
const NonLValue& R1 = cast<NonLValue>(V1);
const NonLValue& R1 = cast<NonLValue>(GetValue(N1->getState(), L1));
const NonLValue& R2 = cast<NonLValue>(V2);
Nodify(Dst, B, N2, SetValue(St, B, R1.EQ(ValMgr, R2)));
Result = R1.EvalBinaryOp(ValMgr, Op, R2);
}
Nodify(Dst, B, N2, SetValue(SetValue(St, B, Result), L1, Result));
break;
}
}
}
}

View File

@ -115,37 +115,157 @@ ValueManager::getConstraint(SymbolID sym, BinaryOperator::Opcode Op,
// Transfer function for Casts.
//===----------------------------------------------------------------------===//
RValue RValue::Cast(ValueManager& ValMgr, Expr* CastExpr) const {
RValue RValue::EvalCast(ValueManager& ValMgr, Expr* CastExpr) const {
switch (getBaseKind()) {
default: assert(false && "Invalid RValue."); break;
case LValueKind: return cast<LValue>(this)->Cast(ValMgr, CastExpr);
case NonLValueKind: return cast<NonLValue>(this)->Cast(ValMgr, CastExpr);
case LValueKind: return cast<LValue>(this)->EvalCast(ValMgr, CastExpr);
case NonLValueKind: return cast<NonLValue>(this)->EvalCast(ValMgr, CastExpr);
case UninitializedKind: case InvalidKind: break;
}
return *this;
}
RValue LValue::Cast(ValueManager& ValMgr, Expr* CastExpr) const {
if (CastExpr->getType()->isPointerType())
return *this;
assert (CastExpr->getType()->isIntegerType());
if (!isa<lval::ConcreteInt>(*this))
return InvalidValue();
//===----------------------------------------------------------------------===//
// Transfer function dispatch for Non-LValues.
//===----------------------------------------------------------------------===//
APSInt V = cast<lval::ConcreteInt>(this)->getValue();
QualType T = CastExpr->getType();
V.setIsUnsigned(T->isUnsignedIntegerType());
V.extOrTrunc(ValMgr.getContext().getTypeSize(T, CastExpr->getLocStart()));
return nonlval::ConcreteInt(ValMgr.getValue(V));
// Binary Operators (except assignments and comma).
NonLValue NonLValue::EvalBinaryOp(ValueManager& ValMgr,
BinaryOperator::Opcode Op,
const NonLValue& RHS) const {
if (isa<InvalidValue>(this) || isa<InvalidValue>(RHS))
return cast<NonLValue>(InvalidValue());
if (isa<UninitializedValue>(this) || isa<UninitializedValue>(RHS))
return cast<NonLValue>(UninitializedValue());
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<InvalidValue>(RHS))
return cast<NonLValue>(InvalidValue());
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);
}
}
}
}
}
RValue NonLValue::Cast(ValueManager& ValMgr, Expr* CastExpr) const {
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 );
#if 0
case BinaryOperator::Shl:
return ValMgr.getValue( V1 << V2 );
case BinaryOperator::Shr:
return ValMgr.getValue( V1 >> V2 );
#endif
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>(InvalidValue());
}
}
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))
return InvalidValue();
APSInt V = cast<nonlval::ConcreteInt>(this)->getValue();
QualType T = CastExpr->getType();
V.setIsUnsigned(T->isUnsignedIntegerType() || T->isPointerType());
@ -157,123 +277,100 @@ RValue NonLValue::Cast(ValueManager& ValMgr, Expr* CastExpr) const {
return nonlval::ConcreteInt(ValMgr.getValue(V));
}
//===----------------------------------------------------------------------===//
// Transfer function dispatch for Non-LValues.
//===----------------------------------------------------------------------===//
// Unary Minus.
NonLValue NonLValue::UnaryMinus(ValueManager& ValMgr, UnaryOperator* U) const {
NonLValue NonLValue::EvalMinus(ValueManager& ValMgr, UnaryOperator* U) const {
switch (getSubKind()) {
case nonlval::ConcreteIntKind:
return cast<nonlval::ConcreteInt>(this)->UnaryMinus(ValMgr, U);
return cast<nonlval::ConcreteInt>(this)->EvalMinus(ValMgr, U);
default:
return cast<NonLValue>(InvalidValue());
}
}
NonLValue NonLValue::BitwiseComplement(ValueManager& ValMgr) const {
switch (getSubKind()) {
case nonlval::ConcreteIntKind:
return cast<nonlval::ConcreteInt>(this)->BitwiseComplement(ValMgr);
default:
return cast<NonLValue>(InvalidValue());
}
nonlval::ConcreteInt
nonlval::ConcreteInt::EvalMinus(ValueManager& ValMgr, UnaryOperator* U) const {
assert (U->getType() == U->getSubExpr()->getType());
assert (U->getType()->isIntegerType());
return ValMgr.getValue(-getValue());
}
#define NONLVALUE_DISPATCH_CASE(k1,k2,Op)\
case (k1##Kind*nonlval::NumKind+k2##Kind):\
return cast<k1>(*this).Op(ValMgr,cast<k2>(RHS));
#define NONLVALUE_DISPATCH(Op)\
switch (getSubKind()*nonlval::NumKind+RHS.getSubKind()){\
NONLVALUE_DISPATCH_CASE(nonlval::ConcreteInt,nonlval::ConcreteInt,Op)\
default:\
if (getBaseKind() == UninitializedKind ||\
RHS.getBaseKind() == UninitializedKind)\
return cast<NonLValue>(UninitializedValue());\
assert (!isValid() || !RHS.isValid() && "Missing case.");\
break;\
}\
return cast<NonLValue>(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.
//===----------------------------------------------------------------------===//
// 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>(InvalidValue());
case lval::ConcreteIntKind:
if (isa<lval::ConcreteInt>(RHS)) {
bool b = cast<lval::ConcreteInt>(this)->getValue() ==
cast<lval::ConcreteInt>(RHS).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());
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 =
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);
}
return nonlval::SymIntConstraintVal(C);
assert (!isa<lval::SymbolVal>(RHS) && "FIXME: Implement unification.");
break;
}
assert (!isa<lval::SymbolVal>(RHS) && "FIXME: Implement unification.");
break;
}
case lval::DeclValKind:
case lval::DeclValKind:
if (isa<lval::DeclVal>(RHS)) {
bool b = cast<lval::DeclVal>(*this) == cast<lval::DeclVal>(RHS);
return NonLValue::GetIntTruthValue(ValMgr, b);
@ -294,7 +391,7 @@ NonLValue LValue::NE(ValueManager& ValMgr, const LValue& RHS) const {
case lval::ConcreteIntKind:
if (isa<lval::ConcreteInt>(RHS)) {
bool b = cast<lval::ConcreteInt>(this)->getValue() !=
cast<lval::ConcreteInt>(RHS).getValue();
cast<lval::ConcreteInt>(RHS).getValue();
return NonLValue::GetIntTruthValue(ValMgr, b);
}
@ -338,6 +435,23 @@ NonLValue LValue::NE(ValueManager& ValMgr, const LValue& RHS) const {
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))
return InvalidValue();
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.
@ -354,6 +468,10 @@ NonLValue NonLValue::GetValue(ValueManager& ValMgr, IntegerLiteral* I) {
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();
@ -363,6 +481,8 @@ RValue RValue::GetSymbolValue(SymbolManager& SymMgr, ParmVarDecl* D) {
return nonlval::SymbolVal(SymMgr.getSymbol(D));
}
//===----------------------------------------------------------------------===//
// Pretty-Printing.
//===----------------------------------------------------------------------===//
@ -402,6 +522,10 @@ 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';
break;
case nonlval::SymbolValKind:
@ -415,6 +539,10 @@ void NonLValue::print(std::ostream& Out) const {
Out << '$' << C.getConstraint().getSymbol() << ' ';
printOpcode(Out, C.getConstraint().getOpcode());
Out << ' ' << C.getConstraint().getInt().toString();
if (C.getConstraint().getInt().isUnsigned())
Out << 'U';
break;
}

View File

@ -150,13 +150,23 @@ public:
~ValueManager();
ASTContext& getContext() const { return Ctx; }
const llvm::APSInt& getValue(const llvm::APSInt& X);
const llvm::APSInt& getValue(uint64_t X, unsigned BitWidth, bool isUnsigned);
const llvm::APSInt& getValue(uint64_t X, QualType T,
SourceLocation Loc = SourceLocation());
inline const llvm::APSInt& getZeroWithPtrWidth() {
return getValue(0, Ctx.getTypeSize(Ctx.VoidPtrTy, SourceLocation()), true);
return getValue( 0,
Ctx.getTypeSize(Ctx.VoidPtrTy, SourceLocation()),
true );
}
inline const llvm::APSInt& getTruthValue(bool b) {
return getValue( b ? 1 : 0,
Ctx.getTypeSize(Ctx.IntTy, SourceLocation()),
false );
}
const SymIntConstraint& getConstraint(SymbolID sym, BinaryOperator::Opcode Op,
@ -228,7 +238,7 @@ public:
typedef llvm::SmallVector<RValue,5> BufferTy;
RValue Cast(ValueManager& ValMgr, Expr* CastExpr) const;
RValue EvalCast(ValueManager& ValMgr, Expr* CastExpr) const;
unsigned getRawKind() const { return Kind; }
BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); }
@ -245,6 +255,7 @@ public:
static RValue GetSymbolValue(SymbolManager& SymMgr, ParmVarDecl *D);
inline bool isValid() const { return getRawKind() != InvalidKind; }
inline bool isInvalid() const { return getRawKind() == InvalidKind; }
@ -280,21 +291,13 @@ protected:
public:
void print(std::ostream& Out) const;
RValue Cast(ValueManager& ValMgr, Expr* CastExpr) const;
NonLValue EvalBinaryOp(ValueManager& ValMgr,
BinaryOperator::Opcode Op,
const NonLValue& RHS) 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;
NonLValue BitwiseComplement(ValueManager& ValMgr) const;
// Equality operators.
NonLValue EQ(ValueManager& ValMgr, const NonLValue& RHS) const;
NonLValue NE(ValueManager& ValMgr, const NonLValue& RHS) const;
RValue EvalCast(ValueManager& ValMgr, Expr* CastExpr) const;
NonLValue EvalMinus(ValueManager& ValMgr, UnaryOperator* U) const;
NonLValue EvalComplement(ValueManager& ValMgr) const;
// Utility methods to create NonLValues.
static NonLValue GetValue(ValueManager& ValMgr, uint64_t X, QualType T,
@ -302,10 +305,8 @@ public:
static NonLValue GetValue(ValueManager& ValMgr, IntegerLiteral* I);
static inline NonLValue GetIntTruthValue(ValueManager& ValMgr, bool X) {
return GetValue(ValMgr, X ? 1U : 0U, ValMgr.getContext().IntTy);
}
static NonLValue GetIntTruthValue(ValueManager& ValMgr, bool b);
// Implement isa<T> support.
static inline bool classof(const RValue* V) {
return V->getBaseKind() >= NonLValueKind;
@ -316,16 +317,19 @@ class LValue : public RValue {
protected:
LValue(unsigned SubKind, const void* D) : RValue(const_cast<void*>(D),
true, SubKind) {}
public:
void print(std::ostream& Out) const;
RValue Cast(ValueManager& ValMgr, Expr* CastExpr) const;
// Equality operators.
NonLValue EQ(ValueManager& ValMgr, const LValue& RHS) const;
NonLValue NE(ValueManager& ValMgr, const LValue& RHS) const;
public:
void print(std::ostream& Out) const;
RValue EvalBinaryOp(ValueManager& ValMgr, BinaryOperator::Opcode Op,
const LValue& RHS) const;
RValue EvalCast(ValueManager& ValMgr, Expr* CastExpr) const;
// Implement isa<T> support.
static inline bool classof(const RValue* V) {
return V->getBaseKind() == LValueKind;
@ -380,67 +384,22 @@ namespace nonlval {
return *static_cast<llvm::APSInt*>(getRawPtr());
}
// Arithmetic operators.
// Transfer functions for binary/unary operations on ConcreteInts.
ConcreteInt EvalBinaryOp(ValueManager& ValMgr,
BinaryOperator::Opcode Op,
const ConcreteInt& RHS) const;
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());
}
ConcreteInt BitwiseComplement(ValueManager& ValMgr) const {
return ValMgr.getValue(~getValue());
}
// Casting.
ConcreteInt Cast(ValueManager& ValMgr, Expr* CastExpr) const {
assert (CastExpr->getType()->isIntegerType());
llvm::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 llvm::APSInt& Val = getValue();
return ValMgr.getValue(Val == V.getValue() ? 1U : 0U,
Val.getBitWidth(), Val.isUnsigned());
}
ConcreteInt NE(ValueManager& ValMgr, const ConcreteInt& V) const {
const llvm::APSInt& Val = getValue();
return ValMgr.getValue(Val != V.getValue() ? 1U : 0U,
Val.getBitWidth(), Val.isUnsigned());
}
ConcreteInt EvalComplement(ValueManager& ValMgr) const;
ConcreteInt EvalMinus(ValueManager& ValMgr, UnaryOperator* U) const;
// Implement isa<T> support.
static inline bool classof(const RValue* V) {
return isa<NonLValue>(V) && V->getSubKind() == ConcreteIntKind;
}
static inline bool classof(const NonLValue* V) {
return V->getSubKind() == ConcreteIntKind;
}
};
} // end namespace clang::nonlval
@ -500,34 +459,21 @@ namespace lval {
return *static_cast<llvm::APSInt*>(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());
}
// Equality operators.
ConcreteInt EQ(ValueManager& ValMgr, const ConcreteInt& V) const {
const llvm::APSInt& Val = getValue();
return ValMgr.getValue(Val == V.getValue() ? 1U : 0U,
Val.getBitWidth(), Val.isUnsigned());
}
ConcreteInt NE(ValueManager& ValMgr, const ConcreteInt& V) const {
const llvm::APSInt& Val = getValue();
return ValMgr.getValue(Val != V.getValue() ? 1U : 0U,
Val.getBitWidth(), Val.isUnsigned());
}
// Transfer functions for binary/unary operations on ConcreteInts.
ConcreteInt EvalBinaryOp(ValueManager& ValMgr,
BinaryOperator::Opcode Op,
const ConcreteInt& RHS) const;
// Implement isa<T> support.
static inline bool classof(const RValue* V) {
return isa<LValue>(V) && V->getSubKind() == ConcreteIntKind;
}
static inline bool classof(const LValue* V) {
return V->getSubKind() == ConcreteIntKind;
}
};
} // end clang::lval namespace