Index: clang/docs/UsersManual.rst =================================================================== --- clang/docs/UsersManual.rst +++ clang/docs/UsersManual.rst @@ -1296,6 +1296,72 @@ With the 'no-strict' option, Clang attempts to match the overflowing behavior of the target's native float-to-int conversion instructions. +.. option:: -f[no-]rounding-math + + LLVM constrained floating point supports five rounding modes: ``tonearest``, + ``downward``, ``upward``, ``towardzero`` and ``dynamic``. The first four + values represent corresponding IEEE rounding rules, + The option ``-fno-rounding-math``, which is the default, + specifies the ``tonearest`` rounding mode. + The rounding mode ``dynamic`` informs the + compiler that it must not assume any particular rounding mode + this is the setting implemented by the switch ``-frounding-math``. + ``-ffrounding-math`` has the same meaning as ``-ffp-model=strict``. + Consequently, this option sets exception behavior to strict and + it conflicts with ``-ffast-math`` etc. + FIXME: Not certain if ``-frounding-math`` should have identical semantics to + ``-ffp-model=strict``, or merely establish the rounding mode setting + parameter to the llvm floating point constrained intrinsics. + +.. option:: -ffp-model= + + Specify floating point behavior. ``-ffp-model`` is an umbrella + option that encompasses functionality provided by lower level, single + purpose, clang fp options. Conflicts can exist between pairs of options + on the command line. If the ``-ffp-model`` or ``-ffp-exception-behavior`` + conflict with other fp options on the command line, then some or all of + the earlier fp options will be disabled. ``-ffast-math`` and any of its + lower-level floating point enablements conflict with ``-ffp-model=strict``, + and the same is true for ``-funsafe-math-optimizations`` and + ``-ffinite-math``. If ``-ffp-model-strict`` appears on the command line, + then it behaves as though both ``-ffp-model-strict`` and ``-fno-fast-math`` + appeared on the command line. Since ``-ffp-model=strict`` implies + ``-ffp-exception-behavior=strict``, ``-ffp-model=strict`` also conflicts + with ``-ffp-exception-behavior=ignore`` and + ``-ffp-exception-behavior=maytrap``. When ``-ffp-model`` appears on the + command line, it overrides any previous setting of ``-ffp-model``. + ``-ffp-model=fast`` is very similar to ``-ffast-math``: it also sets + the __FAST_MATH__ macro setting. In addition to the FMF flags, this option + enables ``-fp-contract=fast``, and conflicts with: ``-fp-contract=on``, + ``-fp-contract=off``. + + Valid values are: ``precise``, ``strict``, ``fast``. + Details: + + * ``precise`` Disables optimizations that are not value-safe on floating-point data, although FP contraction (FMA) is enabled (``fp-contract=fast``). + * ``strict`` Enables precise and except, and disables contractions (FMA). + * ``fast`` Equivalent to -ffast-math + +.. 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. + + + .. option:: -fwhole-program-vtables Enable whole-program vtable optimizations, such as single-implementation Index: clang/include/clang/Basic/LangOptions.h =================================================================== --- clang/include/clang/Basic/LangOptions.h +++ clang/include/clang/Basic/LangOptions.h @@ -184,6 +184,21 @@ FEA_On }; + enum FPModelKind { + // -fp-model option is not specified + FPM_Off, + FPM_Precise, + FPM_Strict, + FPM_Fast + }; + + enum FPExceptionBehaviorKind { + // -fp-exception-behavior option not specified + FPE_Off, + FPE_Ignore, + FPE_MayTrap, + FPE_Strict + }; public: /// Set of enabled sanitizers. @@ -307,6 +322,36 @@ /// Return the OpenCL C or C++ version as a VersionTuple. VersionTuple getOpenCLVersionTuple() const; + + /// Floating point model options + class FPModelOptions { + public: + FPModelOptions() : FPM(LangOptions::FPM_Off), + FPE(LangOptions::FPE_Off) {} + + LangOptions::FPModelKind getFPModelSetting() const { + return FPM; + } + void setFPModelSetting(LangOptions::FPModelKind Value) {FPM = Value;} + + LangOptions::FPExceptionBehaviorKind getFPExceptionBehaviorSetting() const + { + return FPE; + } + void setFPExceptionBehaviorSetting( + LangOptions::FPExceptionBehaviorKind Value) { + FPE = Value; + } + + private: + LangOptions::FPModelKind FPM = LangOptions::FPM_Off; + LangOptions::FPExceptionBehaviorKind FPE = LangOptions::FPE_Off; + }; + + 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 @@ -915,6 +915,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 fp_model_EQ : Joined<["-"], "ffp-model=">, Group, Flags<[CC1Option]>, + HelpText<"Controls the semantics of floating-point calculations.">; +def fp_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; @@ -1131,7 +1135,9 @@ // This option was originally misspelt "infinites" [sic]. def : Flag<["-"], "fhonor-infinites">, Alias; def : Flag<["-"], "fno-honor-infinites">, Alias; -def ftrapping_math : Flag<["-"], "ftrapping-math">, Group, Flags<[CC1Option]>; +def frounding_math : Flag<["-"], "frounding-math">, Group, Flags<[CC1Option]>; +def fno_rounding_math : Flag<["-"], "fno-rounding-math">, Group, Flags<[CC1Option]>; +def frounding_math : Flag<["-"], "frounding-math">, Group, Flags<[CC1Option]>; def fno_trapping_math : Flag<["-"], "fno-trapping-math">, Group, Flags<[CC1Option]>; def ffp_contract : Joined<["-"], "ffp-contract=">, Group, Flags<[CC1Option]>, HelpText<"Form fused FP ops (e.g. FMAs): fast (everywhere)" 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,68 @@ CGM.getOpenMPRuntime().functionFinished(*this); } +void CodeGenFunction::SetFPModel(void) +{ + auto fpModel = getLangOpts().getFPMOptions().getFPModelSetting(); + auto fpExceptionBehavior = + getLangOpts().getFPMOptions().getFPExceptionBehaviorSetting(); + + // Translate the compiler options into + // the 3 settings that are transmitted to the IR Builder + bool IsConstrainedRounding = false; + bool IsConstrainedExcept = false; + llvm::ConstrainedFPIntrinsic::RoundingMode ConstrainedRoundingMD; + llvm::ConstrainedFPIntrinsic::ExceptionBehavior ConstrainedExceptMD = + llvm::ConstrainedFPIntrinsic::ebIgnore; + + switch (fpModel) { + case LangOptions::FPM_Off: + case LangOptions::FPM_Precise: + case LangOptions::FPM_Fast: + break; + case LangOptions::FPM_Strict: + IsConstrainedRounding = true; + ConstrainedRoundingMD = llvm::ConstrainedFPIntrinsic::rmDynamic; + IsConstrainedExcept = true; + ConstrainedExceptMD = llvm::ConstrainedFPIntrinsic::ebStrict; + break; + default: + llvm_unreachable("Unsupported FP Model"); + } + + switch (fpExceptionBehavior) { + case LangOptions::FPE_Off: + break; + case LangOptions::FPE_Ignore: + IsConstrainedExcept = true; + ConstrainedExceptMD = llvm::ConstrainedFPIntrinsic::ebIgnore; + break; + case LangOptions::FPE_MayTrap: + IsConstrainedExcept = true; + ConstrainedExceptMD = llvm::ConstrainedFPIntrinsic::ebMayTrap; + break; + case LangOptions::FPE_Strict: + IsConstrainedExcept = true; + ConstrainedExceptMD = llvm::ConstrainedFPIntrinsic::ebStrict; + break; + default: + llvm_unreachable("Unsupported FP Exception Behavior"); + } + + if (IsConstrainedExcept && !IsConstrainedRounding) { + // If the rounding mode isn't set explicitly above, then use ebToNearest + // as the value when the constrained intrinsic is created + IsConstrainedRounding = true; + ConstrainedRoundingMD = llvm::ConstrainedFPIntrinsic::rmToNearest; + } + + if (IsConstrainedExcept || IsConstrainedRounding) { + 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 @@ -2299,6 +2299,158 @@ if (C.getDriver().embedBitcodeEnabled() || C.getDriver().embedBitcodeMarkerOnly()) Args.AddLastArg(CmdArgs, options::OPT_fembed_bitcode_EQ); +}; + +// This is just a capture of all the floating point options that +// need to be treated specially in RenderFloatingPointOptions, as well +// as simplifying the parameterized options (e.g. fp-model=precise) into +// simple enumeration values. +enum floatOpt { + fp_Ofast, + fp_ffast_math, + fp_fno_fast_math, + fp_flimited_precision_EQ, + fp_model_strict, + fp_model_fast, + fp_model_precise, + fp_fno_rounding_math, + fp_frounding_math, + fp_exception_behavior_ignore, + fp_exception_behavior_maytrap, + fp_exception_behavior_strict, + fp_fhonor_infinities, + fp_fno_honor_infinities, + fp_fhonor_nans, + fp_fno_honor_nans, + fp_fmath_errno, + fp_fno_math_errno, + fp_fassociative_math, + fp_fno_associative_math, + fp_freciprocal_math, + fp_fno_reciprocal_math, + fp_fsigned_zeros, + fp_fno_signed_zeros, + fp_ftrapping_math, + fp_fno_trapping_math, + fp_fdenormal_fp_math_EQ, + fp_ffp_contract_on, + fp_ffp_contract_off, + fp_ffp_contract_fast, + fp_ffinite_math_only, + fp_fno_finite_math_only, + fp_funsafe_math_optimizations, + fp_fno_unsafe_math_optimizations, + fp_fno_strict_float_cast_overflow, + fp_fstrict_float_cast_overflow, + fp_Count}; + +// Show which floating point options conflict with each other +// FIXME, not all conflicts are present e.g. +// the conflict array should show that ffast-math conflicts with +// fno-fast math etc. +// FIXME, this won't compile on gcc5, will need to use a different +// representation +constexpr bool fpConflict[fp_Count][fp_Count] = { + /* fp_Ofast */ + { [fp_model_strict]=true }, + /* fp_ffast_math */ + { [fp_model_strict]=true }, + /* fp_fno_fast_math */ + { false }, + /* fp_flimited_precision_EQ */ + { false }, + /* fp_model_strict */ + {[fp_Ofast]=true, [fp_ffast_math]=true, + [fp_model_precise] = true, + [fp_model_fast] = true, + [fp_exception_behavior_ignore] = true, + [fp_exception_behavior_maytrap] = true, + [fp_fno_honor_infinities] = true, + [fp_fno_honor_nans] = true, + [fp_fassociative_math] = true, + [fp_freciprocal_math] = true, + [fp_fno_signed_zeros] = true, + [fp_fno_trapping_math] = true, + [fp_ffp_contract_on] = true, + [fp_ffp_contract_fast] = true, + [fp_ffinite_math_only] = true, + [fp_funsafe_math_optimizations] = true}, + + /* fp_model_fast */ + { [fp_model_strict]=true, [fp_model_precise]=true }, + /* fp_model_precise */ + { [fp_model_strict]=true, [fp_model_fast]=true}, + /* fp_fno_rounding_math */ + { false }, + /* fp_frounding_math */ + { [fp_model_fast]=true, [fp_model_precise]=true }, + /* fp_exception_behavior_ignore */ + { [fp_model_strict]=true }, + /* fp_exception_behavior_maytrap */ + { [fp_model_strict]=true }, + /* fp_exception_behavior_strict */ + { [fp_exception_behavior_ignore]=true, + [fp_exception_behavior_maytrap]=true }, + /* fp_fhonor_infinities */ + { false }, + /* fp_fno_honor_infinities */ + { [fp_model_strict]=true }, + /* fp_fhonor_nans */ + { false }, + /* fp_fno_honor_nans */ + { [fp_model_strict]=true }, + /* fp_fmath_errno */ + { false }, + /* fp_fno_math_errno */ + { false }, + /* fp_fassociative_math */ + { [fp_model_strict]=true }, + /* fp_fno_associative_math */ + { false }, + /* fp_freciprocal_math */ + { [fp_model_strict]=true }, + /* fp_fno_reciprocal_math */ + { false }, + /* fp_fsigned_zeros */ + { false }, + /* fp_fno_signed_zeros */ + { [fp_model_strict]=true }, + /* fp_ftrapping_math */ + { false }, + /* fp_fno_trapping_math */ + { [fp_model_strict]=true }, + /* fp_fdenormal_fp_math_EQ */ + + /* fp_ffp_contract_on */ + { [fp_model_strict]=true, [fp_model_fast]=true }, + /* fp_ffp_contract_off */ + { [fp_model_precise]=true, [fp_model_fast]=true }, + /* fp_ffp_contract_fast */ + { [fp_model_strict]=true, [fp_model_precise]=true }, + /* fp_ffinite_math_only */ + { [fp_model_strict]=true }, + /* fp_fno_finite_math_only */ + { false }, + /* fp_funsafe_math_optimizations */ + { [fp_model_strict]=true }, + /* fp_fno_unsafe_math_optimizations */ + { false }, + /* fp_fno_strict_float_cast_overflow */ + { false }, + /* fp_fstrict_float_cast_overflow */ + { false }}; + +// Convert Arg to floatOpt if possible +// Return invalid value 'fp_Count' if A is not a valid fp argument +// Issue error or warning diagnostics for malformed options. +static floatOpt option_to_floatOpt(const Arg *A, const Driver &d, + bool OFastEnabled) +{ + // The simple options such as trapping-math are simply converted into + // the corresponding enumeration value + // and in the case of options that have arguments e.g. + // fp-model=strict or fp-contract=on, flatten them into a + // simple enumeration value. } static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, @@ -2309,16 +2461,8 @@ // "umbrella" flags, so we do this by stepping through the flags incrementally // adjusting what we think is enabled/disabled, then at the end setting the // LLVM flags based on the final state. - bool HonorINFs = true; - bool HonorNaNs = true; - // -fmath-errno is the default on some platforms, e.g. BSD-derived OSes. - bool MathErrno = TC.IsMathErrnoDefault(); - bool AssociativeMath = false; - bool ReciprocalMath = false; - bool SignedZeros = true; - bool TrappingMath = true; - StringRef DenormalFPMath = ""; - StringRef FPContract = ""; + + bool fpEnabled[fp_Count] = {false}; if (const Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) { CmdArgs.push_back("-mlimit-float-precision"); @@ -2326,133 +2470,34 @@ } for (const Arg *A : Args) { - switch (A->getOption().getID()) { - // If this isn't an FP option skip the claim below - default: continue; - - // Options controlling individual features - case options::OPT_fhonor_infinities: HonorINFs = true; break; - case options::OPT_fno_honor_infinities: HonorINFs = false; break; - case options::OPT_fhonor_nans: HonorNaNs = true; break; - case options::OPT_fno_honor_nans: HonorNaNs = false; break; - case options::OPT_fmath_errno: MathErrno = true; break; - case options::OPT_fno_math_errno: MathErrno = false; break; - case options::OPT_fassociative_math: AssociativeMath = true; break; - case options::OPT_fno_associative_math: AssociativeMath = false; break; - case options::OPT_freciprocal_math: ReciprocalMath = true; break; - 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_fno_trapping_math: TrappingMath = false; break; - - case options::OPT_fdenormal_fp_math_EQ: - DenormalFPMath = A->getValue(); - break; - - // Validate and pass through -fp-contract option. - case options::OPT_ffp_contract: { - StringRef Val = A->getValue(); - if (Val == "fast" || Val == "on" || Val == "off") - FPContract = Val; - else - D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Val; - break; - } - - case options::OPT_ffinite_math_only: - HonorINFs = false; - HonorNaNs = false; - break; - case options::OPT_fno_finite_math_only: - HonorINFs = true; - HonorNaNs = true; - break; - - case options::OPT_funsafe_math_optimizations: - AssociativeMath = true; - ReciprocalMath = true; - SignedZeros = false; - TrappingMath = false; - break; - case options::OPT_fno_unsafe_math_optimizations: - AssociativeMath = false; - ReciprocalMath = false; - SignedZeros = true; - TrappingMath = true; - // -fno_unsafe_math_optimizations restores default denormal handling - DenormalFPMath = ""; - break; - - case options::OPT_Ofast: - // If -Ofast is the optimization level, then -ffast-math should be enabled - if (!OFastEnabled) - continue; - LLVM_FALLTHROUGH; - case options::OPT_ffast_math: - HonorINFs = false; - HonorNaNs = false; - MathErrno = false; - AssociativeMath = true; - ReciprocalMath = true; - SignedZeros = false; - TrappingMath = false; - // If fast-math is set then set the fp-contract mode to fast. - FPContract = "fast"; - break; - case options::OPT_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; - // -fno_fast_math restores default denormal and fpcontract handling - DenormalFPMath = ""; - FPContract = ""; - break; + auto thisOption = option_to_floatOpt(A, OFastEnabled); + if (thisOption == fp_Count) + // Arg wasn't a legal fp option, skip. + continue; + if (fpConflict[thisOpt] & fpEnabled) { + // This option conflicts with floating point options + // previously listed on the command line, this option will + // override the preivously listed enablements. + // FIXME: Issue warning diagnostic when fp-model or fp-exception-behavior + // options override or are overridden. + // FIXME: will need to use a different representation for conflict + // array which allow vector boolean operations + // FIXME may need to create a separate enablement vector which is + // different from the conflict vector. + fpEnabled &= !fpConflict[thisOpt]; } + fpEnabled[thisOption] = true; // If we handled this option claim it A->claim(); } - if (!HonorINFs) - CmdArgs.push_back("-menable-no-infs"); - - if (!HonorNaNs) - CmdArgs.push_back("-menable-no-nans"); - - if (MathErrno) - CmdArgs.push_back("-fmath-errno"); - - if (!MathErrno && AssociativeMath && ReciprocalMath && !SignedZeros && - !TrappingMath) - CmdArgs.push_back("-menable-unsafe-fp-math"); - - if (!SignedZeros) - CmdArgs.push_back("-fno-signed-zeros"); - - if (AssociativeMath && !SignedZeros && !TrappingMath) - CmdArgs.push_back("-mreassociate"); - - if (ReciprocalMath) - CmdArgs.push_back("-freciprocal-math"); - - if (!TrappingMath) - CmdArgs.push_back("-fno-trapping-math"); - - if (!DenormalFPMath.empty()) - CmdArgs.push_back( - Args.MakeArgString("-fdenormal-fp-math=" + DenormalFPMath)); - - if (!FPContract.empty()) - CmdArgs.push_back(Args.MakeArgString("-ffp-contract=" + FPContract)); + // Iterate through fpEnabled and print out the + // fp options that have been enabled + for (const auto O : floatOpt) { + if (thisOption == fp_Count) continue; + // FIXME dump this option setting via CmdArgs.push_back + } ParseMRecip(D, Args, CmdArgs); Index: clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- clang/lib/Frontend/CompilerInvocation.cpp +++ clang/lib/Frontend/CompilerInvocation.cpp @@ -3074,6 +3074,45 @@ Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val; } + LangOptions::FPModelKind FPM = LangOptions::FPM_Off; + if (Arg *A = Args.getLastArg(OPT_fp_model_EQ)) { + StringRef Val = A->getValue(); + if (Val == "precise") + FPM = LangOptions::FPM_Precise; + else if (Val == "strict") + FPM = LangOptions::FPM_Strict; + else if (Val == "fast") + FPM = LangOptions::FPM_Fast; + else + llvm_unreachable("invalid -fp-model setting"); + } + Opts.getFPMOptions().setFPModelSetting(FPM); + + LangOptions::FPExceptionBehaviorKind FPE = LangOptions::FPE_Off; + if (Arg *A = Args.getLastArg(OPT_fp_exception_behavior_EQ)) { + StringRef Val = A->getValue(); + if (Val == "ignore") + FPE = LangOptions::FPE_Ignore; + else if (Val == "maytrap") + FPE = LangOptions::FPE_MayTrap; + else if (Val == "strict") + FPE = LangOptions::FPE_Strict; + else + llvm_unreachable("invalid -fp-exception-behavior setting"); + Opts.getFPMOptions().setFPExceptionBehaviorSetting(FPE); + } + + if (FPM == LangOptions::FPM_Precise) + // This doesn't correspond to constrained fp, + // equivalent to -fp-contract=fast + Opts.setDefaultFPContractMode(LangOptions::FPC_Fast); + else if (FPM == LangOptions::FPM_Fast) { + // This doesn't correspond to constrained fp, equivalent to -ffast-math + Opts.FastMath = true; + Opts.FiniteMathOnly = true; + Opts.setDefaultFPContractMode(LangOptions::FPC_Fast); + } + Opts.RetainCommentsFromSystemHeaders = Args.hasArg(OPT_fretain_comments_from_system_headers); @@ -3443,6 +3482,15 @@ // FIXME: Should we really be calling this for an Language::Asm input? ParseLangArgs(LangOpts, Args, DashX, Res.getTargetOpts(), Res.getPreprocessorOpts(), Diags); + auto fpm = LangOpts.getFPMOptions().getFPModelSetting(); + if (fpm == LangOptions::FPM_Fast) { + auto CGOpts = Res.getCodeGenOpts(); + CGOpts.NoInfsFPMath = true; + CGOpts.UnsafeFPMath = true; + CGOpts.ReciprocalMath = true; + CGOpts.NoTrappingMath = true; + CGOpts.NoSignedZeros = true; + } if (Res.getFrontendOpts().ProgramAction == frontend::RewriteObjC) LangOpts.ObjCExceptions = 1; if (T.isOSDarwin() && DashX.isPreprocessed()) { Index: clang/test/CodeGen/fpconstrained.c =================================================================== --- /dev/null +++ clang/test/CodeGen/fpconstrained.c @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -fp-model=strict -emit-llvm -o - %s | FileCheck %s -check-prefix=STRICT +// RUN: %clang_cc1 -fp-model=precise -emit-llvm -o - %s | FileCheck %s -check-prefix=PRECISE +// RUN: %clang_cc1 -fp-model=fast -emit-llvm -o - %s | FileCheck %s -check-prefix=FAST +// RUN: %clang_cc1 -fp-model=fast -fp-exception-behavior=ignore -emit-llvm -o - %s | FileCheck %s -check-prefix=NOEXCEPT +// RUN: %clang_cc1 -fp-model=fast -fp-exception-behavior=strict -emit-llvm -o - %s | FileCheck %s -check-prefix=EXCEPT +// RUN: %clang_cc1 -fp-model=fast -fp-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") + // NOEXCEPT: llvm.experimental.constrained.fadd.f32(float %0, float %1, metadata !"round.tonearest", metadata !"fpexcept.ignore") + // STRICT: 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 float + // FAST: fadd fast + f0 = f1 + f2; + + // CHECK: ret +}