about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_llvm/build.rs1
-rw-r--r--src/librustc_llvm/ffi.rs10
-rw-r--r--src/librustc_trans/back/lto.rs40
-rw-r--r--src/rustllvm/Linker.cpp72
-rw-r--r--src/rustllvm/RustWrapper.cpp40
5 files changed, 114 insertions, 49 deletions
diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs
index 49b93f3c7d6..54e3f544acb 100644
--- a/src/librustc_llvm/build.rs
+++ b/src/librustc_llvm/build.rs
@@ -155,6 +155,7 @@ fn main() {
     cfg.file("../rustllvm/PassWrapper.cpp")
        .file("../rustllvm/RustWrapper.cpp")
        .file("../rustllvm/ArchiveWrapper.cpp")
+       .file("../rustllvm/Linker.cpp")
        .cpp(true)
        .cpp_link_stdlib(None) // we handle this below
        .compile("rustllvm");
diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs
index 99e43a2ddf9..e71bef512cf 100644
--- a/src/librustc_llvm/ffi.rs
+++ b/src/librustc_llvm/ffi.rs
@@ -444,6 +444,9 @@ pub type RustArchiveMemberRef = *mut RustArchiveMember_opaque;
 #[allow(missing_copy_implementations)]
 pub enum OperandBundleDef_opaque {}
 pub type OperandBundleDefRef = *mut OperandBundleDef_opaque;
+#[allow(missing_copy_implementations)]
+pub enum Linker_opaque {}
+pub type LinkerRef = *mut Linker_opaque;
 
 pub type DiagnosticHandler = unsafe extern "C" fn(DiagnosticInfoRef, *mut c_void);
 pub type InlineAsmDiagHandler = unsafe extern "C" fn(SMDiagnosticRef, *const c_void, c_uint);
@@ -1608,7 +1611,6 @@ extern "C" {
     pub fn LLVMRustPrintPasses();
     pub fn LLVMRustSetNormalizedTarget(M: ModuleRef, triple: *const c_char);
     pub fn LLVMRustAddAlwaysInlinePass(P: PassManagerBuilderRef, AddLifetimes: bool);
-    pub fn LLVMRustLinkInExternalBitcode(M: ModuleRef, bc: *const c_char, len: size_t) -> bool;
     pub fn LLVMRustRunRestrictionPass(M: ModuleRef, syms: *const *const c_char, len: size_t);
     pub fn LLVMRustMarkAllFunctionsNounwind(M: ModuleRef);
 
@@ -1724,4 +1726,10 @@ extern "C" {
                                            CU2: *mut *mut c_void);
     pub fn LLVMRustThinLTOPatchDICompileUnit(M: ModuleRef, CU: *mut c_void);
     pub fn LLVMRustThinLTORemoveAvailableExternally(M: ModuleRef);
+
+    pub fn LLVMRustLinkerNew(M: ModuleRef) -> LinkerRef;
+    pub fn LLVMRustLinkerAdd(linker: LinkerRef,
+                             bytecode: *const c_char,
+                             bytecode_len: usize) -> bool;
+    pub fn LLVMRustLinkerFree(linker: LinkerRef);
 }
diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs
index 9ff5bcf7a33..a3327038019 100644
--- a/src/librustc_trans/back/lto.rs
+++ b/src/librustc_trans/back/lto.rs
@@ -247,22 +247,20 @@ fn fat_lto(cgcx: &CodegenContext,
     // know much about the memory management here so we err on the side of being
     // save and persist everything with the original module.
     let mut serialized_bitcode = Vec::new();
+    let mut linker = Linker::new(llmod);
     for (bc_decoded, name) in serialized_modules {
         info!("linking {:?}", name);
-        time(cgcx.time_passes, &format!("ll link {:?}", name), || unsafe {
+        time(cgcx.time_passes, &format!("ll link {:?}", name), || {
             let data = bc_decoded.data();
-            if llvm::LLVMRustLinkInExternalBitcode(llmod,
-                                                   data.as_ptr() as *const libc::c_char,
-                                                   data.len() as libc::size_t) {
-                Ok(())
-            } else {
+            linker.add(&data).map_err(|()| {
                 let msg = format!("failed to load bc of {:?}", name);
-                Err(write::llvm_err(&diag_handler, msg))
-            }
+                write::llvm_err(&diag_handler, msg)
+            })
         })?;
         timeline.record(&format!("link {:?}", name));
         serialized_bitcode.push(bc_decoded);
     }
+    drop(linker);
     cgcx.save_temp_bitcode(&module, "lto.input");
 
     // Internalize everything that *isn't* in our whitelist to help strip out
@@ -289,6 +287,32 @@ fn fat_lto(cgcx: &CodegenContext,
     }])
 }
 
+struct Linker(llvm::LinkerRef);
+
+impl Linker {
+    fn new(llmod: ModuleRef) -> Linker {
+        unsafe { Linker(llvm::LLVMRustLinkerNew(llmod)) }
+    }
+
+    fn add(&mut self, bytecode: &[u8]) -> Result<(), ()> {
+        unsafe {
+            if llvm::LLVMRustLinkerAdd(self.0,
+                                       bytecode.as_ptr() as *const libc::c_char,
+                                       bytecode.len()) {
+                Ok(())
+            } else {
+                Err(())
+            }
+        }
+    }
+}
+
+impl Drop for Linker {
+    fn drop(&mut self) {
+        unsafe { llvm::LLVMRustLinkerFree(self.0); }
+    }
+}
+
 /// Prepare "thin" LTO to get run on these modules.
 ///
 /// The general structure of ThinLTO is quite different from the structure of
diff --git a/src/rustllvm/Linker.cpp b/src/rustllvm/Linker.cpp
new file mode 100644
index 00000000000..534e4b91090
--- /dev/null
+++ b/src/rustllvm/Linker.cpp
@@ -0,0 +1,72 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#include "llvm/Linker/Linker.h"
+
+#include "rustllvm.h"
+
+using namespace llvm;
+
+struct RustLinker {
+  Linker L;
+  LLVMContext &Ctx;
+
+  RustLinker(Module &M) :
+    L(M),
+    Ctx(M.getContext())
+  {}
+};
+
+extern "C" RustLinker*
+LLVMRustLinkerNew(LLVMModuleRef DstRef) {
+  Module *Dst = unwrap(DstRef);
+
+  auto Ret = llvm::make_unique<RustLinker>(*Dst);
+  return Ret.release();
+}
+
+extern "C" void
+LLVMRustLinkerFree(RustLinker *L) {
+  delete L;
+}
+
+extern "C" bool
+LLVMRustLinkerAdd(RustLinker *L, char *BC, size_t Len) {
+  std::unique_ptr<MemoryBuffer> Buf =
+      MemoryBuffer::getMemBufferCopy(StringRef(BC, Len));
+
+#if LLVM_VERSION_GE(4, 0)
+  Expected<std::unique_ptr<Module>> SrcOrError =
+      llvm::getLazyBitcodeModule(Buf->getMemBufferRef(), L->Ctx);
+  if (!SrcOrError) {
+    LLVMRustSetLastError(toString(SrcOrError.takeError()).c_str());
+    return false;
+  }
+
+  auto Src = std::move(*SrcOrError);
+#else
+  ErrorOr<std::unique_ptr<Module>> Src =
+      llvm::getLazyBitcodeModule(std::move(Buf), L->Ctx);
+  if (!Src) {
+    LLVMRustSetLastError(Src.getError().message().c_str());
+    return false;
+  }
+#endif
+
+#if LLVM_VERSION_GE(4, 0)
+  if (L->L.linkInModule(std::move(Src))) {
+#else
+  if (L->L.linkInModule(std::move(Src.get()))) {
+#endif
+    LLVMRustSetLastError("");
+    return false;
+  }
+  return true;
+}
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index 4dfc4029d75..27d5496f576 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -916,46 +916,6 @@ extern "C" void LLVMRustWriteValueToString(LLVMValueRef V,
   }
 }
 
-extern "C" bool LLVMRustLinkInExternalBitcode(LLVMModuleRef DstRef, char *BC,
-                                              size_t Len) {
-  Module *Dst = unwrap(DstRef);
-
-  std::unique_ptr<MemoryBuffer> Buf =
-      MemoryBuffer::getMemBufferCopy(StringRef(BC, Len));
-
-#if LLVM_VERSION_GE(4, 0)
-  Expected<std::unique_ptr<Module>> SrcOrError =
-      llvm::getLazyBitcodeModule(Buf->getMemBufferRef(), Dst->getContext());
-  if (!SrcOrError) {
-    LLVMRustSetLastError(toString(SrcOrError.takeError()).c_str());
-    return false;
-  }
-
-  auto Src = std::move(*SrcOrError);
-#else
-  ErrorOr<std::unique_ptr<Module>> Src =
-      llvm::getLazyBitcodeModule(std::move(Buf), Dst->getContext());
-  if (!Src) {
-    LLVMRustSetLastError(Src.getError().message().c_str());
-    return false;
-  }
-#endif
-
-  std::string Err;
-
-  raw_string_ostream Stream(Err);
-  DiagnosticPrinterRawOStream DP(Stream);
-#if LLVM_VERSION_GE(4, 0)
-  if (Linker::linkModules(*Dst, std::move(Src))) {
-#else
-  if (Linker::linkModules(*Dst, std::move(Src.get()))) {
-#endif
-    LLVMRustSetLastError(Err.c_str());
-    return false;
-  }
-  return true;
-}
-
 // Note that the two following functions look quite similar to the
 // LLVMGetSectionName function. Sadly, it appears that this function only
 // returns a char* pointer, which isn't guaranteed to be null-terminated. The