ARM: Honor -mfpu= and set __VFP_FP__ and __ARM_NEON__ "correctly".
 - Correctly is in quotes, because we are following what I interpreted as GCC's
   intent (which diverges from practice, naturally).
 - Also, fix the arch define for arm1136jf-s.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@91855 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 7b0ce67..182f7bc 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -391,6 +391,7 @@
 def mdynamic_no_pic : Joined<"-mdynamic-no-pic">, Group<m_Group>, Flags<[NoArgumentUnused]>;
 def mfix_and_continue : Flag<"-mfix-and-continue">, Group<clang_ignored_m_Group>;
 def mfloat_abi_EQ : Joined<"-mfloat-abi=">, Group<m_Group>;
+def mfpu_EQ : Joined<"-mfpu=">, Group<m_Group>;
 def mhard_float : Flag<"-mhard-float">, Group<m_Group>;
 def miphoneos_version_min_EQ : Joined<"-miphoneos-version-min=">, Group<m_Group>;
 def mkernel : Flag<"-mkernel">, Group<m_Group>;
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 66d1814..3b32797 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -1183,10 +1183,25 @@
 
 namespace {
 class ARMTargetInfo : public TargetInfo {
-   static const TargetInfo::GCCRegAlias GCCRegAliases[];
-   static const char * const GCCRegNames[];
+  // Possible FPU choices.
+  enum FPUMode {
+    NoFPU,
+    VFP2FPU,
+    VFP3FPU,
+    NeonFPU
+  };
+
+  static bool FPUModeIsVFP(FPUMode Mode) {
+    return Mode >= VFP2FPU && Mode <= NeonFPU;
+  }
+
+  static const TargetInfo::GCCRegAlias GCCRegAliases[];
+  static const char * const GCCRegNames[];
 
   std::string ABI, CPU;
+
+  unsigned FPU : 3;
+
   unsigned IsThumb : 1;
 
   // Initialized via features.
@@ -1245,23 +1260,49 @@
     return true;
   }
 
+  void getDefaultFeatures(const std::string &CPU,
+                          llvm::StringMap<bool> &Features) const {
+    // FIXME: This should not be here.
+    Features["vfp2"] = false;
+    Features["vfp3"] = false;
+    Features["neon"] = false;
+
+    if (CPU == "arm1136jf-s" || CPU == "arm1176jzf-s" || CPU == "mpcore")
+      Features["vfp2"] = true;
+    else if (CPU == "cortex-a8" || CPU == "cortex-a9")
+      Features["neon"] = true;
+  }
+  
   virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features,
                                  const std::string &Name,
                                  bool Enabled) const {
-    if (Name != "soft-float" && Name != "soft-float-abi")
+    if (Name == "soft-float" || Name == "soft-float-abi") {
+      Features[Name] = Enabled;
+    } else if (Name == "vfp2" || Name == "vfp3" || Name == "neon") {
+      // These effectively are a single option, reset them when any is enabled.
+      if (Enabled)
+        Features["vfp2"] = Features["vfp3"] = Features["neon"] = false;
+      Features[Name] = Enabled;
+    } else
       return false;
 
-    Features[Name] = Enabled;
     return true;
   }
 
   virtual void HandleTargetFeatures(std::vector<std::string> &Features) {
+    FPU = NoFPU;
     SoftFloat = SoftFloatABI = false;
     for (unsigned i = 0, e = Features.size(); i != e; ++i) {
       if (Features[i] == "+soft-float")
         SoftFloat = true;
       else if (Features[i] == "+soft-float-abi")
         SoftFloatABI = true;
+      else if (Features[i] == "+vfp2")
+        FPU = VFP2FPU;
+      else if (Features[i] == "+vfp3")
+        FPU = VFP3FPU;
+      else if (Features[i] == "+neon")
+        FPU = NeonFPU;
     }
 
     // Remove front-end specific options which the backend handles differently.
@@ -1286,9 +1327,9 @@
       .Case("arm926ej-s", "5TEJ")
       .Cases("arm10e", "arm1020e", "arm1022e", "5TE")
       .Cases("xscale", "iwmmxt", "5TE")
-      .Cases("arm1136j-s", "arm1136jf-s", "6J")
+      .Case("arm1136j-s", "6J")
       .Cases("arm1176jz-s", "arm1176jzf-s", "6ZK")
-      .Cases("mpcorenovfp", "mpcore", "6K")
+      .Cases("arm1136jf-s", "mpcorenovfp", "mpcore", "6K")
       .Cases("arm1156t2-s", "arm1156t2f-s", "6T2")
       .Cases("cortex-a8", "cortex-a9", "7A")
       .Default(0);
@@ -1334,17 +1375,26 @@
     if (CPU == "xscale")
       Define(Defs, "__XSCALE__");
 
+    bool IsThumb2 = IsThumb && (CPUArch == "6T2" || CPUArch.startswith("7"));
     if (IsThumb) {
       Define(Defs, "__THUMBEL__");
       Define(Defs, "__thumb__");
-      if (CPUArch == "6T2" || CPUArch.startswith("7"))
+      if (IsThumb2)
         Define(Defs, "__thumb2__");
     }
 
     // Note, this is always on in gcc, even though it doesn't make sense.
     Define(Defs, "__APCS_32__");
-    // FIXME: This should be conditional on VFP instruction support.
-    Define(Defs, "__VFP_FP__");
+
+    if (FPUModeIsVFP((FPUMode) FPU))
+      Define(Defs, "__VFP_FP__");
+
+    // This only gets set when Neon instructions are actually available, unlike
+    // the VFP define, hence the soft float and arch check. This is subtly
+    // different from gcc, we follow the intent which was that it should be set
+    // when Neon instructions are actually available.
+    if (FPU == NeonFPU && !SoftFloat && IsThumb2)
+      Define(Defs, "__ARM_NEON__");
 
     if (getTriple().getOS() == llvm::Triple::Darwin)
       Define(Defs, "__USING_SJLJ_EXCEPTIONS__");
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 8cdd00c..8ac448f 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -450,6 +450,35 @@
     CmdArgs.push_back("-target-feature");
     CmdArgs.push_back("+soft-float-abi");
   }
