gollvm: pass arch info to the integrated assembler

Currently, architecture information is passed to the compiler but not
the integrated assembler, causing discrepancies in the ABI chosen by
the two tools, especially on the RISC-V platform.

This patch makes sure both share the same architecture information.

Change-Id: I29f441e86e06f1f0b46c3ea62576a7d1291c2ce4
Reviewed-on: https://go-review.googlesource.com/c/gollvm/+/425854
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
diff --git a/driver/ArchCpuSetup.cpp b/driver/ArchCpuSetup.cpp
new file mode 100644
index 0000000..a7eb765
--- /dev/null
+++ b/driver/ArchCpuSetup.cpp
@@ -0,0 +1,71 @@
+//===-- ArchCpuSetup.cpp --------------------------------------------------===//
+//
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+//===----------------------------------------------------------------------===//
+//
+// Gollvm driver helper function setupArchCpu
+//
+//===----------------------------------------------------------------------===//
+
+#include "ArchCpuSetup.h"
+
+#include "llvm/Option/Arg.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace gollvm { namespace arch {
+#include "ArchCpusAttrs.h"
+} }
+
+using namespace llvm;
+
+bool gollvm::driver::setupArchCpu(opt::Arg *cpuarg, std::string &cpu,
+                               std::string &attrs, Triple triple,
+                               const char *progname) {
+  std::string cpuStr;
+  if (cpuarg != nullptr) {
+    std::string val(cpuarg->getValue());
+    if (val == "native")
+      cpuStr = sys::getHostCPUName().str();
+    else
+      cpuStr = cpuarg->getValue();
+  }
+
+  // Locate correct entry in architectures table for this triple
+  const gollvm::arch::CpuAttrs *cpuAttrs = nullptr;
+  for (unsigned i = 0; gollvm::arch::triples[i].cpuattrs != nullptr; i += 1) {
+    if (!strcmp(triple.str().c_str(), gollvm::arch::triples[i].triple)) {
+      cpuAttrs = gollvm::arch::triples[i].cpuattrs;
+      break;
+    }
+  }
+  if (cpuAttrs == nullptr) {
+    errs() << progname << ": unable to determine target CPU features for "
+           << "target " << triple.str() << "\n";
+    return false;
+  }
+
+  // If no CPU specified, use first entry. Otherwise look for CPU name.
+  if (!cpuStr.empty()) {
+    bool found = false;
+    while (strlen(cpuAttrs->cpu) != 0) {
+      if (!strcmp(cpuAttrs->cpu, cpuStr.c_str())) {
+        // found
+        found = true;
+        break;
+      }
+      cpuAttrs++;
+    }
+    if (!found) {
+      errs() << progname << ": invalid setting for -march:"
+             << " -- unable to identify CPU '" << cpuStr << "'\n";
+      return false;
+    }
+  }
+  cpu = cpuAttrs->cpu;
+  attrs = cpuAttrs->attrs;
+  return true;
+}
diff --git a/driver/ArchCpuSetup.h b/driver/ArchCpuSetup.h
new file mode 100644
index 0000000..7129c04
--- /dev/null
+++ b/driver/ArchCpuSetup.h
@@ -0,0 +1,27 @@
+//===-- ArchCpuSetup.cpp --------------------------------------------------===//
+//
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+//===----------------------------------------------------------------------===//
+//
+// Declares gollvm driver helper function setupArchCpu.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef GOLLVM_DRIVER_ARCHCPUSETUP_H
+#define GOLLVM_DRIVER_ARCHCPUSETUP_H
+
+#include "Tool.h"
+
+namespace gollvm {
+namespace driver {
+
+bool setupArchCpu(llvm::opt::Arg *cpuarg, std::string &cpu, std::string &attrs,
+               llvm::Triple triple_, const char *progname_);
+
+} // end namespace driver
+} // end namespace gollvm
+
+#endif
diff --git a/driver/CMakeLists.txt b/driver/CMakeLists.txt
index c6429df..62b457a 100644
--- a/driver/CMakeLists.txt
+++ b/driver/CMakeLists.txt
@@ -26,6 +26,7 @@
 # A library containing driver utility code.
 add_llvm_library(LLVMDriverUtils
   Action.cpp
+  ArchCpuSetup.cpp
   Artifact.cpp
   Command.cpp
   Compilation.cpp
diff --git a/driver/CompileGo.cpp b/driver/CompileGo.cpp
index 6affe49..b317c9b 100644
--- a/driver/CompileGo.cpp
+++ b/driver/CompileGo.cpp
@@ -22,6 +22,7 @@
 #include "GollvmPasses.h"
 
 #include "Action.h"
+#include "ArchCpuSetup.h"
 #include "Artifact.h"
 #include "Driver.h"
 #include "ToolChain.h"
@@ -466,49 +467,9 @@
   Options.AllowFPOpFusion = *dofuse;
 
   // Support -march
-  std::string cpuStr;
   opt::Arg *cpuarg = args_.getLastArg(gollvm::options::OPT_march_EQ);
-  if (cpuarg != nullptr) {
-    std::string val(cpuarg->getValue());
-    if (val == "native")
-      cpuStr = sys::getHostCPUName().str();
-    else
-      cpuStr = cpuarg->getValue();
-  }
-
-  // Locate correct entry in architectures table for this triple
-  const gollvm::arch::CpuAttrs *cpuAttrs = nullptr;
-  for (unsigned i = 0; gollvm::arch::triples[i].cpuattrs != nullptr; i += 1) {
-    if (!strcmp(triple_.str().c_str(), gollvm::arch::triples[i].triple)) {
-      cpuAttrs = gollvm::arch::triples[i].cpuattrs;
-      break;
-    }
-  }
-  if (cpuAttrs == nullptr) {
-    errs() << progname_ << ": unable to determine target CPU features for "
-           << "target " << triple_.str() << "\n";
+  if (!setupArchCpu(cpuarg, targetCpuAttr_, targetFeaturesAttr_, triple_, progname_))
     return false;
-  }
-
-  // If no CPU specified, use first entry. Otherwise look for CPU name.
-  if (!cpuStr.empty()) {
-    bool found = false;
-    while (strlen(cpuAttrs->cpu) != 0) {
-      if (!strcmp(cpuAttrs->cpu, cpuStr.c_str())) {
-        // found
-        found = true;
-        break;
-      }
-      cpuAttrs++;
-    }
-    if (!found) {
-      errs() << progname_ << ": invalid setting for -march:"
-             << " -- unable to identify CPU '" << cpuStr << "'\n";
-      return false;
-    }
-  }
-  targetCpuAttr_ = cpuAttrs->cpu;
-  targetFeaturesAttr_ = cpuAttrs->attrs;
 
   // Create target machine
   Optional<llvm::CodeModel::Model> CM = None;
diff --git a/driver/Driver.cpp b/driver/Driver.cpp
index 8debbab..777cc2b 100644
--- a/driver/Driver.cpp
+++ b/driver/Driver.cpp
@@ -186,7 +186,8 @@
       continue;
     }
     if (value.startswith("-compress-debug-sections") ||
-        value.startswith("--compress-debug-sections")) {
+        value.startswith("--compress-debug-sections") ||
+        value.startswith("-march")) {
       continue;
     }
     // Unrecognized -Wa,... option
