Index: include/clang/Basic/LangOptions.h =================================================================== --- include/clang/Basic/LangOptions.h +++ include/clang/Basic/LangOptions.h @@ -21,6 +21,7 @@ #include "clang/Basic/Visibility.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" +#include "llvm/IR/FPState.h" #include #include @@ -178,6 +179,29 @@ FEA_On }; + llvm::FPState::FPModelKind DefaultFPModel = llvm::FPState::FPM_Off; + llvm::FPState::FPModelKind getDefaultFPModel() const { + return DefaultFPModel; + } + void setDefaultFPModel(llvm::FPState::FPModelKind Value) { + DefaultFPModel = Value; + } + llvm::FPState::FPModelExceptKind DefaultFPModelExcept = + llvm::FPState::FPME_Off; + llvm::FPState::FPModelExceptKind getDefaultFPModelExcept() const { + return DefaultFPModelExcept; + } + void setDefaultFPModelExcept(llvm::FPState::FPModelExceptKind Value) { + DefaultFPModelExcept = Value; + } + llvm::FPState::FPSpeculationKind DefaultFPSpeculation = + llvm::FPState::FPS_Off; + llvm::FPState::FPSpeculationKind getDefaultFPSpeculation() const { + return DefaultFPSpeculation; + } + void setDefaultFPSpeculation(llvm::FPState::FPSpeculationKind Value) { + DefaultFPSpeculation = Value; + } public: /// Set of enabled sanitizers. Index: include/clang/Driver/CC1Options.td =================================================================== --- include/clang/Driver/CC1Options.td +++ include/clang/Driver/CC1Options.td @@ -775,6 +775,10 @@ HelpText<"Use the native __fp16 type for arguments and returns (and skip ABI-specific lowering)">; def fallow_half_arguments_and_returns : Flag<["-"], "fallow-half-arguments-and-returns">, HelpText<"Allow function arguments and returns of type half">; +def fp_model_except : Flag<["-"], "fp-model-except">, + HelpText<"Controls the constrained exception setting of floating-point calculations.">; +def no_fp_model_except : Flag<["-"], "no-fp-model-except">, + HelpText<"Exceptions in floating-point calculations are ignored.">; def fdefault_calling_conv_EQ : Joined<["-"], "fdefault-calling-conv=">, HelpText<"Set default calling convention">, Values<"cdecl,fastcall,stdcall,vectorcall,regcall">; def finclude_default_header : Flag<["-"], "finclude-default-header">, Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -904,6 +904,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<["-"], "fp-model=">, Group, Flags<[CC1Option]>, + HelpText<"Controls the semantics of floating-point calculations.">; +def fp_speculation_EQ : Joined<["-"], "fp-speculation=">, Group, Flags<[CC1Option]>, + HelpText<"Specifies the mode in which to speculate on 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; Index: lib/CodeGen/CodeGenFunction.cpp =================================================================== --- lib/CodeGen/CodeGenFunction.cpp +++ lib/CodeGen/CodeGenFunction.cpp @@ -90,6 +90,11 @@ FMF.setAllowReassoc(); } Builder.setFastMathFlags(FMF); + llvm::FPState fpState(Builder); + auto fpModel = getLangOpts().getDefaultFPModel(); + auto fpModelExcept = getLangOpts().getDefaultFPModelExcept(); + auto fpSpeculation = getLangOpts().getDefaultFPSpeculation(); + fpState.updateBuilder(fpModel, fpModelExcept, fpSpeculation); } CodeGenFunction::~CodeGenFunction() { Index: lib/Driver/ToolChains/Clang.cpp =================================================================== --- lib/Driver/ToolChains/Clang.cpp +++ lib/Driver/ToolChains/Clang.cpp @@ -32,6 +32,7 @@ #include "clang/Driver/XRayArgs.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Config/llvm-config.h" +#include "llvm/IR/FPState.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/Compression.h" @@ -2268,6 +2269,9 @@ bool TrappingMath = true; StringRef DenormalFPMath = ""; StringRef FPContract = ""; + llvm::FPState::FPModelKind FPModel = llvm::FPState::FPM_Off; + llvm::FPState::FPModelExceptKind FPModelExcept = llvm::FPState::FPME_Off; + llvm::FPState::FPSpeculationKind FPSpeculation = llvm::FPState::FPS_Off; if (const Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) { CmdArgs.push_back("-mlimit-float-precision"); @@ -2278,6 +2282,39 @@ switch (A->getOption().getID()) { // If this isn't an FP option skip the claim below default: continue; + // Options controlling floating point model and speculation + case options::OPT_fp_model_EQ: { + StringRef Val = A->getValue(); + if (Val == "precise") + FPModel = llvm::FPState::FPM_Precise; + else if (Val == "strict") + FPModel = llvm::FPState::FPM_Strict; + else if (Val == "except") + FPModelExcept = llvm::FPState::FPME_Except; + else if (Val == "except-") + FPModelExcept= llvm::FPState::FPME_NoExcept; + else if (Val == "fast") + FPModel = llvm::FPState::FPM_Fast; + else { + D.Diag(diag::err_drv_invalid_value) << "-fp-model" << Val; + continue; + } + break; + } + case options::OPT_fp_speculation_EQ: { + StringRef Val = A->getValue(); + if (Val == "fast") + FPSpeculation = llvm::FPState::FPS_Fast; + else if (Val == "strict") + FPSpeculation = llvm::FPState::FPS_Strict; + else if (Val == "safe") + FPSpeculation = llvm::FPState::FPS_Safe; + else { + D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << Val; + continue; + } + break; + } // Options controlling individual features case options::OPT_fhonor_infinities: HonorINFs = true; break; @@ -2371,6 +2408,42 @@ A->claim(); } + if ((FPModelExcept == llvm::FPState::FPME_Except) && + (FPModel == llvm::FPState::FPM_Fast)) + D.Diag(diag::err_drv_argument_not_allowed_with) + << "fp-model=fast" << "fp-model=except"; + + switch (FPModel) { + case llvm::FPState::FPM_Precise: + CmdArgs.push_back("-fp-model=precise"); break; + case llvm::FPState::FPM_Strict: + CmdArgs.push_back("-fp-model=strict"); break; + case llvm::FPState::FPM_Fast: + CmdArgs.push_back("-fp-model=fast"); break; + case llvm::FPState::FPM_Off: break; + default: llvm_unreachable("Unrecognized FPModel"); + } + + switch (FPModelExcept) { + case llvm::FPState::FPME_Except: + CmdArgs.push_back("-fp-model-except"); break; + case llvm::FPState::FPME_NoExcept: + CmdArgs.push_back("-no-fpmodel-except-"); break; + case llvm::FPState::FPME_Off: break; + default: llvm_unreachable("Unrecognized FPModel"); + } + + switch (FPSpeculation) { + case llvm::FPState::FPS_Fast: + CmdArgs.push_back("-fp-speculation=fast"); break; + case llvm::FPState::FPS_Strict: + CmdArgs.push_back("-fp-speculation=strict"); break; + case llvm::FPState::FPS_Safe: + CmdArgs.push_back("-fp-speculation=safe"); break; + case llvm::FPState::FPS_Off: break; + default: llvm_unreachable("Unrecognized FPSpeculation"); + } + if (!HonorINFs) CmdArgs.push_back("-menable-no-infs"); Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -2978,6 +2978,58 @@ Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val; } + llvm::FPState::FPModelKind FPM = llvm::FPState::FPM_Off; + if (Arg *A = Args.getLastArg(OPT_fp_model_EQ)) { + StringRef Val = A->getValue(); + if (Val == "precise") + FPM = llvm::FPState::FPM_Precise; + else if (Val == "strict") + FPM = llvm::FPState::FPM_Strict; + else if (Val == "fast") + FPM = llvm::FPState::FPM_Fast; + else + llvm_unreachable("invalid -fp-model setting"); + } + Opts.setDefaultFPModel(FPM); + + llvm::FPState::FPModelExceptKind FPME = llvm::FPState::FPME_Off; + if (const Arg *A = + Args.getLastArg(OPT_fp_model_except, OPT_no_fp_model_except)) + switch (A->getOption().getID()) { + case OPT_fp_model_except: + FPME = llvm::FPState::FPME_Except; + break; + case OPT_no_fp_model_except: + FPME = llvm::FPState::FPME_NoExcept; + break; + default : llvm_unreachable("invalid -fp-model-except setting"); + } + Opts.setDefaultFPModelExcept(FPME); + + llvm::FPState::FPSpeculationKind FPS = llvm::FPState::FPS_Off; + if (Arg *A = Args.getLastArg(OPT_fp_speculation_EQ)) { + StringRef Val = A->getValue(); + if (Val == "fast") + FPS = llvm::FPState::FPS_Fast; + else if (Val == "strict") + FPS = llvm::FPState::FPS_Strict; + else if (Val == "safe") + FPS = llvm::FPState::FPS_Safe; + else + llvm_unreachable("invalid -fp-speculation setting"); + Opts.setDefaultFPSpeculation(FPS); + } + + if (FPM == llvm::FPState::FPM_Precise) + // This doesn't correspond to constrained fp, equivalent to -fp-contract=on + Opts.setDefaultFPContractMode(LangOptions::FPC_On); + else if (FPM == llvm::FPState::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); @@ -3340,6 +3392,15 @@ // FIXME: Should we really be calling this for an InputKind::Asm input? ParseLangArgs(LangOpts, Args, DashX, Res.getTargetOpts(), Res.getPreprocessorOpts(), Diags); + auto fpm = LangOpts.getDefaultFPModel(); + if (fpm == llvm::FPState::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: test/CodeGen/fpconstrained.c =================================================================== --- /dev/null +++ test/CodeGen/fpconstrained.c @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -fp-model=strict -emit-llvm -o - %s | FileCheck %s -check-prefix=STRICT +// RUN: %clang_cc1 -fp-model=strict -fp-model-except -emit-llvm -o - %s | FileCheck %s -check-prefix=STRICTEXCEPT +// RUN: %clang_cc1 -fp-model=strict -no-fp-model-except -emit-llvm -o - %s | FileCheck %s -check-prefix=STRICTNOEXCEPT +// RUN: %clang_cc1 -fp-model-except -emit-llvm -o - %s | FileCheck %s -check-prefix=EXCEPT +// RUN: %clang_cc1 -no-fp-model-except -emit-llvm -o - %s | FileCheck %s -check-prefix=NOEXCEPT +// 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 -emit-llvm -o - %s | FileCheck %s -check-prefix=FAST +// RUN: %clang_cc1 -fp-model=fast -fp-speculation=fast -emit-llvm -o - %s | FileCheck %s -check-prefix=NOEXCEPT +// RUN: %clang_cc1 -fp-model=fast -fp-speculation=strict -emit-llvm -o - %s | FileCheck %s -check-prefix=EXCEPT +// RUN: %clang_cc1 -fp-model=fast -fp-speculation=safe -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 +} Index: test/Driver/clang_f_opts.c =================================================================== --- test/Driver/clang_f_opts.c +++ test/Driver/clang_f_opts.c @@ -217,6 +217,11 @@ // RUN: %clang -### -S -fexec-charset=iso-8859-1 -o /dev/null %s 2>&1 | FileCheck -check-prefix=CHECK-INVALID-INPUT-CHARSET %s // CHECK-INVALID-INPUT-CHARSET: error: invalid value 'iso-8859-1' in '-fexec-charset=iso-8859-1' +// RUN: %clang -### -S -fp-model=fast -fp-model=except -o /dev/null %s 2>&1 | FileCheck -check-prefix=CHECK-INVALID-FAST-EXCEPT %s +// RUN: %clang -### -S -fp-model=fast -fp-model=except -o /dev/null %s 2>&1 | FileCheck -check-prefix=CHECK-INVALID-FAST-EXCEPT %s +// CHECK-INVALID-FAST-EXCEPT: error: invalid argument 'fp-model=fast' not allowed with 'fp-model=except' +// + // Test that we don't error on these. // RUN: %clang -### -S -Werror \ // RUN: -falign-functions -falign-functions=2 -fno-align-functions \