Add --plugin-opt=emit-llvm option.

`--plugin-opt=emit-llvm` is an option for LTO. It makes the linker to
combine all bitcode files and write the result to an output file without
doing codegen. Gold LTO plugin has this option.

This option is being used for some post-link code analysis tools that
have to see a whole program but don't need to see them in the native
machine code.

Differential Revision: https://reviews.llvm.org/D55717

git-svn-id: https://llvm.org/svn/llvm-project/lld/trunk@349198 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/ELF/Config.h b/ELF/Config.h
index 37f713f..8fb760e 100644
--- a/ELF/Config.h
+++ b/ELF/Config.h
@@ -135,6 +135,7 @@
   bool Demangle = true;
   bool DisableVerify;
   bool EhFrameHdr;
+  bool EmitLLVM;
   bool EmitRelocs;
   bool EnableNewDtags;
   bool ExecuteOnly;
diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp
index 37fab4c..a858241 100644
--- a/ELF/Driver.cpp
+++ b/ELF/Driver.cpp
@@ -776,6 +776,7 @@
   Config->DynamicLinker = getDynamicLinker(Args);
   Config->EhFrameHdr =
       Args.hasFlag(OPT_eh_frame_hdr, OPT_no_eh_frame_hdr, false);
+  Config->EmitLLVM = Args.hasArg(OPT_plugin_opt_emit_llvm, false);
   Config->EmitRelocs = Args.hasArg(OPT_emit_relocs);
   Config->CallGraphProfileSort = Args.hasFlag(
       OPT_call_graph_profile_sort, OPT_no_call_graph_profile_sort, true);
@@ -1581,6 +1582,12 @@
   if (Config->ThinLTOIndexOnly)
     return;
 
+  // Likewise, --plugin-opt=emit-llvm is an option to make LTO create
+  // an output file in bitcode and exit, so that you can just get a
+  // combined bitcode file.
+  if (Config->EmitLLVM)
+    return;
+
   // Apply symbol renames for -wrap.
   if (!Wrapped.empty())
     wrapSymbols<ELFT>(Wrapped);
diff --git a/ELF/LTO.cpp b/ELF/LTO.cpp
index c3e59b5..ca44581 100644
--- a/ELF/LTO.cpp
+++ b/ELF/LTO.cpp
@@ -103,6 +103,14 @@
   C.DebugPassManager = Config->LTODebugPassManager;
   C.DwoDir = Config->DwoDir;
 
+  if (Config->EmitLLVM) {
+    C.PostInternalizeModuleHook = [](size_t Task, const Module &M) {
+      if (std::unique_ptr<raw_fd_ostream> OS = openFile(Config->OutputFile))
+        WriteBitcodeToFile(M, *OS, false);
+      return false;
+    };
+  }
+
   if (Config->SaveTemps)
     checkError(C.addSaveTemps(Config->OutputFile.str() + ".",
                               /*UseInputModulePath*/ true));
diff --git a/ELF/Options.td b/ELF/Options.td
index 27cbade..e43a21b 100644
--- a/ELF/Options.td
+++ b/ELF/Options.td
@@ -458,6 +458,7 @@
 def: F<"plugin-opt=disable-verify">, Alias<disable_verify>, HelpText<"Alias for -disable-verify">;
 def plugin_opt_dwo_dir_eq: J<"plugin-opt=dwo_dir=">,
   HelpText<"Directory to store .dwo files when LTO and debug fission are used">;
+def plugin_opt_emit_llvm: F<"plugin-opt=emit-llvm">;
 def: J<"plugin-opt=jobs=">, Alias<thinlto_jobs>, HelpText<"Alias for -thinlto-jobs">;
 def: J<"plugin-opt=lto-partitions=">, Alias<lto_partitions>, HelpText<"Alias for -lto-partitions">;
 def plugin_opt_mcpu_eq: J<"plugin-opt=mcpu=">;
diff --git a/test/ELF/lto/emit-llvm.ll b/test/ELF/lto/emit-llvm.ll
new file mode 100644
index 0000000..bf38c98
--- /dev/null
+++ b/test/ELF/lto/emit-llvm.ll
@@ -0,0 +1,14 @@
+; REQUIRES: x86
+
+; RUN: opt -module-hash -module-summary %s -o %t.o
+; RUN: ld.lld --plugin-opt=emit-llvm -o %t.out.o %t.o
+; RUN: llvm-dis < %t.out.o -o - | FileCheck %s
+
+; CHECK: define internal void @main()
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @main() {
+  ret void
+}