mibintc updated this revision to Diff 215666.
mibintc marked an inline comment as not done.
mibintc edited the summary of this revision.
mibintc added a comment.

I addressed some comments from @kpn: I corrected the documentation formatting 
and added some details, and used Diag instead of llvm_unreachable.

I decided to change -fp-model=except- to -fp-model=noexcept

When the user requests -fp-model=strict I explicitly set the FMA Contraction 
mode to off.


Repository:
  rL LLVM

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D62731/new/

https://reviews.llvm.org/D62731

Files:
  clang/docs/UsersManual.rst
  clang/include/clang/Basic/LangOptions.h
  clang/include/clang/Driver/CC1Options.td
  clang/include/clang/Driver/Options.td
  clang/lib/CodeGen/CodeGenFunction.cpp
  clang/lib/CodeGen/CodeGenFunction.h
  clang/lib/Driver/ToolChains/Clang.cpp
  clang/lib/Frontend/CompilerInvocation.cpp
  clang/test/CodeGen/fpconstrained.c
  clang/test/Driver/clang_f_opts.c

Index: clang/test/Driver/clang_f_opts.c
===================================================================
--- clang/test/Driver/clang_f_opts.c
+++ clang/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        \
Index: clang/test/CodeGen/fpconstrained.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/fpconstrained.c
@@ -0,0 +1,27 @@
+// 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 -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: clang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- clang/lib/Frontend/CompilerInvocation.cpp
+++ clang/lib/Frontend/CompilerInvocation.cpp
@@ -3039,6 +3039,59 @@
       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::FPModelExceptKind FPME = LangOptions::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 = LangOptions::FPME_Except;
+      break;
+    case OPT_no_fp_model_except:
+      FPME = LangOptions::FPME_NoExcept;
+      break;
+    default:
+      llvm_unreachable("invalid -fp-model-except setting");
+    }
+  Opts.getFPMOptions().setFPModelExceptSetting(FPME);
+
+  LangOptions::FPSpeculationKind FPS = LangOptions::FPS_Off;
+  if (Arg *A = Args.getLastArg(OPT_fp_speculation_EQ)) {
+    StringRef Val = A->getValue();
+    if (Val == "fast")
+      FPS = LangOptions::FPS_Fast;
+    else if (Val == "strict")
+      FPS = LangOptions::FPS_Strict;
+    else if (Val == "safe")
+      FPS = LangOptions::FPS_Safe;
+    else
+      llvm_unreachable("invalid -fp-speculation setting");
+    Opts.getFPMOptions().setFPSpeculationSetting(FPS);
+  }
+
+  if (FPM == LangOptions::FPM_Precise)
+    // This doesn't correspond to constrained fp, equivalent to -fp-contract=on
+    Opts.setDefaultFPContractMode(LangOptions::FPC_On);
+  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);
 
@@ -3404,6 +3457,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/lib/Driver/ToolChains/Clang.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Clang.cpp
+++ clang/lib/Driver/ToolChains/Clang.cpp
@@ -2277,6 +2277,11 @@
   bool TrappingMath = true;
   StringRef DenormalFPMath = "";
   StringRef FPContract = "";
+  LangOptions::FPModelKind FPModel = LangOptions::FPM_Off;
+  LangOptions::FPModelExceptKind FPModelExcept =
+    LangOptions::FPME_Off;
+  LangOptions::FPSpeculationKind FPSpeculation =
+    LangOptions::FPS_Off;
 
   if (const Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) {
     CmdArgs.push_back("-mlimit-float-precision");
@@ -2287,6 +2292,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 = LangOptions::FPM_Precise;
+      else if (Val == "strict")
+        FPModel = LangOptions::FPM_Strict;
+      else if (Val == "except")
+        FPModelExcept = LangOptions::FPME_Except;
+      else if (Val == "except-")
+        FPModelExcept = LangOptions::FPME_NoExcept;
+      else if (Val == "fast")
+        FPModel = LangOptions::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 = LangOptions::FPS_Fast;
+      else if (Val == "strict")
+        FPSpeculation = LangOptions::FPS_Strict;
+      else if (Val == "safe")
+        FPSpeculation = LangOptions::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;
@@ -2380,6 +2418,56 @@
     A->claim();
   }
 
