]> granicus.if.org Git - clang/commitdiff
Fix PR11685 by implementing -ffast-math and its various friends in the
authorChandler Carruth <chandlerc@gmail.com>
Mon, 2 Jan 2012 14:19:45 +0000 (14:19 +0000)
committerChandler Carruth <chandlerc@gmail.com>
Mon, 2 Jan 2012 14:19:45 +0000 (14:19 +0000)
Clang driver. This involves a bunch of silly option parsing code to try
to carefully emulate GCC's options. Currently, this takes a conservative
approach, and unless all of the unsafe optimizations are enabled, none
of them are. The fine grained control doesn't seem particularly useful.
If it ever becomes useful, we can add that to LLVM first, and then
expose it here.

This also fixes a few tiny bugs in the flag management around
-fhonor-infinities and -fhonor-nans; the flags now form proper sets both
for enabling and disabling, with the last flag winning.

I've also implemented a moderately terrifying GCC feature where
a language change is also provided by the '-ffast-math' flag by defining
the __FAST_MATH__ preprocessor macro. This feature is tracked and
serialized in the frontend but it isn't used yet. A subsequent patch
will add the preprocessor macro and tests for it.

I've manually tested that codegen appears to respect this, but I've not
dug in enough to see if there is an easy way to test codegen options w/o
relying on the particulars of LLVM's optimizations.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147434 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/LangOptions.def
include/clang/Driver/ArgList.h
include/clang/Driver/CC1Options.td
include/clang/Driver/Options.td
lib/Driver/ArgList.cpp
lib/Driver/Tools.cpp
lib/Frontend/CompilerInvocation.cpp
test/Driver/fast-math.c [new file with mode: 0644]

index 1f7bcd6f9427f6938ee15969b873aaa545cb28d3..6c1038ee1d7147d6183afb4a5ea4967bec4cc031 100644 (file)
@@ -100,6 +100,7 @@ VALUE_LANGOPT(PICLevel          , 2, 0, "__PIC__ level")
 LANGOPT(GNUInline         , 1, 0, "GNU inline semantics")
 LANGOPT(NoInline          , 1, 0, "__NO_INLINE__ predefined macro")
 LANGOPT(Deprecated        , 1, 0, "__DEPRECATED predefined macro")
+LANGOPT(FastMath          , 1, 0, "__FAST_MATH__ predefined macro")
 
 BENIGN_LANGOPT(ObjCGCBitmapPrint , 1, 0, "printing of GC's bitmap layout for __weak/__strong ivars")
 
