gollvm: support debug compression options for integ assembler

Add support for accepting the -Wa,--compress-debug-sections option
in combination with the integrated assembler.

Change-Id: Ib0b1bab8297626f10b416a1024fb44056a7135bf
Reviewed-on: https://go-review.googlesource.com/c/gollvm/+/260736
Trust: Than McIntosh <thanm@google.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
diff --git a/driver/CompileGo.cpp b/driver/CompileGo.cpp
index a270d83..6510b72 100644
--- a/driver/CompileGo.cpp
+++ b/driver/CompileGo.cpp
@@ -414,6 +414,10 @@
   assert(jat == Action::A_CompileAndAssemble ||
          jat == Action::A_Compile);
   Options.DisableIntegratedAS = !(jat == Action::A_CompileAndAssemble);
+  llvm::DebugCompressionType dct = llvm::DebugCompressionType::None;
+  if (!driver_.determineDebugCompressionType(&dct))
+    return false;
+  Options.CompressDebugSections = dct;
 
   // FIXME: this hard-wires on the equivalent of -ffunction-sections
   // and -fdata-sections, since there doesn't seem to be a high-level
diff --git a/driver/Driver.cpp b/driver/Driver.cpp
index 13e7cf7..e8aa35a 100644
--- a/driver/Driver.cpp
+++ b/driver/Driver.cpp
@@ -163,17 +163,104 @@
   if (arg != nullptr)
     return arg->getOption().matches(options::OPT_fintegrated_as);
 
-  // If -Xassembler or -Wa,... used, then don't use the integrated
-  // assembler, since the driver doesn't support the full complement
-  // of assembler options (this can be removed if/when we do).
-  auto waComArg = args_.getLastArg(gollvm::options::OPT_Wa_COMMA);
-  auto xAsmArg = args_.getLastArg(gollvm::options::OPT_Xassembler);
-  if (waComArg != nullptr || xAsmArg != nullptr)
+  // If -Xassembler or -Wa,... is used with an unsupported asm option then don't
+  // use the integrated assembler, since the driver doesn't support the full
+  // complement of assembler options (this can be removed if/when a more
+  // complete set is implemented).
+  if (!supportedAsmOptions())
     return false;
 
   return true;
 }
 
+// Returns TRUE if the assembler options given on the command line fall into the
+// subset that we support, FALSE otherwise. At the moment the driver handles a
+// very limited set of -Wa,... options, mainly --compress-debug-sections.
+bool Driver::supportedAsmOptions()
+{
+  for (const opt::Arg *arg : args_.filtered(gollvm::options::OPT_Wa_COMMA,
+                                            gollvm::options::OPT_Xassembler)) {
+    auto value = llvm::StringRef(arg->getValue());
+    if (value == "-nocompress-debug-sections" ||
+        value == "--nocompress-debug-sections") {
+      continue;
+    }
+    if (value.startswith("-compress-debug-sections") ||
+        value.startswith("--compress-debug-sections")) {
+      continue;
+    }
+    // Unrecognized -Wa,... option
+    return false;
+  }
+  return true;
+}
+
+// Convert a "-gz=" argument to llvm::DebugCompressionType. Returns
+// its second argument if ok, nullptr if a bad argument is given (and
+// issues an error in this case).
+llvm::DebugCompressionType *Driver::gzArgToDCT(llvm::StringRef ga,
+                                               llvm::DebugCompressionType *dct,
+                                               const char *which)
+{
+  if (ga == "zlib") {
+    *dct = llvm::DebugCompressionType::Z;
+    return dct;
+  } else if (ga == "zlib-gnu") {
+    *dct = llvm::DebugCompressionType::GNU;
+    return dct;
+  } else if (ga == "none") {
+    *dct = llvm::DebugCompressionType::None;
+    return dct;
+  } else {
+    errs() << progname_ << ": error: Invalid " << which
+           << " argument '" << ga << "'\n";
+    return nullptr;
+  }
+}
+
+// This method sifts through the command line from left to right and picks out
+// arguments related to debug info compression (-gz,
+// -Wa,--compress-debug-sections, etc), with the rightmost setting taking
+// precedence. If an invalid argument is suplied to '-gz=' or related, we return
+// FALSE; otherwise return TRUE with a possibly updated value stored to "*dct".
+bool Driver::determineDebugCompressionType(llvm::DebugCompressionType *dct)
+{
+  for (const opt::Arg *arg : args_.filtered(gollvm::options::OPT_gz,
+                                            gollvm::options::OPT_gz_EQ,
+                                            gollvm::options::OPT_Wa_COMMA,
+                                            gollvm::options::OPT_Xassembler)) {
+    if (arg->getOption().matches(gollvm::options::OPT_gz)) {
+      *dct = llvm::DebugCompressionType::GNU;
+    } else if (arg->getOption().matches(gollvm::options::OPT_gz_EQ)) {
+      auto value = llvm::StringRef(arg->getValue());
+     if (gzArgToDCT(value, dct, "-gz=") == nullptr)
+        return false;
+    } else if (arg->getOption().matches(gollvm::options::OPT_Wa_COMMA) ||
+               arg->getOption().matches(gollvm::options::OPT_Xassembler)) {
+      auto value = llvm::StringRef(arg->getValue());
+      if (value == "-nocompress-debug-sections" ||
+          value == "--nocompress-debug-sections") {
+        *dct = llvm::DebugCompressionType::None;
+      } else if (value.startswith("-compress-debug-sections") ||
+                 value.startswith("--compress-debug-sections")) {
+        const char *wh =
+            (arg->getOption().matches(gollvm::options::OPT_Xassembler) ?
+             "-Xassembler" : "-Wa,");
+        value.consume_front("--compress-debug-sections");
+        value.consume_front("-compress-debug-sections");
+        auto arg = value;
+        if (value.startswith("="))
+          arg.consume_front("=");
+        else
+          arg = "zlib";
+        if (gzArgToDCT(arg, dct, wh) == nullptr)
+          return false;
+      }
+    }
+  }
+  return true;
+}
+
 // FIXME: some  platforms have PIE enabled by default; we don't
 // yet support auto-detection of such platforms.
 
