Moving from bugs to tech.

cwen reported that base-clang crashed on macppc in graphics/babl and
emulators/mednafen [1].  I observed that clang crashed on powerpc64 in
mednafen.  I now propose to backport a commit in llvm 11.x git [2] to
prevent these crashes.  This change affects other arches.

[1] https://marc.info/?l=openbsd-bugs&m=159775378014683&w=2
[2] https://github.com/llvm/llvm-project/commit/d4ce862

FreeBSD on powerpc64 found the problems earlier:
https://bugs.llvm.org/show_bug.cgi?id=45237 (babl)
https://bugs.llvm.org/show_bug.cgi?id=45274 (mednafen)

The problem is with clang -fno-unsafe-math-optimizations, one of the
new floating-point options in clang-10.  The diff disables the new
options on all targets except X86 (and SystemZ), so it also affects
arches other than PowerPC.  The disabled options cause a warning.

With the diff in clang:
 - mednafen stops using -fno-unsafe-math-optimizations, because the
   new warning fails the configure test.  I can build and package
   mednafen on macppc (where a single *m68k*.cpp takes over 2 hours),
   but when I try to play Super Mario World (snes), mednafen crashes
   with a SIGSEGV.  The build on powerpc64 stops crashing clang, but
   fails at an altivec error.
 - babl uses -fno-unsafe-math-optimizations and ignores the new
   warning.  I can build and package babl, and all 27 tests pass on
   both macppc and powerpc64.
 - I have built src and xenocara on powerpc64.

The diff is in llvm 11.x.  To backport the diff, I manually applied
some parts (where the context had changed), and I renamed
RoundingMode::NearestTiesToEven back to FPR_RoundToNearest.

Apply the diff in /usr/src/gnu/llvm.  If DiagnosticFrontendKinds.inc
exists under /usr/obj/gnu/usr.bin/clang/, you must delete the .inc,
because there is a missing dependency in our Makefiles.

Is this OK?  Should we do something else?  --George

Index: clang/docs/ClangCommandLineReference.rst
===================================================================
RCS file: /cvs/src/gnu/llvm/clang/docs/ClangCommandLineReference.rst,v
retrieving revision 1.1.1.2
diff -u -p -r1.1.1.2 ClangCommandLineReference.rst
--- clang/docs/ClangCommandLineReference.rst    9 Aug 2020 15:51:07 -0000       
1.1.1.2
+++ clang/docs/ClangCommandLineReference.rst    30 Aug 2020 19:37:51 -0000
@@ -818,6 +818,10 @@ Enables the experimental global instruct
 
 Enables an experimental new pass manager in LLVM.
 
+.. option:: -fexperimental-strict-floating-point
+
+Enables the use of non-default rounding modes and non-default exception 
handling on targets that are not currently ready.
+
 .. option:: -ffine-grained-bitfield-accesses, 
-fno-fine-grained-bitfield-accesses
 
 Use separate accesses for consecutive bitfield runs with legal widths and 
alignments.
Index: clang/include/clang/Basic/CodeGenOptions.def
===================================================================
RCS file: /cvs/src/gnu/llvm/clang/include/clang/Basic/CodeGenOptions.def,v
retrieving revision 1.1.1.1
diff -u -p -r1.1.1.1 CodeGenOptions.def
--- clang/include/clang/Basic/CodeGenOptions.def        3 Aug 2020 14:31:32 
-0000       1.1.1.1
+++ clang/include/clang/Basic/CodeGenOptions.def        30 Aug 2020 19:37:51 
-0000
@@ -58,6 +58,8 @@ CODEGENOPT(DisableLLVMPasses , 1, 0) ///
                                      ///< frontend.
 CODEGENOPT(DisableLifetimeMarkers, 1, 0) ///< Don't emit any lifetime markers
 CODEGENOPT(DisableO0ImplyOptNone , 1, 0) ///< Don't annonate function with 
