]> granicus.if.org Git - clang/commitdiff
Move -mfpmath handling to -cc1 and implement it for x86.
authorRafael Espindola <rafael.espindola@gmail.com>
Wed, 21 Aug 2013 21:59:03 +0000 (21:59 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Wed, 21 Aug 2013 21:59:03 +0000 (21:59 +0000)
The original idea was to implement it all on the driver, but to do that the
driver needs to know the sse level and to do that it has to know the default
features of a cpu.

Benjamin Kramer pointed out that if one day we decide to implement support for
' __attribute__ ((__target__ ("arch=core2")))', then the frontend needs to
keep its knowledge of default features of a cpu.

To avoid duplicating which part of clang handles default cpu features,
it is probably better to handle -mfpmath in the frontend.

For ARM this patch is just a small improvement. Instead of a cpu list, we
check if neon is enabled, which allows us to reject things like

-mcpu=cortex-a9 -mfpu=vfp -mfpmath=neon

For X86, since LLVM doesn't support an independent ssefp feature, we just
make sure the selected -mfpmath matches the sse level.

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

include/clang/Basic/DiagnosticCommonKinds.td
include/clang/Basic/TargetInfo.h
include/clang/Basic/TargetOptions.h
include/clang/Driver/CC1Options.td
lib/Basic/Targets.cpp
lib/Driver/Tools.cpp
lib/Frontend/CompilerInvocation.cpp
test/Driver/arm-mfpmath.c [deleted file]
test/Frontend/mfpmath.c [new file with mode: 0644]

index c67b437ddff88071330240f3f08ff6a8ef7693d9..c54bafc07fe8d34e480f74e0f9b14cad8dce2860 100644 (file)
@@ -115,6 +115,9 @@ def err_target_unknown_triple : Error<
 def err_target_unknown_cpu : Error<"unknown target CPU '%0'">;
 def err_target_unknown_abi : Error<"unknown target ABI '%0'">;
 def err_target_unknown_cxxabi : Error<"unknown C++ ABI '%0'">;
+def err_target_unknown_fpmath : Error<"unknown FP unit '%0'">;
+def err_target_unsupported_fpmath : Error<
+    "the '%0' unit is not supported with this instruction set">;
 
 // Source manager
 def err_cannot_open_file : Error<"cannot open file '%0': %1">, DefaultFatal;
index 821a469d617c56a1fe591472068047910b6c694f..ec7cdec7ad4399e673bed5ecf6f39ba27d0802e2 100644 (file)
@@ -653,6 +653,13 @@ public:
     return false;
   }
 
+  /// \brief Use the specified unit for FP math.
+  ///
+  /// \return False on error (invalid unit name).
+  virtual bool setFPMath(StringRef Name) {
+    return false;
+  }
+
   /// \brief Use this specified C++ ABI.
   ///
   /// \return False on error (invalid C++ ABI name).
@@ -685,7 +692,11 @@ public:
   ///
   /// The target may modify the features list, to change which options are
   /// passed onwards to the backend.