index 04faf64dc5ec9f2fab10f547ab3bfcd2bb4c2e46..f9698048b2bd12cb80d65ddc82e27ac6556d42f9 100644 (file)
@@ -185,6 +185,8 @@ namespace driver {
     Arg *getLastArg(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2) const;
     Arg *getLastArg(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2,
                     OptSpecifier Id3) const;
+    Arg *getLastArg(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2,
+                    OptSpecifier Id3, OptSpecifier Id4) const;
 
     /// getArgString - Return the input argument string at \arg Index.
     virtual const char *getArgString(unsigned Index) const = 0;
index d275af24f2f38d8268889421c2fc35192cd269fa..ec6e03bf767b8f493c8c94b810cd9e3eb38a854b 100644 (file)
@@ -170,6 +170,9 @@ def menable_no_infinities : Flag<"-menable-no-infs">,
   HelpText<"Allow optimization to assume there are no infinities.">;
 def menable_no_nans : Flag<"-menable-no-nans">,
   HelpText<"Allow optimization to assume there are no NaNs.">;
+def menable_unsafe_fp_math : Flag<"-menable-unsafe-fp-math">,
+  HelpText<"Allow unsafe floating-point math optimizations which may decrease "
+           "precision">;
 def mfloat_abi : Separate<"-mfloat-abi">,
   HelpText<"The float ABI to use">;
 def mno_global_merge : Flag<"-mno-global-merge">,
@@ -482,6 +485,10 @@ def fcxx_exceptions : Flag<"-fcxx-exceptions">,
   HelpText<"Enable C++ exceptions">;
 def fsjlj_exceptions : Flag<"-fsjlj-exceptions">,
   HelpText<"Use SjLj style exceptions">;
+def ffast_math : Flag<"-ffast-math">,
+  HelpText<"Enable the *frontend*'s 'fast-math' mode. This has no effect on "
+           "optimizations, but provides a preprocessor macro __FAST_MATH__ the "
+           "same as GCC's -ffast-math flag.">;
 def ffreestanding : Flag<"-ffreestanding">,
   HelpText<"Assert that the compilation takes place in a freestanding environment">;
 def fgnu_runtime : Flag<"-fgnu-runtime">,
index 892a972a620d811a4608bab4d41fe29603549494..08b3f03eae7f4b855ca67b24941e0885f0b40b07 100644 (file)
@@ -319,8 +319,23 @@ def ferror_limit_EQ : Joined<"-ferror-limit=">, Group<f_Group>;
 def fexceptions : Flag<"-fexceptions">, Group<f_Group>;
 def fextdirs_EQ : Joined<"-fextdirs=">, Group<f_Group>;
 def fhosted : Flag<"-fhosted">, Group<f_Group>;
-def ffast_math : Flag<"-ffast-math">, Group<clang_ignored_f_Group>;
+def ffast_math : Flag<"-ffast-math">, Group<f_Group>;
+def fmath_errno : Flag<"-fmath-errno">, Group<f_Group>;
+def fno_math_errno : Flag<"-fno-math-errno">, Group<f_Group>;
+def fsignaling_math : Flag<"-fsignaling-math">, Group<f_Group>;
+def fno_signaling_math : Flag<"-fno-signaling-math">, Group<f_Group>;
+def funsafe_math_optimizations : Flag<"-funsafe-math-optimizations">,
+  Group<f_Group>;
+def fno_unsafe_math_optimizations : Flag<"-fno-unsafe-math-optimizations">,
+  Group<f_Group>;
+def fassociative_math : Flag<"-fassociative-math">, Group<f_Group>;
+def fno_associative_math : Flag<"-fno-associative-math">, Group<f_Group>;
+def freciprocal_math : Flag<"-freciprocal-math">, Group<f_Group>;
+def fno_reciprocal_math : Flag<"-fno-reciprocal-math">, Group<f_Group>;
 def ffinite_math_only : Flag<"-ffinite-math-only">, Group<f_Group>;
+def fno_finite_math_only : Flag<"-fno-finite-math-only">, Group<f_Group>;
+def fsigned_zeros : Flag<"-fsigned-zeros">, Group<f_Group>;
+def fno_signed_zeros : Flag<"-fno-signed-zeros">, Group<f_Group>;
 def fhonor_nans : Flag<"-fhonor-nans">, Group<f_Group>;
 def fno_honor_nans : Flag<"-fno-honor-nans">, Group<f_Group>;
 def fhonor_infinities : Flag<"-fhonor-infinities">, Group<f_Group>;
@@ -330,6 +345,8 @@ def fhonor_infinites : Flag<"-fhonor-infinites">, Group<f_Group>,
     Alias<fhonor_infinities>;
 def fno_honor_infinites : Flag<"-fno-honor-infinites">, Group<f_Group>,
     Alias<fno_honor_infinities>;
+def ftrapping_math : Flag<"-ftrapping-math">, Group<f_Group>;
+def fno_trapping_math : Flag<"-fno-trapping-math">, Group<f_Group>;
 
 def ffor_scope : Flag<"-ffor-scope">, Group<f_Group>;
 def fno_for_scope : Flag<"-fno-for-scope">, Group<f_Group>;
@@ -355,7 +372,6 @@ def flto : Flag<"-flto">, Group<f_Group>;
 def fno_lto : Flag<"-fno-lto">, Group<f_Group>;
 def fmacro_backtrace_limit_EQ : Joined<"-fmacro-backtrace-limit=">,
                                 Group<f_Group>;
-def fmath_errno : Flag<"-fmath-errno">, Group<f_Group>;
 def fmerge_all_constants : Flag<"-fmerge-all-constants">, Group<f_Group>;
 def fmessage_length_EQ : Joined<"-fmessage-length=">, Group<f_Group>;
 def fms_extensions : Flag<"-fms-extensions">, Group<f_Group>;
@@ -394,7 +410,6 @@ def fno_dollars_in_identifiers : Flag<"-fno-dollars-in-identifiers">, Group<f_Gr
 def fno_elide_constructors : Flag<"-fno-elide-constructors">, Group<f_Group>;
 def fno_eliminate_unused_debug_symbols : Flag<"-fno-eliminate-unused-debug-symbols">, Group<f_Group>;
 def fno_exceptions : Flag<"-fno-exceptions">, Group<f_Group>;
-def fno_finite_math_only : Flag<"-fno-finite-math-only">, Group<clang_ignored_f_Group>;
 def fno_gnu_keywords : Flag<"-fno-gnu-keywords">, Group<f_Group>;
 def fno_inline_functions : Flag<"-fno-inline-functions">, Group<clang_ignored_f_Group>;
 def fno_inline : Flag<"-fno-inline">, Group<clang_ignored_f_Group>;
@@ -402,7 +417,6 @@ def fno_keep_inline_functions : Flag<"-fno-keep-inline-functions">, Group<clang_
 def fno_lax_vector_conversions : Flag<"-fno-lax-vector-conversions">, Group<f_Group>;
 def fno_limit_debug_info : Flag<"-fno-limit-debug-info">, Group<f_Group>,
   HelpText<"Do not limit debug information produced to reduce size of debug binary">;
-def fno_math_errno : Flag<"-fno-math-errno">, Group<f_Group>;
 def fno_merge_all_constants : Flag<"-fno-merge-all-constants">, Group<f_Group>;
 def fno_ms_extensions : Flag<"-fno-ms-extensions">, Group<f_Group>;
 def fno_ms_compatibility : Flag<"-fno-ms-compatibility">, Group<f_Group>;
index ca9b944950e13cd190862a2750d8ad7e241702ab..3c9e71d6f80f96026069b235beda1d7d2ca9d7e3 100644 (file)
@@ -122,6 +122,24 @@ Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1,
   return Res;
 }
 
+Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1,
+                         OptSpecifier Id2, OptSpecifier Id3,
+                         OptSpecifier Id4) const {
+  Arg *Res = 0;
+  for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
+    if ((*it)->getOption().matches(Id0) ||
+        (*it)->getOption().matches(Id1) ||
+        (*it)->getOption().matches(Id2) ||
+        (*it)->getOption().matches(Id3) ||
+        (*it)->getOption().matches(Id4)) {
+      Res = *it;
+      Res->claim();
+    }
+  }
+
+  return Res;
+}
+
 bool ArgList::hasFlag(OptSpecifier Pos, OptSpecifier Neg, bool Default) const {
   if (Arg *A = getLastArg(Pos, Neg))
     return A->getOption().matches(Pos);
index 41ff1102bfc88e7160a1f4bbe079201cc31e905e..f678667c33cfc0252f8c05fdf91bb7f9b753e6ae 100644 (file)
@@ -1435,18 +1435,90 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
                     getToolChain().IsStrictAliasingDefault()))
     CmdArgs.push_back("-relaxed-aliasing");
 
-  // Handle -f{no-}honor-infinities, -f{no-}honor-nans, and -ffinite-math-only.
-  bool HonorInfinities = Args.hasFlag(options::OPT_fhonor_infinities,
-                                      options::OPT_fno_honor_infinities);
-  bool HonorNaNs = Args.hasFlag(options::OPT_fhonor_nans,
-                                options::OPT_fno_honor_nans);
-  if (Args.hasArg(options::OPT_ffinite_math_only))
-    HonorInfinities = HonorNaNs = false;
-  if (!HonorInfinities)
-    CmdArgs.push_back("-menable-no-infs");
-  if (!HonorNaNs)
-    CmdArgs.push_back("-menable-no-nans");
-    
+  // Handle various floating point optimization flags, mapping them to the
+  // appropriate LLVM code generation flags. The pattern for all of these is to
+  // default off the codegen optimizations, and if any flag enables them and no
+  // flag disables them after the flag enabling them, enable the codegen
+  // optimization. This is complicated by several "umbrella" flags.
+  if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+                               options::OPT_ffinite_math_only,
+                               options::OPT_fno_finite_math_only,
+                               options::OPT_fhonor_infinities,
+                               options::OPT_fno_honor_infinities))
+    if (A->getOption().getID() != options::OPT_fno_finite_math_only &&
+        A->getOption().getID() != options::OPT_fhonor_infinities)
+      CmdArgs.push_back("-menable-no-infs");
+  if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+                               options::OPT_ffinite_math_only,
+                               options::OPT_fno_finite_math_only,
+                               options::OPT_fhonor_nans,
+                               options::OPT_fno_honor_nans))
+    if (A->getOption().getID() != options::OPT_fno_finite_math_only &&
+        A->getOption().getID() != options::OPT_fhonor_nans)
+      CmdArgs.push_back("-menable-no-nans");
+
+  // -fno-math-errno is default.
+  bool MathErrno = false;
+  if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+                               options::OPT_fmath_errno,
+                               options::OPT_fno_math_errno)) {
+    if (A->getOption().getID() == options::OPT_fmath_errno) {
+      CmdArgs.push_back("-fmath-errno");
+      MathErrno = true;
+    }
+  }
+
+  // There are several flags which require disabling very specific
+  // optimizations. Any of these being disabled forces us to turn off the
+  // entire set of LLVM optimizations, so collect them through all the flag
+  // madness.
+  bool AssociativeMath = false;
+  if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+                               options::OPT_funsafe_math_optimizations,
+                               options::OPT_fno_unsafe_math_optimizations,
+                               options::OPT_fassociative_math,
+                               options::OPT_fno_associative_math))
+    if (A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
+        A->getOption().getID() != options::OPT_fno_associative_math)
+      AssociativeMath = true;
+  bool ReciprocalMath = false;
+  if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+                               options::OPT_funsafe_math_optimizations,
+                               options::OPT_fno_unsafe_math_optimizations,
+                               options::OPT_freciprocal_math,
+                               options::OPT_fno_reciprocal_math))
+    if (A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
+        A->getOption().getID() != options::OPT_fno_reciprocal_math)
+      ReciprocalMath = true;
+  bool SignedZeros = true;
+  if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+                               options::OPT_funsafe_math_optimizations,
+                               options::OPT_fno_unsafe_math_optimizations,
+                               options::OPT_fsigned_zeros,
+                               options::OPT_fno_signed_zeros))
+    if (A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
+        A->getOption().getID() != options::OPT_fsigned_zeros)
+      SignedZeros = false;
+  bool TrappingMath = true;
+  if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+                               options::OPT_funsafe_math_optimizations,
+                               options::OPT_fno_unsafe_math_optimizations,
+                               options::OPT_ftrapping_math,
+                               options::OPT_fno_trapping_math))
+    if (A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
+        A->getOption().getID() != options::OPT_ftrapping_math)
+      TrappingMath = false;
+  if (!MathErrno && AssociativeMath && ReciprocalMath && !SignedZeros &&
+      !TrappingMath)
+    CmdArgs.push_back("-menable-unsafe-fp-math");
+
+  // We separately look for the '-ffast-math' flag, and if we find it, tell the
+  // frontend to provide the appropriate preprocessor macros. This is distinct
+  // from enabling any optimizations as it induces a language change which must
+  // survive serialization and deserialization, etc.
+  if (Args.hasArg(options::OPT_ffast_math))
+    CmdArgs.push_back("-ffast-math");
+
   // Decide whether to use verbose asm. Verbose assembly is the default on
   // toolchains which have the integrated assembler on by default.
   bool IsVerboseAsmDefault = getToolChain().IsIntegratedAssemblerDefault();
