Have the driver pass CPU and target feature information to cc1as.

When creating the MCSubtargetInfo, the assembler driver uses the CPU and
feature string to construct a more accurate model of what instructions
are and are not legal.

rdar://10840476


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150273 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Driver/CC1AsOptions.td b/include/clang/Driver/CC1AsOptions.td
index ac4d65c..37ba602 100644
--- a/include/clang/Driver/CC1AsOptions.td
+++ b/include/clang/Driver/CC1AsOptions.td
@@ -20,6 +20,10 @@
 
 def triple : Separate<"-triple">,
   HelpText<"Specify target triple (e.g. x86_64-pc-linux-gnu)">;
+def target_cpu : Separate<"-target-cpu">,
+  HelpText<"Target a specific cpu type">;
+def target_feature : Separate<"-target-feature">,
+  HelpText<"Target specific attributes">;
 
 //===----------------------------------------------------------------------===//
 // Language Options
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 714a21a..c963654 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -2545,6 +2545,56 @@
   Args.ClaimAllArgs(options::OPT_emit_llvm);
 }
 
+void ClangAs::AddARMTargetArgs(const ArgList &Args,
+                               ArgStringList &CmdArgs) const {
+  const Driver &D = getToolChain().getDriver();
+  llvm::Triple Triple = getToolChain().getTriple();
+
+  // Set the CPU based on -march= and -mcpu=.
+  CmdArgs.push_back("-target-cpu");
+  CmdArgs.push_back(getARMTargetCPU(Args, Triple));
+
+  // 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)) {
+    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 == "vfp3-d16" || FPU == "vfpv3-d16") {
+      CmdArgs.push_back("-target-feature");
+      CmdArgs.push_back("+vfp3");
+      CmdArgs.push_back("-target-feature");
+      CmdArgs.push_back("+d16");
+      CmdArgs.push_back("-target-feature");
+      CmdArgs.push_back("-neon");
+    } else if (FPU == "vfp") {
+      CmdArgs.push_back("-target-feature");
+      CmdArgs.push_back("+vfp2");
+      CmdArgs.push_back("-target-feature");
+      CmdArgs.push_back("-neon");
+    } else if (FPU == "vfp3" || FPU == "vfpv3") {
+      CmdArgs.push_back("-target-feature");
+      CmdArgs.push_back("+vfp3");
+      CmdArgs.push_back("-target-feature");
+      CmdArgs.push_back("-neon");
+    } else if (FPU == "neon") {
+      CmdArgs.push_back("-target-feature");
+      CmdArgs.push_back("+neon");
+    } else
+      D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
+  }
+}
+
 void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
                            const InputInfo &Output,
                            const InputInfoList &Inputs,
@@ -2581,6 +2631,17 @@
   if (UseRelaxAll(C, Args))
     CmdArgs.push_back("-relax-all");
 
+  // Add target specific cpu and features flags.
+  switch(getToolChain().getTriple().getArch()) {
+  default:
+    break;
+
+  case llvm::Triple::arm:
+  case llvm::Triple::thumb:
+    AddARMTargetArgs(Args, CmdArgs);
+    break;
+  }
+
   // Ignore explicit -force_cpusubtype_ALL option.
   (void) Args.hasArg(options::OPT_force__cpusubtype__ALL);
 
diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h
index fac524d..e607acb 100644
--- a/lib/Driver/Tools.h
+++ b/lib/Driver/Tools.h
@@ -59,6 +59,7 @@
 
   /// \brief Clang integrated assembler tool.
   class LLVM_LIBRARY_VISIBILITY ClangAs : public Tool {
+    void AddARMTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
   public:
     ClangAs(const ToolChain &TC) : Tool("clang::as",
                                         "clang integrated assembler", TC) {}
diff --git a/test/lit.cfg b/test/lit.cfg
index 726e861..f759275 100644
--- a/test/lit.cfg
+++ b/test/lit.cfg
@@ -32,7 +32,7 @@
 config.test_format = lit.formats.ShTest(execute_external)
 
 # suffixes: A list of file extensions to treat as test files.
-config.suffixes = ['.c', '.cpp', '.m', '.mm', '.cu', '.ll', '.cl']
+config.suffixes = ['.c', '.cpp', '.m', '.mm', '.cu', '.ll', '.cl', '.s']
 
 # test_source_root: The root path where tests are located.
 config.test_source_root = os.path.dirname(__file__)
diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp
index 84aeced..fc8c5dc 100644
--- a/tools/driver/cc1as_main.cpp
+++ b/tools/driver/cc1as_main.cpp
@@ -63,8 +63,17 @@
   /// @name Target Options
   /// @{
 
+  /// The name of the target triple to assemble for.
   std::string Triple;
 
+  /// If given, the name of the target CPU to determine which instructions
+  /// are legal.
+  std::string CPU;
+
+  /// The list of target specific features to enable or disable -- this should
+  /// be a list of strings starting with '+' or '-'.
+  std::vector<std::string> Features;
+
   /// @}
   /// @name Language Options
   /// @{
@@ -158,9 +167,13 @@
   // Construct the invocation.
 
   // Target Options
-  Opts.Triple = Triple::normalize(Args->getLastArgValue(OPT_triple));
-  if (Opts.Triple.empty()) // Use the default target triple if unspecified.
-    Opts.Triple = sys::getDefaultTargetTriple();
+  Opts.Triple = llvm::Triple::normalize(Args->getLastArgValue(OPT_triple));
+  Opts.CPU = Args->getLastArgValue(OPT_target_cpu);
+  Opts.Features = Args->getAllArgValues(OPT_target_feature);
+
+  // Use the default target triple if unspecified.
+  if (Opts.Triple.empty())
+    Opts.Triple = llvm::sys::getDefaultTargetTriple();
 
   // Language Options
   Opts.IncludePaths = Args->getAllArgValues(OPT_I);
@@ -293,11 +306,19 @@
   if (!Opts.DwarfDebugFlags.empty())
     Ctx.setDwarfDebugFlags(StringRef(Opts.DwarfDebugFlags));
 
+  // Build up the feature string from the target feature list.
+  std::string FS;
+  if (!Opts.Features.empty()) {
+    FS = Opts.Features[0];
+    for (unsigned i = 1, e = Opts.Features.size(); i != e; ++i)
+      FS += "," + Opts.Features[i];
+  }
+
   OwningPtr<MCStreamer> Str;
 
   OwningPtr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
   OwningPtr<MCSubtargetInfo>
-    STI(TheTarget->createMCSubtargetInfo(Opts.Triple, "", ""));
+    STI(TheTarget->createMCSubtargetInfo(Opts.Triple, Opts.CPU, FS));
 
   // FIXME: There is a bit of code duplication with addPassesToEmitFile.
   if (Opts.OutputType == AssemblerInvocation::FT_Asm) {