-  virtual void HandleTargetFeatures(std::vector<std::string> &Features) {
+  ///
+  /// \return  False on error.
+  virtual bool HandleTargetFeatures(std::vector<std::string> &Features,
+                                    DiagnosticsEngine &Diags) {
+    return true;
   }
 
   /// \brief Determine whether the given target has the given feature.
index c2183fd29d562c1622f02385fcd6b0ff93141779..9909182ab6dd697375c272dcf46f17e0d992ab8e 100644 (file)
@@ -32,6 +32,9 @@ public:
   /// If given, the name of the target CPU to generate code for.
   std::string CPU;
 
+  /// If given, the unit to use for floating point math.
+  std::string FPMath;
+
   /// If given, the name of the target ABI to use.
   std::string ABI;
 
index 2774dc69f2ea46178cac26816028f6181afe4ee0..b74f4453e654a020da10ed201452571351057bd1 100644 (file)
@@ -23,6 +23,8 @@ def target_abi : Separate<["-"], "target-abi">,
   HelpText<"Target a particular ABI type">;
 def target_cpu : Separate<["-"], "target-cpu">,
   HelpText<"Target a specific cpu type">;
+def mfpmath : Separate<["-"], "mfpmath">,
+  HelpText<"Which unit to use for fp math">;
 def target_feature : Separate<["-"], "target-feature">,
   HelpText<"Target specific attributes">;
 def target_linker_version : Separate<["-"], "target-linker-version">,
index 8674b2a4a4055d11d93828887e3857f3f8994cc6..fd3cfa6eff3092368b6e96cb33177a9e9ee4adcd 100644 (file)
@@ -1709,6 +1709,12 @@ class X86TargetInfo : public TargetInfo {
     //@}
   } CPU;
 
+  enum FPMathKind {
+    FP_Default,
+    FP_SSE,
+    FP_387
+  } FPMath;
+
 public:
   X86TargetInfo(const llvm::Triple &Triple)
       : TargetInfo(Triple), SSELevel(NoSSE), MMX3DNowLevel(NoMMX3DNow),
@@ -1716,7 +1722,7 @@ public:
         HasRDRND(false), HasBMI(false), HasBMI2(false), HasPOPCNT(false),
         HasRTM(false), HasPRFCHW(false), HasRDSEED(false), HasFMA(false),
         HasF16C(false), HasAVX512CD(false), HasAVX512ER(false),
-        HasAVX512PF(false), CPU(CK_Generic) {
+        HasAVX512PF(false), CPU(CK_Generic), FPMath(FP_Default) {
     BigEndian = false;
     LongDoubleFormat = &llvm::APFloat::x87DoubleExtended;
   }
@@ -1763,7 +1769,8 @@ public:
                                  bool Enabled) const;
   virtual void getDefaultFeatures(llvm::StringMap<bool> &Features) const;
   virtual bool hasFeature(StringRef Feature) const;
-  virtual void HandleTargetFeatures(std::vector<std::string> &Features);
+  virtual bool HandleTargetFeatures(std::vector<std::string> &Features,
+                                    DiagnosticsEngine &Diags);
   virtual const char* getABI() const {
     if (getTriple().getArch() == llvm::Triple::x86_64 && SSELevel >= AVX)
       return "avx";
@@ -1895,6 +1902,8 @@ public:
     llvm_unreachable("Unhandled CPU kind");
   }
 
+  virtual bool setFPMath(StringRef Name);
+
   virtual CallingConvCheckResult checkCallingConvention(CallingConv CC) const {
     // We accept all non-ARM calling conventions
     return (CC == CC_X86ThisCall ||
@@ -1910,6 +1919,18 @@ public:
   }
 };
 
+bool X86TargetInfo::setFPMath(StringRef Name) {
+  if (Name == "387") {
+    FPMath = FP_387;
+    return true;
+  }
+  if (Name == "sse") {
+    FPMath = FP_SSE;
+    return true;
+  }
+  return false;
+}
+
 void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
   // FIXME: This *really* should not be here.
 
@@ -2246,7 +2267,8 @@ void X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
 
 /// HandleTargetOptions - Perform initialization based on the user
 /// configured set of features.
-void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) {
+bool X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features,
+                                         DiagnosticsEngine &Diags) {
   // Remember the maximum enabled sselevel.
   for (unsigned i = 0, e = Features.size(); i !=e; ++i) {
     // Ignore disabled features.
@@ -2360,12 +2382,23 @@ void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) {
     XOPLevel = std::max(XOPLevel, XLevel);
   }
 
+  // LLVM doesn't have a separate switch for fpmath, so only accept it if it
+  // matches the selected sse level.
+  if (FPMath == FP_SSE && SSELevel < SSE1) {
+    Diags.Report(diag::err_target_unsupported_fpmath) << "sse";
+    return false;
+  } else if (FPMath == FP_387 && SSELevel >= SSE1) {
+    Diags.Report(diag::err_target_unsupported_fpmath) << "387";
+    return false;
+  }
+
   // Don't tell the backend if we're turning off mmx; it will end up disabling
   // SSE, which we don't want.
   std::vector<std::string>::iterator it;
   it = std::find(Features.begin(), Features.end(), "-mmx");
   if (it != Features.end())
     Features.erase(it);
+  return true;
 }
 
 /// X86TargetInfo::getTargetDefines - Return the set of the X86-specific macro
@@ -3280,12 +3313,14 @@ public:
     return Feature == "aarch64" || (Feature == "neon" && FPU == NeonMode);
   }
 
