sepavloff updated this revision to Diff 292841.
sepavloff added a comment.
Updated patch
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D87822/new/
https://reviews.llvm.org/D87822
Files:
clang/include/clang/AST/Expr.h
clang/lib/AST/Expr.cpp
clang/lib/AST/ExprConstant.cpp
clang/lib/Sema/SemaAttr.cpp
clang/test/AST/const-fpfeatures-diag.c
clang/test/AST/const-fpfeatures.c
Index: clang/test/AST/const-fpfeatures.c
===================================================================
--- /dev/null
+++ 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
Index: clang/test/AST/const-fpfeatures-diag.c
===================================================================
--- /dev/null
+++ 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}}
Index: clang/lib/Sema/SemaAttr.cpp
===================================================================
--- clang/lib/Sema/SemaAttr.cpp
+++ 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();
Index: clang/lib/AST/ExprConstant.cpp
===================================================================
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -2418,14 +2418,59 @@
return true;
}
+/// Get rounding mode used for evaluation of the specified expression.
+/// \param[out] DynamicRM Is set to true is the requested rounding mode is
+/// dynamic.
+/// If rounding mode is unknown at compile time, still try to evaluate the
+/// expression. If the result is exact, it does not depend on rounding mode.
+/// So return "tonearest" mode instead of "dynamic".
+static llvm::RoundingMode getActiveRoundingMode(EvalInfo &Info, const Expr *E,
+ bool &DynamicRM) {
+ llvm::RoundingMode RM =
+ E->getFPFeaturesInEffect(Info.Ctx.getLangOpts()).getRoundingMode();
+ DynamicRM = (RM == llvm::RoundingMode::Dynamic);
+ if (DynamicRM)
+ RM = llvm::RoundingMode::NearestTiesToEven;
+ return RM;
+}
+
+/// Check if the given evaluation result is allowed for constant evaluation.
+static bool checkFloatingPointResult(EvalInfo &Info, const Expr *E,
+ APFloat::opStatus St) {
+ FPOptions FPO = E->getFPFeaturesInEffect(Info.Ctx.getLangOpts());
+ if ((St & APFloat::opInexact) &&
+ FPO.getRoundingMode() == llvm::RoundingMode::Dynamic) {
+ // Inexact result means that it depends on rounding mode. If the requested
+ // mode is dynamic, the evaluation cannot be made in compile time.
+ Info.FFDiag(E);
+ return false;
+ }
+
+ if (St & APFloat::opStatus::opInvalidOp) {
+ // There is no usefully definable result.
+ Info.FFDiag(E);
+ return false;
+ }
+
+ // FIXME: if:
+ // - evaluation triggered other 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;
+}
+
static bool HandleFloatToFloatCast(EvalInfo &Info, const Expr *E,
QualType SrcType, QualType DestType,
APFloat &Result) {
+ bool DynamicRM;
+ llvm::RoundingMode RM = getActiveRoundingMode(Info, E, DynamicRM);
+ APFloat::opStatus St;
APFloat Value = Result;
bool ignored;
- Result.convert(Info.Ctx.getFloatTypeSemantics(DestType),
- APFloat::rmNearestTiesToEven, &ignored);
- return true;
+ St = Result.convert(Info.Ctx.getFloatTypeSemantics(DestType), RM, &ignored);
+ return checkFloatingPointResult(Info, E, St);
}
static APSInt HandleIntToIntCast(EvalInfo &Info, const Expr *E,
@@ -2647,28 +2692,31 @@
}
/// 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) {
+ bool DynamicRM;
+ llvm::RoundingMode RM = getActiveRoundingMode(Info, E, DynamicRM);
+ 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;
}
@@ -2680,7 +2728,8 @@
Info.CCEDiag(E, diag::note_constexpr_float_arithmetic) << LHS.isNaN();
return Info.noteUndefinedBehavior();
}
- return true;
+
+ return checkFloatingPointResult(Info, E, St);
}
static bool handleLogicalOpForVector(const APInt &LHSValue,
@@ -2763,7 +2812,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 +4126,7 @@
namespace {
struct CompoundAssignSubobjectHandler {
EvalInfo &Info;
- const Expr *E;
+ const CompoundAssignOperator *E;
QualType PromotedLHSType;
BinaryOperatorKind Opcode;
const APValue &RHS;
@@ -4197,10 +4246,12 @@
const AccessKinds CompoundAssignSubobjectHandler::AccessKind;
/// Perform a compound assignment of LVal <op>= 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;
Index: clang/lib/AST/Expr.cpp
===================================================================
--- clang/lib/AST/Expr.cpp
+++ clang/lib/AST/Expr.cpp
@@ -3577,6 +3577,21 @@
return false;
}
+FPOptions Expr::getFPFeaturesInEffect(const LangOptions &LO) const {
+ switch (getStmtClass()) {
+ case Stmt::UnaryOperatorClass:
+ return cast<UnaryOperator>(this)->getFPFeaturesInEffect(LO);
+ case Stmt::BinaryOperatorClass:
+ return cast<BinaryOperator>(this)->getFPFeaturesInEffect(LO);
+ case Stmt::CallExprClass:
+ return cast<CallExpr>(this)->getFPFeaturesInEffect(LO);
+ default:
+ if (CastExpr::classof(this))
+ return cast<CastExpr>(this)->getFPFeaturesInEffect(LO);
+ }
+ return FPOptions::defaultWithoutTrailingStorage(LO);
+}
+
namespace {
/// Look for a call to a non-trivial function within an expression.
class NonTrivialCallFinder : public ConstEvaluatedExprVisitor<NonTrivialCallFinder>
Index: clang/include/clang/AST/Expr.h
===================================================================
--- clang/include/clang/AST/Expr.h
+++ clang/include/clang/AST/Expr.h
@@ -413,6 +413,10 @@
return ClassifyImpl(Ctx, &Loc);
}
+ /// Returns the set of floating point options that apply to this expression.
+ /// Only meaningful for operations on floating point values.
+ FPOptions getFPFeaturesInEffect(const LangOptions &LO) const;
+
/// getValueKindForType - Given a formal return or parameter type,
/// give its value kind.
static ExprValueKind getValueKindForType(QualType T) {
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits