diff options
author | Eli Friedman <eli.friedman@gmail.com> | 2008-08-22 00:06:13 +0000 |
---|---|---|
committer | Eli Friedman <eli.friedman@gmail.com> | 2008-08-22 00:06:13 +0000 |
commit | d8bfe7f25a695ca947effbccdf9ecbe3e018e221 (patch) | |
tree | 7cba6b5da34fe2798c616c1686908ccf741423eb /lib/AST/ExprConstant.cpp | |
parent | a950fe2af7fa897c45b41fe6062bc29e35af340e (diff) |
Initial implementation of floats in Expr::tryEvaluate; this doesn't
implement some things, like unary operators and casts, but it's enough
to fix PR2703 as filed.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55155 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/AST/ExprConstant.cpp')
-rw-r--r-- | lib/AST/ExprConstant.cpp | 103 |
1 files changed, 82 insertions, 21 deletions
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 8ba27f0133..e987617811 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -19,6 +19,7 @@ #include "llvm/Support/Compiler.h" using namespace clang; using llvm::APSInt; +using llvm::APFloat; /// EvalInfo - This is a private struct used by the evaluator to capture /// information about a subexpression as it is folded. It retains information @@ -63,7 +64,7 @@ struct EvalInfo { static bool EvaluatePointer(const Expr *E, APValue &Result, EvalInfo &Info); static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info); - +static bool EvaluateFloat(const Expr *E, APFloat &Result, EvalInfo &Info); //===----------------------------------------------------------------------===// // Pointer Evaluation @@ -477,23 +478,13 @@ bool IntExprEvaluator::HandleCast(SourceLocation CastLoc, if (!SubExpr->getType()->isRealFloatingType()) return Error(CastLoc, diag::err_expr_not_constant); - // FIXME: Generalize floating point constant folding! For now we just permit - // which is allowed by integer constant expressions. - - // Allow floating constants that are the immediate operands of casts or that - // are parenthesized. - const Expr *Operand = SubExpr; - while (const ParenExpr *PE = dyn_cast<ParenExpr>(Operand)) - Operand = PE->getSubExpr(); - - // If this isn't a floating literal, we can't handle it. - const FloatingLiteral *FL = dyn_cast<FloatingLiteral>(Operand); - if (!FL) + APFloat F(0.0); + if (!EvaluateFloat(SubExpr, F, Info)) return Error(CastLoc, diag::err_expr_not_constant); - + // If the destination is boolean, compare against zero. if (DestType->isBooleanType()) { - Result = !FL->getValue().isZero(); + Result = !F.isZero(); Result.zextOrTrunc(DestWidth); Result.setIsUnsigned(DestType->isUnsignedIntegerType()); return true; @@ -504,28 +495,98 @@ bool IntExprEvaluator::HandleCast(SourceLocation CastLoc, // FIXME: Warning for overflow. uint64_t Space[4]; - (void)FL->getValue().convertToInteger(Space, DestWidth, DestSigned, - llvm::APFloat::rmTowardZero); + (void)F.convertToInteger(Space, DestWidth, DestSigned, + llvm::APFloat::rmTowardZero); Result = llvm::APInt(DestWidth, 4, Space); Result.setIsUnsigned(!DestSigned); return true; } //===----------------------------------------------------------------------===// +// Float Evaluation +//===----------------------------------------------------------------------===// + +namespace { +class VISIBILITY_HIDDEN FloatExprEvaluator + : public StmtVisitor<FloatExprEvaluator, bool> { + EvalInfo &Info; + APFloat &Result; +public: + FloatExprEvaluator(EvalInfo &info, APFloat &result) + : Info(info), Result(result) {} + + bool VisitStmt(Stmt *S) { + return false; + } + + bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } + + bool VisitBinaryOperator(const BinaryOperator *E); + bool VisitFloatingLiteral(const FloatingLiteral *E); +}; +} // end anonymous namespace + +static bool EvaluateFloat(const Expr* E, APFloat& Result, EvalInfo &Info) { + return FloatExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E)); +} + +bool FloatExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { + // FIXME: Diagnostics? I really don't understand how the warnings + // and errors are supposed to work. + APFloat LHS(0.0), RHS(0.0); + if (!EvaluateFloat(E->getLHS(), Result, Info)) + return false; + if (!EvaluateFloat(E->getRHS(), RHS, Info)) + return false; + + switch (E->getOpcode()) { + default: return false; + case BinaryOperator::Mul: + Result.multiply(RHS, APFloat::rmNearestTiesToEven); + return true; + case BinaryOperator::Add: + Result.add(RHS, APFloat::rmNearestTiesToEven); + return true; + case BinaryOperator::Sub: + Result.subtract(RHS, APFloat::rmNearestTiesToEven); + return true; + case BinaryOperator::Div: + Result.divide(RHS, APFloat::rmNearestTiesToEven); + return true; + case BinaryOperator::Rem: + Result.mod(RHS, APFloat::rmNearestTiesToEven); + return true; + } +} + +bool FloatExprEvaluator::VisitFloatingLiteral(const FloatingLiteral *E) { + Result = E->getValue(); + return true; +} + +//===----------------------------------------------------------------------===// // Top level TryEvaluate. //===----------------------------------------------------------------------===// bool Expr::tryEvaluate(APValue &Result, ASTContext &Ctx) const { - llvm::APSInt sInt(32); - EvalInfo Info(Ctx); if (getType()->isIntegerType()) { + llvm::APSInt sInt(32); if (EvaluateInteger(this, sInt, Info)) { Result = APValue(sInt); return true; } - } else - return false; + } else if (getType()->isPointerType()) { + if (EvaluatePointer(this, Result, Info)) { + return true; + } + } else if (getType()->isRealFloatingType()) { + llvm::APFloat f(0.0); + if (EvaluateFloat(this, f, Info)) { + Result = APValue(f); + return true; + } + } return false; } |