// Copyright 2013 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 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #include "rustllvm.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ObjectFile.h" //===----------------------------------------------------------------------=== // // This file defines alternate interfaces to core functions that are more // readily callable by Rust's FFI. // //===----------------------------------------------------------------------=== using namespace llvm; using namespace llvm::sys; using namespace llvm::object; const char *LLVMRustError; extern "C" LLVMMemoryBufferRef LLVMRustCreateMemoryBufferWithContentsOfFile(const char *Path) { LLVMMemoryBufferRef MemBuf = NULL; LLVMCreateMemoryBufferWithContentsOfFile(Path, &MemBuf, const_cast(&LLVMRustError)); return MemBuf; } extern "C" const char *LLVMRustGetLastError(void) { return LLVMRustError; } 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); } 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); } 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(FunctionTy))); } extern "C" LLVMTypeRef LLVMMetadataTypeInContext(LLVMContextRef C) { return wrap(Type::getMetadataTy(*unwrap(C))); } extern "C" void LLVMAddFunctionAttrString(LLVMValueRef fn, const char *Name) { unwrap(fn)->addFnAttr(Name); } extern "C" void LLVMRemoveFunctionAttrString(LLVMValueRef fn, const char *Name) { Function *f = unwrap(fn); LLVMContext &C = f->getContext(); AttrBuilder B; B.addAttribute(Name); AttributeSet to_remove = AttributeSet::get(C, AttributeSet::FunctionIndex, B); AttributeSet attrs = f->getAttributes(); f->setAttributes(attrs.removeAttributes(f->getContext(), AttributeSet::FunctionIndex, to_remove)); } extern "C" void LLVMAddReturnAttribute(LLVMValueRef Fn, LLVMAttribute PA) { Function *A = unwrap(Fn); AttrBuilder B(PA); A->addAttributes(AttributeSet::ReturnIndex, AttributeSet::get(A->getContext(), AttributeSet::ReturnIndex, B)); } extern "C" void LLVMRemoveReturnAttribute(LLVMValueRef Fn, LLVMAttribute PA) { Function *A = unwrap(Fn); AttrBuilder B(PA); A->removeAttributes(AttributeSet::ReturnIndex, AttributeSet::get(A->getContext(), AttributeSet::ReturnIndex, B)); } #if LLVM_VERSION_MINOR >= 5 extern "C" void LLVMAddColdAttribute(LLVMValueRef Fn) { Function *A = unwrap(Fn); A->addAttribute(AttributeSet::FunctionIndex, Attribute::Cold); } #else extern "C" void LLVMAddColdAttribute(LLVMValueRef Fn) {} #endif 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); 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 )); } 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 } extern "C" LLVMValueRef LLVMInlineAsm(LLVMTypeRef Ty, char *AsmString, char *Constraints, LLVMBool HasSideEffects, LLVMBool IsAlignStack, unsigned Dialect) { return wrap(InlineAsm::get(unwrap(Ty), AsmString, Constraints, HasSideEffects, IsAlignStack, (InlineAsm::AsmDialect) Dialect)); } typedef DIBuilder* DIBuilderRef; template DIT unwrapDI(LLVMValueRef ref) { return DIT(ref ? unwrap(ref) : NULL); } #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) { return new DIBuilder(*unwrap(M)); } extern "C" void LLVMDIBuilderDispose(DIBuilderRef Builder) { delete Builder; } extern "C" void LLVMDIBuilderFinalize(DIBuilderRef Builder) { Builder->finalize(); } extern "C" void LLVMDIBuilderCreateCompileUnit( DIBuilderRef Builder, unsigned Lang, const char* File, const char* Dir, const char* Producer, bool isOptimized, const char* Flags, unsigned RuntimeVer, const char* SplitName) { Builder->createCompileUnit(Lang, File, Dir, Producer, isOptimized, Flags, RuntimeVer, SplitName); } extern "C" LLVMValueRef LLVMDIBuilderCreateFile( DIBuilderRef Builder, const char* Filename, const char* Directory) { return wrap(Builder->createFile(Filename, Directory)); } extern "C" LLVMValueRef LLVMDIBuilderCreateSubroutineType( DIBuilderRef Builder, LLVMValueRef File, LLVMValueRef ParameterTypes) { return wrap(Builder->createSubroutineType( unwrapDI(File), unwrapDI(ParameterTypes))); } extern "C" LLVMValueRef LLVMDIBuilderCreateFunction( DIBuilderRef Builder, LLVMValueRef Scope, const char* Name, const char* LinkageName, LLVMValueRef File, unsigned LineNo, LLVMValueRef Ty, bool isLocalToUnit, bool isDefinition, unsigned ScopeLine, unsigned Flags, bool isOptimized, LLVMValueRef Fn, LLVMValueRef TParam, LLVMValueRef Decl) { return wrap(Builder->createFunction( unwrapDI(Scope), Name, LinkageName, unwrapDI(File), LineNo, unwrapDI(Ty), isLocalToUnit, isDefinition, ScopeLine, Flags, isOptimized, unwrap(Fn), unwrapDI(TParam), unwrapDI(Decl))); } extern "C" LLVMValueRef LLVMDIBuilderCreateBasicType( DIBuilderRef Builder, const char* Name, uint64_t SizeInBits, uint64_t AlignInBits, unsigned Encoding) { return wrap(Builder->createBasicType( Name, SizeInBits, AlignInBits, Encoding)); } extern "C" LLVMValueRef LLVMDIBuilderCreatePointerType( DIBuilderRef Builder, LLVMValueRef PointeeTy, uint64_t SizeInBits, uint64_t AlignInBits, const char* Name) { return wrap(Builder->createPointerType( unwrapDI(PointeeTy), SizeInBits, AlignInBits, Name)); } extern "C" LLVMValueRef LLVMDIBuilderCreateStructType( DIBuilderRef Builder, LLVMValueRef Scope, const char* Name, LLVMValueRef File, unsigned LineNumber, uint64_t SizeInBits, uint64_t AlignInBits, unsigned Flags, LLVMValueRef DerivedFrom, LLVMValueRef Elements, unsigned RunTimeLang, LLVMValueRef VTableHolder, const char *UniqueId) { return wrap(Builder->createStructType( unwrapDI(Scope), Name, unwrapDI(File), LineNumber, SizeInBits, AlignInBits, Flags, unwrapDI(DerivedFrom), unwrapDI(Elements), RunTimeLang, unwrapDI(VTableHolder) #if LLVM_VERSION_MINOR >= 5 ,UniqueId #endif )); } extern "C" LLVMValueRef LLVMDIBuilderCreateMemberType( DIBuilderRef Builder, LLVMValueRef Scope, const char* Name, LLVMValueRef File, unsigned LineNo, uint64_t SizeInBits, uint64_t AlignInBits, uint64_t OffsetInBits, unsigned Flags, LLVMValueRef Ty) { return wrap(Builder->createMemberType( unwrapDI(Scope), Name, unwrapDI(File), LineNo, SizeInBits, AlignInBits, OffsetInBits, Flags, unwrapDI(Ty))); } extern "C" LLVMValueRef LLVMDIBuilderCreateLexicalBlock( DIBuilderRef Builder, LLVMValueRef Scope, LLVMValueRef File, unsigned Line, unsigned Col, unsigned Discriminator) { return wrap(Builder->createLexicalBlock( unwrapDI(Scope), unwrapDI(File), Line, Col #if LLVM_VERSION_MINOR >= 5 , Discriminator #endif )); } extern "C" LLVMValueRef LLVMDIBuilderCreateStaticVariable( DIBuilderRef Builder, LLVMValueRef Context, const char* Name, const char* LinkageName, LLVMValueRef File, unsigned LineNo, LLVMValueRef Ty, bool isLocalToUnit, LLVMValueRef Val, LLVMValueRef Decl = NULL) { return wrap(Builder->createStaticVariable(unwrapDI(Context), Name, LinkageName, unwrapDI(File), LineNo, unwrapDI(Ty), isLocalToUnit, unwrap(Val), unwrapDI(Decl))); } extern "C" LLVMValueRef LLVMDIBuilderCreateLocalVariable( DIBuilderRef Builder, unsigned Tag, LLVMValueRef Scope, const char* Name, LLVMValueRef File, unsigned LineNo, LLVMValueRef Ty, bool AlwaysPreserve, unsigned Flags, unsigned ArgNo) { return wrap(Builder->createLocalVariable(Tag, unwrapDI(Scope), Name, unwrapDI(File), LineNo, unwrapDI(Ty), AlwaysPreserve, Flags, ArgNo)); } extern "C" LLVMValueRef LLVMDIBuilderCreateArrayType( DIBuilderRef Builder, uint64_t Size, uint64_t AlignInBits, LLVMValueRef Ty, LLVMValueRef Subscripts) { return wrap(Builder->createArrayType(Size, AlignInBits, unwrapDI(Ty), unwrapDI(Subscripts))); } extern "C" LLVMValueRef LLVMDIBuilderCreateVectorType( DIBuilderRef Builder, uint64_t Size, uint64_t AlignInBits, LLVMValueRef Ty, LLVMValueRef Subscripts) { return wrap(Builder->createVectorType(Size, AlignInBits, unwrapDI(Ty), unwrapDI(Subscripts))); } extern "C" LLVMValueRef LLVMDIBuilderGetOrCreateSubrange( DIBuilderRef Builder, int64_t Lo, int64_t Count) { return wrap(Builder->getOrCreateSubrange(Lo, Count)); } extern "C" LLVMValueRef LLVMDIBuilderGetOrCreateArray( DIBuilderRef Builder, LLVMValueRef* Ptr, unsigned Count) { return wrap(Builder->getOrCreateArray( ArrayRef(reinterpret_cast(Ptr), Count))); } extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareAtEnd( DIBuilderRef Builder, LLVMValueRef Val, LLVMValueRef VarInfo, LLVMBasicBlockRef InsertAtEnd) { return wrap(Builder->insertDeclare( unwrap(Val), unwrapDI(VarInfo), unwrap(InsertAtEnd))); } extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareBefore( DIBuilderRef Builder, LLVMValueRef Val, LLVMValueRef VarInfo, LLVMValueRef InsertBefore) { return wrap(Builder->insertDeclare( unwrap(Val), unwrapDI(VarInfo), unwrap(InsertBefore))); } extern "C" LLVMValueRef LLVMDIBuilderCreateEnumerator( DIBuilderRef Builder, const char* Name, uint64_t Val) { return wrap(Builder->createEnumerator(Name, Val)); } extern "C" LLVMValueRef LLVMDIBuilderCreateEnumerationType( DIBuilderRef Builder, LLVMValueRef Scope, const char* Name, LLVMValueRef File, unsigned LineNumber, uint64_t SizeInBits, uint64_t AlignInBits, LLVMValueRef Elements, LLVMValueRef ClassType) { return wrap(Builder->createEnumerationType( unwrapDI(Scope), Name, unwrapDI(File), LineNumber, SizeInBits, AlignInBits, unwrapDI(Elements), unwrapDI(ClassType))); } extern "C" LLVMValueRef LLVMDIBuilderCreateUnionType( DIBuilderRef Builder, LLVMValueRef Scope, const char* Name, LLVMValueRef File, unsigned LineNumber, uint64_t SizeInBits, uint64_t AlignInBits, unsigned Flags, LLVMValueRef Elements, unsigned RunTimeLang, const char* UniqueId) { return wrap(Builder->createUnionType( unwrapDI(Scope), Name, unwrapDI(File), LineNumber, SizeInBits, AlignInBits, Flags, unwrapDI(Elements), RunTimeLang #if LLVM_VERSION_MINOR >= 5 ,UniqueId #endif )); } #if LLVM_VERSION_MINOR < 5 extern "C" void LLVMSetUnnamedAddr(LLVMValueRef Value, LLVMBool Unnamed) { unwrap(Value)->setUnnamedAddr(Unnamed); } #endif extern "C" LLVMValueRef LLVMDIBuilderCreateTemplateTypeParameter( DIBuilderRef Builder, LLVMValueRef Scope, const char* Name, LLVMValueRef Ty, LLVMValueRef File, unsigned LineNo, unsigned ColumnNo) { return wrap(Builder->createTemplateTypeParameter( unwrapDI(Scope), Name, unwrapDI(Ty), unwrapDI(File), LineNo, ColumnNo)); } extern "C" LLVMValueRef LLVMDIBuilderCreateOpDeref(LLVMTypeRef IntTy) { return LLVMConstInt(IntTy, DIBuilder::OpDeref, true); } extern "C" LLVMValueRef LLVMDIBuilderCreateOpPlus(LLVMTypeRef IntTy) { return LLVMConstInt(IntTy, DIBuilder::OpPlus, true); } extern "C" LLVMValueRef LLVMDIBuilderCreateComplexVariable( DIBuilderRef Builder, unsigned Tag, LLVMValueRef Scope, const char *Name, LLVMValueRef File, unsigned LineNo, LLVMValueRef Ty, LLVMValueRef* AddrOps, unsigned AddrOpsCount, unsigned ArgNo) { llvm::ArrayRef addr_ops((llvm::Value**)AddrOps, AddrOpsCount); return wrap(Builder->createComplexVariable( Tag, unwrapDI(Scope), Name, unwrapDI(File), LineNo, unwrapDI(Ty), addr_ops, ArgNo )); } extern "C" LLVMValueRef LLVMDIBuilderCreateNameSpace( DIBuilderRef Builder, LLVMValueRef Scope, const char* Name, LLVMValueRef File, unsigned LineNo) { return wrap(Builder->createNameSpace( unwrapDI(Scope), Name, unwrapDI(File), LineNo)); } extern "C" void LLVMDICompositeTypeSetTypeArray( LLVMValueRef CompositeType, LLVMValueRef TypeArray) { unwrapDI(CompositeType).setTypeArray(unwrapDI(TypeArray)); } extern "C" char *LLVMTypeToString(LLVMTypeRef Type) { std::string s; llvm::raw_string_ostream os(s); unwrap(Type)->print(os); return strdup(os.str().data()); } extern "C" char *LLVMValueToString(LLVMValueRef Value) { std::string s; llvm::raw_string_ostream os(s); os << "("; unwrap(Value)->getType()->print(os); os << ":"; unwrap(Value)->print(os); os << ")"; return strdup(os.str().data()); } #if LLVM_VERSION_MINOR >= 5 extern "C" bool LLVMRustLinkInExternalBitcode(LLVMModuleRef dst, char *bc, size_t len) { Module *Dst = unwrap(dst); MemoryBuffer* buf = MemoryBuffer::getMemBufferCopy(StringRef(bc, len)); ErrorOr Src = llvm::getLazyBitcodeModule(buf, Dst->getContext()); if (!Src) { LLVMRustError = Src.getError().message().c_str(); delete buf; return false; } std::string Err; if (Linker::LinkModules(Dst, *Src, Linker::DestroySource, &Err)) { LLVMRustError = Err.c_str(); 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) { LLVMRustError = Err.c_str(); delete buf; return false; } if (Linker::LinkModules(Dst, Src, Linker::DestroySource, &Err)) { LLVMRustError = Err.c_str(); return false; } return true; } #endif #if LLVM_VERSION_MINOR >= 5 extern "C" void* LLVMRustOpenArchive(char *path) { std::unique_ptr buf; error_code err = MemoryBuffer::getFile(path, buf); if (err) { LLVMRustError = err.message().c_str(); return NULL; } Archive *ret = new Archive(buf.release(), err); if (err) { LLVMRustError = err.message().c_str(); return NULL; } return ret; } #else extern "C" void* LLVMRustOpenArchive(char *path) { OwningPtr buf; error_code err = MemoryBuffer::getFile(path, buf); if (err) { LLVMRustError = err.message().c_str(); return NULL; } Archive *ret = new Archive(buf.take(), err); if (err) { LLVMRustError = err.message().c_str(); return NULL; } return ret; } #endif extern "C" const char* LLVMRustArchiveReadSection(Archive *ar, char *name, size_t *size) { #if LLVM_VERSION_MINOR >= 5 Archive::child_iterator child = ar->child_begin(), end = ar->child_end(); #else Archive::child_iterator child = ar->begin_children(), end = ar->end_children(); #endif for (; child != end; ++child) { StringRef sect_name; error_code err = child->getName(sect_name); if (err) continue; if (sect_name.trim(" ") == name) { StringRef buf = child->getBuffer(); *size = buf.size(); return buf.data(); } } return NULL; } extern "C" void LLVMRustDestroyArchive(Archive *ar) { delete ar; } #if LLVM_VERSION_MINOR >= 5 extern "C" void LLVMRustSetDLLExportStorageClass(LLVMValueRef Value) { GlobalValue *V = unwrap(Value); V->setDLLStorageClass(GlobalValue::DLLExportStorageClass); } #else extern "C" void LLVMRustSetDLLExportStorageClass(LLVMValueRef Value) { LLVMSetLinkage(Value, LLVMDLLExportLinkage); } #endif extern "C" int LLVMVersionMinor() { return LLVM_VERSION_MINOR; } // 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(SI); } extern "C" int LLVMRustGetSectionName(LLVMSectionIteratorRef SI, const char **ptr) { StringRef ret; if (error_code ec = (*unwrap(SI))->getName(ret)) report_fatal_error(ec.message()); *ptr = ret.data(); return ret.size(); }