@@ -1548,12 +1620,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
                    !getToolChain().getTriple().isOSDarwin()))
     CmdArgs.push_back("-momit-leaf-frame-pointer");
 
-  // -fno-math-errno is default.
-  if (Args.hasFlag(options::OPT_fmath_errno,
-                   options::OPT_fno_math_errno,
-                   false))
-    CmdArgs.push_back("-fmath-errno");
-
   // Explicitly error on some things we know we don't support and can't just
   // ignore.
   types::ID InputType = Inputs[0].getType();
index caeb416a59b8eaebd0bcf78d7f8ac8abc57afd6e..0137774cf10836ed6deeacbd54749b9558e25924 100644 (file)
@@ -735,6 +735,8 @@ static void LangOptsToArgs(const LangOptions &Opts,
     Res.push_back("-fheinous-gnu-extensions");
   // Optimize is implicit.
   // OptimizeSize is implicit.
+  if (Opts.FastMath)
+    Res.push_back("-ffast-math");
   if (Opts.Static)
     Res.push_back("-static-define");
   if (Opts.DumpRecordLayouts)
@@ -1117,7 +1119,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
   Opts.NoDwarf2CFIAsm = Args.hasArg(OPT_fno_dwarf2_cfi_asm);
   Opts.NoDwarfDirectoryAsm = Args.hasArg(OPT_fno_dwarf_directory_asm);
   Opts.SoftFloat = Args.hasArg(OPT_msoft_float);
-  Opts.UnsafeFPMath = Args.hasArg(OPT_cl_unsafe_math_optimizations) ||
+  Opts.UnsafeFPMath = Args.hasArg(OPT_menable_unsafe_fp_math) ||
+                      Args.hasArg(OPT_cl_unsafe_math_optimizations) ||
                       Args.hasArg(OPT_cl_fast_relaxed_math);
   Opts.UnwindTables = Args.hasArg(OPT_munwind_tables);
   Opts.RelocationModel = Args.getLastArgValue(OPT_mrelocation_model, "pic");
@@ -1874,6 +1877,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
   // FIXME: This is affected by other options (-fno-inline).
   Opts.NoInline = !Opt;
 
+  Opts.FastMath = Args.hasArg(OPT_ffast_math);
+
   unsigned SSP = Args.getLastArgIntValue(OPT_stack_protector, 0, Diags);
   switch (SSP) {
   default:
diff --git a/test/Driver/fast-math.c b/test/Driver/fast-math.c
new file mode 100644 (file)
index 0000000..aef7cc3
--- /dev/null
@@ -0,0 +1,119 @@
+// Test that the GCC fast-math floating point flags get lowered to the correct
+// permutation of Clang frontend flags. This is non-trivial for a few reasons.
+// First, the GCC flags have many different and surprising effects. Second,
+// LLVM only supports three switches which is more coarse grained than GCC's
+// support.
+//
+// RUN: %clang -### -fno-honor-infinities -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-NO-INFS %s
+// CHECK-NO-INFS: "-cc1"
+// CHECK-NO-INFS: "-menable-no-infs"
+//
+// RUN: %clang -### -fno-honor-nans -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-NO-NANS %s
+// CHECK-NO-NANS: "-cc1"
+// CHECK-NO-NANS: "-menable-no-nans"
+//
+// RUN: %clang -### -fmath-errno -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-MATH-ERRNO %s
+// CHECK-MATH-ERRNO: "-cc1"
+// CHECK-MATH-ERRNO: "-fmath-errno"
+//
+// RUN: %clang -### -fassociative-math -freciprocal-math -fno-signed-zeros \
+// RUN:     -fno-trapping-math -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-UNSAFE-MATH %s
+// CHECK-UNSAFE-MATH: "-cc1"
+// CHECK-UNSAFE-MATH: "-menable-unsafe-fp-math"
+//
+// Check that various umbrella flags also enable these frontend options.
+// RUN: %clang -### -ffast-math -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-NO-INFS %s
+// RUN: %clang -### -ffast-math -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-NO-NANS %s
+// RUN: %clang -### -ffast-math -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-UNSAFE-MATH %s
+// RUN: %clang -### -ffinite-math-only -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-NO-INFS %s
+// RUN: %clang -### -ffinite-math-only -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-NO-NANS %s
+// RUN: %clang -### -funsafe-math-optimizations -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-UNSAFE-MATH %s
+//
+// One umbrella flag is *really* weird and also changes the semantics of the
+// program by adding a special preprocessor macro. Check that the frontend flag
+// modeling this semantic change is provided. Also check that the semantic
+// impact remains even if every optimization is disabled.
+// RUN: %clang -### -ffast-math -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-FAST-MATH %s
+// RUN: %clang -### -ffast-math -fno-finite-math-only \
+// RUN:     -fno-unsafe-math-optimizations -fmath-errno -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-FAST-MATH %s
+// CHECK-FAST-MATH: "-cc1"
+// CHECK-FAST-MATH: "-ffast-math"
+//
+// Check various means of disabling these flags, including disabling them after
+// they've been enabled via an umbrella flag.
+// RUN: %clang -### -fno-honor-infinities -fhonor-infinities -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-NO-NO-INFS %s
+// RUN: %clang -### -ffinite-math-only -fhonor-infinities -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-NO-NO-INFS %s
+// RUN: %clang -### -ffinite-math-only -fno-finite-math-only -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-NO-NO-INFS %s
+// RUN: %clang -### -ffast-math -fhonor-infinities -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-NO-NO-INFS %s
+// RUN: %clang -### -ffast-math -fno-finite-math-only -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-NO-NO-INFS %s
+// CHECK-NO-NO-INFS: "-cc1"
+// CHECK-NO-NO-INFS-NOT: "-menable-no-infs"
+// CHECK-NO-NO-INFS: "-o"
+//
+// RUN: %clang -### -fno-honor-nans -fhonor-nans -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-NO-NO-NANS %s
+// RUN: %clang -### -ffinite-math-only -fhonor-nans -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-NO-NO-NANS %s
+// RUN: %clang -### -ffinite-math-only -fno-finite-math-only -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-NO-NO-NANS %s
+// RUN: %clang -### -ffast-math -fhonor-nans -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-NO-NO-NANS %s
+// RUN: %clang -### -ffast-math -fno-finite-math-only -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-NO-NO-NANS %s
+// CHECK-NO-NO-NANS: "-cc1"
+// CHECK-NO-NO-NANS-NOT: "-menable-no-nans"
+// CHECK-NO-NO-NANS: "-o"
+//
+// RUN: %clang -### -fassociative-math -freciprocal-math -fno-signed-zeros \
+// RUN:     -fno-trapping-math -fno-associative-math -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-NO-UNSAFE-MATH %s
+// RUN: %clang -### -fassociative-math -freciprocal-math -fno-signed-zeros \
+// RUN:     -fno-trapping-math -fno-reciprocal-math -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-NO-UNSAFE-MATH %s
+// RUN: %clang -### -fassociative-math -freciprocal-math -fno-signed-zeros \
+// RUN:     -fno-trapping-math -fsigned-zeros -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-NO-UNSAFE-MATH %s
+// RUN: %clang -### -fassociative-math -freciprocal-math -fno-signed-zeros \
+// RUN:     -fno-trapping-math -ftrapping-math -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-NO-UNSAFE-MATH %s
+// RUN: %clang -### -funsafe-math-optimizations -fno-associative-math -c %s \
+// RUN:   2>&1 | FileCheck --check-prefix=CHECK-NO-UNSAFE-MATH %s
+// RUN: %clang -### -funsafe-math-optimizations -fno-reciprocal-math -c %s \
+// RUN:   2>&1 | FileCheck --check-prefix=CHECK-NO-UNSAFE-MATH %s
+// RUN: %clang -### -funsafe-math-optimizations -fsigned-zeros -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-NO-UNSAFE-MATH %s
+// RUN: %clang -### -funsafe-math-optimizations -ftrapping-math -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-NO-UNSAFE-MATH %s
+// RUN: %clang -### -funsafe-math-optimizations -fno-unsafe-math-optimizations \
+// RUN:     -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-NO-UNSAFE-MATH %s
+// RUN: %clang -### -ffast-math -fno-associative-math -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-NO-UNSAFE-MATH %s
+// RUN: %clang -### -ffast-math -fno-reciprocal-math -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-NO-UNSAFE-MATH %s
+// RUN: %clang -### -ffast-math -fsigned-zeros -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-NO-UNSAFE-MATH %s
+// RUN: %clang -### -ffast-math -ftrapping-math -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-NO-UNSAFE-MATH %s
+// RUN: %clang -### -ffast-math -fno-unsafe-math-optimizations -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-NO-UNSAFE-MATH %s
+// CHECK-NO-UNSAFE-MATH: "-cc1"
+// CHECK-NO-UNSAFE-MATH-NOT: "-menable-unsafe-fp-math"
+// CHECK-NO-UNSAFE-MATH: "-o"