optnone at O0
+CODEGENOPT(ExperimentalStrictFloatingPoint, 1, 0) ///< Enables the new, 
experimental
+                                                  ///< strict floating point.
 CODEGENOPT(ExperimentalNewPassManager, 1, 0) ///< Enables the new, experimental
                                              ///< pass manager.
 CODEGENOPT(DebugPassManager, 1, 0) ///< Prints debug information for the new
Index: clang/include/clang/Basic/DiagnosticFrontendKinds.td
===================================================================
RCS file: 
/cvs/src/gnu/llvm/clang/include/clang/Basic/DiagnosticFrontendKinds.td,v
retrieving revision 1.1.1.1
diff -u -p -r1.1.1.1 DiagnosticFrontendKinds.td
--- clang/include/clang/Basic/DiagnosticFrontendKinds.td        3 Aug 2020 
14:31:32 -0000       1.1.1.1
+++ clang/include/clang/Basic/DiagnosticFrontendKinds.td        30 Aug 2020 
19:37:51 -0000
@@ -37,6 +37,12 @@ def note_fe_backend_plugin: Note<"%0">, 
 def warn_fe_override_module : Warning<
     "overriding the module target triple with %0">,
     InGroup<DiagGroup<"override-module">>;
+def warn_fe_backend_unsupported_fp_rounding : Warning<
+    "overriding currently unsupported rounding mode on this target">,
+    InGroup<UnsupportedFPOpt>;
+def warn_fe_backend_unsupported_fp_exceptions : Warning<
+    "overriding currently unsupported use of floating point exceptions "
+    "on this target">, InGroup<UnsupportedFPOpt>;
 
 def remark_fe_backend_optimization_remark : Remark<"%0">, BackendInfo,
     InGroup<BackendOptimizationRemark>;
Index: clang/include/clang/Basic/DiagnosticGroups.td
===================================================================
RCS file: /cvs/src/gnu/llvm/clang/include/clang/Basic/DiagnosticGroups.td,v
retrieving revision 1.1.1.1
diff -u -p -r1.1.1.1 DiagnosticGroups.td
--- clang/include/clang/Basic/DiagnosticGroups.td       3 Aug 2020 14:31:32 
-0000       1.1.1.1
+++ clang/include/clang/Basic/DiagnosticGroups.td       30 Aug 2020 19:37:51 
-0000
@@ -103,6 +103,7 @@ def DoublePromotion : DiagGroup<"double-
 def EnumTooLarge : DiagGroup<"enum-too-large">;
 def UnsupportedNan : DiagGroup<"unsupported-nan">;
 def UnsupportedAbs : DiagGroup<"unsupported-abs">;
+def UnsupportedFPOpt : DiagGroup<"unsupported-floating-point-opt">;
 def UnsupportedCB : DiagGroup<"unsupported-cb">;
 def UnsupportedGPOpt : DiagGroup<"unsupported-gpopt">;
 def UnsupportedTargetOpt : DiagGroup<"unsupported-target-opt">;