diff --git a/driver/IntegAssembler.cpp b/driver/IntegAssembler.cpp
index 39d080f..a40be9f 100644
--- a/driver/IntegAssembler.cpp
+++ b/driver/IntegAssembler.cpp
@@ -22,6 +22,7 @@
 #include "GollvmPasses.h"
 
 #include "Action.h"
+#include "ArchCpuSetup.h"
 #include "Artifact.h"
 #include "Driver.h"
 #include "ToolChain.h"
@@ -185,16 +186,6 @@
   // Note: -Xassembler and -Wa, options should already have been
   // examined at this point.
 
-  // FIXME: no support yet for -march (bring over from CompileGo.cpp)
-  opt::Arg *cpuarg = args_.getLastArg(gollvm::options::OPT_march_EQ);
-  if (cpuarg != nullptr) {
-    errs() << progname_ << ": internal error: option '"
-           <<  cpuarg->getAsString(args_)
-           << "' not yet implemented in integrated assembler\n";
-    assert(false);
-    return false;
-  }
-
   // Support for compressed debug.
   llvm::DebugCompressionType CompressDebugSections =
       llvm::DebugCompressionType::None;
@@ -208,6 +199,8 @@
   // Build up the feature string from the target feature list.
   std::string FS;
   std::string CPU;
+  opt::Arg *cpuarg = args_.getLastArg(gollvm::options::OPT_march_EQ);
+  setupArchCpu(cpuarg, CPU, FS, triple_, progname_);
   std::unique_ptr<MCStreamer> Str;
   std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
   std::unique_ptr<MCSubtargetInfo> STI(