зеркало из https://github.com/microsoft/clang-1.git
Port more of Eli's evaluator over. This makes the int evaluator handle binary and unary operators.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@53221 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
c754aa6264
Коммит
06a3675627
|
@ -15,6 +15,7 @@
|
|||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/STmtVisitor.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
using namespace clang;
|
||||
|
@ -59,9 +60,13 @@ class VISIBILITY_HIDDEN IntExprEvaluator
|
|||
: Ctx(ctx) {}
|
||||
|
||||
public:
|
||||
static bool Evaluate(const Expr* E, APValue& Result, ASTContext &Ctx) {
|
||||
Result = IntExprEvaluator(Ctx).Visit(const_cast<Expr*>(E));
|
||||
return Result.isSInt();
|
||||
static bool Evaluate(const Expr* E, llvm::APSInt& Result, ASTContext &Ctx) {
|
||||
APValue Value = IntExprEvaluator(Ctx).Visit(const_cast<Expr*>(E));
|
||||
if (!Value.isSInt())
|
||||
return false;
|
||||
|
||||
Result = Value.getSInt();
|
||||
return true;
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
@ -74,8 +79,136 @@ public:
|
|||
return APValue();
|
||||
}
|
||||
|
||||
APValue VisitParenExpr(ParenExpr *PE) { return Visit(PE->getSubExpr()); }
|
||||
APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
|
||||
|
||||
APValue VisitBinaryOperator(const BinaryOperator *E) {
|
||||
// The LHS of a constant expr is always evaluated and needed.
|
||||
llvm::APSInt Result(32);
|
||||
if (!Evaluate(E->getRHS(), Result, Ctx))
|
||||
return APValue();
|
||||
|
||||
llvm::APSInt RHS(32);
|
||||
if (!Evaluate(E->getRHS(), RHS, Ctx))
|
||||
return APValue();
|
||||
|
||||
switch (E->getOpcode()) {
|
||||
default:
|
||||
return APValue();
|
||||
case BinaryOperator::Mul:
|
||||
Result *= RHS;
|
||||
break;
|
||||
case BinaryOperator::Div:
|
||||
if (RHS == 0)
|
||||
return APValue();
|
||||
Result /= RHS;
|
||||
break;
|
||||
case BinaryOperator::Rem:
|
||||
if (RHS == 0)
|
||||
return APValue();
|
||||
Result %= RHS;
|
||||
break;
|
||||
case BinaryOperator::Add: Result += RHS; break;
|
||||
case BinaryOperator::Sub: Result -= RHS; break;
|
||||
case BinaryOperator::Shl:
|
||||
Result <<=
|
||||
static_cast<uint32_t>(RHS.getLimitedValue(Result.getBitWidth()-1));
|
||||
break;
|
||||
case BinaryOperator::Shr:
|
||||
Result >>=
|
||||
static_cast<uint32_t>(RHS.getLimitedValue(Result.getBitWidth()-1));
|
||||
break;
|
||||
case BinaryOperator::LT: Result = Result < RHS; break;
|
||||
case BinaryOperator::GT: Result = Result > RHS; break;
|
||||
case BinaryOperator::LE: Result = Result <= RHS; break;
|
||||
case BinaryOperator::GE: Result = Result >= RHS; break;
|
||||
case BinaryOperator::EQ: Result = Result == RHS; break;
|
||||
case BinaryOperator::NE: Result = Result != RHS; break;
|
||||
case BinaryOperator::And: Result &= RHS; break;
|
||||
case BinaryOperator::Xor: Result ^= RHS; break;
|
||||
case BinaryOperator::Or: Result |= RHS; break;
|
||||
|
||||
case BinaryOperator::Comma:
|
||||
// C99 6.6p3: "shall not contain assignment, ..., or comma operators,
|
||||
// *except* when they are contained within a subexpression that is not
|
||||
// evaluated". Note that Assignment can never happen due to constraints
|
||||
// on the LHS subexpr, so we don't need to check it here.
|
||||
// FIXME: Need to come up with an efficient way to deal with the C99
|
||||
// rules on evaluation while still evaluating this. Maybe a
|
||||
// "evaluated comma" out parameter?
|
||||
return APValue();
|
||||
}
|
||||
|
||||
Result.setIsUnsigned(E->getType()->isUnsignedIntegerType());
|
||||
|
||||
return APValue(Result);
|
||||
}
|
||||
|
||||
APValue VisitUnaryOperator(const UnaryOperator *E) {
|
||||
llvm::APSInt Result(32);
|
||||
|
||||
if (E->isOffsetOfOp())
|
||||
Result = E->evaluateOffsetOf(Ctx);
|
||||
else if (E->isSizeOfAlignOfOp()) {
|
||||
// Return the result in the right width.
|
||||
Result.zextOrTrunc(static_cast<uint32_t>(Ctx.getTypeSize(E->getType())));
|
||||
|
||||
// sizeof(void) and __alignof__(void) = 1 as a gcc extension.
|
||||
if (E->getSubExpr()->getType()->isVoidType())
|
||||
Result = 1;
|
||||
|
||||
// sizeof(vla) is not a constantexpr: C99 6.5.3.4p2.
|
||||
if (!E->getSubExpr()->getType()->isConstantSizeType()) {
|
||||
// FIXME: Should we attempt to evaluate this?
|
||||
return APValue();
|
||||
}
|
||||
|
||||
// Get information about the size or align.
|
||||
if (E->getSubExpr()->getType()->isFunctionType()) {
|
||||
// GCC extension: sizeof(function) = 1.
|
||||
// FIXME: AlignOf shouldn't be unconditionally 4!
|
||||
Result = E->getOpcode() == UnaryOperator::AlignOf ? 4 : 1;
|
||||
} else {
|
||||
unsigned CharSize = Ctx.Target.getCharWidth();
|
||||
if (E->getOpcode() == UnaryOperator::AlignOf)
|
||||
Result = Ctx.getTypeAlign(E->getSubExpr()->getType()) / CharSize;
|
||||
else
|
||||
Result = Ctx.getTypeSize(E->getSubExpr()->getType()) / CharSize;
|
||||
}
|
||||
} else {
|
||||
// Get the operand value. If this is sizeof/alignof, do not evalute the
|
||||
// operand. This affects C99 6.6p3.
|
||||
if (!Evaluate(E->getSubExpr(), Result, Ctx))
|
||||
return APValue();
|
||||
|
||||
switch (E->getOpcode()) {
|
||||
// Address, indirect, pre/post inc/dec, etc are not valid constant exprs.
|
||||
// See C99 6.6p3.
|
||||
default:
|
||||
return APValue();
|
||||
case UnaryOperator::Extension:
|
||||
assert(0 && "Handle UnaryOperator::Extension");
|
||||
return APValue();
|
||||
case UnaryOperator::LNot: {
|
||||
bool Val = Result == 0;
|
||||
uint32_t typeSize = Ctx.getTypeSize(E->getType());
|
||||
Result.zextOrTrunc(typeSize);
|
||||
Result = Val;
|
||||
break;
|
||||
}
|
||||
case UnaryOperator::Plus:
|
||||
break;
|
||||
case UnaryOperator::Minus:
|
||||
Result = -Result;
|
||||
break;
|
||||
case UnaryOperator::Not:
|
||||
Result = ~Result;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Result.setIsUnsigned(E->getType()->isUnsignedIntegerType());
|
||||
return APValue(Result);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -84,9 +217,12 @@ bool Expr::tryEvaluate(APValue& Result, ASTContext &Ctx) const
|
|||
llvm::APSInt sInt(1);
|
||||
|
||||
#if USE_NEW_EVALUATOR
|
||||
if (getType()->isIntegerType())
|
||||
return IntExprEvaluator::Evaluate(this, Result, Ctx);
|
||||
else
|
||||
if (getType()->isIntegerType()) {
|
||||
if (IntExprEvaluator::Evaluate(this, sInt, Ctx)) {
|
||||
Result = APValue(sInt);
|
||||
return true;
|
||||
}
|
||||
} else
|
||||
return false;
|
||||
|
||||
#else
|
||||
|
|
Загрузка…
Ссылка в новой задаче