rust/src/rustllvm/RustWrapper.cpp

1013 lines
30 KiB
C++
Raw Normal View History

// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2012-12-10 23:44:02 +00:00
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
2012-12-10 23:44:02 +00:00
// 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 "rustllvm.h"
rustc: Optimize reading metadata by 4x We were previously reading metadata via `ar p`, but as learned from rustdoc awhile back, spawning a process to do something is pretty slow. Turns out LLVM has an Archive class to read archives, but it cannot write archives. This commits adds bindings to the read-only version of the LLVM archive class (with a new type that only has a read() method), and then it uses this class when reading the metadata out of rlibs. When you put this in tandem of not compressing the metadata, reading the metadata is 4x faster than it used to be The timings I got for reading metadata from the respective libraries was: libstd-04ff901e-0.9-pre.dylib => 100ms libstd-04ff901e-0.9-pre.rlib => 23ms librustuv-7945354c-0.9-pre.dylib => 4ms librustuv-7945354c-0.9-pre.rlib => 1ms librustc-5b94a16f-0.9-pre.dylib => 87ms librustc-5b94a16f-0.9-pre.rlib => 35ms libextra-a6ebb16f-0.9-pre.dylib => 63ms libextra-a6ebb16f-0.9-pre.rlib => 15ms libsyntax-2e4c0458-0.9-pre.dylib => 86ms libsyntax-2e4c0458-0.9-pre.rlib => 22ms In order to always take advantage of these faster metadata read-times, I sort the files in filesearch based on whether they have an rlib extension or not (prefer all rlib files first). Overall, this halved the compile time for a `fn main() {}` crate from 0.185s to 0.095s on my system (when preferring dynamic linking). Reading metadata is still the slowest pass of the compiler at 0.035s, but it's getting pretty close to linking at 0.021s! The next best optimization is to just not copy the metadata from LLVM because that's the most expensive part of reading metadata right now.
2013-12-17 04:58:21 +00:00
#include "llvm/Object/Archive.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/DiagnosticPrinter.h"
#if LLVM_VERSION_MINOR >= 5
#include "llvm/IR/CallSite.h"
#else
#include "llvm/Support/CallSite.h"
#endif
//===----------------------------------------------------------------------===
//
// This file defines alternate interfaces to core functions that are more
// readily callable by Rust's FFI.
//
//===----------------------------------------------------------------------===
using namespace llvm;
using namespace llvm::sys;
rustc: Optimize reading metadata by 4x We were previously reading metadata via `ar p`, but as learned from rustdoc awhile back, spawning a process to do something is pretty slow. Turns out LLVM has an Archive class to read archives, but it cannot write archives. This commits adds bindings to the read-only version of the LLVM archive class (with a new type that only has a read() method), and then it uses this class when reading the metadata out of rlibs. When you put this in tandem of not compressing the metadata, reading the metadata is 4x faster than it used to be The timings I got for reading metadata from the respective libraries was: libstd-04ff901e-0.9-pre.dylib => 100ms libstd-04ff901e-0.9-pre.rlib => 23ms librustuv-7945354c-0.9-pre.dylib => 4ms librustuv-7945354c-0.9-pre.rlib => 1ms librustc-5b94a16f-0.9-pre.dylib => 87ms librustc-5b94a16f-0.9-pre.rlib => 35ms libextra-a6ebb16f-0.9-pre.dylib => 63ms libextra-a6ebb16f-0.9-pre.rlib => 15ms libsyntax-2e4c0458-0.9-pre.dylib => 86ms libsyntax-2e4c0458-0.9-pre.rlib => 22ms In order to always take advantage of these faster metadata read-times, I sort the files in filesearch based on whether they have an rlib extension or not (prefer all rlib files first). Overall, this halved the compile time for a `fn main() {}` crate from 0.185s to 0.095s on my system (when preferring dynamic linking). Reading metadata is still the slowest pass of the compiler at 0.035s, but it's getting pretty close to linking at 0.021s! The next best optimization is to just not copy the metadata from LLVM because that's the most expensive part of reading metadata right now.
2013-12-17 04:58:21 +00:00
using namespace llvm::object;
static char *LastError;
#if LLVM_VERSION_MINOR >= 5
extern "C" LLVMMemoryBufferRef
LLVMRustCreateMemoryBufferWithContentsOfFile(const char *Path) {
ErrorOr<std::unique_ptr<MemoryBuffer>> buf_or = MemoryBuffer::getFile(Path,
-1,
false);
if (!buf_or) {
LLVMRustSetLastError(buf_or.getError().message().c_str());
return nullptr;
}
return wrap(buf_or.get().release());
}
#else
extern "C" LLVMMemoryBufferRef
LLVMRustCreateMemoryBufferWithContentsOfFile(const char *Path) {
OwningPtr<MemoryBuffer> buf;
error_code err = MemoryBuffer::getFile(Path, buf, -1, false);
if (err) {
LLVMRustSetLastError(err.message().c_str());
return NULL;
}
return wrap(buf.take());
}
#endif
extern "C" char *LLVMRustGetLastError(void) {
char *ret = LastError;
LastError = NULL;
return ret;
}
void LLVMRustSetLastError(const char *err) {
free((void*) LastError);
LastError = strdup(err);
}
2013-08-23 03:58:42 +00:00
extern "C" void
LLVMRustSetNormalizedTarget(LLVMModuleRef M, const char *triple) {
unwrap(M)->setTargetTriple(Triple::normalize(triple));
}
extern "C" LLVMValueRef LLVMRustConstSmallInt(LLVMTypeRef IntTy, unsigned N,
LLVMBool SignExtend) {
return LLVMConstInt(IntTy, (unsigned long long)N, SignExtend);
}
2011-05-10 23:10:08 +00:00
extern "C" LLVMValueRef LLVMRustConstInt(LLVMTypeRef IntTy,
unsigned N_hi,
unsigned N_lo,
LLVMBool SignExtend) {
unsigned long long N = N_hi;
N <<= 32;
N |= N_lo;
return LLVMConstInt(IntTy, N, SignExtend);
}
2011-05-10 23:10:08 +00:00
extern "C" void LLVMRustPrintPassTimings() {
raw_fd_ostream OS (2, false); // stderr.
TimerGroup::printAll(OS);
}
extern "C" LLVMValueRef LLVMGetOrInsertFunction(LLVMModuleRef M,
const char* Name,
LLVMTypeRef FunctionTy) {
return wrap(unwrap(M)->getOrInsertFunction(Name,
unwrap<FunctionType>(FunctionTy)));
}
extern "C" LLVMTypeRef LLVMMetadataTypeInContext(LLVMContextRef C) {
return wrap(Type::getMetadataTy(*unwrap(C)));
}
extern "C" void LLVMAddCallSiteAttribute(LLVMValueRef Instr, unsigned index, uint64_t Val) {
CallSite Call = CallSite(unwrap<Instruction>(Instr));
AttrBuilder B;
B.addRawValue(Val);
Call.setAttributes(
Call.getAttributes().addAttributes(Call->getContext(), index,
AttributeSet::get(Call->getContext(),
index, B)));
}
#if LLVM_VERSION_MINOR >= 5
extern "C" void LLVMAddDereferenceableCallSiteAttr(LLVMValueRef Instr, unsigned idx, uint64_t b) {
CallSite Call = CallSite(unwrap<Instruction>(Instr));
AttrBuilder B;
B.addDereferenceableAttr(b);
Call.setAttributes(
Call.getAttributes().addAttributes(Call->getContext(), idx,
AttributeSet::get(Call->getContext(),
idx, B)));
}
#else
extern "C" void LLVMAddDereferenceableCallSiteAttr(LLVMValueRef, unsigned, uint64_t) {}
#endif
extern "C" void LLVMAddFunctionAttribute(LLVMValueRef Fn, unsigned index, uint64_t Val) {
Function *A = unwrap<Function>(Fn);
AttrBuilder B;
B.addRawValue(Val);
A->addAttributes(index, AttributeSet::get(A->getContext(), index, B));
}
#if LLVM_VERSION_MINOR >= 5
extern "C" void LLVMAddDereferenceableAttr(LLVMValueRef Fn, unsigned index, uint64_t bytes) {
Function *A = unwrap<Function>(Fn);
AttrBuilder B;
B.addDereferenceableAttr(bytes);
A->addAttributes(index, AttributeSet::get(A->getContext(), index, B));
}
#else
extern "C" void LLVMAddDereferenceableAttr(LLVMValueRef, unsigned, uint64_t) {}
#endif
extern "C" void LLVMAddFunctionAttrString(LLVMValueRef Fn, unsigned index, const char *Name) {
Function *F = unwrap<Function>(Fn);
AttrBuilder B;
B.addAttribute(Name);
F->addAttributes(index, AttributeSet::get(F->getContext(), index, B));
}
extern "C" void LLVMRemoveFunctionAttrString(LLVMValueRef fn, unsigned index, const char *Name) {
Function *f = unwrap<Function>(fn);
LLVMContext &C = f->getContext();
AttrBuilder B;
B.addAttribute(Name);
AttributeSet to_remove = AttributeSet::get(C, index, B);
AttributeSet attrs = f->getAttributes();
f->setAttributes(attrs.removeAttributes(f->getContext(),
index,
to_remove));
}
extern "C" LLVMValueRef LLVMBuildAtomicLoad(LLVMBuilderRef B,
LLVMValueRef source,
const char* Name,
AtomicOrdering order,
unsigned alignment) {
LoadInst* li = new LoadInst(unwrap(source),0);
li->setVolatile(true);
li->setAtomic(order);
li->setAlignment(alignment);
2013-05-17 02:48:24 +00:00
return wrap(unwrap(B)->Insert(li, Name));
}
extern "C" LLVMValueRef LLVMBuildAtomicStore(LLVMBuilderRef B,
LLVMValueRef val,
LLVMValueRef target,
AtomicOrdering order,
unsigned alignment) {
StoreInst* si = new StoreInst(unwrap(val),unwrap(target));
si->setVolatile(true);
si->setAtomic(order);
si->setAlignment(alignment);
return wrap(unwrap(B)->Insert(si));
}
extern "C" LLVMValueRef LLVMBuildAtomicCmpXchg(LLVMBuilderRef B,
LLVMValueRef target,
LLVMValueRef old,
LLVMValueRef source,
AtomicOrdering order,
AtomicOrdering failure_order) {
return wrap(unwrap(B)->CreateAtomicCmpXchg(unwrap(target), unwrap(old),
unwrap(source), order
#if LLVM_VERSION_MINOR >= 5
, failure_order
#endif
));
}
2013-07-28 07:48:16 +00:00
extern "C" LLVMValueRef LLVMBuildAtomicFence(LLVMBuilderRef B, AtomicOrdering order) {
return wrap(unwrap(B)->CreateFence(order));
}
extern "C" void LLVMSetDebug(int Enabled) {
#ifndef NDEBUG
DebugFlag = Enabled;
#endif
}
2013-03-10 06:37:50 +00:00
extern "C" LLVMValueRef LLVMInlineAsm(LLVMTypeRef Ty,
char *AsmString,
char *Constraints,
LLVMBool HasSideEffects,
2013-03-10 08:38:29 +00:00
LLVMBool IsAlignStack,
unsigned Dialect) {
2013-03-10 06:37:50 +00:00
return wrap(InlineAsm::get(unwrap<FunctionType>(Ty), AsmString,
Constraints, HasSideEffects,
IsAlignStack, (InlineAsm::AsmDialect) Dialect));
2013-03-10 06:37:50 +00:00
}
2013-06-14 18:38:29 +00:00
typedef DIBuilder* DIBuilderRef;
2015-01-30 18:25:07 +00:00
#if LLVM_VERSION_MINOR >= 6
typedef struct LLVMOpaqueMetadata *LLVMMetadataRef;
namespace llvm {
DEFINE_ISA_CONVERSION_FUNCTIONS(Metadata, LLVMMetadataRef)
inline Metadata **unwrap(LLVMMetadataRef *Vals) {
return reinterpret_cast<Metadata**>(Vals);
}
}
#else
typedef LLVMValueRef LLVMMetadataRef;
#endif
2013-06-14 18:38:29 +00:00
template<typename DIT>
2015-01-30 18:25:07 +00:00
DIT unwrapDI(LLVMMetadataRef ref) {
return DIT(ref ? unwrap<MDNode>(ref) : NULL);
2013-06-17 15:42:05 +00:00
}
2013-06-14 18:38:29 +00:00
#if LLVM_VERSION_MINOR >= 5
extern "C" const uint32_t LLVMRustDebugMetadataVersion = DEBUG_METADATA_VERSION;
#else
extern "C" const uint32_t LLVMRustDebugMetadataVersion = 1;
#endif
extern "C" void LLVMRustAddModuleFlag(LLVMModuleRef M,
const char *name,
uint32_t value) {
unwrap(M)->addModuleFlag(Module::Warning, name, value);
}
extern "C" DIBuilderRef LLVMDIBuilderCreate(LLVMModuleRef M) {
2013-06-14 18:38:29 +00:00
return new DIBuilder(*unwrap(M));
}
extern "C" void LLVMDIBuilderDispose(DIBuilderRef Builder) {
2013-06-14 18:38:29 +00:00
delete Builder;
}
extern "C" void LLVMDIBuilderFinalize(DIBuilderRef Builder) {
2013-06-14 18:38:29 +00:00
Builder->finalize();
}
2015-01-30 18:25:07 +00:00
extern "C" LLVMMetadataRef LLVMDIBuilderCreateCompileUnit(
2013-06-14 18:38:29 +00:00
DIBuilderRef Builder,
unsigned Lang,
const char* File,
const char* Dir,
const char* Producer,
bool isOptimized,
const char* Flags,
unsigned RuntimeVer,
const char* SplitName) {
return wrap(Builder->createCompileUnit(Lang,
File,
Dir,
Producer,
isOptimized,
Flags,
RuntimeVer,
SplitName));
2013-06-14 18:38:29 +00:00
}
2015-01-30 18:25:07 +00:00
extern "C" LLVMMetadataRef LLVMDIBuilderCreateFile(
2013-06-14 18:38:29 +00:00
DIBuilderRef Builder,
const char* Filename,
const char* Directory) {
return wrap(Builder->createFile(Filename, Directory));
}
2015-01-30 18:25:07 +00:00
extern "C" LLVMMetadataRef LLVMDIBuilderCreateSubroutineType(
2013-06-14 18:38:29 +00:00
DIBuilderRef Builder,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef File,
LLVMMetadataRef ParameterTypes) {
2013-06-14 18:38:29 +00:00
return wrap(Builder->createSubroutineType(
unwrapDI<DIFile>(File),
2014-08-15 14:36:05 +00:00
#if LLVM_VERSION_MINOR >= 6
2014-08-01 09:23:05 +00:00
unwrapDI<DITypeArray>(ParameterTypes)));
2014-08-15 14:36:05 +00:00
#else
unwrapDI<DIArray>(ParameterTypes)));
#endif
2013-06-14 18:38:29 +00:00
}
2015-01-30 18:25:07 +00:00
extern "C" LLVMMetadataRef LLVMDIBuilderCreateFunction(
2013-06-14 18:38:29 +00:00
DIBuilderRef Builder,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef Scope,
2013-06-14 18:38:29 +00:00
const char* Name,
const char* LinkageName,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef File,
2013-06-14 18:38:29 +00:00
unsigned LineNo,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef Ty,
2013-06-14 18:38:29 +00:00
bool isLocalToUnit,
bool isDefinition,
unsigned ScopeLine,
unsigned Flags,
bool isOptimized,
LLVMValueRef Fn,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef TParam,
LLVMMetadataRef Decl) {
2013-06-14 18:38:29 +00:00
return wrap(Builder->createFunction(
unwrapDI<DIScope>(Scope), Name, LinkageName,
unwrapDI<DIFile>(File), LineNo,
unwrapDI<DICompositeType>(Ty), isLocalToUnit, isDefinition, ScopeLine,
2013-06-14 18:38:29 +00:00
Flags, isOptimized,
unwrap<Function>(Fn),
2013-06-14 18:38:29 +00:00
unwrapDI<MDNode*>(TParam),
unwrapDI<MDNode*>(Decl)));
}
2015-01-30 18:25:07 +00:00
extern "C" LLVMMetadataRef LLVMDIBuilderCreateBasicType(
2013-06-14 18:38:29 +00:00
DIBuilderRef Builder,
const char* Name,
uint64_t SizeInBits,
uint64_t AlignInBits,
unsigned Encoding) {
return wrap(Builder->createBasicType(
Name, SizeInBits,
2013-06-14 18:38:29 +00:00
AlignInBits, Encoding));
}
2015-01-30 18:25:07 +00:00
extern "C" LLVMMetadataRef LLVMDIBuilderCreatePointerType(
2013-06-14 18:38:29 +00:00
DIBuilderRef Builder,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef PointeeTy,
2013-06-14 18:38:29 +00:00
uint64_t SizeInBits,
uint64_t AlignInBits,
const char* Name) {
return wrap(Builder->createPointerType(
unwrapDI<DIType>(PointeeTy), SizeInBits, AlignInBits, Name));
}
2015-01-30 18:25:07 +00:00
extern "C" LLVMMetadataRef LLVMDIBuilderCreateStructType(
2013-06-14 18:38:29 +00:00
DIBuilderRef Builder,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef Scope,
2013-06-14 18:38:29 +00:00
const char* Name,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef File,
2013-06-14 18:38:29 +00:00
unsigned LineNumber,
uint64_t SizeInBits,
uint64_t AlignInBits,
unsigned Flags,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef DerivedFrom,
LLVMMetadataRef Elements,
2013-06-14 18:38:29 +00:00
unsigned RunTimeLang,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef VTableHolder,
const char *UniqueId) {
2013-06-14 18:38:29 +00:00
return wrap(Builder->createStructType(
unwrapDI<DIDescriptor>(Scope),
Name,
unwrapDI<DIFile>(File),
LineNumber,
SizeInBits,
AlignInBits,
Flags,
unwrapDI<DIType>(DerivedFrom),
unwrapDI<DIArray>(Elements),
RunTimeLang,
unwrapDI<DIType>(VTableHolder)
#if LLVM_VERSION_MINOR >= 4
,UniqueId
#endif
));
2013-06-14 18:38:29 +00:00
}
2015-01-30 18:25:07 +00:00
extern "C" LLVMMetadataRef LLVMDIBuilderCreateMemberType(
2013-06-14 18:38:29 +00:00
DIBuilderRef Builder,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef Scope,
2013-06-14 18:38:29 +00:00
const char* Name,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef File,
2013-06-14 18:38:29 +00:00
unsigned LineNo,
uint64_t SizeInBits,
uint64_t AlignInBits,
uint64_t OffsetInBits,
unsigned Flags,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef Ty) {
2013-06-14 18:38:29 +00:00
return wrap(Builder->createMemberType(
unwrapDI<DIDescriptor>(Scope), Name,
2013-06-14 18:38:29 +00:00
unwrapDI<DIFile>(File), LineNo,
SizeInBits, AlignInBits, OffsetInBits, Flags,
2013-06-14 18:38:29 +00:00
unwrapDI<DIType>(Ty)));
}
2015-01-30 18:25:07 +00:00
extern "C" LLVMMetadataRef LLVMDIBuilderCreateLexicalBlock(
2013-06-14 18:38:29 +00:00
DIBuilderRef Builder,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef Scope,
LLVMMetadataRef File,
2013-06-14 18:38:29 +00:00
unsigned Line,
2014-09-30 21:20:22 +00:00
unsigned Col) {
2013-06-14 18:38:29 +00:00
return wrap(Builder->createLexicalBlock(
unwrapDI<DIDescriptor>(Scope),
unwrapDI<DIFile>(File), Line, Col
2014-09-30 21:20:22 +00:00
#if LLVM_VERSION_MINOR == 5
, 0
#endif
));
2013-06-14 18:38:29 +00:00
}
2015-01-30 18:25:07 +00:00
extern "C" LLVMMetadataRef LLVMDIBuilderCreateStaticVariable(
DIBuilderRef Builder,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef Context,
const char* Name,
const char* LinkageName,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef File,
unsigned LineNo,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef Ty,
bool isLocalToUnit,
LLVMValueRef Val,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef Decl = NULL) {
2014-09-30 21:20:22 +00:00
#if LLVM_VERSION_MINOR == 6
return wrap(Builder->createGlobalVariable(unwrapDI<DIDescriptor>(Context),
#else
return wrap(Builder->createStaticVariable(unwrapDI<DIDescriptor>(Context),
2014-09-30 21:20:22 +00:00
#endif
Name,
LinkageName,
unwrapDI<DIFile>(File),
LineNo,
unwrapDI<DIType>(Ty),
isLocalToUnit,
2015-01-30 18:25:07 +00:00
cast<Constant>(unwrap(Val)),
unwrapDI<MDNode*>(Decl)));
}
2015-01-30 18:25:07 +00:00
extern "C" LLVMMetadataRef LLVMDIBuilderCreateVariable(
2013-06-14 18:38:29 +00:00
DIBuilderRef Builder,
unsigned Tag,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef Scope,
2013-06-14 18:38:29 +00:00
const char* Name,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef File,
2013-06-14 18:38:29 +00:00
unsigned LineNo,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef Ty,
2013-06-14 18:38:29 +00:00
bool AlwaysPreserve,
unsigned Flags,
2015-01-30 18:25:07 +00:00
int64_t* AddrOps,
unsigned AddrOpsCount,
2013-06-14 18:38:29 +00:00
unsigned ArgNo) {
2015-01-30 18:25:07 +00:00
#if LLVM_VERSION_MINOR < 6
if (AddrOpsCount > 0) {
SmallVector<llvm::Value *, 16> addr_ops;
llvm::Type *Int64Ty = Type::getInt64Ty(VMContext);
for (int i = 0; i < AddrOpsCount; ++i)
addr_ops.push_back(ConstantInt::get(Int64Ty, AddrOps[i]));
return wrap(Builder->createComplexVariable(
Tag,
unwrapDI<DIDescriptor>(Scope),
Name,
unwrapDI<DIFile>(File),
LineNo,
unwrapDI<DIType>(Ty),
addr_ops,
ArgNo
));
}
#endif
return wrap(Builder->createLocalVariable(Tag,
unwrapDI<DIDescriptor>(Scope), Name,
unwrapDI<DIFile>(File),
LineNo,
2013-06-14 18:38:29 +00:00
unwrapDI<DIType>(Ty), AlwaysPreserve, Flags, ArgNo));
}
2015-01-30 18:25:07 +00:00
extern "C" LLVMMetadataRef LLVMDIBuilderCreateArrayType(
DIBuilderRef Builder,
uint64_t Size,
uint64_t AlignInBits,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef Ty,
LLVMMetadataRef Subscripts) {
return wrap(Builder->createArrayType(Size, AlignInBits,
unwrapDI<DIType>(Ty),
unwrapDI<DIArray>(Subscripts)));
}
2015-01-30 18:25:07 +00:00
extern "C" LLVMMetadataRef LLVMDIBuilderCreateVectorType(
2013-06-14 18:38:29 +00:00
DIBuilderRef Builder,
uint64_t Size,
uint64_t AlignInBits,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef Ty,
LLVMMetadataRef Subscripts) {
2013-06-14 18:38:29 +00:00
return wrap(Builder->createVectorType(Size, AlignInBits,
unwrapDI<DIType>(Ty),
2013-06-14 18:38:29 +00:00
unwrapDI<DIArray>(Subscripts)));
}
2015-01-30 18:25:07 +00:00
extern "C" LLVMMetadataRef LLVMDIBuilderGetOrCreateSubrange(
DIBuilderRef Builder,
int64_t Lo,
2013-06-14 18:38:29 +00:00
int64_t Count) {
return wrap(Builder->getOrCreateSubrange(Lo, Count));
}
2015-01-30 18:25:07 +00:00
extern "C" LLVMMetadataRef LLVMDIBuilderGetOrCreateArray(
2013-06-14 18:38:29 +00:00
DIBuilderRef Builder,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef* Ptr,
2013-06-14 18:38:29 +00:00
unsigned Count) {
return wrap(Builder->getOrCreateArray(
2015-01-30 18:25:07 +00:00
ArrayRef<Metadata*>(unwrap(Ptr), Count)));
2013-06-14 18:38:29 +00:00
}
extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareAtEnd(
DIBuilderRef Builder,
LLVMValueRef Val,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef VarInfo,
int64_t* AddrOps,
unsigned AddrOpsCount,
LLVMBasicBlockRef InsertAtEnd) {
2015-01-30 18:25:07 +00:00
#if LLVM_VERSION_MINOR >= 6
DIExpression Expr;
if (AddrOpsCount == 0) {
Expr = Builder->createExpression();
} else {
llvm::ArrayRef<int64_t> addr_ops(AddrOps, AddrOpsCount);
Expr = Builder->createExpression(addr_ops);
}
#endif
return wrap(Builder->insertDeclare(
unwrap(Val),
unwrapDI<DIVariable>(VarInfo),
2015-01-30 18:25:07 +00:00
#if LLVM_VERSION_MINOR >= 6
Expr,
#endif
unwrap(InsertAtEnd)));
}
extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareBefore(
2013-06-14 18:38:29 +00:00
DIBuilderRef Builder,
LLVMValueRef Val,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef VarInfo,
int64_t* AddrOps,
unsigned AddrOpsCount,
2013-06-14 18:38:29 +00:00
LLVMValueRef InsertBefore) {
2015-01-30 18:25:07 +00:00
#if LLVM_VERSION_MINOR >= 6
DIExpression Expr;
if (AddrOpsCount == 0) {
Expr = Builder->createExpression();
} else {
llvm::ArrayRef<int64_t> addr_ops(AddrOps, AddrOpsCount);
Expr = Builder->createExpression(addr_ops);
}
#endif
2013-06-14 18:38:29 +00:00
return wrap(Builder->insertDeclare(
unwrap(Val),
unwrapDI<DIVariable>(VarInfo),
2015-01-30 18:25:07 +00:00
#if LLVM_VERSION_MINOR >= 6
Expr,
#endif
2013-06-14 18:38:29 +00:00
unwrap<Instruction>(InsertBefore)));
}
2015-01-30 18:25:07 +00:00
extern "C" LLVMMetadataRef LLVMDIBuilderCreateEnumerator(
DIBuilderRef Builder,
const char* Name,
uint64_t Val)
{
return wrap(Builder->createEnumerator(Name, Val));
}
2015-01-30 18:25:07 +00:00
extern "C" LLVMMetadataRef LLVMDIBuilderCreateEnumerationType(
DIBuilderRef Builder,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef Scope,
const char* Name,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef File,
unsigned LineNumber,
uint64_t SizeInBits,
uint64_t AlignInBits,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef Elements,
LLVMMetadataRef ClassType)
{
return wrap(Builder->createEnumerationType(
unwrapDI<DIDescriptor>(Scope),
Name,
unwrapDI<DIFile>(File),
LineNumber,
SizeInBits,
AlignInBits,
unwrapDI<DIArray>(Elements),
unwrapDI<DIType>(ClassType)));
}
2015-01-30 18:25:07 +00:00
extern "C" LLVMMetadataRef LLVMDIBuilderCreateUnionType(
DIBuilderRef Builder,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef Scope,
const char* Name,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef File,
unsigned LineNumber,
uint64_t SizeInBits,
uint64_t AlignInBits,
unsigned Flags,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef Elements,
unsigned RunTimeLang,
const char* UniqueId)
{
return wrap(Builder->createUnionType(
unwrapDI<DIDescriptor>(Scope),
Name,
unwrapDI<DIFile>(File),
LineNumber,
SizeInBits,
AlignInBits,
Flags,
unwrapDI<DIArray>(Elements),
RunTimeLang
#if LLVM_VERSION_MINOR >= 4
,UniqueId
#endif
));
2013-07-28 07:48:16 +00:00
}
#if LLVM_VERSION_MINOR < 5
extern "C" void LLVMSetUnnamedAddr(LLVMValueRef Value, LLVMBool Unnamed) {
unwrap<GlobalValue>(Value)->setUnnamedAddr(Unnamed);
}
#endif
2015-01-30 18:25:07 +00:00
extern "C" LLVMMetadataRef LLVMDIBuilderCreateTemplateTypeParameter(
DIBuilderRef Builder,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef Scope,
const char* Name,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef Ty,
LLVMMetadataRef File,
unsigned LineNo,
unsigned ColumnNo)
{
return wrap(Builder->createTemplateTypeParameter(
unwrapDI<DIDescriptor>(Scope),
Name,
unwrapDI<DIType>(Ty),
unwrapDI<MDNode*>(File),
LineNo,
ColumnNo));
}
2015-01-30 18:25:07 +00:00
extern "C" int64_t LLVMDIBuilderCreateOpDeref()
{
2015-01-30 18:25:07 +00:00
return dwarf::DW_OP_deref;
}
2015-01-30 18:25:07 +00:00
extern "C" int64_t LLVMDIBuilderCreateOpPlus()
{
2015-01-30 18:25:07 +00:00
return dwarf::DW_OP_plus;
}
2015-01-30 18:25:07 +00:00
extern "C" LLVMMetadataRef LLVMDIBuilderCreateNameSpace(
DIBuilderRef Builder,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef Scope,
const char* Name,
2015-01-30 18:25:07 +00:00
LLVMMetadataRef File,
unsigned LineNo)
{
return wrap(Builder->createNameSpace(
unwrapDI<DIDescriptor>(Scope),
Name,
unwrapDI<DIFile>(File),
LineNo));
}
extern "C" void LLVMDICompositeTypeSetTypeArray(
2015-01-30 18:25:07 +00:00
DIBuilderRef Builder,
LLVMMetadataRef CompositeType,
LLVMMetadataRef TypeArray)
{
2014-08-15 14:36:05 +00:00
#if LLVM_VERSION_MINOR >= 6
2015-01-30 18:25:07 +00:00
DICompositeType tmp = unwrapDI<DICompositeType>(CompositeType);
Builder->replaceArrays(tmp, unwrapDI<DIArray>(TypeArray));
2014-08-15 14:36:05 +00:00
#else
unwrapDI<DICompositeType>(CompositeType).setTypeArray(unwrapDI<DIArray>(TypeArray));
#endif
}
2015-01-30 18:25:07 +00:00
extern "C" LLVMValueRef LLVMDIBuilderCreateDebugLocation(
LLVMContextRef Context,
unsigned Line,
unsigned Column,
LLVMMetadataRef Scope,
LLVMMetadataRef InlinedAt) {
LLVMContext& context = *unwrap(Context);
DebugLoc debug_loc = DebugLoc::get(Line,
Column,
unwrapDI<MDNode*>(Scope),
unwrapDI<MDNode*>(InlinedAt));
#if LLVM_VERSION_MINOR >= 6
return wrap(MetadataAsValue::get(context, debug_loc.getAsMDNode(context)));
#else
return wrap(debug_loc.getAsMDNode(context));
#endif
}
2014-09-10 06:12:09 +00:00
extern "C" void LLVMWriteTypeToString(LLVMTypeRef Type, RustStringRef str) {
raw_rust_string_ostream os(str);
unwrap<llvm::Type>(Type)->print(os);
}
Implement LTO This commit implements LTO for rust leveraging LLVM's passes. What this means is: * When compiling an rlib, in addition to insdering foo.o into the archive, also insert foo.bc (the LLVM bytecode) of the optimized module. * When the compiler detects the -Z lto option, it will attempt to perform LTO on a staticlib or binary output. The compiler will emit an error if a dylib or rlib output is being generated. * The actual act of performing LTO is as follows: 1. Force all upstream libraries to have an rlib version available. 2. Load the bytecode of each upstream library from the rlib. 3. Link all this bytecode into the current LLVM module (just using llvm apis) 4. Run an internalization pass which internalizes all symbols except those found reachable for the local crate of compilation. 5. Run the LLVM LTO pass manager over this entire module 6a. If assembling an archive, then add all upstream rlibs into the output archive. This ignores all of the object/bitcode/metadata files rust generated and placed inside the rlibs. 6b. If linking a binary, create copies of all upstream rlibs, remove the rust-generated object-file, and then link everything as usual. As I have explained in #10741, this process is excruciatingly slow, so this is *not* turned on by default, and it is also why I have decided to hide it behind a -Z flag for now. The good news is that the binary sizes are about as small as they can be as a result of LTO, so it's definitely working. Closes #10741 Closes #10740
2013-12-03 07:19:29 +00:00
2014-09-10 06:12:09 +00:00
extern "C" void LLVMWriteValueToString(LLVMValueRef Value, RustStringRef str) {
raw_rust_string_ostream os(str);
os << "(";
unwrap<llvm::Value>(Value)->getType()->print(os);
os << ":";
unwrap<llvm::Value>(Value)->print(os);
os << ")";
}
#if LLVM_VERSION_MINOR >= 5
Implement LTO This commit implements LTO for rust leveraging LLVM's passes. What this means is: * When compiling an rlib, in addition to insdering foo.o into the archive, also insert foo.bc (the LLVM bytecode) of the optimized module. * When the compiler detects the -Z lto option, it will attempt to perform LTO on a staticlib or binary output. The compiler will emit an error if a dylib or rlib output is being generated. * The actual act of performing LTO is as follows: 1. Force all upstream libraries to have an rlib version available. 2. Load the bytecode of each upstream library from the rlib. 3. Link all this bytecode into the current LLVM module (just using llvm apis) 4. Run an internalization pass which internalizes all symbols except those found reachable for the local crate of compilation. 5. Run the LLVM LTO pass manager over this entire module 6a. If assembling an archive, then add all upstream rlibs into the output archive. This ignores all of the object/bitcode/metadata files rust generated and placed inside the rlibs. 6b. If linking a binary, create copies of all upstream rlibs, remove the rust-generated object-file, and then link everything as usual. As I have explained in #10741, this process is excruciatingly slow, so this is *not* turned on by default, and it is also why I have decided to hide it behind a -Z flag for now. The good news is that the binary sizes are about as small as they can be as a result of LTO, so it's definitely working. Closes #10741 Closes #10740
2013-12-03 07:19:29 +00:00
extern "C" bool
LLVMRustLinkInExternalBitcode(LLVMModuleRef dst, char *bc, size_t len) {
Module *Dst = unwrap(dst);
2014-09-30 21:20:22 +00:00
#if LLVM_VERSION_MINOR == 5
Implement LTO This commit implements LTO for rust leveraging LLVM's passes. What this means is: * When compiling an rlib, in addition to insdering foo.o into the archive, also insert foo.bc (the LLVM bytecode) of the optimized module. * When the compiler detects the -Z lto option, it will attempt to perform LTO on a staticlib or binary output. The compiler will emit an error if a dylib or rlib output is being generated. * The actual act of performing LTO is as follows: 1. Force all upstream libraries to have an rlib version available. 2. Load the bytecode of each upstream library from the rlib. 3. Link all this bytecode into the current LLVM module (just using llvm apis) 4. Run an internalization pass which internalizes all symbols except those found reachable for the local crate of compilation. 5. Run the LLVM LTO pass manager over this entire module 6a. If assembling an archive, then add all upstream rlibs into the output archive. This ignores all of the object/bitcode/metadata files rust generated and placed inside the rlibs. 6b. If linking a binary, create copies of all upstream rlibs, remove the rust-generated object-file, and then link everything as usual. As I have explained in #10741, this process is excruciatingly slow, so this is *not* turned on by default, and it is also why I have decided to hide it behind a -Z flag for now. The good news is that the binary sizes are about as small as they can be as a result of LTO, so it's definitely working. Closes #10741 Closes #10740
2013-12-03 07:19:29 +00:00
MemoryBuffer* buf = MemoryBuffer::getMemBufferCopy(StringRef(bc, len));
ErrorOr<Module *> Src = llvm::getLazyBitcodeModule(buf, Dst->getContext());
2014-09-30 21:20:22 +00:00
#else
std::unique_ptr<MemoryBuffer> buf = MemoryBuffer::getMemBufferCopy(StringRef(bc, len));
ErrorOr<Module *> Src = llvm::getLazyBitcodeModule(std::move(buf), Dst->getContext());
#endif
if (!Src) {
LLVMRustSetLastError(Src.getError().message().c_str());
2014-09-30 21:20:22 +00:00
#if LLVM_VERSION_MINOR == 5
Implement LTO This commit implements LTO for rust leveraging LLVM's passes. What this means is: * When compiling an rlib, in addition to insdering foo.o into the archive, also insert foo.bc (the LLVM bytecode) of the optimized module. * When the compiler detects the -Z lto option, it will attempt to perform LTO on a staticlib or binary output. The compiler will emit an error if a dylib or rlib output is being generated. * The actual act of performing LTO is as follows: 1. Force all upstream libraries to have an rlib version available. 2. Load the bytecode of each upstream library from the rlib. 3. Link all this bytecode into the current LLVM module (just using llvm apis) 4. Run an internalization pass which internalizes all symbols except those found reachable for the local crate of compilation. 5. Run the LLVM LTO pass manager over this entire module 6a. If assembling an archive, then add all upstream rlibs into the output archive. This ignores all of the object/bitcode/metadata files rust generated and placed inside the rlibs. 6b. If linking a binary, create copies of all upstream rlibs, remove the rust-generated object-file, and then link everything as usual. As I have explained in #10741, this process is excruciatingly slow, so this is *not* turned on by default, and it is also why I have decided to hide it behind a -Z flag for now. The good news is that the binary sizes are about as small as they can be as a result of LTO, so it's definitely working. Closes #10741 Closes #10740
2013-12-03 07:19:29 +00:00
delete buf;
2014-09-30 21:20:22 +00:00
#endif
Implement LTO This commit implements LTO for rust leveraging LLVM's passes. What this means is: * When compiling an rlib, in addition to insdering foo.o into the archive, also insert foo.bc (the LLVM bytecode) of the optimized module. * When the compiler detects the -Z lto option, it will attempt to perform LTO on a staticlib or binary output. The compiler will emit an error if a dylib or rlib output is being generated. * The actual act of performing LTO is as follows: 1. Force all upstream libraries to have an rlib version available. 2. Load the bytecode of each upstream library from the rlib. 3. Link all this bytecode into the current LLVM module (just using llvm apis) 4. Run an internalization pass which internalizes all symbols except those found reachable for the local crate of compilation. 5. Run the LLVM LTO pass manager over this entire module 6a. If assembling an archive, then add all upstream rlibs into the output archive. This ignores all of the object/bitcode/metadata files rust generated and placed inside the rlibs. 6b. If linking a binary, create copies of all upstream rlibs, remove the rust-generated object-file, and then link everything as usual. As I have explained in #10741, this process is excruciatingly slow, so this is *not* turned on by default, and it is also why I have decided to hide it behind a -Z flag for now. The good news is that the binary sizes are about as small as they can be as a result of LTO, so it's definitely working. Closes #10741 Closes #10740
2013-12-03 07:19:29 +00:00
return false;
}
std::string Err;
2015-01-30 18:25:07 +00:00
#if LLVM_VERSION_MINOR >= 6
raw_string_ostream Stream(Err);
DiagnosticPrinterRawOStream DP(Stream);
if (Linker::LinkModules(Dst, *Src, [&](const DiagnosticInfo &DI) { DI.print(DP); })) {
#else
if (Linker::LinkModules(Dst, *Src, Linker::DestroySource, &Err)) {
2015-01-30 18:25:07 +00:00
#endif
LLVMRustSetLastError(Err.c_str());
Implement LTO This commit implements LTO for rust leveraging LLVM's passes. What this means is: * When compiling an rlib, in addition to insdering foo.o into the archive, also insert foo.bc (the LLVM bytecode) of the optimized module. * When the compiler detects the -Z lto option, it will attempt to perform LTO on a staticlib or binary output. The compiler will emit an error if a dylib or rlib output is being generated. * The actual act of performing LTO is as follows: 1. Force all upstream libraries to have an rlib version available. 2. Load the bytecode of each upstream library from the rlib. 3. Link all this bytecode into the current LLVM module (just using llvm apis) 4. Run an internalization pass which internalizes all symbols except those found reachable for the local crate of compilation. 5. Run the LLVM LTO pass manager over this entire module 6a. If assembling an archive, then add all upstream rlibs into the output archive. This ignores all of the object/bitcode/metadata files rust generated and placed inside the rlibs. 6b. If linking a binary, create copies of all upstream rlibs, remove the rust-generated object-file, and then link everything as usual. As I have explained in #10741, this process is excruciatingly slow, so this is *not* turned on by default, and it is also why I have decided to hide it behind a -Z flag for now. The good news is that the binary sizes are about as small as they can be as a result of LTO, so it's definitely working. Closes #10741 Closes #10740
2013-12-03 07:19:29 +00:00
return false;
}
return true;
}
#else
extern "C" bool
LLVMRustLinkInExternalBitcode(LLVMModuleRef dst, char *bc, size_t len) {
Module *Dst = unwrap(dst);
MemoryBuffer* buf = MemoryBuffer::getMemBufferCopy(StringRef(bc, len));
std::string Err;
Module *Src = llvm::getLazyBitcodeModule(buf, Dst->getContext(), &Err);
if (!Src) {
LLVMRustSetLastError(Err.c_str());
delete buf;
return false;
}
if (Linker::LinkModules(Dst, Src, Linker::DestroySource, &Err)) {
LLVMRustSetLastError(Err.c_str());
return false;
}
return true;
}
#endif
rustc: Optimize reading metadata by 4x We were previously reading metadata via `ar p`, but as learned from rustdoc awhile back, spawning a process to do something is pretty slow. Turns out LLVM has an Archive class to read archives, but it cannot write archives. This commits adds bindings to the read-only version of the LLVM archive class (with a new type that only has a read() method), and then it uses this class when reading the metadata out of rlibs. When you put this in tandem of not compressing the metadata, reading the metadata is 4x faster than it used to be The timings I got for reading metadata from the respective libraries was: libstd-04ff901e-0.9-pre.dylib => 100ms libstd-04ff901e-0.9-pre.rlib => 23ms librustuv-7945354c-0.9-pre.dylib => 4ms librustuv-7945354c-0.9-pre.rlib => 1ms librustc-5b94a16f-0.9-pre.dylib => 87ms librustc-5b94a16f-0.9-pre.rlib => 35ms libextra-a6ebb16f-0.9-pre.dylib => 63ms libextra-a6ebb16f-0.9-pre.rlib => 15ms libsyntax-2e4c0458-0.9-pre.dylib => 86ms libsyntax-2e4c0458-0.9-pre.rlib => 22ms In order to always take advantage of these faster metadata read-times, I sort the files in filesearch based on whether they have an rlib extension or not (prefer all rlib files first). Overall, this halved the compile time for a `fn main() {}` crate from 0.185s to 0.095s on my system (when preferring dynamic linking). Reading metadata is still the slowest pass of the compiler at 0.035s, but it's getting pretty close to linking at 0.021s! The next best optimization is to just not copy the metadata from LLVM because that's the most expensive part of reading metadata right now.
2013-12-17 04:58:21 +00:00
#if LLVM_VERSION_MINOR >= 5
extern "C" void*
LLVMRustOpenArchive(char *path) {
ErrorOr<std::unique_ptr<MemoryBuffer>> buf_or = MemoryBuffer::getFile(path,
-1,
false);
if (!buf_or) {
LLVMRustSetLastError(buf_or.getError().message().c_str());
return nullptr;
}
2014-09-30 21:20:22 +00:00
#if LLVM_VERSION_MINOR >= 6
ErrorOr<std::unique_ptr<Archive>> archive_or =
Archive::create(buf_or.get()->getMemBufferRef());
if (!archive_or) {
LLVMRustSetLastError(archive_or.getError().message().c_str());
return nullptr;
}
OwningBinary<Archive> *ret = new OwningBinary<Archive>(
std::move(archive_or.get()), std::move(buf_or.get()));
#else
std::error_code err;
Archive *ret = new Archive(std::move(buf_or.get()), err);
if (err) {
LLVMRustSetLastError(err.message().c_str());
2014-09-30 21:20:22 +00:00
return nullptr;
}
2014-09-30 21:20:22 +00:00
#endif
return ret;
}
#else
rustc: Optimize reading metadata by 4x We were previously reading metadata via `ar p`, but as learned from rustdoc awhile back, spawning a process to do something is pretty slow. Turns out LLVM has an Archive class to read archives, but it cannot write archives. This commits adds bindings to the read-only version of the LLVM archive class (with a new type that only has a read() method), and then it uses this class when reading the metadata out of rlibs. When you put this in tandem of not compressing the metadata, reading the metadata is 4x faster than it used to be The timings I got for reading metadata from the respective libraries was: libstd-04ff901e-0.9-pre.dylib => 100ms libstd-04ff901e-0.9-pre.rlib => 23ms librustuv-7945354c-0.9-pre.dylib => 4ms librustuv-7945354c-0.9-pre.rlib => 1ms librustc-5b94a16f-0.9-pre.dylib => 87ms librustc-5b94a16f-0.9-pre.rlib => 35ms libextra-a6ebb16f-0.9-pre.dylib => 63ms libextra-a6ebb16f-0.9-pre.rlib => 15ms libsyntax-2e4c0458-0.9-pre.dylib => 86ms libsyntax-2e4c0458-0.9-pre.rlib => 22ms In order to always take advantage of these faster metadata read-times, I sort the files in filesearch based on whether they have an rlib extension or not (prefer all rlib files first). Overall, this halved the compile time for a `fn main() {}` crate from 0.185s to 0.095s on my system (when preferring dynamic linking). Reading metadata is still the slowest pass of the compiler at 0.035s, but it's getting pretty close to linking at 0.021s! The next best optimization is to just not copy the metadata from LLVM because that's the most expensive part of reading metadata right now.
2013-12-17 04:58:21 +00:00
extern "C" void*
LLVMRustOpenArchive(char *path) {
OwningPtr<MemoryBuffer> buf;
error_code err = MemoryBuffer::getFile(path, buf, -1, false);
rustc: Optimize reading metadata by 4x We were previously reading metadata via `ar p`, but as learned from rustdoc awhile back, spawning a process to do something is pretty slow. Turns out LLVM has an Archive class to read archives, but it cannot write archives. This commits adds bindings to the read-only version of the LLVM archive class (with a new type that only has a read() method), and then it uses this class when reading the metadata out of rlibs. When you put this in tandem of not compressing the metadata, reading the metadata is 4x faster than it used to be The timings I got for reading metadata from the respective libraries was: libstd-04ff901e-0.9-pre.dylib => 100ms libstd-04ff901e-0.9-pre.rlib => 23ms librustuv-7945354c-0.9-pre.dylib => 4ms librustuv-7945354c-0.9-pre.rlib => 1ms librustc-5b94a16f-0.9-pre.dylib => 87ms librustc-5b94a16f-0.9-pre.rlib => 35ms libextra-a6ebb16f-0.9-pre.dylib => 63ms libextra-a6ebb16f-0.9-pre.rlib => 15ms libsyntax-2e4c0458-0.9-pre.dylib => 86ms libsyntax-2e4c0458-0.9-pre.rlib => 22ms In order to always take advantage of these faster metadata read-times, I sort the files in filesearch based on whether they have an rlib extension or not (prefer all rlib files first). Overall, this halved the compile time for a `fn main() {}` crate from 0.185s to 0.095s on my system (when preferring dynamic linking). Reading metadata is still the slowest pass of the compiler at 0.035s, but it's getting pretty close to linking at 0.021s! The next best optimization is to just not copy the metadata from LLVM because that's the most expensive part of reading metadata right now.
2013-12-17 04:58:21 +00:00
if (err) {
LLVMRustSetLastError(err.message().c_str());
rustc: Optimize reading metadata by 4x We were previously reading metadata via `ar p`, but as learned from rustdoc awhile back, spawning a process to do something is pretty slow. Turns out LLVM has an Archive class to read archives, but it cannot write archives. This commits adds bindings to the read-only version of the LLVM archive class (with a new type that only has a read() method), and then it uses this class when reading the metadata out of rlibs. When you put this in tandem of not compressing the metadata, reading the metadata is 4x faster than it used to be The timings I got for reading metadata from the respective libraries was: libstd-04ff901e-0.9-pre.dylib => 100ms libstd-04ff901e-0.9-pre.rlib => 23ms librustuv-7945354c-0.9-pre.dylib => 4ms librustuv-7945354c-0.9-pre.rlib => 1ms librustc-5b94a16f-0.9-pre.dylib => 87ms librustc-5b94a16f-0.9-pre.rlib => 35ms libextra-a6ebb16f-0.9-pre.dylib => 63ms libextra-a6ebb16f-0.9-pre.rlib => 15ms libsyntax-2e4c0458-0.9-pre.dylib => 86ms libsyntax-2e4c0458-0.9-pre.rlib => 22ms In order to always take advantage of these faster metadata read-times, I sort the files in filesearch based on whether they have an rlib extension or not (prefer all rlib files first). Overall, this halved the compile time for a `fn main() {}` crate from 0.185s to 0.095s on my system (when preferring dynamic linking). Reading metadata is still the slowest pass of the compiler at 0.035s, but it's getting pretty close to linking at 0.021s! The next best optimization is to just not copy the metadata from LLVM because that's the most expensive part of reading metadata right now.
2013-12-17 04:58:21 +00:00
return NULL;
}
Archive *ret = new Archive(buf.take(), err);
if (err) {
LLVMRustSetLastError(err.message().c_str());
rustc: Optimize reading metadata by 4x We were previously reading metadata via `ar p`, but as learned from rustdoc awhile back, spawning a process to do something is pretty slow. Turns out LLVM has an Archive class to read archives, but it cannot write archives. This commits adds bindings to the read-only version of the LLVM archive class (with a new type that only has a read() method), and then it uses this class when reading the metadata out of rlibs. When you put this in tandem of not compressing the metadata, reading the metadata is 4x faster than it used to be The timings I got for reading metadata from the respective libraries was: libstd-04ff901e-0.9-pre.dylib => 100ms libstd-04ff901e-0.9-pre.rlib => 23ms librustuv-7945354c-0.9-pre.dylib => 4ms librustuv-7945354c-0.9-pre.rlib => 1ms librustc-5b94a16f-0.9-pre.dylib => 87ms librustc-5b94a16f-0.9-pre.rlib => 35ms libextra-a6ebb16f-0.9-pre.dylib => 63ms libextra-a6ebb16f-0.9-pre.rlib => 15ms libsyntax-2e4c0458-0.9-pre.dylib => 86ms libsyntax-2e4c0458-0.9-pre.rlib => 22ms In order to always take advantage of these faster metadata read-times, I sort the files in filesearch based on whether they have an rlib extension or not (prefer all rlib files first). Overall, this halved the compile time for a `fn main() {}` crate from 0.185s to 0.095s on my system (when preferring dynamic linking). Reading metadata is still the slowest pass of the compiler at 0.035s, but it's getting pretty close to linking at 0.021s! The next best optimization is to just not copy the metadata from LLVM because that's the most expensive part of reading metadata right now.
2013-12-17 04:58:21 +00:00
return NULL;
}
return ret;
}
#endif
rustc: Optimize reading metadata by 4x We were previously reading metadata via `ar p`, but as learned from rustdoc awhile back, spawning a process to do something is pretty slow. Turns out LLVM has an Archive class to read archives, but it cannot write archives. This commits adds bindings to the read-only version of the LLVM archive class (with a new type that only has a read() method), and then it uses this class when reading the metadata out of rlibs. When you put this in tandem of not compressing the metadata, reading the metadata is 4x faster than it used to be The timings I got for reading metadata from the respective libraries was: libstd-04ff901e-0.9-pre.dylib => 100ms libstd-04ff901e-0.9-pre.rlib => 23ms librustuv-7945354c-0.9-pre.dylib => 4ms librustuv-7945354c-0.9-pre.rlib => 1ms librustc-5b94a16f-0.9-pre.dylib => 87ms librustc-5b94a16f-0.9-pre.rlib => 35ms libextra-a6ebb16f-0.9-pre.dylib => 63ms libextra-a6ebb16f-0.9-pre.rlib => 15ms libsyntax-2e4c0458-0.9-pre.dylib => 86ms libsyntax-2e4c0458-0.9-pre.rlib => 22ms In order to always take advantage of these faster metadata read-times, I sort the files in filesearch based on whether they have an rlib extension or not (prefer all rlib files first). Overall, this halved the compile time for a `fn main() {}` crate from 0.185s to 0.095s on my system (when preferring dynamic linking). Reading metadata is still the slowest pass of the compiler at 0.035s, but it's getting pretty close to linking at 0.021s! The next best optimization is to just not copy the metadata from LLVM because that's the most expensive part of reading metadata right now.
2013-12-17 04:58:21 +00:00
extern "C" const char*
2014-09-30 21:20:22 +00:00
#if LLVM_VERSION_MINOR >= 6
LLVMRustArchiveReadSection(OwningBinary<Archive> *ob, char *name, size_t *size) {
2015-01-30 18:25:07 +00:00
Archive *ar = ob->getBinary();
2014-09-30 21:20:22 +00:00
#else
rustc: Optimize reading metadata by 4x We were previously reading metadata via `ar p`, but as learned from rustdoc awhile back, spawning a process to do something is pretty slow. Turns out LLVM has an Archive class to read archives, but it cannot write archives. This commits adds bindings to the read-only version of the LLVM archive class (with a new type that only has a read() method), and then it uses this class when reading the metadata out of rlibs. When you put this in tandem of not compressing the metadata, reading the metadata is 4x faster than it used to be The timings I got for reading metadata from the respective libraries was: libstd-04ff901e-0.9-pre.dylib => 100ms libstd-04ff901e-0.9-pre.rlib => 23ms librustuv-7945354c-0.9-pre.dylib => 4ms librustuv-7945354c-0.9-pre.rlib => 1ms librustc-5b94a16f-0.9-pre.dylib => 87ms librustc-5b94a16f-0.9-pre.rlib => 35ms libextra-a6ebb16f-0.9-pre.dylib => 63ms libextra-a6ebb16f-0.9-pre.rlib => 15ms libsyntax-2e4c0458-0.9-pre.dylib => 86ms libsyntax-2e4c0458-0.9-pre.rlib => 22ms In order to always take advantage of these faster metadata read-times, I sort the files in filesearch based on whether they have an rlib extension or not (prefer all rlib files first). Overall, this halved the compile time for a `fn main() {}` crate from 0.185s to 0.095s on my system (when preferring dynamic linking). Reading metadata is still the slowest pass of the compiler at 0.035s, but it's getting pretty close to linking at 0.021s! The next best optimization is to just not copy the metadata from LLVM because that's the most expensive part of reading metadata right now.
2013-12-17 04:58:21 +00:00
LLVMRustArchiveReadSection(Archive *ar, char *name, size_t *size) {
2014-09-30 21:20:22 +00:00
#endif
#if LLVM_VERSION_MINOR >= 5
Archive::child_iterator child = ar->child_begin(),
end = ar->child_end();
for (; child != end; ++child) {
ErrorOr<StringRef> name_or_err = child->getName();
if (name_or_err.getError()) continue;
StringRef sect_name = name_or_err.get();
#else
Archive::child_iterator child = ar->begin_children(),
end = ar->end_children();
for (; child != end; ++child) {
rustc: Optimize reading metadata by 4x We were previously reading metadata via `ar p`, but as learned from rustdoc awhile back, spawning a process to do something is pretty slow. Turns out LLVM has an Archive class to read archives, but it cannot write archives. This commits adds bindings to the read-only version of the LLVM archive class (with a new type that only has a read() method), and then it uses this class when reading the metadata out of rlibs. When you put this in tandem of not compressing the metadata, reading the metadata is 4x faster than it used to be The timings I got for reading metadata from the respective libraries was: libstd-04ff901e-0.9-pre.dylib => 100ms libstd-04ff901e-0.9-pre.rlib => 23ms librustuv-7945354c-0.9-pre.dylib => 4ms librustuv-7945354c-0.9-pre.rlib => 1ms librustc-5b94a16f-0.9-pre.dylib => 87ms librustc-5b94a16f-0.9-pre.rlib => 35ms libextra-a6ebb16f-0.9-pre.dylib => 63ms libextra-a6ebb16f-0.9-pre.rlib => 15ms libsyntax-2e4c0458-0.9-pre.dylib => 86ms libsyntax-2e4c0458-0.9-pre.rlib => 22ms In order to always take advantage of these faster metadata read-times, I sort the files in filesearch based on whether they have an rlib extension or not (prefer all rlib files first). Overall, this halved the compile time for a `fn main() {}` crate from 0.185s to 0.095s on my system (when preferring dynamic linking). Reading metadata is still the slowest pass of the compiler at 0.035s, but it's getting pretty close to linking at 0.021s! The next best optimization is to just not copy the metadata from LLVM because that's the most expensive part of reading metadata right now.
2013-12-17 04:58:21 +00:00
StringRef sect_name;
error_code err = child->getName(sect_name);
if (err) continue;
#endif
rustc: Optimize reading metadata by 4x We were previously reading metadata via `ar p`, but as learned from rustdoc awhile back, spawning a process to do something is pretty slow. Turns out LLVM has an Archive class to read archives, but it cannot write archives. This commits adds bindings to the read-only version of the LLVM archive class (with a new type that only has a read() method), and then it uses this class when reading the metadata out of rlibs. When you put this in tandem of not compressing the metadata, reading the metadata is 4x faster than it used to be The timings I got for reading metadata from the respective libraries was: libstd-04ff901e-0.9-pre.dylib => 100ms libstd-04ff901e-0.9-pre.rlib => 23ms librustuv-7945354c-0.9-pre.dylib => 4ms librustuv-7945354c-0.9-pre.rlib => 1ms librustc-5b94a16f-0.9-pre.dylib => 87ms librustc-5b94a16f-0.9-pre.rlib => 35ms libextra-a6ebb16f-0.9-pre.dylib => 63ms libextra-a6ebb16f-0.9-pre.rlib => 15ms libsyntax-2e4c0458-0.9-pre.dylib => 86ms libsyntax-2e4c0458-0.9-pre.rlib => 22ms In order to always take advantage of these faster metadata read-times, I sort the files in filesearch based on whether they have an rlib extension or not (prefer all rlib files first). Overall, this halved the compile time for a `fn main() {}` crate from 0.185s to 0.095s on my system (when preferring dynamic linking). Reading metadata is still the slowest pass of the compiler at 0.035s, but it's getting pretty close to linking at 0.021s! The next best optimization is to just not copy the metadata from LLVM because that's the most expensive part of reading metadata right now.
2013-12-17 04:58:21 +00:00
if (sect_name.trim(" ") == name) {
StringRef buf = child->getBuffer();
*size = buf.size();
return buf.data();
}
}
return NULL;
}
extern "C" void
2014-09-30 21:20:22 +00:00
#if LLVM_VERSION_MINOR >= 6
LLVMRustDestroyArchive(OwningBinary<Archive> *ar) {
#else
rustc: Optimize reading metadata by 4x We were previously reading metadata via `ar p`, but as learned from rustdoc awhile back, spawning a process to do something is pretty slow. Turns out LLVM has an Archive class to read archives, but it cannot write archives. This commits adds bindings to the read-only version of the LLVM archive class (with a new type that only has a read() method), and then it uses this class when reading the metadata out of rlibs. When you put this in tandem of not compressing the metadata, reading the metadata is 4x faster than it used to be The timings I got for reading metadata from the respective libraries was: libstd-04ff901e-0.9-pre.dylib => 100ms libstd-04ff901e-0.9-pre.rlib => 23ms librustuv-7945354c-0.9-pre.dylib => 4ms librustuv-7945354c-0.9-pre.rlib => 1ms librustc-5b94a16f-0.9-pre.dylib => 87ms librustc-5b94a16f-0.9-pre.rlib => 35ms libextra-a6ebb16f-0.9-pre.dylib => 63ms libextra-a6ebb16f-0.9-pre.rlib => 15ms libsyntax-2e4c0458-0.9-pre.dylib => 86ms libsyntax-2e4c0458-0.9-pre.rlib => 22ms In order to always take advantage of these faster metadata read-times, I sort the files in filesearch based on whether they have an rlib extension or not (prefer all rlib files first). Overall, this halved the compile time for a `fn main() {}` crate from 0.185s to 0.095s on my system (when preferring dynamic linking). Reading metadata is still the slowest pass of the compiler at 0.035s, but it's getting pretty close to linking at 0.021s! The next best optimization is to just not copy the metadata from LLVM because that's the most expensive part of reading metadata right now.
2013-12-17 04:58:21 +00:00
LLVMRustDestroyArchive(Archive *ar) {
2014-09-30 21:20:22 +00:00
#endif
rustc: Optimize reading metadata by 4x We were previously reading metadata via `ar p`, but as learned from rustdoc awhile back, spawning a process to do something is pretty slow. Turns out LLVM has an Archive class to read archives, but it cannot write archives. This commits adds bindings to the read-only version of the LLVM archive class (with a new type that only has a read() method), and then it uses this class when reading the metadata out of rlibs. When you put this in tandem of not compressing the metadata, reading the metadata is 4x faster than it used to be The timings I got for reading metadata from the respective libraries was: libstd-04ff901e-0.9-pre.dylib => 100ms libstd-04ff901e-0.9-pre.rlib => 23ms librustuv-7945354c-0.9-pre.dylib => 4ms librustuv-7945354c-0.9-pre.rlib => 1ms librustc-5b94a16f-0.9-pre.dylib => 87ms librustc-5b94a16f-0.9-pre.rlib => 35ms libextra-a6ebb16f-0.9-pre.dylib => 63ms libextra-a6ebb16f-0.9-pre.rlib => 15ms libsyntax-2e4c0458-0.9-pre.dylib => 86ms libsyntax-2e4c0458-0.9-pre.rlib => 22ms In order to always take advantage of these faster metadata read-times, I sort the files in filesearch based on whether they have an rlib extension or not (prefer all rlib files first). Overall, this halved the compile time for a `fn main() {}` crate from 0.185s to 0.095s on my system (when preferring dynamic linking). Reading metadata is still the slowest pass of the compiler at 0.035s, but it's getting pretty close to linking at 0.021s! The next best optimization is to just not copy the metadata from LLVM because that's the most expensive part of reading metadata right now.
2013-12-17 04:58:21 +00:00
delete ar;
}
#if LLVM_VERSION_MINOR >= 5
extern "C" void
LLVMRustSetDLLExportStorageClass(LLVMValueRef Value) {
GlobalValue *V = unwrap<GlobalValue>(Value);
V->setDLLStorageClass(GlobalValue::DLLExportStorageClass);
}
#else
extern "C" void
LLVMRustSetDLLExportStorageClass(LLVMValueRef Value) {
LLVMSetLinkage(Value, LLVMDLLExportLinkage);
}
#endif
extern "C" int
LLVMVersionMinor() {
return LLVM_VERSION_MINOR;
}
extern "C" int
LLVMVersionMajor() {
return LLVM_VERSION_MAJOR;
}
// 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
// function provided by LLVM doesn't return the length, so we've created our own
// function which returns the length as well as the data pointer.
//
// For an example of this not returning a null terminated string, see
// lib/Object/COFFObjectFile.cpp in the getSectionName function. One of the
// branches explicitly creates a StringRef without a null terminator, and then
// that's returned.
inline section_iterator *unwrap(LLVMSectionIteratorRef SI) {
return reinterpret_cast<section_iterator*>(SI);
}
extern "C" int
LLVMRustGetSectionName(LLVMSectionIteratorRef SI, const char **ptr) {
StringRef ret;
#if LLVM_VERSION_MINOR >= 5
if (std::error_code ec = (*unwrap(SI))->getName(ret))
#else
if (error_code ec = (*unwrap(SI))->getName(ret))
#endif
report_fatal_error(ec.message());
*ptr = ret.data();
return ret.size();
}
// LLVMArrayType function does not support 64-bit ElementCount
extern "C" LLVMTypeRef
LLVMRustArrayType(LLVMTypeRef ElementType, uint64_t ElementCount) {
return wrap(ArrayType::get(unwrap(ElementType), ElementCount));
}
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(Twine, LLVMTwineRef)
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DebugLoc, LLVMDebugLocRef)
extern "C" void
LLVMWriteTwineToString(LLVMTwineRef T, RustStringRef str) {
raw_rust_string_ostream os(str);
unwrap(T)->print(os);
}
extern "C" void
LLVMUnpackOptimizationDiagnostic(
LLVMDiagnosticInfoRef di,
const char **pass_name_out,
LLVMValueRef *function_out,
LLVMDebugLocRef *debugloc_out,
LLVMTwineRef *message_out)
{
// Undefined to call this not on an optimization diagnostic!
llvm::DiagnosticInfoOptimizationBase *opt
= static_cast<llvm::DiagnosticInfoOptimizationBase*>(unwrap(di));
*pass_name_out = opt->getPassName();
*function_out = wrap(&opt->getFunction());
*debugloc_out = wrap(&opt->getDebugLoc());
*message_out = wrap(&opt->getMsg());
}
2015-01-22 18:43:39 +00:00
extern "C" void
LLVMUnpackInlineAsmDiagnostic(
LLVMDiagnosticInfoRef di,
unsigned *cookie_out,
LLVMTwineRef *message_out,
LLVMValueRef *instruction_out)
{
// Undefined to call this not on an inline assembly diagnostic!
llvm::DiagnosticInfoInlineAsm *ia
= static_cast<llvm::DiagnosticInfoInlineAsm*>(unwrap(di));
*cookie_out = ia->getLocCookie();
*message_out = wrap(&ia->getMsgStr());
*instruction_out = wrap(ia->getInstruction());
}
extern "C" void LLVMWriteDiagnosticInfoToString(LLVMDiagnosticInfoRef di, RustStringRef str) {
raw_rust_string_ostream os(str);
DiagnosticPrinterRawOStream dp(os);
unwrap(di)->print(dp);
}
extern "C" int LLVMGetDiagInfoKind(LLVMDiagnosticInfoRef di) {
return unwrap(di)->getKind();
}
extern "C" void LLVMWriteDebugLocToString(
LLVMContextRef C,
LLVMDebugLocRef dl,
RustStringRef str)
{
raw_rust_string_ostream os(str);
unwrap(dl)->print(*unwrap(C), os);
}
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(SMDiagnostic, LLVMSMDiagnosticRef)
extern "C" void LLVMSetInlineAsmDiagnosticHandler(
LLVMContextRef C,
LLVMContext::InlineAsmDiagHandlerTy H,
void *CX)
{
unwrap(C)->setInlineAsmDiagnosticHandler(H, CX);
}
extern "C" void LLVMWriteSMDiagnosticToString(LLVMSMDiagnosticRef d, RustStringRef str) {
raw_rust_string_ostream os(str);
unwrap(d)->print("", os);
}