diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -2421,10 +2421,29 @@ static bool HandleFloatToFloatCast(EvalInfo &Info, const Expr *E, QualType SrcType, QualType DestType, APFloat &Result) { + llvm::RoundingMode RM = llvm::RoundingMode::NearestTiesToEven; + if (auto Cast = dyn_cast(E)) { + FPOptions FPFeatures = Cast->getFPFeaturesInEffect(Info.Ctx.getLangOpts()); + RM = FPFeatures.getRoundingMode(); + } + bool DynamicRM = RM == llvm::RoundingMode::Dynamic; + if (DynamicRM) + // If rounding mode is unknown at compile time, still try to execute the + // operation. If the result is exact, it does not depend on rounding mode. + RM = llvm::RoundingMode::NearestTiesToEven; + + APFloat::opStatus St; APFloat Value = Result; bool ignored; - Result.convert(Info.Ctx.getFloatTypeSemantics(DestType), - APFloat::rmNearestTiesToEven, &ignored); + St = Result.convert(Info.Ctx.getFloatTypeSemantics(DestType), RM, &ignored); + + // FIXME: if: + // - evaluation triggered some FP exception, and + // - exception mode is not "ignore", and + // - the expression being evaluated is not a part of global variable + // initializer, + // the evaluation probably need to be rejected. + return true; } @@ -2647,31 +2666,51 @@ } /// Perform the given binary floating-point operation, in-place, on LHS. -static bool handleFloatFloatBinOp(EvalInfo &Info, const Expr *E, +static bool handleFloatFloatBinOp(EvalInfo &Info, const BinaryOperator *E, APFloat &LHS, BinaryOperatorKind Opcode, const APFloat &RHS) { + FPOptions FPFeatures = E->getFPFeaturesInEffect(Info.Ctx.getLangOpts()); + llvm::RoundingMode RM = FPFeatures.getRoundingMode(); + bool DynamicRM = RM == llvm::RoundingMode::Dynamic; + if (DynamicRM) + // If rounding mode is unknown at compile time, still try to execute the + // operation. If the result is exact, it does not depend on rounding mode. + RM = llvm::RoundingMode::NearestTiesToEven; + APFloat::opStatus St; switch (Opcode) { default: Info.FFDiag(E); return false; case BO_Mul: - LHS.multiply(RHS, APFloat::rmNearestTiesToEven); + St = LHS.multiply(RHS, RM); break; case BO_Add: - LHS.add(RHS, APFloat::rmNearestTiesToEven); + St = LHS.add(RHS, RM); break; case BO_Sub: - LHS.subtract(RHS, APFloat::rmNearestTiesToEven); + St = LHS.subtract(RHS, RM); break; case BO_Div: // [expr.mul]p4: // If the second operand of / or % is zero the behavior is undefined. if (RHS.isZero()) Info.CCEDiag(E, diag::note_expr_divide_by_zero); - LHS.divide(RHS, APFloat::rmNearestTiesToEven); + St = LHS.divide(RHS, RM); break; } + if (DynamicRM && (St & APFloat::opInexact)) { + Info.FFDiag(E); + return false; + } + + // FIXME: if: + // - evaluation triggered some FP exception, and + // - exception mode is not "ignore", and + // - the expression being evaluated is not a part of global variable + // initializer, + // the evaluation probably need to be rejected. + // [expr.pre]p4: // If during the evaluation of an expression, the result is not // mathematically defined [...], the behavior is undefined. @@ -2763,7 +2802,7 @@ } // Perform binary operations for vector types, in place on the LHS. -static bool handleVectorVectorBinOp(EvalInfo &Info, const Expr *E, +static bool handleVectorVectorBinOp(EvalInfo &Info, const BinaryOperator *E, BinaryOperatorKind Opcode, APValue &LHSValue, const APValue &RHSValue) { @@ -4077,7 +4116,7 @@ namespace { struct CompoundAssignSubobjectHandler { EvalInfo &Info; - const Expr *E; + const CompoundAssignOperator *E; QualType PromotedLHSType; BinaryOperatorKind Opcode; const APValue &RHS; @@ -4197,10 +4236,12 @@ const AccessKinds CompoundAssignSubobjectHandler::AccessKind; /// Perform a compound assignment of LVal = RVal. -static bool handleCompoundAssignment( - EvalInfo &Info, const Expr *E, - const LValue &LVal, QualType LValType, QualType PromotedLValType, - BinaryOperatorKind Opcode, const APValue &RVal) { +static bool handleCompoundAssignment(EvalInfo &Info, + const CompoundAssignOperator *E, + const LValue &LVal, QualType LValType, + QualType PromotedLValType, + BinaryOperatorKind Opcode, + const APValue &RVal) { if (LVal.Designator.Invalid) return false; diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -981,7 +981,9 @@ void Sema::setRoundingMode(SourceLocation Loc, llvm::RoundingMode FPR) { // C2x: 7.6.2p3 If the FE_DYNAMIC mode is specified and FENV_ACCESS is "off", // the translator may assume that the default rounding mode is in effect. - if (FPR == llvm::RoundingMode::Dynamic && !CurFPFeatures.getAllowFEnvAccess()) + if (FPR == llvm::RoundingMode::Dynamic && + !CurFPFeatures.getAllowFEnvAccess() && + CurFPFeatures.getFPExceptionMode() == LangOptions::FPE_Ignore) FPR = llvm::RoundingMode::NearestTiesToEven; FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides(); diff --git a/clang/test/AST/const-fpfeatures-diag.c b/clang/test/AST/const-fpfeatures-diag.c new file mode 100644 --- /dev/null +++ b/clang/test/AST/const-fpfeatures-diag.c @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -verify -ffp-exception-behavior=strict -Wno-unknown-pragmas %s + +#pragma STDC FENV_ROUND FE_DYNAMIC + +// nextUp(1.F) == 0x1.000002p0F + +float F1 = 0x1.000000p0F + 0x0.000002p0F; +float F2 = 0x1.000000p0F + 0x0.000001p0F; // expected-error{{initializer element is not a compile-time constant}} diff --git a/clang/test/AST/const-fpfeatures.c b/clang/test/AST/const-fpfeatures.c new file mode 100644 --- /dev/null +++ b/clang/test/AST/const-fpfeatures.c @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -S -emit-llvm -Wno-unknown-pragmas %s -o - | FileCheck %s + +// nextUp(1.F) == 0x1.000002p0F + +#pragma STDC FENV_ROUND FE_UPWARD + +float F1u = 1.0F + 0x0.000002p0F; +float F2u = 1.0F + 0x0.000001p0F; +float F3u = 0x1.000001p0; +// CHECK: @F1u = {{.*}} float 0x3FF0000020000000 +// CHECK: @F2u = {{.*}} float 0x3FF0000020000000 +// CHECK: @F3u = {{.*}} float 0x3FF0000020000000 + +#pragma STDC FENV_ROUND FE_DOWNWARD + +float F1d = 1.0F + 0x0.000002p0F; +float F2d = 1.0F + 0x0.000001p0F; +float F3d = 0x1.000001p0; + +// CHECK: @F1d = {{.*}} float 0x3FF0000020000000 +// CHECK: @F2d = {{.*}} float 1.000000e+00 +// CHECK: @F3d = {{.*}} float 1.000000e+00