+  if ((FPModelExcept == LangOptions::FPME_Except) &&
+      (FPModel == LangOptions::FPM_Fast))
+    D.Diag(diag::err_drv_argument_not_allowed_with) << "fp-model=fast"
+                                                    << "fp-model=except";
+
+  switch (FPModel) {
+  case LangOptions::FPM_Precise:
+    CmdArgs.push_back("-fp-model=precise");
+    break;
+  case LangOptions::FPM_Strict:
+    CmdArgs.push_back("-fp-model=strict");
+    break;
+  case LangOptions::FPM_Fast:
+    CmdArgs.push_back("-fp-model=fast");
+    break;
+  case LangOptions::FPM_Off:
+    break;
+  default:
+    llvm_unreachable("Unrecognized FPModel");
+  }
+
+  switch (FPModelExcept) {
+  case LangOptions::FPME_Except:
+    CmdArgs.push_back("-fp-model-except");
+    break;
+  case LangOptions::FPME_NoExcept:
+    CmdArgs.push_back("-no-fpmodel-except-");
+    break;
+  case LangOptions::FPME_Off:
+    break;
+  default:
+    llvm_unreachable("Unrecognized FPModel");
+  }
+
+  switch (FPSpeculation) {
+  case LangOptions::FPS_Fast:
+    CmdArgs.push_back("-fp-speculation=fast");
+    break;
+  case LangOptions::FPS_Strict:
+    CmdArgs.push_back("-fp-speculation=strict");
+    break;
+  case LangOptions::FPS_Safe:
+    CmdArgs.push_back("-fp-speculation=safe");
+    break;
+  case LangOptions::FPS_Off:
+    break;
+  default:
+    llvm_unreachable("Unrecognized FPSpeculation");
+  }
+
   if (!HonorINFs)
     CmdArgs.push_back("-menable-no-infs");
 
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"
@@ -90,6 +91,7 @@
     FMF.setAllowReassoc();
   }
   Builder.setFastMathFlags(FMF);
+  SetFPModel();
 }
 
 CodeGenFunction::~CodeGenFunction() {
@@ -105,6 +107,82 @@
     CGM.getOpenMPRuntime().functionFinished(*this);
 }
 
+void CodeGenFunction::SetFPModel(void)
+{
+  auto fpModel = getLangOpts().getFPMOptions().getFPModelSetting();
+  auto fpModelExcept = getLangOpts().getFPMOptions().getFPModelExceptSetting();
+  auto fpSpeculation = getLangOpts().getFPMOptions().getFPSpeculationSetting();
+
+  // 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;
+
+  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 (fpModelExcept) {
+  case LangOptions::FPME_Off:
+    break;
+  case LangOptions::FPME_Except:
+    IsConstrainedExcept = true;
+    ConstrainedExceptMD = llvm::ConstrainedFPIntrinsic::ebStrict;
+    break;
+  case LangOptions::FPME_NoExcept:
+    IsConstrainedExcept = true;
+    ConstrainedExceptMD = llvm::ConstrainedFPIntrinsic::ebIgnore;
+    break;
+  default:
+    llvm_unreachable("Unsupported FP Except Model");
+  }
+
+  switch (fpSpeculation) {
+  case LangOptions::FPS_Off:
+    break;
+  case LangOptions::FPS_Fast:
+    IsConstrainedExcept = true;
+    ConstrainedExceptMD = llvm::ConstrainedFPIntrinsic::ebIgnore;
+    break;
+  case LangOptions::FPS_Strict:
+    IsConstrainedExcept = true;
+    ConstrainedExceptMD = llvm::ConstrainedFPIntrinsic::ebStrict;
+    break;
+  case LangOptions::FPS_Safe:
+    IsConstrainedExcept = true;
+    ConstrainedExceptMD = llvm::ConstrainedFPIntrinsic::ebMayTrap;
+    break;
+  default:
+    llvm_unreachable("Unsupported FP Speculation");
+  }
+
+  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/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -910,6 +910,10 @@
 def : Flag<["-"], "fno-extended-identifiers">, Group<f_Group>, Flags<[Unsupported]>;
 def fhosted : Flag<["-"], "fhosted">, Group<f_Group>;
 def fdenormal_fp_math_EQ : Joined<["-"], "fdenormal-fp-math=">, Group<f_Group>, Flags<[CC1Option]>;
+def fp_model_EQ : Joined<["-"], "fp-model=">, Group<f_Group>, Flags<[CC1Option]>,
+  HelpText<"Controls the semantics of floating-point calculations.">;
+def fp_speculation_EQ : Joined<["-"], "fp-speculation=">, Group<f_Group>, Flags<[CC1Option]>,
+  HelpText<"Specifies the mode in which to speculate on floating-point operations.">;
 def ffast_math : Flag<["-"], "ffast-math">, Group<f_Group>, Flags<[CC1Option]>,
   HelpText<"Allow aggressive, lossy floating-point optimizations">;
 def fno_fast_math : Flag<["-"], "fno-fast-math">, Group<f_Group>;
Index: clang/include/clang/Driver/CC1Options.td
===================================================================
--- clang/include/clang/Driver/CC1Options.td
+++ clang/include/clang/Driver/CC1Options.td
@@ -783,6 +783,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: clang/include/clang/Basic/LangOptions.h
===================================================================
--- clang/include/clang/Basic/LangOptions.h
+++ clang/include/clang/Basic/LangOptions.h
@@ -178,6 +178,28 @@
     FEA_On
   };
 
