diff --git a/clang/include/clang/Basic/FPOptions.def b/clang/include/clang/Basic/FPOptions.def --- a/clang/include/clang/Basic/FPOptions.def +++ b/clang/include/clang/Basic/FPOptions.def @@ -14,9 +14,10 @@ // OPTION(name, type, width, previousName) OPTION(FPContractMode, LangOptions::FPModeKind, 2, First) -OPTION(RoundingMode, LangOptions::RoundingMode, 3, FPContractMode) -OPTION(FPExceptionMode, LangOptions::FPExceptionModeKind, 2, RoundingMode) -OPTION(AllowFEnvAccess, bool, 1, FPExceptionMode) +OPTION(RoundingMath, bool, 1, FPContractMode) +OPTION(ConstRoundingMode, LangOptions::RoundingMode, 3, RoundingMath) +OPTION(SpecifiedExceptionMode, LangOptions::FPExceptionModeKind, 2, ConstRoundingMode) +OPTION(AllowFEnvAccess, bool, 1, SpecifiedExceptionMode) OPTION(AllowFPReassociate, bool, 1, AllowFEnvAccess) OPTION(NoHonorNaNs, bool, 1, AllowFPReassociate) OPTION(NoHonorInfs, bool, 1, NoHonorNaNs) diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -259,10 +259,6 @@ FPM_FastHonorPragmas }; - /// Alias for RoundingMode::NearestTiesToEven. - static constexpr unsigned FPR_ToNearest = - static_cast(llvm::RoundingMode::NearestTiesToEven); - /// Possible floating point exception behavior. enum FPExceptionModeKind { /// Assume that floating-point exceptions are masked. @@ -270,7 +266,9 @@ /// Transformations do not cause new exceptions but may hide some. FPE_MayTrap, /// Strictly preserve the floating-point exception semantics. - FPE_Strict + FPE_Strict, + /// Used internally to represent initial unspecified value. + FPE_Default }; /// Possible float expression evaluation method choices. @@ -610,6 +608,18 @@ /// Remap path prefix according to -fmacro-prefix-path option. void remapPathPrefix(SmallVectorImpl &Path) const; + + RoundingMode getDefaultRoundingMode() const { + return RoundingMath ? RoundingMode::Dynamic + : RoundingMode::NearestTiesToEven; + } + + FPExceptionModeKind getDefaultExceptionMode() const { + FPExceptionModeKind EM = getFPExceptionMode(); + if (EM == FPExceptionModeKind::FPE_Default) + return FPExceptionModeKind::FPE_Ignore; + return EM; + } }; /// Floating point control options @@ -617,7 +627,7 @@ class FPOptions { public: // We start by defining the layout. - using storage_type = uint16_t; + using storage_type = uint32_t; using RoundingMode = llvm::RoundingMode; @@ -646,8 +656,8 @@ public: FPOptions() : Value(0) { setFPContractMode(LangOptions::FPM_Off); - setRoundingMode(static_cast(LangOptions::FPR_ToNearest)); - setFPExceptionMode(LangOptions::FPE_Ignore); + setConstRoundingMode(RoundingMode::Dynamic); + setSpecifiedExceptionMode(LangOptions::FPE_Default); } explicit FPOptions(const LangOptions &LO) { Value = 0; @@ -658,8 +668,9 @@ if (LangOptContractMode == LangOptions::FPM_FastHonorPragmas) LangOptContractMode = LangOptions::FPM_Fast; setFPContractMode(LangOptContractMode); - setRoundingMode(LO.getFPRoundingMode()); - setFPExceptionMode(LO.getFPExceptionMode()); + setRoundingMath(LO.RoundingMath); + setConstRoundingMode(LangOptions::RoundingMode::Dynamic); + setSpecifiedExceptionMode(LO.getFPExceptionMode()); setAllowFPReassociate(LO.AllowFPReassoc); setNoHonorNaNs(LO.NoHonorNaNs); setNoHonorInfs(LO.NoHonorInfs); @@ -668,7 +679,7 @@ setAllowApproxFunc(LO.ApproxFunc); if (getFPContractMode() == LangOptions::FPM_On && getRoundingMode() == llvm::RoundingMode::Dynamic && - getFPExceptionMode() == LangOptions::FPE_Strict) + getExceptionMode() == LangOptions::FPE_Strict) // If the FP settings are set to the "strict" model, then // FENV access is set to true. (ffp-model=strict) setAllowFEnvAccess(true); @@ -692,10 +703,33 @@ bool isFPConstrained() const { return getRoundingMode() != llvm::RoundingMode::NearestTiesToEven || - getFPExceptionMode() != LangOptions::FPE_Ignore || + getExceptionMode() != LangOptions::FPE_Ignore || getAllowFEnvAccess(); } + RoundingMode getRoundingMode() const { + RoundingMode RM = getConstRoundingMode(); + if (RM == RoundingMode::Dynamic) { + // 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 (!getAllowFEnvAccess() && !getRoundingMath()) + RM = RoundingMode::NearestTiesToEven; + } + return RM; + } + + LangOptions::FPExceptionModeKind getExceptionMode() const { + LangOptions::FPExceptionModeKind EM = getSpecifiedExceptionMode(); + if (EM == LangOptions::FPExceptionModeKind::FPE_Default) { + if (getAllowFEnvAccess()) + return LangOptions::FPExceptionModeKind::FPE_Strict; + else + return LangOptions::FPExceptionModeKind::FPE_Ignore; + } + return EM; + } + bool operator==(FPOptions other) const { return Value == other.Value; } /// Return the default value of FPOptions that's used when trailing @@ -743,7 +777,7 @@ /// The type suitable for storing values of FPOptionsOverride. Must be twice /// as wide as bit size of FPOption. - using storage_type = uint32_t; + using storage_type = uint64_t; static_assert(sizeof(storage_type) >= 2 * sizeof(FPOptions::storage_type), "Too short type for FPOptionsOverride"); diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -311,8 +311,8 @@ /// FP_CONTRACT mode (on/off/fast). BENIGN_ENUM_LANGOPT(DefaultFPContractMode, FPModeKind, 2, FPM_Off, "FP contraction type") COMPATIBLE_LANGOPT(ExpStrictFP, 1, false, "Enable experimental strict floating point") -BENIGN_ENUM_LANGOPT(FPRoundingMode, RoundingMode, 3, RoundingMode::NearestTiesToEven, "FP Rounding Mode type") -BENIGN_ENUM_LANGOPT(FPExceptionMode, FPExceptionModeKind, 2, FPE_Ignore, "FP Exception Behavior Mode type") +BENIGN_LANGOPT(RoundingMath, 1, false, "Do not assume default floating-point rounding behavior") +BENIGN_ENUM_LANGOPT(FPExceptionMode, FPExceptionModeKind, 2, FPE_Default, "FP Exception Behavior Mode type") BENIGN_ENUM_LANGOPT(FPEvalMethod, FPEvalMethodKind, 2, FEM_UnsetOnCommandLine, "FP type used for floating point arithmetic") LANGOPT(NoBitFieldTypeAlign , 1, 0, "bit-field type alignment") LANGOPT(HexagonQdsp6Compat , 1, 0, "hexagon-qdsp6 backward compatibility") diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1544,7 +1544,7 @@ HelpText<"Specifies the exception behavior of floating-point operations.">, Values<"ignore,maytrap,strict">, NormalizedValuesScope<"LangOptions">, NormalizedValues<["FPE_Ignore", "FPE_MayTrap", "FPE_Strict"]>, - MarshallingInfoEnum, "FPE_Ignore">; + MarshallingInfoEnum, "FPE_Default">; defm fast_math : BoolFOption<"fast-math", LangOpts<"FastMath">, DefaultFalse, PosFlag, Alias; def : Flag<["-"], "fno-honor-infinites">, Alias; def frounding_math : Flag<["-"], "frounding-math">, Group, Flags<[CC1Option]>, - MarshallingInfoFlag, "llvm::RoundingMode::NearestTiesToEven">, + MarshallingInfoFlag>, Normalizer<"makeFlagToValueNormalizer(llvm::RoundingMode::Dynamic)">; def fno_rounding_math : Flag<["-"], "fno-rounding-math">, Group, Flags<[CC1Option]>; def ftrapping_math : Flag<["-"], "ftrapping-math">, Group; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -10311,7 +10311,7 @@ LangOptions::FPExceptionModeKind); /// Called to set constant rounding mode for floating point operations. - void setRoundingMode(SourceLocation Loc, llvm::RoundingMode); + void ActOnPragmaFEnvRound(SourceLocation Loc, llvm::RoundingMode); /// Called to set exception behavior for floating point operations. void setExceptionMode(SourceLocation Loc, LangOptions::FPExceptionModeKind); 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 @@ -2584,14 +2584,14 @@ if ((St != APFloat::opOK) && (FPO.getRoundingMode() == llvm::RoundingMode::Dynamic || - FPO.getFPExceptionMode() != LangOptions::FPE_Ignore || + FPO.getExceptionMode() != LangOptions::FPE_Ignore || FPO.getAllowFEnvAccess())) { Info.FFDiag(E, diag::note_constexpr_float_arithmetic_strict); return false; } if ((St & APFloat::opStatus::opInvalidOp) && - FPO.getFPExceptionMode() != LangOptions::FPE_Ignore) { + FPO.getExceptionMode() != LangOptions::FPE_Ignore) { // There is no usefully definable result. Info.FFDiag(E); return false; diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -1849,7 +1849,7 @@ CodeGenOpts.FP32DenormalMode.str()); } - if (LangOpts.getFPExceptionMode() == LangOptions::FPE_Ignore) + if (LangOpts.getDefaultExceptionMode() == LangOptions::FPE_Ignore) FuncAttrs.addAttribute("no-trapping-math", "true"); // TODO: Are these all needed? diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -105,8 +105,9 @@ case LangOptions::FPE_Ignore: return llvm::fp::ebIgnore; case LangOptions::FPE_MayTrap: return llvm::fp::ebMayTrap; case LangOptions::FPE_Strict: return llvm::fp::ebStrict; + default: + llvm_unreachable("Unsupported FP Exception Behavior"); } - llvm_unreachable("Unsupported FP Exception Behavior"); } void CodeGenFunction::SetFastMathFlags(FPOptions FPFeatures) { @@ -145,12 +146,11 @@ FMFGuard.emplace(CGF.Builder); - llvm::RoundingMode NewRoundingBehavior = - static_cast(FPFeatures.getRoundingMode()); + llvm::RoundingMode NewRoundingBehavior = FPFeatures.getRoundingMode(); CGF.Builder.setDefaultConstrainedRounding(NewRoundingBehavior); auto NewExceptionBehavior = ToConstrainedExceptMD(static_cast( - FPFeatures.getFPExceptionMode())); + FPFeatures.getExceptionMode())); CGF.Builder.setDefaultConstrainedExcept(NewExceptionBehavior); CGF.SetFastMathFlags(FPFeatures); @@ -971,9 +971,9 @@ (getLangOpts().CUDA && FD->hasAttr()))) Fn->addFnAttr(llvm::Attribute::NoRecurse); - llvm::RoundingMode RM = getLangOpts().getFPRoundingMode(); + llvm::RoundingMode RM = getLangOpts().getDefaultRoundingMode(); llvm::fp::ExceptionBehavior FPExceptionBehavior = - ToConstrainedExceptMD(getLangOpts().getFPExceptionMode()); + ToConstrainedExceptMD(getLangOpts().getDefaultExceptionMode()); Builder.setDefaultConstrainedRounding(RM); Builder.setDefaultConstrainedExcept(FPExceptionBehavior); if ((FD && (FD->UsesFPIntrin() || FD->hasAttr())) || diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -123,12 +123,12 @@ } if (!getTarget().hasStrictFP() && !getLangOpts().ExpStrictFP) { - if (getLangOpts().getFPRoundingMode() != - llvm::RoundingMode::NearestTiesToEven) { + if (getLangOpts().RoundingMath) { getDiagnostics().Report(diag::warn_fe_backend_unsupported_fp_rounding); - getLangOpts().setFPRoundingMode(llvm::RoundingMode::NearestTiesToEven); + getLangOpts().RoundingMath = false; } - if (getLangOpts().getFPExceptionMode() != LangOptions::FPE_Ignore) { + auto FPExc = getLangOpts().getFPExceptionMode(); + if (FPExc != LangOptions::FPE_Default && FPExc != LangOptions::FPE_Ignore) { getDiagnostics().Report(diag::warn_fe_backend_unsupported_fp_exceptions); getLangOpts().setFPExceptionMode(LangOptions::FPE_Ignore); } diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -804,7 +804,7 @@ reinterpret_cast(Tok.getAnnotationValue())); SourceLocation PragmaLoc = ConsumeAnnotationToken(); - Actions.setRoundingMode(PragmaLoc, RM); + Actions.ActOnPragmaFEnvRound(PragmaLoc, RM); } StmtResult Parser::HandlePragmaCaptured() 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 @@ -571,7 +571,7 @@ PP.setCurrentFPEvalMethod(SourceLocation(), PP.getLastFPEvalMethod()); break; case PFC_NoPrecise: - if (CurFPFeatures.getFPExceptionMode() == LangOptions::FPE_Strict) + if (CurFPFeatures.getExceptionMode() == LangOptions::FPE_Strict) Diag(Loc, diag::err_pragma_fc_noprecise_requires_noexcept); else if (CurFPFeatures.getAllowFEnvAccess()) Diag(Loc, diag::err_pragma_fc_noprecise_requires_nofenv); @@ -587,11 +587,11 @@ if (!isPreciseFPEnabled()) Diag(Loc, diag::err_pragma_fc_except_requires_precise); else - NewFPFeatures.setFPExceptionModeOverride(LangOptions::FPE_Strict); + NewFPFeatures.setSpecifiedExceptionModeOverride(LangOptions::FPE_Strict); FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures); break; case PFC_NoExcept: - NewFPFeatures.setFPExceptionModeOverride(LangOptions::FPE_Ignore); + NewFPFeatures.setSpecifiedExceptionModeOverride(LangOptions::FPE_Ignore); FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures); break; case PFC_Push: @@ -1294,16 +1294,9 @@ CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts()); } -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() && - CurFPFeatures.getFPExceptionMode() == LangOptions::FPE_Ignore) - FPR = llvm::RoundingMode::NearestTiesToEven; - +void Sema::ActOnPragmaFEnvRound(SourceLocation Loc, llvm::RoundingMode FPR) { FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides(); - NewFPFeatures.setRoundingModeOverride(FPR); + NewFPFeatures.setConstRoundingModeOverride(FPR); FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures); CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts()); } @@ -1311,14 +1304,13 @@ void Sema::setExceptionMode(SourceLocation Loc, LangOptions::FPExceptionModeKind FPE) { FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides(); - NewFPFeatures.setFPExceptionModeOverride(FPE); + NewFPFeatures.setSpecifiedExceptionModeOverride(FPE); FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures); CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts()); } void Sema::ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled) { FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides(); - auto LO = getLangOpts(); if (IsEnabled) { // Verify Microsoft restriction: // You can't enable fenv_access unless precise semantics are enabled. @@ -1326,16 +1318,10 @@ // pragma, or by using the /fp:precise or /fp:strict compiler options if (!isPreciseFPEnabled()) Diag(Loc, diag::err_pragma_fenv_requires_precise); - NewFPFeatures.setAllowFEnvAccessOverride(true); - // Enabling FENV access sets the RoundingMode to Dynamic. - // and ExceptionBehavior to Strict - NewFPFeatures.setRoundingModeOverride(llvm::RoundingMode::Dynamic); - NewFPFeatures.setFPExceptionModeOverride(LangOptions::FPE_Strict); - } else { - NewFPFeatures.setAllowFEnvAccessOverride(false); } + NewFPFeatures.setAllowFEnvAccessOverride(IsEnabled); FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures); - CurFPFeatures = NewFPFeatures.applyOverrides(LO); + CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts()); } void Sema::ActOnPragmaFPExceptions(SourceLocation Loc, diff --git a/clang/test/AST/ast-dump-fpfeatures.cpp b/clang/test/AST/ast-dump-fpfeatures.cpp --- a/clang/test/AST/ast-dump-fpfeatures.cpp +++ b/clang/test/AST/ast-dump-fpfeatures.cpp @@ -87,7 +87,7 @@ } // CHECK-LABEL: FunctionDecl {{.*}} func_10 'float (float, float)' -// CHECK: BinaryOperator {{.*}} 'float' '+' RoundingMode=downward +// CHECK: BinaryOperator {{.*}} 'float' '+' ConstRoundingMode=downward float func_11(float x, float y) { if (x < 0) { @@ -98,8 +98,8 @@ } // CHECK-LABEL: FunctionDecl {{.*}} func_11 'float (float, float)' -// CHECK: BinaryOperator {{.*}} 'float' '+' RoundingMode=upward -// CHECK: BinaryOperator {{.*}} 'float' '-' RoundingMode=downward +// CHECK: BinaryOperator {{.*}} 'float' '+' ConstRoundingMode=upward +// CHECK: BinaryOperator {{.*}} 'float' '-' ConstRoundingMode=downward #pragma STDC FENV_ROUND FE_DYNAMIC @@ -109,7 +109,7 @@ } // CHECK-LABEL: FunctionDecl {{.*}} func_12 'float (float, float)' -// CHECK: BinaryOperator {{.*}} 'float' '+' RoundingMode=tonearest +// CHECK: BinaryOperator {{.*}} 'float' '+' ConstRoundingMode=dynamic #pragma STDC FENV_ROUND FE_TONEAREST @@ -118,7 +118,7 @@ } // CHECK-LABEL: FunctionDecl {{.*}} func_13 'float (float, float)' -// CHECK: BinaryOperator {{.*}} 'float' '+' RoundingMode=tonearest +// CHECK: BinaryOperator {{.*}} 'float' '+' ConstRoundingMode=tonearest template @@ -136,8 +136,8 @@ // CHECK: FunctionDecl {{.*}} func_14 'T (T, T)' // CHECK: CompoundStmt // CHECK-NEXT: ReturnStmt -// CHECK-NEXT: BinaryOperator {{.*}} '+' RoundingMode=towardzero +// CHECK-NEXT: BinaryOperator {{.*}} '+' ConstRoundingMode=towardzero // CHECK: FunctionDecl {{.*}} func_14 'float (float, float)' // CHECK: CompoundStmt // CHECK-NEXT: ReturnStmt -// CHECK-NEXT: BinaryOperator {{.*}} 'float' '+' RoundingMode=towardzero +// CHECK-NEXT: BinaryOperator {{.*}} 'float' '+' ConstRoundingMode=towardzero diff --git a/clang/test/CodeGen/pragma-fenv_access.c b/clang/test/CodeGen/pragma-fenv_access.c --- a/clang/test/CodeGen/pragma-fenv_access.c +++ b/clang/test/CodeGen/pragma-fenv_access.c @@ -1,5 +1,15 @@ -// RUN: %clang_cc1 -fexperimental-strict-floating-point -ffp-exception-behavior=strict -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck %s -// RUN: %clang_cc1 -fexperimental-strict-floating-point -ffp-exception-behavior=strict -triple %itanium_abi_triple -emit-llvm %s -o - -fms-extensions -DMS | FileCheck %s +// RUN: %clang_cc1 -fexperimental-strict-floating-point -ffp-exception-behavior=strict -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,STRICT %s +// RUN: %clang_cc1 -fexperimental-strict-floating-point -ffp-exception-behavior=strict -triple %itanium_abi_triple -emit-llvm %s -o - -fms-extensions -DMS | FileCheck --check-prefixes=CHECK,STRICT %s +// RUN: %clang_cc1 -fexperimental-strict-floating-point -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,DEFAULT %s + + +float func_00(float x, float y) { + return x + y; +} +// CHECK-LABEL: @func_00 +// STRICT: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") +// DEFAULT: fadd float + #ifdef MS #pragma fenv_access (on) @@ -20,7 +30,7 @@ return x + y; } // CHECK-LABEL: @func_02 -// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore") +// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore") float func_03(float x, float y) { @@ -41,7 +51,16 @@ return x + y; } // CHECK-LABEL: @func_04 -// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore") +// STRICT: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore") +// DEFAULT: fadd float + + +float func_04a(float x, float y) { + #pragma float_control(except, on) + return x + y; +} +// CHECK-LABEL: @func_04a +// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") float func_05(float x, float y) { @@ -57,18 +76,151 @@ return x + y; } // CHECK-LABEL: @func_06 -// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore") +// STRICT: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore") +// DEFAULT: fadd float float func_07(float x, float y) { x -= y; if (x) { #pragma STDC FENV_ACCESS ON - y *= 2; + y *= 2.0F; } - return y + 4; + return y + 4.0F; } // CHECK-LABEL: @func_07 -// CHECK: call float @llvm.experimental.constrained.fsub.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict") -// CHECK: call float @llvm.experimental.constrained.fmul.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict") +// STRICT: call float @llvm.experimental.constrained.fsub.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") +// STRICT: call float @llvm.experimental.constrained.fmul.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict") +// STRICT: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") +// DEFAULT: call float @llvm.experimental.constrained.fsub.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore") +// DEFAULT: call float @llvm.experimental.constrained.fmul.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict") +// DEFAULT: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore") + + +float func_08(float x, float y) { + #pragma STDC FENV_ROUND FE_UPWARD + #pragma STDC FENV_ACCESS ON + return x + y; +} +// CHECK-LABEL: @func_08 +// CHECK: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.strict") + + +float func_09(float x, float y) { + #pragma STDC FENV_ROUND FE_TONEAREST + #pragma STDC FENV_ACCESS ON + return x + y; +} +// CHECK-LABEL: @func_09 +// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") + + +float func_10(float x, float y) { + #pragma STDC FENV_ROUND FE_TONEAREST + #pragma clang fp exceptions(ignore) + #pragma STDC FENV_ACCESS ON + return x + y; +} +// CHECK-LABEL: @func_10 +// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore") + + +float func_11(float x, float y) { + #pragma STDC FENV_ROUND FE_TONEAREST + #pragma clang fp exceptions(ignore) + #pragma STDC FENV_ACCESS OFF + return x + y; +} +// CHECK-LABEL: @func_11 +// STRICT: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore") +// DEFAULT: fadd float + + +float func_12(float x, float y) { + #pragma clang fp exceptions(maytrap) + #pragma STDC FENV_ACCESS ON + return x + y; +} +// CHECK-LABEL: @func_12 +// CHECK: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.maytrap") + + +float func_13(float x, float y) { + #pragma clang fp exceptions(maytrap) + #pragma STDC FENV_ROUND FE_UPWARD + #pragma STDC FENV_ACCESS ON + return x + y; +} +// CHECK-LABEL: @func_13 +// CHECK: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.maytrap") + + +float func_14(float x, float y, float z) { + #pragma STDC FENV_ACCESS ON + float res = x * y; + { + #pragma STDC FENV_ACCESS OFF + return res + z; + } +} +// CHECK-LABEL: @func_14 +// STRICT: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict") +// STRICT: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") +// DEFAULT: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict") +// DEFAULT: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore") + + +float func_15(float x, float y, float z) { + #pragma STDC FENV_ROUND FE_TOWARDZERO + #pragma STDC FENV_ACCESS ON + float res = x * y; + { + #pragma STDC FENV_ACCESS OFF + return res + z; + } +} +// CHECK-LABEL: @func_15 +// STRICT: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.strict") +// STRICT: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.strict") +// DEFAULT: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.strict") +// DEFAULT: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore") + + +float func_16(float x, float y) { + x -= y; + { + #pragma STDC FENV_ROUND FE_TONEAREST + #pragma STDC FENV_ACCESS ON + y *= 2.0F; + } + { + #pragma STDC FENV_ACCESS ON + return y + 4.0F; + } +} +// CHECK-LABEL: @func_16 +// STRICT: call float @llvm.experimental.constrained.fsub.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") +// STRICT: call float @llvm.experimental.constrained.fmul.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") +// STRICT: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict") +// DEFAULT: call float @llvm.experimental.constrained.fsub.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore") +// DEFAULT: call float @llvm.experimental.constrained.fmul.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") +// DEFAULT: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict") + + +float func_17(float x, float y) { + #pragma STDC FENV_ROUND FE_DYNAMIC + #pragma STDC FENV_ACCESS ON + return x + y; +} +// CHECK-LABEL: @func_17 // CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict") + + +float func_18(float x, float y) { + #pragma STDC FENV_ROUND FE_DYNAMIC + return x + y; +} +// CHECK-LABEL: @func_18 +// STRICT: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") +// DEFAULT: fadd float +