mibintc created this revision.
mibintc added reviewers: kpn, sepavloff, andrew.w.kaylor, rjmccall.
Herald added subscribers: dexonsmith, dang.
mibintc requested review of this revision.
Herald added a project: clang.

The Intel compiler supports the option -fp-model={source|double|extended} which 
causes the compiler to use a wider type for intermediate floating point 
calculations.  Also supported is a way to embed this effect in the source 
program with #pragma float_control(source|double|extended).  This patch 
proposes to extend pragma float_control syntax, and also to support a new 
floating point option via -ffp-eval-method={source|double|extended}

Note that the C floating point working group has proposed nearly identical 
pragma semantics in http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1974.pdf 
like this
#pragma STDC FENV_FLT_EVAL_METHOD width
I would like to add support for this also, but it's not in this patch.

I'm going to add an inline question about how to redefine __FLT_EVAL_METHOD__ 
macro

The ICL option with description of semantics is at this url, 
https://software.intel.com/content/www/us/en/develop/documentation/cpp-compiler-developer-guide-and-reference/top/compiler-reference/compiler-options/compiler-option-details/floating-point-options/fp-model-fp.html


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D93769

Files:
  clang/docs/LanguageExtensions.rst
  clang/docs/UsersManual.rst
  clang/include/clang/Basic/FPOptions.def
  clang/include/clang/Basic/LangOptions.def
  clang/include/clang/Basic/LangOptions.h
  clang/include/clang/Basic/PragmaKinds.h
  clang/include/clang/Driver/Options.td
  clang/lib/Driver/ToolChains/Clang.cpp
  clang/lib/Frontend/CompilerInvocation.cpp
  clang/lib/Parse/ParsePragma.cpp
  clang/lib/Sema/SemaAttr.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/test/CodeGen/fp-floatcontrol-pragma.cpp

Index: clang/test/CodeGen/fp-floatcontrol-pragma.cpp
===================================================================
--- clang/test/CodeGen/fp-floatcontrol-pragma.cpp
+++ clang/test/CodeGen/fp-floatcontrol-pragma.cpp
@@ -2,6 +2,9 @@
 // RUN: %clang_cc1 -fexperimental-strict-floating-point -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s
 // RUN: %clang_cc1 -fexperimental-strict-floating-point -DFENV_ON=1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-FENV %s
 // RUN: %clang_cc1 -fexperimental-strict-floating-point -triple %itanium_abi_triple -O3 -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-O3 %s
+// RUN: %clang_cc1 -fexperimental-strict-floating-point -triple x86_64-linux-gnu -emit-llvm -o - %s -ffp-eval-method=source | FileCheck %s -check-prefix=CHECK-SOURCE
+// RUN: %clang_cc1 -fexperimental-strict-floating-point -triple x86_64-linux-gnu -emit-llvm -o - %s -ffp-eval-method=double | FileCheck %s -check-prefix=CHECK-DOUBLE
+// RUN: %clang_cc1 -fexperimental-strict-floating-point -triple x86_64-linux-gnu -emit-llvm -o - %s -ffp-eval-method=extended | FileCheck %s -check-prefix=CHECK-EXTENDED
 
 // Verify float_control(precise, off) enables fast math flags on fp operations.
 float fp_precise_1(float a, float b, float c) {
@@ -229,3 +232,45 @@
   result = x + t;
   return result;
 }
+
+float mySub(float x, float y) {
+// CHECK: define float {{.*}}mySub{{.*}}
+// CHECK-NS: fsub float
+// CHECK-SOURCE: fsub float
+// CHECK-DOUBLE: fpext float
+// CHECK-DOUBLE: fpext float
+// CHECK-DOUBLE: fsub double
+// CHECK-DOUBLE: fptrunc double {{.*}} to float
+// CHECK-EXTENDED: fpext float
+// CHECK-EXTENDED: fpext float
+// CHECK-EXTENDED: fsub double
+// CHECK-EXTENDED: fptrunc double {{.*}} to float
+  return x - y;
+}
+
+float mySubSource( float x, float y ) {
+// CHECK: define float {{.*}}mySubSource{{.*}}
+#pragma float_control(source)
+  return x - y;
+// CHECK: fsub float
+}
+
+float mySubExtended( float x, float y ) {
+// CHECK: define float {{.*}}mySubExtended{{.*}}
+#pragma float_control(extended)
+  return x - y;
+// CHECK: fpext float
+// CHECK: fpext float
+// CHECK: fsub x86_fp80
+// CHECK: fptrunc x86_fp80 {{.*}} to float
+}
+
+float mySubDouble( float x, float y ) {
+// CHECK: define float {{.*}}mySubDouble{{.*}}
+#pragma float_control(double)
+  return x - y;
+// CHECK: fpext float
+// CHECK: fpext float
+// CHECK: fsub double
+// CHECK: fptrunc double {{.*}} to float
+}
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -773,6 +773,32 @@
   QualType Ty = E->getType();
   assert(!Ty.isNull() && "UsualUnaryConversions - missing type");
 
