Skip to content

Commit 24c0154

Browse files
committed
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. llvm-svn: 55155
1 parent 25084af commit 24c0154

File tree

1 file changed

+82
-21
lines changed

1 file changed

+82
-21
lines changed

clang/lib/AST/ExprConstant.cpp

Lines changed: 82 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "llvm/Support/Compiler.h"
2020
using namespace clang;
2121
using llvm::APSInt;
22+
using llvm::APFloat;
2223

2324
/// EvalInfo - This is a private struct used by the evaluator to capture
2425
/// information about a subexpression as it is folded. It retains information
@@ -63,7 +64,7 @@ struct EvalInfo {
6364

6465
static bool EvaluatePointer(const Expr *E, APValue &Result, EvalInfo &Info);
6566
static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info);
66-
67+
static bool EvaluateFloat(const Expr *E, APFloat &Result, EvalInfo &Info);
6768

6869
//===----------------------------------------------------------------------===//
6970
// Pointer Evaluation
@@ -477,23 +478,13 @@ bool IntExprEvaluator::HandleCast(SourceLocation CastLoc,
477478
if (!SubExpr->getType()->isRealFloatingType())
478479
return Error(CastLoc, diag::err_expr_not_constant);
479480

480-
// FIXME: Generalize floating point constant folding! For now we just permit
481-
// which is allowed by integer constant expressions.
482-
483-
// Allow floating constants that are the immediate operands of casts or that
484-
// are parenthesized.
485-
const Expr *Operand = SubExpr;
486-
while (const ParenExpr *PE = dyn_cast<ParenExpr>(Operand))
487-
Operand = PE->getSubExpr();
488-
489-
// If this isn't a floating literal, we can't handle it.
490-
const FloatingLiteral *FL = dyn_cast<FloatingLiteral>(Operand);
491-
if (!FL)
481+
APFloat F(0.0);
482+
if (!EvaluateFloat(SubExpr, F, Info))
492483
return Error(CastLoc, diag::err_expr_not_constant);
493-
484+
494485
// If the destination is boolean, compare against zero.
495486
if (DestType->isBooleanType()) {
496-
Result = !FL->getValue().isZero();
487+
Result = !F.isZero();
497488
Result.zextOrTrunc(DestWidth);
498489
Result.setIsUnsigned(DestType->isUnsignedIntegerType());
499490
return true;
@@ -504,28 +495,98 @@ bool IntExprEvaluator::HandleCast(SourceLocation CastLoc,
504495

505496
// FIXME: Warning for overflow.
506497
uint64_t Space[4];
507-
(void)FL->getValue().convertToInteger(Space, DestWidth, DestSigned,
508-
llvm::APFloat::rmTowardZero);
498+
(void)F.convertToInteger(Space, DestWidth, DestSigned,
499+
llvm::APFloat::rmTowardZero);
509500
Result = llvm::APInt(DestWidth, 4, Space);
510501
Result.setIsUnsigned(!DestSigned);
511502
return true;
512503
}
513504

505+
//===----------------------------------------------------------------------===//
506+
// Float Evaluation
507+
//===----------------------------------------------------------------------===//
508+
509+
namespace {
510+
class VISIBILITY_HIDDEN FloatExprEvaluator
511+
: public StmtVisitor<FloatExprEvaluator, bool> {
512+
EvalInfo &Info;
513+
APFloat &Result;
514+
public:
515+
FloatExprEvaluator(EvalInfo &info, APFloat &result)
516+
: Info(info), Result(result) {}
517+
518+
bool VisitStmt(Stmt *S) {
519+
return false;
520+
}
521+
522+
bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
523+
524+
bool VisitBinaryOperator(const BinaryOperator *E);
525+
bool VisitFloatingLiteral(const FloatingLiteral *E);
526+
};
527+
} // end anonymous namespace
528+
529+
static bool EvaluateFloat(const Expr* E, APFloat& Result, EvalInfo &Info) {
530+
return FloatExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E));
531+
}
532+
533+
bool FloatExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
534+
// FIXME: Diagnostics? I really don't understand how the warnings
535+
// and errors are supposed to work.
536+
APFloat LHS(0.0), RHS(0.0);
537+
if (!EvaluateFloat(E->getLHS(), Result, Info))
538+
return false;
539+
if (!EvaluateFloat(E->getRHS(), RHS, Info))
540+
return false;
541+
542+
switch (E->getOpcode()) {
543+
default: return false;
544+
case BinaryOperator::Mul:
545+
Result.multiply(RHS, APFloat::rmNearestTiesToEven);
546+
return true;
547+
case BinaryOperator::Add:
548+
Result.add(RHS, APFloat::rmNearestTiesToEven);
549+
return true;
550+
case BinaryOperator::Sub:
551+
Result.subtract(RHS, APFloat::rmNearestTiesToEven);
552+
return true;
553+
case BinaryOperator::Div:
554+
Result.divide(RHS, APFloat::rmNearestTiesToEven);
555+
return true;
556+
case BinaryOperator::Rem:
557+
Result.mod(RHS, APFloat::rmNearestTiesToEven);
558+
return true;
559+
}
560+
}
561+
562+
bool FloatExprEvaluator::VisitFloatingLiteral(const FloatingLiteral *E) {
563+
Result = E->getValue();
564+
return true;
565+
}
566+
514567
//===----------------------------------------------------------------------===//
515568
// Top level TryEvaluate.
516569
//===----------------------------------------------------------------------===//
517570

518571
bool Expr::tryEvaluate(APValue &Result, ASTContext &Ctx) const {
519-
llvm::APSInt sInt(32);
520-
521572
EvalInfo Info(Ctx);
522573
if (getType()->isIntegerType()) {
574+
llvm::APSInt sInt(32);
523575
if (EvaluateInteger(this, sInt, Info)) {
524576
Result = APValue(sInt);
525577
return true;
526578
}
527-
} else
528-
return false;
579+
} else if (getType()->isPointerType()) {
580+
if (EvaluatePointer(this, Result, Info)) {
581+
return true;
582+
}
583+
} else if (getType()->isRealFloatingType()) {
584+
llvm::APFloat f(0.0);
585+
if (EvaluateFloat(this, f, Info)) {
586+
Result = APValue(f);
587+
return true;
588+
}
589+
}
529590

530591
return false;
531592
}

0 commit comments

Comments
 (0)