diff --git a/driver/Driver.h b/driver/Driver.h
index 34ce9d4..3b2813d 100644
--- a/driver/Driver.h
+++ b/driver/Driver.h
@@ -109,6 +109,8 @@
   bool picIsPIE();
   bool isPIE();
   bool useIntegratedAssembler();
+  bool supportedAsmOptions();
+  bool determineDebugCompressionType(llvm::DebugCompressionType *dct);
   bool usingSplitStack() const { return usingSplitStack_; }
   template<typename IT>
   llvm::Optional<IT> getLastArgAsInteger(gollvm::options::ID id,
@@ -148,6 +150,9 @@
 
   bool processAction(Action *act, Compilation &compilation, bool lastAct);
   ArtifactList collectInputArtifacts(Action *act, InternalTool *it);
+  llvm::DebugCompressionType *gzArgToDCT(llvm::StringRef ga,
+                                         llvm::DebugCompressionType *dct,
+                                         const char *which);
 };
 
 template<typename IT>
diff --git a/driver/IntegAssembler.cpp b/driver/IntegAssembler.cpp
index 5ba554b..f6262c8 100644
--- a/driver/IntegAssembler.cpp
+++ b/driver/IntegAssembler.cpp
@@ -181,19 +181,8 @@
       TheTarget->createMCAsmInfo(*MRI, Trip, MCOptions));
   assert(MAI && "Unable to create target asm info!");
 
-  // FIXME: at this point what we need to do is collect up any assembler
-  // arguments specified with -Wa,XXX and turn them into the correct
-  // back end setup options. For now, just assert if we see -Wa.
-  auto waComArg = args_.getLastArg(gollvm::options::OPT_Wa_COMMA);
-  auto xAsmArg = args_.getLastArg(gollvm::options::OPT_Xassembler);
-  if (waComArg != nullptr || xAsmArg != nullptr) {
-    errs() << progname_ << ": internal error: option '"
-           <<  (waComArg != nullptr ? waComArg->getAsString(args_) :
-                xAsmArg->getAsString(args_))
-           << "' not yet implemented in integrated assembler\n";
-    assert(false);
-    return false;
-  }
+  // 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);
@@ -208,23 +197,8 @@
   // Support for compressed debug.
   llvm::DebugCompressionType CompressDebugSections =
       llvm::DebugCompressionType::None;
-  llvm::opt::Arg *gzarg = args_.getLastArg(gollvm::options::OPT_gz,
-                                           gollvm::options::OPT_gz_EQ);
-  if (gzarg != nullptr) {
-    if (gzarg->getOption().matches(gollvm::options::OPT_gz)) {
-      CompressDebugSections = llvm::DebugCompressionType::GNU;
-    } else {
-      std::string ga(gzarg->getValue());
-      if (ga == "zlib") {
-        CompressDebugSections = llvm::DebugCompressionType::Z;
-      } else if (ga == "zlib-gnu") {
-        CompressDebugSections = llvm::DebugCompressionType::GNU;
-      } else if (ga != "none") {
-        errs() << progname_ << ": error: Invalid -Wa,--compress-debug-sections"
-               << " argument '" << ga << "'\n";
-      }
-    }
-  }
+  if (!driver_.determineDebugCompressionType(&CompressDebugSections))
+    return false;
 
   // Ensure MCAsmInfo initialization occurs before any use, otherwise sections
   // may be created with a combination of default and explicit settings.