+  auto EvalMethod = CurFPFeatures.getFPEvalMethod();
+  if (EvalMethod != LangOptions::FEM_Source &&
+      Ty->isFloatingType()) {
+    switch (EvalMethod) {
+    default:
+      llvm_unreachable("Unrecognized float evaluation method");
+      break;
+    case LangOptions::FEM_Double:
+      if (Context.getFloatingTypeOrder(Context.DoubleTy, Ty) >0)
+        // Widen the expression to double.
+        return Ty->isComplexType() ?
+          ImpCastExprToType(E, Context.getComplexType(Context.DoubleTy),
+		              CK_FloatingComplexCast)
+          : ImpCastExprToType(E, Context.DoubleTy, CK_FloatingCast);
+      break;
+    case LangOptions::FEM_Extended:
+      if (Context.getFloatingTypeOrder(Context.LongDoubleTy, Ty) > 0)
+        // Widen the expression to long double.
+        return Ty->isComplexType() ?
+          ImpCastExprToType(E, Context.getComplexType(Context.LongDoubleTy),
+		              CK_FloatingComplexCast)
+          : ImpCastExprToType(E, Context.LongDoubleTy, CK_FloatingCast);
+      break;
+    }
+  }
+
   // Half FP have to be promoted to float unless it is natively supported
   if (Ty->isHalfType() && !getLangOpts().NativeHalfType)
     return ImpCastExprToType(Res.get(), Context.FloatTy, CK_FloatingCast);
Index: clang/lib/Sema/SemaAttr.cpp
===================================================================
--- clang/lib/Sema/SemaAttr.cpp
+++ clang/lib/Sema/SemaAttr.cpp
@@ -425,6 +425,18 @@
   switch (Value) {
   default:
     llvm_unreachable("invalid pragma float_control kind");
+  case PFC_Source:
+    //Builder.defineMacro("__FLT_EVAL_METHOD__", Twine("0"));
+    NewFPFeatures.setFPEvalMethodOverride(LangOptions::FEM_Source);
+    break;
+  case PFC_Double:
+    //Builder.defineMacro("__FLT_EVAL_METHOD__", Twine("1"));
+    NewFPFeatures.setFPEvalMethodOverride(LangOptions::FEM_Double);
+    break;
+  case PFC_Extended:
+    //Builder.defineMacro("__FLT_EVAL_METHOD__", Twine("2"));
+    NewFPFeatures.setFPEvalMethodOverride(LangOptions::FEM_Extended);
+    break;
   case PFC_Precise:
     NewFPFeatures.setFPPreciseEnabled(true);
     FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures);
Index: clang/lib/Parse/ParsePragma.cpp
===================================================================
--- clang/lib/Parse/ParsePragma.cpp
+++ clang/lib/Parse/ParsePragma.cpp
@@ -2573,21 +2573,28 @@
 
   // Read the identifier.
   PP.Lex(Tok);