Index: clang/include/clang/Basic/LangOptions.def
===================================================================
RCS file: /cvs/src/gnu/llvm/clang/include/clang/Basic/LangOptions.def,v
retrieving revision 1.1.1.1
diff -u -p -r1.1.1.1 LangOptions.def
--- clang/include/clang/Basic/LangOptions.def   3 Aug 2020 14:31:32 -0000       
1.1.1.1
+++ clang/include/clang/Basic/LangOptions.def   30 Aug 2020 19:37:51 -0000
@@ -257,6 +257,7 @@ LANGOPT(SinglePrecisionConstants , 1, 0,
 LANGOPT(FastRelaxedMath , 1, 0, "OpenCL fast relaxed math")
 /// FP_CONTRACT mode (on/off/fast).
 ENUM_LANGOPT(DefaultFPContractMode, FPContractModeKind, 2, FPC_Off, "FP 
contraction type")
+COMPATIBLE_LANGOPT(ExpStrictFP, 1, false, "Enable experimental strict floating 
point")
 ENUM_LANGOPT(FPRoundingMode, FPRoundingModeKind, 3, FPR_ToNearest, "FP 
Rounding Mode type")
 ENUM_LANGOPT(FPExceptionMode, FPExceptionModeKind, 2, FPE_Ignore, "FP 
Exception Behavior Mode type")
 LANGOPT(NoBitFieldTypeAlign , 1, 0, "bit-field type alignment")
Index: clang/include/clang/Basic/TargetInfo.h
===================================================================
RCS file: /cvs/src/gnu/llvm/clang/include/clang/Basic/TargetInfo.h,v
retrieving revision 1.1.1.1
diff -u -p -r1.1.1.1 TargetInfo.h
--- clang/include/clang/Basic/TargetInfo.h      3 Aug 2020 14:31:32 -0000       
1.1.1.1
+++ clang/include/clang/Basic/TargetInfo.h      30 Aug 2020 19:37:51 -0000
@@ -176,6 +176,7 @@ protected:
                          // LLVM IR type.
   bool HasFloat128;
   bool HasFloat16;
+  bool HasStrictFP;
 
   unsigned char MaxAtomicPromoteWidth, MaxAtomicInlineWidth;
   unsigned short SimdDefaultAlign;
@@ -532,6 +533,9 @@ public:
 
   /// Determine whether the _Float16 type is supported on this target.
   virtual bool hasFloat16Type() const { return HasFloat16; }
+
+  /// Determine whether constrained floating point is supported on this target.
+  virtual bool hasStrictFP() const { return HasStrictFP; }
 
   /// Return the alignment that is suitable for storing any
   /// object with a fundamental alignment requirement.
Index: clang/include/clang/Driver/Options.td
===================================================================
RCS file: /cvs/src/gnu/llvm/clang/include/clang/Driver/Options.td,v
retrieving revision 1.1.1.2
diff -u -p -r1.1.1.2 Options.td
--- clang/include/clang/Driver/Options.td       9 Aug 2020 15:51:08 -0000       
1.1.1.2
+++ clang/include/clang/Driver/Options.td       30 Aug 2020 19:37:51 -0000
@@ -1235,6 +1235,9 @@ def fexperimental_isel : Flag<["-"], "fe
 def fexperimental_new_pass_manager : Flag<["-"], 
"fexperimental-new-pass-manager">,
   Group<f_clang_Group>, Flags<[CC1Option]>,
   HelpText<"Enables an experimental new pass manager in LLVM.">;
+def fexperimental_strict_floating_point : Flag<["-"], 
"fexperimental-strict-floating-point">,
+  Group<f_clang_Group>, Flags<[CC1Option]>,
+  HelpText<"Enables experimental strict floating point in LLVM.">;
 def finput_charset_EQ : Joined<["-"], "finput-charset=">, Group<f_Group>;
 def fexec_charset_EQ : Joined<["-"], "fexec-charset=">, Group<f_Group>;
 def finstrument_functions : Flag<["-"], "finstrument-functions">, 
Group<f_Group>, Flags<[CC1Option]>,
Index: clang/lib/Basic/TargetInfo.cpp
===================================================================
RCS file: /cvs/src/gnu/llvm/clang/lib/Basic/TargetInfo.cpp,v
retrieving revision 1.1.1.1
diff -u -p -r1.1.1.1 TargetInfo.cpp
--- clang/lib/Basic/TargetInfo.cpp      3 Aug 2020 14:31:33 -0000       1.1.1.1
+++ clang/lib/Basic/TargetInfo.cpp      30 Aug 2020 19:37:52 -0000
@@ -36,6 +36,7 @@ TargetInfo::TargetInfo(const llvm::Tripl
   HasLegalHalfType = false;
   HasFloat128 = false;
   HasFloat16 = false;
+  HasStrictFP = false;
   PointerWidth = PointerAlign = 32;
   BoolWidth = BoolAlign = 8;
   IntWidth = IntAlign = 32;
Index: clang/lib/Basic/Targets/SystemZ.h
===================================================================
RCS file: /cvs/src/gnu/llvm/clang/lib/Basic/Targets/SystemZ.h,v
retrieving revision 1.1.1.1
diff -u -p -r1.1.1.1 SystemZ.h
--- clang/lib/Basic/Targets/SystemZ.h   3 Aug 2020 14:31:33 -0000       1.1.1.1
+++ clang/lib/Basic/Targets/SystemZ.h   30 Aug 2020 19:37:52 -0000
@@ -47,6 +47,7 @@ public:
     MinGlobalAlign = 16;
     resetDataLayout("E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-a:8:16-n32:64");
     MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
+    HasStrictFP = true;
   }
 
   void getTargetDefines(const LangOptions &Opts,
Index: clang/lib/Basic/Targets/X86.h
===================================================================
RCS file: /cvs/src/gnu/llvm/clang/lib/Basic/Targets/X86.h,v
retrieving revision 1.1.1.1
diff -u -p -r1.1.1.1 X86.h
--- clang/lib/Basic/Targets/X86.h       3 Aug 2020 14:31:33 -0000       1.1.1.1
+++ clang/lib/Basic/Targets/X86.h       30 Aug 2020 19:37:52 -0000
@@ -148,6 +148,7 @@ public:
       : TargetInfo(Triple) {
     LongDoubleFormat = &llvm::APFloat::x87DoubleExtended();
     AddrSpaceMap = &X86AddrSpaceMap;
+    HasStrictFP = true;
   }
 
   const char *getLongDoubleMangling() const override {
Index: clang/lib/Frontend/CompilerInstance.cpp
===================================================================
RCS file: /cvs/src/gnu/llvm/clang/lib/Frontend/CompilerInstance.cpp,v
retrieving revision 1.1.1.1
diff -u -p -r1.1.1.1 CompilerInstance.cpp
--- clang/lib/Frontend/CompilerInstance.cpp     3 Aug 2020 14:31:33 -0000       
1.1.1.1
+++ clang/lib/Frontend/CompilerInstance.cpp     30 Aug 2020 19:37:52 -0000
@@ -927,6 +927,19 @@ bool CompilerInstance::ExecuteAction(Fro
     setAuxTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), TO));
   }
 
+  if (!getTarget().hasStrictFP() && !getLangOpts().ExpStrictFP) {
+    if (getLangOpts().getFPRoundingMode() !=
+        LangOptions::FPR_ToNearest) {
+      getDiagnostics().Report(diag::warn_fe_backend_unsupported_fp_rounding);
+      getLangOpts().setFPRoundingMode(LangOptions::FPR_ToNearest);
+    }
+    if (getLangOpts().getFPExceptionMode() != LangOptions::FPE_Ignore) {
+      getDiagnostics().Report(diag::warn_fe_backend_unsupported_fp_exceptions);
+      getLangOpts().setFPExceptionMode(LangOptions::FPE_Ignore);
+    }
+    // FIXME: can we disable FEnvAccess?
+  }
+
   // Inform the target of the language options.
   //
   // FIXME: We shouldn't need to do this, the target should be immutable once
Index: clang/lib/Frontend/CompilerInvocation.cpp
===================================================================
RCS file: /cvs/src/gnu/llvm/clang/lib/Frontend/CompilerInvocation.cpp,v
retrieving revision 1.1.1.1
diff -u -p -r1.1.1.1 CompilerInvocation.cpp
--- clang/lib/Frontend/CompilerInvocation.cpp   3 Aug 2020 14:31:33 -0000       
1.1.1.1
+++ clang/lib/Frontend/CompilerInvocation.cpp   30 Aug 2020 19:37:52 -0000
@@ -3175,6 +3175,9 @@ static void ParseLangArgs(LangOptions &O
       Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val;
   }
 
+  if (Args.hasArg(OPT_fexperimental_strict_floating_point))
+    Opts.ExpStrictFP = true;
+
   LangOptions::FPRoundingModeKind FPRM = LangOptions::FPR_ToNearest;
   if (Args.hasArg(OPT_frounding_math)) {
     FPRM = LangOptions::FPR_Dynamic;

Reply via email to