Index: clang/docs/UsersManual.rst =================================================================== --- clang/docs/UsersManual.rst +++ clang/docs/UsersManual.rst @@ -1219,10 +1219,10 @@ **-f[no-]trapping-math** - ``-fno-trapping-math`` allows optimizations that assume that - floating point operations cannot generate traps such as divide-by-zero, - overflow and underflow. Defaults to ``-ftrapping-math``. - Currently this option has no effect. + Control floating point exception behavior. ``-fno-trapping-math`` allows optimizations that assume that floating point operations cannot generate traps such as divide-by-zero, overflow and underflow. + +- The option ``-ftrapping-math`` behaves identically to ``-ffp-exception-behavior=strict``. +- The option ``-fno-trapping-math`` behaves identically to ``-ffp-exception-behavior=ignore``. This is the default. .. option:: -ffp-contract= @@ -1307,6 +1307,53 @@ Defaults to ``-fno-finite-math``. +.. _opt_frounding-math: + +**-f[no-]rounding-math** + + LLVM constrained floating point supports five rounding modes: ``tonearest``, + ``downward``, ``upward``, ``towardzero`` and ``dynamic``. The first four + values represent the corresponding IEEE rounding rules, and the ``dynamic`` + mode informs the compiler that it must not assume any particular + rounding mode. + +- The option ``-fno-rounding-math`` specifies ``tonearest`` rounding mode. This is the default. +- The option ``-frounding-math`` specifies ``dynamic`` rounding mode. +- The option ``-frounding-math`` behaves identically to ``-ffp-model=strict``. Consequently, this option also sets ``-ffp-exception-behavior=strict``. + +.. option:: -ffp-model= + + Specify floating point behavior. ``-ffp-model`` is an umbrella + option that encompasses functionality provided by other, single + purpose, clang floating point options. Valid values are: ``precise``, ``strict``, + and ``fast``. + Details: + + * ``precise`` Disables optimizations that are not value-safe on floating-point data, although FP contraction (FMA) is enabled (``-ffp-contract=fast``). This is clang's default behavior. + * ``strict`` Enables ``-frounding-math`` and ``-ffp-exception-behavior=strict``, and disables contractions (FMA). All of the ``-ffast-math`` enablements are disabled. + * ``fast`` Behaves identically to specifying both ``-ffast-math`` and ``ffp-contract=fast`` + + Note: If your command line specifies multiple instances + of the ``-ffp-model`` option, or if your command line option specifies + ``-ffp-model`` and later on the command line selects a floating point + option that has the effect of negating part of the ``ffp-model`` that + has been selected, then the compiler will issue a diagnostic warning + that the override has occurred. + +.. option:: -ffp-exception-behavior= + + Specify the floating-point exception behavior. + + Valid values are: ``ignore``, ``maytrap``, and ``strict``. + The default value is ``ignore``. Details: + + * ``ignore`` The compiler assumes that the exception status flags will not be read and that floating point exceptions will be masked. + * ``maytrap`` The compiler avoids transformations that may raise exceptions that would not have been raised by the original code. Constant folding performed by the compiler is exempt from this option. + * ``strict`` The compiler ensures that all transformations strictly preserve the floating point exception semantics of the original code. + + + + .. _controlling-code-generation: Controlling Code Generation Index: clang/include/clang/Basic/CodeGenOptions.def =================================================================== --- clang/include/clang/Basic/CodeGenOptions.def +++ clang/include/clang/Basic/CodeGenOptions.def @@ -234,6 +234,7 @@ CODEGENOPT(RerollLoops , 1, 0) ///< Control whether loops are rerolled. CODEGENOPT(NoUseJumpTables , 1, 0) ///< Set when -fno-jump-tables is enabled. CODEGENOPT(UnsafeFPMath , 1, 0) ///< Allow unsafe floating point optzns. +CODEGENOPT(RoundingFPMath , 1, 0) ///< Rounding floating point optzns. CODEGENOPT(UnwindTables , 1, 0) ///< Emit unwind tables. CODEGENOPT(VectorizeLoop , 1, 0) ///< Run loop vectorizer. CODEGENOPT(VectorizeSLP , 1, 0) ///< Run SLP vectorizer. Index: clang/include/clang/Basic/LangOptions.h =================================================================== --- clang/include/clang/Basic/LangOptions.h +++ clang/include/clang/Basic/LangOptions.h @@ -184,6 +184,31 @@ FEA_On }; + enum FPRoundingModeKind { + // Round to the nearest integer - IEEE rounding mode + FPRM_ToNearest, // This is the default + // Rounding mode is dynamic: optimizer assumes that rounding mode + // is unknown. + FPRM_Dynamic, + // Round down - IEEE rounding mode + FPRM_Downward, + // Round up - IEEE rounding mode + FPRM_Upward, + // Round towards zero - IEEE rounding mode + FPRM_ToZero + }; + + enum FPExceptionBehaviorKind { + // Floating point exceptions are not handled: fp exceptions are masked. + FPEB_Ignore, // This is the default + // Optimizer will avoid transformations that may raise exceptions that would + // not have been raised by unoptimized code + FPEB_MayTrap, + // Optimizer will strictly preserve the fp exception semantics of the + // unoptimized code + FPEB_Strict + }; + enum class LaxVectorConversionKind { /// Permit no implicit vector bitcasts. None, @@ -317,6 +342,38 @@ /// Return the OpenCL C or C++ version as a VersionTuple. VersionTuple getOpenCLVersionTuple() const; + + /// Floating point model options + class FPModelOptions { + public: + FPModelOptions() : FPRM(LangOptions::FPRM_ToNearest), + FPEB(LangOptions::FPEB_Ignore) {} + + LangOptions::FPRoundingModeKind getFPRoundingModeSetting() const { + return FPRM; + } + void setFPRoundingModeSetting(LangOptions::FPRoundingModeKind Value) { + FPRM = Value; + } + + LangOptions::FPExceptionBehaviorKind getFPExceptionBehaviorSetting() const + { + return FPEB; + } + void setFPExceptionBehaviorSetting( + LangOptions::FPExceptionBehaviorKind Value) { + FPEB = Value; + } + + private: + LangOptions::FPRoundingModeKind FPRM = LangOptions::FPRM_ToNearest; + LangOptions::FPExceptionBehaviorKind FPEB = LangOptions::FPEB_Ignore; + }; + + FPModelOptions& getFPMOptions() { return fpm_options; } + FPModelOptions getFPMOptions() const { return fpm_options; } +private: + FPModelOptions fpm_options; }; /// Floating point control options Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -924,6 +924,10 @@ def : Flag<["-"], "fno-extended-identifiers">, Group, Flags<[Unsupported]>; def fhosted : Flag<["-"], "fhosted">, Group; def fdenormal_fp_math_EQ : Joined<["-"], "fdenormal-fp-math=">, Group, Flags<[CC1Option]>; +def ffp_model_EQ : Joined<["-"], "ffp-model=">, Group, Flags<[DriverOption]>, + HelpText<"Controls the semantics of floating-point calculations.">; +def ffp_exception_behavior_EQ : Joined<["-"], "ffp-exception-behavior=">, Group, Flags<[CC1Option]>, + HelpText<"Specifies the exception behavior of floating-point operations.">; def ffast_math : Flag<["-"], "ffast-math">, Group, Flags<[CC1Option]>, HelpText<"Allow aggressive, lossy floating-point optimizations">; def fno_fast_math : Flag<["-"], "fno-fast-math">, Group; @@ -1140,6 +1144,8 @@ // This option was originally misspelt "infinites" [sic]. def : Flag<["-"], "fhonor-infinites">, Alias; def : Flag<["-"], "fno-honor-infinites">, Alias; +def frounding_math : Flag<["-"], "frounding-math">, Group, Flags<[CC1Option]>; +def fno_rounding_math : Flag<["-"], "fno-rounding-math">, Group, Flags<[CC1Option]>; def ftrapping_math : Flag<["-"], "ftrapping-math">, Group, Flags<[CC1Option]>; def fno_trapping_math : Flag<["-"], "fno-trapping-math">, Group, Flags<[CC1Option]>; def ffp_contract : Joined<["-"], "ffp-contract=">, Group, @@ -3168,7 +3174,6 @@ defm regs_graph : BooleanFFlag<"regs-graph">, Group; defm rename_registers : BooleanFFlag<"rename-registers">, Group; defm ripa : BooleanFFlag<"ripa">, Group; -defm rounding_math : BooleanFFlag<"rounding-math">, Group; defm schedule_insns : BooleanFFlag<"schedule-insns">, Group; defm schedule_insns2 : BooleanFFlag<"schedule-insns2">, Group; defm see : BooleanFFlag<"see">, Group; Index: clang/lib/CodeGen/BackendUtil.cpp =================================================================== --- clang/lib/CodeGen/BackendUtil.cpp +++ clang/lib/CodeGen/BackendUtil.cpp @@ -475,6 +475,7 @@ Options.NoNaNsFPMath = CodeGenOpts.NoNaNsFPMath; Options.NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS; Options.UnsafeFPMath = CodeGenOpts.UnsafeFPMath; + Options.RoundingFPMath = CodeGenOpts.RoundingFPMath; Options.StackAlignmentOverride = CodeGenOpts.StackAlignment; Options.FunctionSections = CodeGenOpts.FunctionSections; Options.DataSections = CodeGenOpts.DataSections; Index: clang/lib/CodeGen/CodeGenFunction.h =================================================================== --- clang/lib/CodeGen/CodeGenFunction.h +++ clang/lib/CodeGen/CodeGenFunction.h @@ -4148,6 +4148,9 @@ /// point operation, expressed as the maximum relative error in ulp. void SetFPAccuracy(llvm::Value *Val, float Accuracy); + /// SetFPModel - Control floating point behavior via fp-model settings. + void SetFPModel(void); + private: llvm::MDNode *getRangeForLoadFromType(QualType Ty); void EmitReturnOfRValue(RValue RV, QualType Ty); Index: clang/lib/CodeGen/CodeGenFunction.cpp =================================================================== --- clang/lib/CodeGen/CodeGenFunction.cpp +++ clang/lib/CodeGen/CodeGenFunction.cpp @@ -33,6 +33,7 @@ #include "clang/Frontend/FrontendDiagnostic.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Dominators.h" +#include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/MDBuilder.h" #include "llvm/IR/Operator.h" @@ -87,6 +88,7 @@ FMF.setAllowReassoc(); } Builder.setFastMathFlags(FMF); + SetFPModel(); } CodeGenFunction::~CodeGenFunction() { @@ -102,6 +104,62 @@ CGM.getOpenMPRuntime().functionFinished(*this); } +void CodeGenFunction::SetFPModel(void) +{ + auto fpRoundingMode = getLangOpts().getFPMOptions().getFPRoundingModeSetting(); + auto fpExceptionBehavior = + getLangOpts().getFPMOptions().getFPExceptionBehaviorSetting(); + + // Translate the compiler options into + // the settings that are transmitted to the IR Builder + llvm::ConstrainedFPIntrinsic::RoundingMode ConstrainedRoundingMD; + llvm::ConstrainedFPIntrinsic::ExceptionBehavior ConstrainedExceptMD; + + switch (fpRoundingMode) { + case LangOptions::FPRM_ToNearest: + ConstrainedRoundingMD = llvm::ConstrainedFPIntrinsic::rmToNearest; + break; + case LangOptions::FPRM_Downward: + ConstrainedRoundingMD = llvm::ConstrainedFPIntrinsic::rmDownward; + break; + case LangOptions::FPRM_Upward: + ConstrainedRoundingMD = llvm::ConstrainedFPIntrinsic::rmUpward; + break; + case LangOptions::FPRM_ToZero: + ConstrainedRoundingMD = llvm::ConstrainedFPIntrinsic::rmTowardZero; + break; + case LangOptions::FPRM_Dynamic: + ConstrainedRoundingMD = llvm::ConstrainedFPIntrinsic::rmDynamic; + break; + default: + llvm_unreachable("Unsupported FP RoundingMode"); + } + + switch (fpExceptionBehavior) { + case LangOptions::FPEB_Ignore: + ConstrainedExceptMD = llvm::ConstrainedFPIntrinsic::ebIgnore; + break; + case LangOptions::FPEB_MayTrap: + ConstrainedExceptMD = llvm::ConstrainedFPIntrinsic::ebMayTrap; + break; + case LangOptions::FPEB_Strict: + ConstrainedExceptMD = llvm::ConstrainedFPIntrinsic::ebStrict; + break; + default: + llvm_unreachable("Unsupported FP Exception Behavior"); + } + + if (fpExceptionBehavior == LangOptions::FPEB_Ignore && + fpRoundingMode == LangOptions::FPRM_ToNearest) + // Constrained intrinsics are not used. + ; + else { + Builder.setIsFPConstrained(true); + Builder.setDefaultConstrainedRounding(ConstrainedRoundingMD); + Builder.setDefaultConstrainedExcept(ConstrainedExceptMD); + } +} + CharUnits CodeGenFunction::getNaturalPointeeTypeAlignment(QualType T, LValueBaseInfo *BaseInfo, TBAAAccessInfo *TBAAInfo) { Index: clang/lib/Driver/ToolChains/Clang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Clang.cpp +++ clang/lib/Driver/ToolChains/Clang.cpp @@ -2323,9 +2323,22 @@ bool AssociativeMath = false; bool ReciprocalMath = false; bool SignedZeros = true; - bool TrappingMath = true; + bool TrappingMath = false; + bool RoundingFPMath = false; + bool RoundingMathPresent = false; + // -fp-model options: + StringRef FPModel = ""; + //bool FPM_Precise = false; + //bool FPM_Strict = false; + //bool FPM_Fast = false; + // -fp-exception-behavior options: + StringRef FPExceptionBehavior = ""; + //bool FPE_Ignore = false; + //bool FPE_MayTrap = false; + //bool FPE_Stric = false; StringRef DenormalFPMath = ""; StringRef FPContract = ""; + bool StrictFPModel = false; if (const Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) { CmdArgs.push_back("-mlimit-float-precision"); @@ -2333,7 +2346,74 @@ } for (const Arg *A : Args) { - switch (A->getOption().getID()) { + auto optID = A->getOption().getID(); + bool PreciseFPModel = false; + switch (optID) { + default: + break; + case options::OPT_ffp_model_EQ: { + StrictFPModel = false; + PreciseFPModel = true; + // ffp-model= is a Driver option, it is entirely rewritten into more + // granular options before being passed into cc1. + // Use the gcc option in the switch below. + StringRef Val = A->getValue(); + if (!FPModel.empty() && !FPModel.equals(Val)) { + D.Diag(clang::diag::warn_drv_overriding_flag_option) + << Args.MakeArgString("-ffp-model=" + FPModel) + << Args.MakeArgString("-ffp-model=" + Val); + FPContract = ""; + } + if (Val.equals("fast")) { + if (!FPContract.empty() && !FPContract.equals("fast")) + // FPContract has already been set to something else + // so warn about the override. + D.Diag(clang::diag::warn_drv_overriding_flag_option) + << Args.MakeArgString("-ffp-contract=" + FPContract) + << "-ffp-contract=fast"; + optID = options::OPT_ffast_math; + FPModel = Val; + FPContract = "fast"; + } else if (Val.equals("precise")) { + if (!FPContract.empty() && !FPContract.equals("fast")) + D.Diag(clang::diag::warn_drv_overriding_flag_option) + << Args.MakeArgString("-ffp-contract=" + FPContract) + << "-ffp-contract=fast"; + optID = options::OPT_ffp_contract; + FPModel = Val; + FPContract = "fast"; + PreciseFPModel = true; + } else if (Val.equals("strict")) { + StrictFPModel = true; + if (!FPContract.empty() && !FPContract.equals("strict")) + D.Diag(clang::diag::warn_drv_overriding_flag_option) + << Args.MakeArgString("-ffp-contract=" + FPContract) + << "-ffp-contract=strict"; + optID = options::OPT_frounding_math; + FPModel = Val; + // fp-model=strict also enables fno-fast-math + HonorINFs = true; + HonorNaNs = true; + // Turning on -ffast-math (with either flag) removes the need for + // MathErrno. However, turning *off* -ffast-math merely restores the + // toolchain default (which may be false). + MathErrno = TC.IsMathErrnoDefault(); + AssociativeMath = false; + ReciprocalMath = false; + SignedZeros = true; + TrappingMath = true; + RoundingFPMath = true; + // -fno_fast_math restores default denormal and fpcontract handling + DenormalFPMath = ""; + FPContract = ""; + } else + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Val; + break; + } + } + + switch (optID) { // If this isn't an FP option skip the claim below default: continue; @@ -2350,8 +2430,24 @@ case options::OPT_fno_reciprocal_math: ReciprocalMath = false; break; case options::OPT_fsigned_zeros: SignedZeros = true; break; case options::OPT_fno_signed_zeros: SignedZeros = false; break; - case options::OPT_ftrapping_math: TrappingMath = true; break; + case options::OPT_ftrapping_math: + TrappingMath = true; + FPExceptionBehavior = "strict"; + break; case options::OPT_fno_trapping_math: TrappingMath = false; break; + case options::OPT_frounding_math: + // The default setting for frounding-math is True and ffast-math + // sets fno-rounding-math, but we only want to use constrained + // floating point intrinsics if the option is specifically requested. + RoundingFPMath = true; + RoundingMathPresent = true; + FPExceptionBehavior = "strict"; + break; + case options::OPT_fno_rounding_math: + RoundingFPMath = false; + RoundingMathPresent = false; + FPExceptionBehavior = ""; + break; case options::OPT_fdenormal_fp_math_EQ: DenormalFPMath = A->getValue(); @@ -2360,10 +2456,38 @@ // Validate and pass through -fp-contract option. case options::OPT_ffp_contract: { StringRef Val = A->getValue(); - if (Val == "fast" || Val == "on" || Val == "off") + if (PreciseFPModel) { + // -fp-model=precise enables fp-contract=fast as a side effect + // the FPContract value has already been set to a string literal + // and the Val string isn't a pertinent value. + ; + } else if (Val.equals("fast") || Val.equals("on") || Val.equals("off")) FPContract = Val; else D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Val; + break; + } + + // Validate and pass through -ffp-model option. + case options::OPT_ffp_model_EQ: + // This should only occur in the error case + // since the optID has been replaced by a more granular + // floating point option. + break; + + // Validate and pass through -ffp-exception-behavior option. + case options::OPT_ffp_exception_behavior_EQ: { + StringRef Val = A->getValue(); + if (!FPExceptionBehavior.empty() && !FPExceptionBehavior.equals(Val)) + // Warn that previous value of option is overridden. + D.Diag(clang::diag::warn_drv_overriding_flag_option) + << Args.MakeArgString("-ffp-exception-behavior=" + FPExceptionBehavior) + << Args.MakeArgString("-ffp-exception-behavior=" + Val); + if (Val.equals("ignore") || Val.equals("maytrap") || Val.equals("strict")) + FPExceptionBehavior = Val; + else + D.Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() << Val; break; } @@ -2405,6 +2529,7 @@ ReciprocalMath = true; SignedZeros = false; TrappingMath = false; + RoundingFPMath = false; // If fast-math is set then set the fp-contract mode to fast. FPContract = "fast"; break; @@ -2419,11 +2544,30 @@ ReciprocalMath = false; SignedZeros = true; TrappingMath = true; + RoundingFPMath = true; // -fno_fast_math restores default denormal and fpcontract handling DenormalFPMath = ""; FPContract = ""; break; } + if (StrictFPModel) { + // If fp-model=strict has been specified on command line but + // subsequent options conflict then emit warning diagnostic. + if (HonorINFs && HonorNaNs && + !AssociativeMath && !ReciprocalMath && + SignedZeros && TrappingMath && RoundingFPMath && + DenormalFPMath.empty() && FPContract.empty()) + // OK: Current Arg doesn't conflict with fp-model=strict + ; + else { + StrictFPModel = false; + FPModel = ""; + D.Diag(clang::diag::warn_drv_overriding_flag_option) + << "-ffp-model=strict" << + ((A->getNumValues() == 0) ? A->getSpelling() + : Args.MakeArgString(A->getSpelling() + A->getValue())); + } + } // If we handled this option claim it A->claim(); @@ -2451,7 +2595,10 @@ if (ReciprocalMath) CmdArgs.push_back("-freciprocal-math"); - if (!TrappingMath) + if (TrappingMath) + // Note: FP Exception Behavior is also set to strict + CmdArgs.push_back("-ftrapping-math"); + else CmdArgs.push_back("-fno-trapping-math"); if (!DenormalFPMath.empty()) @@ -2461,14 +2608,37 @@ if (!FPContract.empty()) CmdArgs.push_back(Args.MakeArgString("-ffp-contract=" + FPContract)); + if (!RoundingFPMath) + CmdArgs.push_back(Args.MakeArgString("-fno-rounding-math")); + + if (RoundingFPMath && RoundingMathPresent) + CmdArgs.push_back(Args.MakeArgString("-frounding-math")); + + if (!FPExceptionBehavior.empty()) + CmdArgs.push_back(Args.MakeArgString("-ffp-exception-behavior=" + + FPExceptionBehavior)); + ParseMRecip(D, Args, CmdArgs); // -ffast-math enables the __FAST_MATH__ preprocessor macro, but check for the // individual features enabled by -ffast-math instead of the option itself as // that's consistent with gcc's behaviour. if (!HonorINFs && !HonorNaNs && !MathErrno && AssociativeMath && - ReciprocalMath && !SignedZeros && !TrappingMath) + ReciprocalMath && !SignedZeros && !TrappingMath && !RoundingFPMath) { CmdArgs.push_back("-ffast-math"); + if (FPModel.equals("fast")) { + if (FPContract.equals("fast")) + // All set, do nothing. + ; + else if (FPContract.empty()) + // Enable fp-contract=fast + CmdArgs.push_back(Args.MakeArgString("-ffp-contract=fast")); + else + D.Diag(clang::diag::warn_drv_overriding_flag_option) + << "-ffp-model=fast" + << Args.MakeArgString("-ffp-contract=" + FPContract); + } + } // Handle __FINITE_MATH_ONLY__ similarly. if (!HonorINFs && !HonorNaNs) Index: clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- clang/lib/Frontend/CompilerInvocation.cpp +++ clang/lib/Frontend/CompilerInvocation.cpp @@ -3090,6 +3090,36 @@ Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val; } + if (Args.hasArg(OPT_frounding_math)) { + Opts.getFPMOptions().setFPRoundingModeSetting(LangOptions::FPRM_Dynamic); + } + + if (Args.hasArg(OPT_fno_rounding_math)) { + Opts.getFPMOptions().setFPRoundingModeSetting(LangOptions::FPRM_ToNearest); + } + + if (Args.hasArg(OPT_ftrapping_math)) { + Opts.getFPMOptions().setFPExceptionBehaviorSetting(LangOptions::FPEB_Strict); + } + + if (Args.hasArg(OPT_fno_trapping_math)) { + Opts.getFPMOptions().setFPExceptionBehaviorSetting(LangOptions::FPEB_Ignore); + } + + LangOptions::FPExceptionBehaviorKind FPEB = LangOptions::FPEB_Ignore; + if (Arg *A = Args.getLastArg(OPT_ffp_exception_behavior_EQ)) { + StringRef Val = A->getValue(); + if (Val.equals("ignore")) + FPEB = LangOptions::FPEB_Ignore; + else if (Val.equals("maytrap")) + FPEB = LangOptions::FPEB_MayTrap; + else if (Val.equals("strict")) + FPEB = LangOptions::FPEB_Strict; + else + Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val; + Opts.getFPMOptions().setFPExceptionBehaviorSetting(FPEB); + } + Opts.RetainCommentsFromSystemHeaders = Args.hasArg(OPT_fretain_comments_from_system_headers); Index: clang/test/CodeGen/fpconstrained.c =================================================================== --- /dev/null +++ clang/test/CodeGen/fpconstrained.c @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -ftrapping-math -frounding-math -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck %s -check-prefix=FPMODELSTRICT +// RUN: %clang_cc1 -ffp-contract=fast -emit-llvm -o - %s | FileCheck %s -check-prefix=PRECISE +// RUN: %clang_cc1 -ffast-math -ffp-contract=fast -emit-llvm -o - %s | FileCheck %s -check-prefix=FAST +// RUN: %clang_cc1 -ffast-math -emit-llvm -o - %s | FileCheck %s -check-prefix=FAST +// RUN: %clang_cc1 -ffast-math -ffp-contract=fast -ffp-exception-behavior=ignore -emit-llvm -o - %s | FileCheck %s -check-prefix=FAST +// RUN: %clang_cc1 -ffast-math -ffp-contract=fast -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck %s -check-prefix=EXCEPT +// RUN: %clang_cc1 -ffast-math -ffp-contract=fast -ffp-exception-behavior=maytrap -emit-llvm -o - %s | FileCheck %s -check-prefix=MAYTRAP +float f0, f1, f2; + +void foo(void) { + // CHECK-LABEL: define {{.*}}void @foo() + + // MAYTRAP: llvm.experimental.constrained.fadd.f32(float %0, float %1, metadata !"round.tonearest", metadata !"fpexcept.maytrap") + // EXCEPT: llvm.experimental.constrained.fadd.f32(float %0, float %1, metadata !"round.tonearest", metadata !"fpexcept.strict") + // FPMODELSTRICT: llvm.experimental.constrained.fadd.f32(float %0, float %1, metadata !"round.dynamic", metadata !"fpexcept.strict") + // STRICTEXCEPT: llvm.experimental.constrained.fadd.f32(float %0, float %1, metadata !"round.dynamic", metadata !"fpexcept.strict") + // STRICTNOEXCEPT: llvm.experimental.constrained.fadd.f32(float %0, float %1, metadata !"round.dynamic", metadata !"fpexcept.ignore") + // PRECISE: fadd contract float %0, %1 + // FAST: fadd fast + f0 = f1 + f2; + + // CHECK: ret +} Index: clang/test/Driver/clang_f_opts.c =================================================================== --- clang/test/Driver/clang_f_opts.c +++ clang/test/Driver/clang_f_opts.c @@ -320,7 +320,6 @@ // RUN: -fprefetch-loop-arrays \ // RUN: -fprofile-correction \ // RUN: -fprofile-values \ -// RUN: -frounding-math \ // RUN: -fschedule-insns \ // RUN: -fsignaling-nans \ // RUN: -fstrength-reduce \ @@ -385,7 +384,6 @@ // CHECK-WARNING-DAG: optimization flag '-fprefetch-loop-arrays' is not supported // CHECK-WARNING-DAG: optimization flag '-fprofile-correction' is not supported // CHECK-WARNING-DAG: optimization flag '-fprofile-values' is not supported -// CHECK-WARNING-DAG: optimization flag '-frounding-math' is not supported // CHECK-WARNING-DAG: optimization flag '-fschedule-insns' is not supported // CHECK-WARNING-DAG: optimization flag '-fsignaling-nans' is not supported // CHECK-WARNING-DAG: optimization flag '-fstrength-reduce' is not supported Index: clang/test/Driver/fast-math.c =================================================================== --- clang/test/Driver/fast-math.c +++ clang/test/Driver/fast-math.c @@ -170,11 +170,11 @@ // RUN: %clang -### -fno-fast-math -ffast-math -c %s 2>&1 \ // RUN: | FileCheck --check-prefix=CHECK-FAST-MATH %s // RUN: %clang -### -funsafe-math-optimizations -ffinite-math-only \ -// RUN: -fno-math-errno -ffp-contract=fast -c %s 2>&1 \ +// RUN: -fno-math-errno -ffp-contract=fast -fno-rounding-math -c %s 2>&1 \ // RUN: | FileCheck --check-prefix=CHECK-FAST-MATH %s // RUN: %clang -### -fno-honor-infinities -fno-honor-nans -fno-math-errno \ // RUN: -fassociative-math -freciprocal-math -fno-signed-zeros \ -// RUN: -fno-trapping-math -ffp-contract=fast -c %s 2>&1 \ +// RUN: -fno-trapping-math -ffp-contract=fast -fno-rounding-math -c %s 2>&1 \ // RUN: | FileCheck --check-prefix=CHECK-FAST-MATH %s // CHECK-FAST-MATH: "-cc1" // CHECK-FAST-MATH: "-ffast-math" Index: clang/test/Driver/fp-model.c =================================================================== --- /dev/null +++ clang/test/Driver/fp-model.c @@ -0,0 +1,64 @@ +// Test that incompatible combinations of -ffp-model= options +// and other floating point options get a warning diagnostic. +// +// REQUIRES: clang-driver + +// RUN: %clang -### -ffp-model=fast -ffp-contract=off -c %s 2>&1 \ +// RUN: | FileCheck --check-prefix=WARN %s +// WARN: warning: overriding '-ffp-model=fast' option with '-ffp-contract=off' [-Woverriding-t-option] + +// RUN: %clang -### -ffp-model=fast -ffp-contract=on -c %s 2>&1 \ +// RUN: | FileCheck --check-prefix=WARN1 %s +// WARN1: warning: overriding '-ffp-model=fast' option with '-ffp-contract=on' [-Woverriding-t-option] + +// RUN: %clang -### -ffp-model=strict -fassociative-math -c %s 2>&1 \ +// RUN: | FileCheck --check-prefix=WARN2 %s +// WARN2: warning: overriding '-ffp-model=strict' option with '-fassociative-math' [-Woverriding-t-option] + +// RUN: %clang -### -ffp-model=strict -ffast-math -c %s 2>&1 \ +// RUN: | FileCheck --check-prefix=WARN3 %s +// WARN3: warning: overriding '-ffp-model=strict' option with '-ffast-math' [-Woverriding-t-option] + +// RUN: %clang -### -ffp-model=strict -ffinite-math-only -c %s 2>&1 \ +// RUN: | FileCheck --check-prefix=WARN4 %s +// WARN4: warning: overriding '-ffp-model=strict' option with '-ffinite-math-only' [-Woverriding-t-option] + +// RUN: %clang -### -ffp-model=strict -ffp-contract=fast -c %s 2>&1 \ +// RUN: | FileCheck --check-prefix=WARN5 %s +// WARN5: warning: overriding '-ffp-model=strict' option with '-ffp-contract=fast' [-Woverriding-t-option] + +// RUN: %clang -### -ffp-model=strict -ffp-contract=off -c %s 2>&1 \ +// RUN: | FileCheck --check-prefix=WARN6 %s +// WARN6: warning: overriding '-ffp-model=strict' option with '-ffp-contract=off' [-Woverriding-t-option] + +// RUN: %clang -### -ffp-model=strict -ffp-contract=on -c %s 2>&1 \ +// RUN: | FileCheck --check-prefix=WARN7 %s +// WARN7: warning: overriding '-ffp-model=strict' option with '-ffp-contract=on' [-Woverriding-t-option] + +// RUN: %clang -### -ffp-model=strict -fno-honor-infinities -c %s 2>&1 \ +// RUN: | FileCheck --check-prefix=WARN8 %s +// WARN8: warning: overriding '-ffp-model=strict' option with '-fno-honor-infinities' [-Woverriding-t-option] + +// RUN: %clang -### -ffp-model=strict -fno-honor-nans -c %s 2>&1 \ +// RUN: | FileCheck --check-prefix=WARN9 %s +// WARN9: warning: overriding '-ffp-model=strict' option with '-fno-honor-nans' [-Woverriding-t-option] + +// RUN: %clang -### -ffp-model=strict -fno-rounding-math -c %s 2>&1 \ +// RUN: | FileCheck --check-prefix=WARNa %s +// WARNa: warning: overriding '-ffp-model=strict' option with '-fno-rounding-math' [-Woverriding-t-option] + +// RUN: %clang -### -ffp-model=strict -fno-signed-zeros -c %s 2>&1 \ +// RUN: | FileCheck --check-prefix=WARNb %s +// WARNb: warning: overriding '-ffp-model=strict' option with '-fno-signed-zeros' [-Woverriding-t-option] + +// RUN: %clang -### -ffp-model=strict -fno-trapping-math -c %s 2>&1 \ +// RUN: | FileCheck --check-prefix=WARNc %s +// WARNc: warning: overriding '-ffp-model=strict' option with '-fno-trapping-math' [-Woverriding-t-option] + +// RUN: %clang -### -ffp-model=strict -freciprocal-math -c %s 2>&1 \ +// RUN: | FileCheck --check-prefix=WARNd %s +// WARNd: warning: overriding '-ffp-model=strict' option with '-freciprocal-math' [-Woverriding-t-option] + +// RUN: %clang -### -ffp-model=strict -funsafe-math-optimizations -c %s 2>&1 \ +// RUN: | FileCheck --check-prefix=WARNe %s +// WARNe: warning: overriding '-ffp-model=strict' option with '-funsafe-math-optimizations' [-Woverriding-t-option] Index: llvm/include/llvm/Target/TargetOptions.h =================================================================== --- llvm/include/llvm/Target/TargetOptions.h +++ llvm/include/llvm/Target/TargetOptions.h @@ -107,7 +107,7 @@ public: TargetOptions() : PrintMachineCode(false), UnsafeFPMath(false), NoInfsFPMath(false), - NoNaNsFPMath(false), NoTrappingFPMath(false), + NoNaNsFPMath(false), NoTrappingFPMath(true), RoundingFPMath(false), NoSignedZerosFPMath(false), HonorSignDependentRoundingFPMathOption(false), NoZerosInBSS(false), GuaranteedTailCallOpt(false), StackSymbolOrdering(true), @@ -154,6 +154,11 @@ /// specifies that there are no trap handlers to handle exceptions. unsigned NoTrappingFPMath : 1; + /// RoundingFPMath - This flag is enabled when the + /// -enable-rounding-fp-math is specified on the command line. This + /// specifies dynamic rounding mode. + unsigned RoundingFPMath : 1; + /// NoSignedZerosFPMath - This flag is enabled when the /// -enable-no-signed-zeros-fp-math is specified on the command line. This /// specifies that optimizations are allowed to treat the sign of a zero