-  if (Tok.isNot(tok::identifier)) {
-    PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
-    return;
-  }
-
-  // Verify that this is one of the float control options.
-  IdentifierInfo *II = Tok.getIdentifierInfo();
-  PragmaFloatControlKind Kind =
-      llvm::StringSwitch<PragmaFloatControlKind>(II->getName())
+  PragmaFloatControlKind Kind;
+  if (Tok.is(tok::kw_double)) {
+    Kind = PFC_Double;
+  } else {
+    if (Tok.isNot(tok::identifier)) {
+      PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
+      return;
+    }
+  
+    // Verify that this is one of the float control options.
+    IdentifierInfo *II = Tok.getIdentifierInfo();
+    Kind =
+        llvm::StringSwitch<PragmaFloatControlKind>(II->getName())
           .Case("precise", PFC_Precise)
           .Case("except", PFC_Except)
           .Case("push", PFC_Push)
           .Case("pop", PFC_Pop)
+          .Case("source", PFC_Source)
+          .Case("extended", PFC_Extended)
           .Default(PFC_Unknown);
-  PP.Lex(Tok); // the identifier
+  }
+  PP.Lex(Tok); // the first pragma token
   if (Kind == PFC_Unknown) {
     PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
     return;
@@ -2616,10 +2623,21 @@
         // Kind is set correctly
         ;
       else if (PushOnOff == "off") {
-        if (Kind == PFC_Precise)
+        switch (Kind) {
+        default:
+          break;
+        case PFC_Precise:
           Kind = PFC_NoPrecise;
-        if (Kind == PFC_Except)
+          break;
+        case PFC_Except:
           Kind = PFC_NoExcept;
+          break;
+        case PFC_Double:
+        case PFC_Extended:
+          // Reset eval mode to 'source'
+          Kind = PFC_Source;
+          break;
+        }
       } else if (PushOnOff == "push") {
         Action = Sema::PSK_Push_Set;
       } else {
Index: clang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- clang/lib/Frontend/CompilerInvocation.cpp
+++ clang/lib/Frontend/CompilerInvocation.cpp
@@ -2756,6 +2756,20 @@
   }
   Opts.setFPExceptionMode(FPEB);
 
+  LangOptions::FPEvalMethodKind FEM = LangOptions::FEM_Source;
+  if (Arg *A = Args.getLastArg(OPT_ffp_eval_method_EQ)) {
+    StringRef Val = A->getValue();
+    if (Val.equals("double"))
+      FEM = LangOptions::FEM_Double;
+    else if (Val.equals("extended"))
+      FEM = LangOptions::FEM_Extended;
+    else if (Val.equals("source"))
+      FEM = LangOptions::FEM_Source;
+    else
+      Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val;
+  }
+  Opts.setFPEvalMethod(FEM);
+
   // Parse -fsanitize= arguments.
   parseSanitizerKinds("-fsanitize=", Args.getAllArgValues(OPT_fsanitize_EQ),
                       Diags, Opts.Sanitize);
Index: clang/lib/Driver/ToolChains/Clang.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Clang.cpp
+++ clang/lib/Driver/ToolChains/Clang.cpp
@@ -2525,6 +2525,8 @@
   StringRef FPModel = "";
   // -ffp-exception-behavior options: strict, maytrap, ignore
   StringRef FPExceptionBehavior = "";
+  // -ffp-eval-method options: double, extended, source
+  StringRef FPEvalMethod = "";
   const llvm::DenormalMode DefaultDenormalFPMath =
       TC.getDefaultDenormalModeForType(Args, JA);
   const llvm::DenormalMode DefaultDenormalFP32Math =
@@ -2716,6 +2718,18 @@
       break;
     }
 
+    // Validate and pass through -ffp-float-precision option.
+    case options::OPT_ffp_eval_method_EQ: {
+      StringRef Val = A->getValue();
+      if (Val.equals("double") || Val.equals("extended") ||
+          Val.equals("source"))
+        FPEvalMethod = 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;
@@ -2862,6 +2876,10 @@
     CmdArgs.push_back(Args.MakeArgString("-ffp-exception-behavior=" +
                       FPExceptionBehavior));
 
+  if (!FPEvalMethod.empty())
+    CmdArgs.push_back(Args.MakeArgString("-ffp-eval-method=" +
+                      FPEvalMethod));
+
   ParseMRecip(D, Args, CmdArgs);
 
   // -ffast-math enables the __FAST_MATH__ preprocessor macro, but check for the
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -1343,6 +1343,8 @@
   HelpText<"Controls the semantics of floating-point calculations.">;
 def ffp_exception_behavior_EQ : Joined<["-"], "ffp-exception-behavior=">, Group<f_Group>, Flags<[CC1Option]>,
   HelpText<"Specifies the exception behavior of floating-point operations.">;
+def ffp_eval_method_EQ : Joined<["-"], "ffp-eval-method=">, Group<f_Group>, Flags<[CC1Option]>,
+  HelpText<"Specifies the evaluation method to use for floating point arithmetic.">;
 defm fast_math : OptInFFlag<"fast-math", "Allow aggressive, lossy floating-point optimizations", "", "", [],
   "LangOpts->FastMath", [cl_fast_relaxed_math]>;
 def menable_unsafe_fp_math : Flag<["-"], "menable-unsafe-fp-math">, Flags<[CC1Option]>,
Index: clang/include/clang/Basic/PragmaKinds.h
===================================================================
--- clang/include/clang/Basic/PragmaKinds.h
+++ clang/include/clang/Basic/PragmaKinds.h
@@ -32,7 +32,10 @@
   PFC_Except,    // #pragma float_control(except [,on])
   PFC_NoExcept,  // #pragma float_control(except, off)
   PFC_Push,      // #pragma float_control(push)
-  PFC_Pop        // #pragma float_control(pop)
+  PFC_Pop,       // #pragma float_control(pop)
+  PFC_Source,    // #pragma float_control(source, {on|off} [,push])
+  PFC_Double,    // #pragma float_control(double, {on|off} [,push])
+  PFC_Extended,  // #pragma float_control(extended, {on|off} [,push])
 };
 }
 