-  virtual void HandleTargetFeatures(std::vector<std::string> &Features) {
+  virtual bool HandleTargetFeatures(std::vector<std::string> &Features,
+                                    DiagnosticsEngine &Diags) {
     FPU = FPUMode;
     for (unsigned i = 0, e = Features.size(); i != e; ++i) {
       if (Features[i] == "+neon")
         FPU = NeonMode;
     }
+    return true;
   }
 
   virtual void getGCCRegNames(const char *const *&Names,
@@ -3421,6 +3456,12 @@ class ARMTargetInfo : public TargetInfo {
 
   std::string ABI, CPU;
 
+  enum {
+    FP_Default,
+    FP_VFP,
+    FP_Neon
+  } FPMath;
+
   unsigned FPU : 4;
 
   unsigned IsAAPCS : 1;
@@ -3465,7 +3506,7 @@ class ARMTargetInfo : public TargetInfo {
 public:
   ARMTargetInfo(const llvm::Triple &Triple)
       : TargetInfo(Triple), ABI("aapcs-linux"), CPU("arm1136j-s"),
-        IsAAPCS(true) {
+        FPMath(FP_Default), IsAAPCS(true) {
     BigEndian = false;
     SizeType = UnsignedInt;
     PtrDiffType = SignedInt;
@@ -3571,7 +3612,8 @@ public:
     }
   }
 
-  virtual void HandleTargetFeatures(std::vector<std::string> &Features) {
+  virtual bool HandleTargetFeatures(std::vector<std::string> &Features,
+                                    DiagnosticsEngine &Diags) {
     FPU = 0;
     SoftFloat = SoftFloatABI = false;
     for (unsigned i = 0, e = Features.size(); i != e; ++i) {
@@ -3589,6 +3631,16 @@ public:
         FPU |= NeonFPU;
     }
 
+    if (!(FPU & NeonFPU) && FPMath == FP_Neon) {
+      Diags.Report(diag::err_target_unsupported_fpmath) << "neon";
+      return false;
+    }
+
+    if (FPMath == FP_Neon)
+      Features.push_back("+neonfp");
+    else if (FPMath == FP_VFP)
+      Features.push_back("-neonfp");
+
     // Remove front-end specific options which the backend handles differently.
     std::vector<std::string>::iterator it;
     it = std::find(Features.begin(), Features.end(), "+soft-float");
@@ -3597,6 +3649,7 @@ public:
     it = std::find(Features.begin(), Features.end(), "+soft-float-abi");
     if (it != Features.end())
       Features.erase(it);
+    return true;
   }
 
   virtual bool hasFeature(StringRef Feature) const {
@@ -3649,6 +3702,7 @@ public:
     CPU = Name;
     return true;
   }
+  virtual bool setFPMath(StringRef Name);
   virtual void getTargetDefines(const LangOptions &Opts,
                                 MacroBuilder &Builder) const {
     // Target identification.
@@ -3820,6 +3874,18 @@ public:
   }
 };
 
+bool ARMTargetInfo::setFPMath(StringRef Name) {
+  if (Name == "neon") {
+    FPMath = FP_Neon;
+    return true;
+  } else if (Name == "vfp" || Name == "vfp2" || Name == "vfp3" ||
+             Name == "vfp4") {
+    FPMath = FP_VFP;
+    return true;
+  }
+  return false;
+}
+
 const char * const ARMTargetInfo::GCCRegNames[] = {
   // Integer registers
   "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
@@ -4070,11 +4136,13 @@ class SparcTargetInfo : public TargetInfo {
 public:
   SparcTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) {}
 
-  virtual void HandleTargetFeatures(std::vector<std::string> &Features) {
+  virtual bool HandleTargetFeatures(std::vector<std::string> &Features,
+                                    DiagnosticsEngine &Diags) {
     SoftFloat = false;
     for (unsigned i = 0, e = Features.size(); i != e; ++i)
       if (Features[i] == "+soft-float")
         SoftFloat = true;
+    return true;
   }
   virtual void getTargetDefines(const LangOptions &Opts,
                                 MacroBuilder &Builder) const {
@@ -4642,7 +4710,8 @@ public:
     return "";
   }
 
-  virtual void HandleTargetFeatures(std::vector<std::string> &Features) {
+  virtual bool HandleTargetFeatures(std::vector<std::string> &Features,
+                                    DiagnosticsEngine &Diags) {
     IsMips16 = false;
     IsMicromips = false;
     IsSingleFloat = false;
@@ -4672,6 +4741,8 @@ public:
       std::find(Features.begin(), Features.end(), "+soft-float");
     if (it != Features.end())
       Features.erase(it);
+
+    return true;
   }
 
   virtual int getEHDataRegisterNumber(unsigned RegNo) const {
@@ -5488,6 +5559,12 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
     return 0;
   }
 
+  // Set the fp math unit.
+  if (!Opts->FPMath.empty() && !Target->setFPMath(Opts->FPMath)) {
+    Diags.Report(diag::err_target_unknown_fpmath) << Opts->FPMath;
+    return 0;
+  }
+
   // Compute the default target features, we need the target to handle this
   // because features may have dependencies on one another.
   llvm::StringMap<bool> Features;
@@ -5510,7 +5587,8 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
   for (llvm::StringMap<bool>::const_iterator it = Features.begin(),
          ie = Features.end(); it != ie; ++it)
     Opts->Features.push_back((it->second ? "+" : "-") + it->first().str());
-  Target->HandleTargetFeatures(Opts->Features);
+  if (!Target->HandleTargetFeatures(Opts->Features, Diags))
+    return 0;
 
   return Target.take();
 }
index 746300000f2fa36e32419d9469567e9b27da9bb1..25be6b48b660f83a339a04176e2ac583117fd34c 100644 (file)
@@ -602,30 +602,6 @@ static void getFPUFeatures(const Driver &D, const Arg *A, const ArgList &Args,
     D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
 }
 
-// Handle -mfpmath=.
-static void getFPMathFeatures(const Driver &D, const Arg *A,
-                              const ArgList &Args,
-                              std::vector<const char *> &Features,
-                              StringRef CPU) {
-  StringRef FPMath = A->getValue();
-
-  // Set the target features based on the FPMath.
-  if (FPMath == "neon") {
-    Features.push_back("+neonfp");
-
-    if (CPU != "cortex-a5" && CPU != "cortex-a7" &&
-        CPU != "cortex-a8" && CPU != "cortex-a9" &&
-        CPU != "cortex-a9-mp" && CPU != "cortex-a15")
-      D.Diag(diag::err_drv_invalid_feature) << "-mfpmath=neon" << CPU;
-
-  } else if (FPMath == "vfp" || FPMath == "vfp2" || FPMath == "vfp3" ||
-             FPMath == "vfp4") {
-    Features.push_back("-neonfp");
-    // FIXME: Add warnings when disabling a feature not present for a given CPU.
-  } else
-    D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
-}
-
 // Select the float ABI as determined by -msoft-float, -mhard-float, and
 // -mfloat-abi=.
 static StringRef getARMFloatABI(const Driver &D,
@@ -725,10 +701,6 @@ static void getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple,
   if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ))
     getFPUFeatures(D, A, Args, Features);
 
-  // Honor -mfpmath=.
-  if (const Arg *A = Args.getLastArg(options::OPT_mfpmath_EQ))
-    getFPMathFeatures(D, A, Args, Features, getARMTargetCPU(Args, Triple));
-
   // Setting -msoft-float effectively disables NEON because of the GCC
   // implementation, although the same isn't true of VFP or VFP3.
   if (FloatABI == "soft")
@@ -2409,6 +2381,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
     CmdArgs.push_back(Args.MakeArgString(CPU));
   }
 
+  if (const Arg *A = Args.getLastArg(options::OPT_mfpmath_EQ)) {
+    CmdArgs.push_back("-mfpmath");
+    CmdArgs.push_back(A->getValue());
+  }
+
   // Add the target features
   getTargetFeatures(D, ETriple, Args, CmdArgs);
 
index 9e6061900804082180455ded364b5b793b4f2add..b637938735c18e3f9d8ea3e1bf356c5d07edda4c 100644 (file)
@@ -1541,6 +1541,7 @@ static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) {
   Opts.ABI = Args.getLastArgValue(OPT_target_abi);
   Opts.CXXABI = Args.getLastArgValue(OPT_cxx_abi);
   Opts.CPU = Args.getLastArgValue(OPT_target_cpu);
+  Opts.FPMath = Args.getLastArgValue(OPT_mfpmath);
   Opts.FeaturesAsWritten = Args.getAllArgValues(OPT_target_feature);
   Opts.LinkerVersion = Args.getLastArgValue(OPT_target_linker_version);
   Opts.Triple = llvm::Triple::normalize(Args.getLastArgValue(OPT_triple));
diff --git a/test/Driver/arm-mfpmath.c b/test/Driver/arm-mfpmath.c
deleted file mode 100644 (file)
index 0421046..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-// Test different values of -mfpmath.
-
-// RUN: %clang -target arm-apple-darwin10 -mfpmath=vfp %s -### -c -o %t.o 2>&1 \
-// RUN:   | FileCheck --check-prefix=CHECK-VFP %s
-// CHECK-VFP: "-target-feature" "-neonfp"
-
-// RUN: %clang -target arm-apple-darwin10 -mfpmath=vfp2 %s -### -c -o %t.o 2>&1 \
-// RUN:   | FileCheck --check-prefix=CHECK-VFP2 %s
-// CHECK-VFP2: "-target-feature" "-neonfp"
-
-// RUN: %clang -target arm-apple-darwin10 -mfpmath=vfp3 %s -### -c -o %t.o 2>&1 \
-// RUN:   | FileCheck --check-prefix=CHECK-VFP3 %s
-// CHECK-VFP3: "-target-feature" "-neonfp"
-
-// RUN: %clang -target arm-apple-darwin10 -mfpmath=vfp4 %s -### -c -o %t.o 2>&1 \
-// RUN:   | FileCheck --check-prefix=CHECK-VFP4 %s
-// CHECK-VFP4: "-target-feature" "-neonfp"
-
-// RUN: %clang -target arm-apple-darwin10 -mfpmath=neon %s -### -c -o %t.o 2>&1 \
-// RUN:   | FileCheck --check-prefix=CHECK-NEON %s
-// CHECK-NEON: "-target-feature" "+neonfp"
-
-// RUN: %clang -target arm-apple-darwin10 -mfpmath=foo %s -### -c -o %t.o 2>&1 \
-// RUN:   | FileCheck --check-prefix=CHECK-ERROR %s
-// CHECK-ERROR: clang compiler does not support '-mfpmath=foo'
-
-// RUN: %clang -target arm-apple-darwin10 -mcpu=arm1136j-s -mfpmath=neon %s -### -c -o %t.o 2>&1 \
-// RUN:   | FileCheck --check-prefix=CHECK-MCPU-ERROR %s
-// CHECK-MCPU-ERROR: error: invalid feature '-mfpmath=neon' for CPU 'arm1136j-s'
diff --git a/test/Frontend/mfpmath.c b/test/Frontend/mfpmath.c
new file mode 100644 (file)
index 0000000..f650e48
--- /dev/null
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -triple i686-pc-linux -target-feature -sse  %s
+
+// RUN: %clang_cc1 -triple i686-pc-linux -target-feature -sse -mfpmath 387 %s
+
+// RUN: %clang_cc1 -triple i686-pc-linux -target-feature +sse %s
+
+// RUN: %clang_cc1 -triple i686-pc-linux -target-feature +sse -mfpmath sse %s
+
+// RUN: not %clang_cc1 -triple i686-pc-linux -target-feature +sse \
+// RUN: -mfpmath xyz %s 2>&1 | FileCheck --check-prefix=CHECK-XYZ %s
+// CHECK-XYZ: error: unknown FP unit 'xyz'
+
+// RUN: not %clang_cc1 -triple i686-pc-linux -target-feature +sse \
+// RUN: -mfpmath 387 %s 2>&1 | FileCheck --check-prefix=CHECK-NO-387 %s
+// CHECK-NO-387: error: the '387' unit is not supported with this instruction set
+
+// RUN: not %clang_cc1 -triple i686-pc-linux -target-feature -sse \
+// RUN: -mfpmath sse %s 2>&1 | FileCheck --check-prefix=CHECK-NO-SSE %s
+// CHECK-NO-SSE: error: the 'sse' unit is not supported with this instruction set
+
+
+// RUN: %clang_cc1 -triple arm-apple-darwin10 -mfpmath vfp %s
+
+// RUN: %clang_cc1 -triple arm-apple-darwin10 -mfpmath vfp2 %s
+
+// RUN: %clang_cc1 -triple arm-apple-darwin10 -mfpmath vfp3 %s
+
+// RUN: %clang_cc1 -triple arm-apple-darwin10 -mfpmath vfp4 %s
+
+// RUN: %clang_cc1 -triple arm-apple-darwin10 -target-cpu cortex-a9 \
+// RUN: -mfpmath neon %s
+
+// RUN: not %clang_cc1 -triple arm-apple-darwin10 -mfpmath foo %s 2>&1 \
+// RUN: FileCheck --check-prefix=CHECK-FOO %s
+// CHECK-FOO: unknown FP unit 'foo'
+
+// RUN: not %clang_cc1 -triple arm-apple-darwin10 -target-cpu arm1136j-s \
+// RUN: -mfpmath neon %s 2>&1 | FileCheck --check-prefix=CHECK-NO-NEON %s
+
+// RUN: not %clang_cc1 -triple arm-apple-darwin10 -target-cpu cortex-a9 \
+// RUN: -target-feature -neon -mfpmath neon %s 2>&1 | FileCheck --check-prefix=CHECK-NO-NEON %s
+
+// CHECK-NO-NEON: error: the 'neon' unit is not supported with this instruction set