+
+  // Honor -mfpu=.
+  //
+  // FIXME: Centralize feature selection, defaulting shouldn't be also in the
+  // frontend target.
+  if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) {
+    llvm::StringRef FPU = A->getValue(Args);
+
+    // Set the target features based on the FPU.
+    if (FPU == "fpa" || FPU == "fpe2" || FPU == "fpe3" || FPU == "maverick") {
+      // Disable any default FPU support.
+      CmdArgs.push_back("-target-feature");
+      CmdArgs.push_back("-vfp2");
+      CmdArgs.push_back("-target-feature");
+      CmdArgs.push_back("-vfp3");
+      CmdArgs.push_back("-target-feature");
+      CmdArgs.push_back("-neon");
+    } else if (FPU == "vfp") {
+      CmdArgs.push_back("-target-feature");
+      CmdArgs.push_back("+vfp2");
+    } else if (FPU == "vfp3") {
+      CmdArgs.push_back("-target-feature");
+      CmdArgs.push_back("+vfp3");
+    } else if (FPU == "neon") {
+      CmdArgs.push_back("-target-feature");
+      CmdArgs.push_back("+neon");
+    } else
+      D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
+  }
 }
 
 void Clang::AddX86TargetArgs(const ArgList &Args,
diff --git a/test/Preprocessor/init.c b/test/Preprocessor/init.c
index 074b2a1..5796b11 100644
--- a/test/Preprocessor/init.c
+++ b/test/Preprocessor/init.c
@@ -189,7 +189,6 @@
 // ARM:#define __THUMB_INTERWORK__ 1
 // ARM:#define __UINTMAX_TYPE__ long long unsigned int
 // ARM:#define __USER_LABEL_PREFIX__ _
-// ARM:#define __VFP_FP__ 1
 // ARM:#define __WCHAR_MAX__ 2147483647
 // ARM:#define __WCHAR_TYPE__ int
 // ARM:#define __WCHAR_WIDTH__ 32