Index: clang/include/clang/Basic/LangOptions.h
===================================================================
--- clang/include/clang/Basic/LangOptions.h
+++ clang/include/clang/Basic/LangOptions.h
@@ -222,6 +222,16 @@
   /// Possible exception handling behavior.
   using ExceptionHandlingKind = llvm::ExceptionHandling;
 
+  /// Possible float expression evaluation method choies.
+  enum FPEvalMethodKind {
+    /// Use the declared type for fp arithmetic. This is default.
+    FEM_Source,
+    /// Use the type double for fp arithmetic.
+    FEM_Double,
+    /// Use extended type for fp arithmetic.
+    FEM_Extended
+  };
+
   enum class LaxVectorConversionKind {
     /// Permit no implicit vector bitcasts.
     None,
@@ -473,6 +483,7 @@
       setAllowFEnvAccess(true);
     else
       setAllowFEnvAccess(LangOptions::FPM_Off);
+    setFPEvalMethod(LO.getFPEvalMethod());
   }
 
   bool allowFPContractWithinStatement() const {
Index: clang/include/clang/Basic/LangOptions.def
===================================================================
--- clang/include/clang/Basic/LangOptions.def
+++ clang/include/clang/Basic/LangOptions.def
@@ -283,6 +283,7 @@
 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_ENUM_LANGOPT(FPEvalMethod, FPEvalMethodKind, 2, FEM_Source, "FP type used for floating point arithmetic")
 LANGOPT(NoBitFieldTypeAlign , 1, 0, "bit-field type alignment")
 LANGOPT(HexagonQdsp6Compat , 1, 0, "hexagon-qdsp6 backward compatibility")
 LANGOPT(ObjCAutoRefCount , 1, 0, "Objective-C automated reference counting")
Index: clang/include/clang/Basic/FPOptions.def
===================================================================
--- clang/include/clang/Basic/FPOptions.def
+++ clang/include/clang/Basic/FPOptions.def
@@ -23,4 +23,5 @@
 OPTION(NoSignedZero, bool, 1, NoHonorInfs)
 OPTION(AllowReciprocal, bool, 1, NoSignedZero)
 OPTION(AllowApproxFunc, bool, 1, AllowReciprocal)
+OPTION(FPEvalMethod, LangOptions::FPEvalMethodKind, 2, AllowApproxFunc)
 #undef OPTION
Index: clang/docs/UsersManual.rst
===================================================================
--- clang/docs/UsersManual.rst
+++ clang/docs/UsersManual.rst
@@ -1453,6 +1453,17 @@
    * ``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:: -ffp-eval-method=<value>
+
+   Specify the floating-point evaluation method.
+
+   Valid values are: ``source``, ``double``, and ``extended``.
+   The default value is ``source``.  Details:
+
+   * ``source`` The compiler uses the floating point type declared in the source program as the evaluation method.
+   * ``double`` The compiler uses ``double`` as the floating-point evaluation method for all float expressions of type that is narrower than ``double``.
+   * ``extended`` The compiler uses ``long double`` as the floating-point evaluation method for all float expressions of type that is narrower than ``long double``.
+
 
 .. _fp-constant-eval:
 
Index: clang/docs/LanguageExtensions.rst
===================================================================
--- clang/docs/LanguageExtensions.rst
+++ clang/docs/LanguageExtensions.rst
@@ -3260,8 +3260,29 @@
 governed by the pragma behaves as though the command-line option
 ``-ffp-exception-behavior=ignore`` is enabled.
 
+When ``pragma float_control(source, on)`` is enabled, the section of code governed
+by the pragma behaves as though the command-line option
+``-ffp-eval-method=source`` is enabled. Note: ``source`` is the default
+floating point evaluation method.
+
+When ``pragma float_control(double, on)`` is enabled, the section of code governed
+by the pragma behaves as though the command-line option
+``-ffp-eval-method=double`` is enabled.
+
+When ``pragma float_control(extended, on)`` is enabled, the section of code governed
+by the pragma behaves as though the command-line option
+``-ffp-eval-method=extended`` is enabled.
+
+When ``pragma float_control(source, off)`` or
+``pragma float_control(double, off)`` or
+``pragma float_control(extended, off)`` is enabled,
+the section of code governed
+by the pragma behaves as though the command-line option
+``-ffp-eval-method=source`` is enabled, returning floating point evaluation
+method to the default setting.
+
 The full syntax this pragma supports is
-``float_control(except|precise, on|off [, push])`` and
+``float_control(except|precise|source|double|extended, on|off [, push])`` and
 ``float_control(push|pop)``.
 The ``push`` and ``pop`` forms, including using ``push`` as the optional
 third argument, can only occur at file scope.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to