+  enum FPModelKind {
+    // -fp-model option is not specified
+    FPM_Off,
+    FPM_Precise,
+    FPM_Strict,
+    FPM_Fast
+  };
+
+  enum FPModelExceptKind {
+   // -fp-except option not specified
+   FPME_Off,
+   FPME_Except,
+   FPME_NoExcept
+  };
+
+  enum FPSpeculationKind {
+   // -fp-speculation option not specified
+   FPS_Off,
+   FPS_Fast,
+   FPS_Strict,
+   FPS_Safe
+  };
 
 public:
   /// Set of enabled sanitizers.
@@ -301,6 +323,43 @@
 
   /// 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),
+                       FPME(LangOptions::FPME_Off),
+                       FPS(LangOptions::FPS_Off) {}
+
+    LangOptions::FPModelKind getFPModelSetting() const {
+      return FPM;
+    }
+    void setFPModelSetting(LangOptions::FPModelKind Value) {FPM = Value;}
+
+    LangOptions::FPModelExceptKind getFPModelExceptSetting() const {
+      return FPME;
+    }
+    void setFPModelExceptSetting(LangOptions::FPModelExceptKind Value) {
+      FPME = Value;
+    }
+
+    LangOptions::FPSpeculationKind getFPSpeculationSetting() const {
+      return FPS;
+    }
+    void setFPSpeculationSetting(LangOptions::FPSpeculationKind Value) {
+      FPS = Value;
+    }
+
+  private:
+    LangOptions::FPModelKind FPM = LangOptions::FPM_Off;
+    LangOptions::FPModelExceptKind FPME = LangOptions::FPME_Off;
+    LangOptions::FPSpeculationKind FPS = LangOptions::FPS_Off;
+  };
+
+  FPModelOptions& getFPMOptions() { return fpm_options; }
+  FPModelOptions getFPMOptions() const { return fpm_options; }
+private:
+  FPModelOptions fpm_options;
 };
 
 /// Floating point control options
Index: clang/docs/UsersManual.rst
===================================================================
--- clang/docs/UsersManual.rst
+++ clang/docs/UsersManual.rst
@@ -1296,6 +1296,30 @@
    With the 'no-strict' option, Clang attempts to match the overflowing behavior
    of the target's native float-to-int conversion instructions.
 
+.. option:: -fp-model=[values]
+
+   Specify floating point behavior.
+
+   Valid values are: ``precise``, ``strict``, ``fast``, ``except``,
+   and ``noexcept``. Note that -fp-model=[no]except can be combined with the
+   other three settings for this option. Details:
+
+   * ``precise``  Disables optimizations that are not value-safe on floating-point data, although FP contraction (FMA) is enabled.
+   * ``strict``  Enables precise and except, and disables contractions (FMA).
+   * ``fast``  Equivalent to -ffast-math
+   * ``except``  Honor strict floating-point exception semantics.
+   * ``noexcept``  Ignore floating-point exceptions.
+
+.. option:: -fp-speculation=[values]
+
+   Specify the mode in which to speculate on floating-point operations.
+
+   Valid values are: ``fast``, ``strict``, and ``safe``. Details:
+
+   * ``fast`` Enables speculation on floating-point operations.
+   * ``strict`` Disables speculation on floating-point operations.
+   * ``safe`` Disables speculation if there is a possibility that speculation may cause a floating-point exception.
+
 .. option:: -fwhole-program-vtables
 
    Enable whole-program vtable optimizations, such as single-implementation
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to