forked from OSchip/llvm-project
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:
parent
1242fff6ec
commit
cdd0be1dc1
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue