From 06a3675627e3b3c47b49c689c8e404a33144194a Mon Sep 17 00:00:00 2001 From: Anders Carlsson Date: Tue, 8 Jul 2008 05:49:43 +0000 Subject: [PATCH] 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 --- lib/AST/ExprConstant.cpp | 150 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 143 insertions(+), 7 deletions(-) diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 8b116ae496..f08499084a 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -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(E)); - return Result.isSInt(); + static bool Evaluate(const Expr* E, llvm::APSInt& Result, ASTContext &Ctx) { + APValue Value = IntExprEvaluator(Ctx).Visit(const_cast(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(RHS.getLimitedValue(Result.getBitWidth()-1)); + break; + case BinaryOperator::Shr: + Result >>= + static_cast(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(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 -- 2.40.0