// 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" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/CallSite.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; // LLVMAtomicOrdering is already an enum - don't create another // one. static AtomicOrdering from_rust(LLVMAtomicOrdering Ordering) { switch (Ordering) { case LLVMAtomicOrderingNotAtomic: return AtomicOrdering::NotAtomic; case LLVMAtomicOrderingUnordered: return AtomicOrdering::Unordered; case LLVMAtomicOrderingMonotonic: return AtomicOrdering::Monotonic; case LLVMAtomicOrderingAcquire: return AtomicOrdering::Acquire; case LLVMAtomicOrderingRelease: return AtomicOrdering::Release; case LLVMAtomicOrderingAcquireRelease: return AtomicOrdering::AcquireRelease; case LLVMAtomicOrderingSequentiallyConsistent: return AtomicOrdering::SequentiallyConsistent; } llvm_unreachable("Invalid LLVMAtomicOrdering value!"); } static char *LastError; extern "C" LLVMMemoryBufferRef LLVMRustCreateMemoryBufferWithContentsOfFile(const char *Path) { ErrorOr> 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()); } extern "C" char *LLVMRustGetLastError(void) { char *ret = LastError; LastError = NULL; return ret; } void LLVMRustSetLastError(const char *err) { free((void*) LastError); LastError = strdup(err); } extern "C" void LLVMRustSetNormalizedTarget(LLVMModuleRef M, const char *triple) { unwrap(M)->setTargetTriple(Triple::normalize(triple)); } extern "C" void LLVMRustPrintPassTimings() { raw_fd_ostream OS (2, false); // stderr. TimerGroup::printAll(OS); } extern "C" LLVMValueRef LLVMRustGetNamedValue(LLVMModuleRef M, const char* Name) { return wrap(unwrap(M)->getNamedValue(Name)); } extern "C" LLVMValueRef LLVMRustGetOrInsertFunction(LLVMModuleRef M, const char* Name, LLVMTypeRef FunctionTy) { return wrap(unwrap(M)->getOrInsertFunction(Name, unwrap(FunctionTy))); } extern "C" LLVMValueRef LLVMRustGetOrInsertGlobal(LLVMModuleRef M, const char* Name, LLVMTypeRef Ty) { return wrap(unwrap(M)->getOrInsertGlobal(Name, unwrap(Ty))); } extern "C" LLVMTypeRef LLVMRustMetadataTypeInContext(LLVMContextRef C) { return wrap(Type::getMetadataTy(*unwrap(C))); } extern "C" void LLVMRustAddCallSiteAttribute(LLVMValueRef Instr, unsigned index, uint64_t Val) { CallSite Call = CallSite(unwrap(Instr)); AttrBuilder B; B.addRawValue(Val); Call.setAttributes( Call.getAttributes().addAttributes(Call->getContext(), index, AttributeSet::get(Call->getContext(), index, B))); } extern "C" void LLVMRustAddDereferenceableCallSiteAttr(LLVMValueRef Instr, unsigned idx, uint64_t b) { CallSite Call = CallSite(unwrap(Instr)); AttrBuilder B; B.addDereferenceableAttr(b); Call.setAttributes( Call.getAttributes().addAttributes(Call->getContext(), idx, AttributeSet::get(Call->getContext(), idx, B))); } extern "C" void LLVMRustAddFunctionAttribute(LLVMValueRef Fn, unsigned index, uint64_t Val) { Function *A = unwrap(Fn); AttrBuilder B; B.addRawValue(Val); A->addAttributes(index, AttributeSet::get(A->getContext(), index, B)); } extern "C" void LLVMRustAddDereferenceableAttr(LLVMValueRef Fn, unsigned index, uint64_t bytes) { Function *A = unwrap(Fn); AttrBuilder B; B.addDereferenceableAttr(bytes); A->addAttributes(index, AttributeSet::get(A->getContext(), index, B)); } extern "C" void LLVMRustAddFunctionAttrString(LLVMValueRef Fn, unsigned index, const char *Name) { Function *F = unwrap(Fn); AttrBuilder B; B.addAttribute(Name); F->addAttributes(index, AttributeSet::get(F->getContext(), index, B)); } extern "C" void LLVMRustAddFunctionAttrStringValue(LLVMValueRef Fn, unsigned index, const char *Name, const char *Value) { Function *F = unwrap(Fn); AttrBuilder B; B.addAttribute(Name, Value); F->addAttributes(index, AttributeSet::get(F->getContext(), index, B)); } extern "C" void LLVMRustRemoveFunctionAttributes(LLVMValueRef Fn, unsigned index, uint64_t Val) { Function *A = unwrap(Fn); const AttributeSet PAL = A->getAttributes(); AttrBuilder B(Val); const AttributeSet PALnew = PAL.removeAttributes(A->getContext(), index, AttributeSet::get(A->getContext(), index, B)); A->setAttributes(PALnew); } extern "C" void LLVMRustRemoveFunctionAttrString(LLVMValueRef fn, unsigned index, const char *Name) { Function *f = unwrap(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)); } // enable fpmath flag UnsafeAlgebra extern "C" void LLVMRustSetHasUnsafeAlgebra(LLVMValueRef V) { if (auto I = dyn_cast(unwrap(V))) { I->setHasUnsafeAlgebra(true); } } extern "C" LLVMValueRef LLVMRustBuildAtomicLoad(LLVMBuilderRef B, LLVMValueRef source, const char* Name, LLVMAtomicOrdering order, unsigned alignment) { LoadInst* li = new LoadInst(unwrap(source),0); li->setAtomic(from_rust(order)); li->setAlignment(alignment); return wrap(unwrap(B)->Insert(li, Name)); } extern "C" LLVMValueRef LLVMRustBuildAtomicStore(LLVMBuilderRef B, LLVMValueRef val, LLVMValueRef target, LLVMAtomicOrdering order, unsigned alignment) { StoreInst* si = new StoreInst(unwrap(val),unwrap(target)); si->setAtomic(from_rust(order)); si->setAlignment(alignment); return wrap(unwrap(B)->Insert(si)); } extern "C" LLVMValueRef LLVMRustBuildAtomicCmpXchg(LLVMBuilderRef B, LLVMValueRef target, LLVMValueRef old, LLVMValueRef source, LLVMAtomicOrdering order, LLVMAtomicOrdering failure_order, LLVMBool weak) { AtomicCmpXchgInst* acxi = unwrap(B)->CreateAtomicCmpXchg( unwrap(target), unwrap(old), unwrap(source), from_rust(order), from_rust(failure_order)); acxi->setWeak(weak); return wrap(acxi); } enum class LLVMRustSynchronizationScope { Other, SingleThread, CrossThread, }; static SynchronizationScope from_rust(LLVMRustSynchronizationScope scope) { switch (scope) { case LLVMRustSynchronizationScope::SingleThread: return SingleThread; case LLVMRustSynchronizationScope::CrossThread: return CrossThread; default: llvm_unreachable("bad SynchronizationScope."); } } extern "C" LLVMValueRef LLVMRustBuildAtomicFence( LLVMBuilderRef B, LLVMAtomicOrdering order, LLVMRustSynchronizationScope scope) { return wrap(unwrap(B)->CreateFence(from_rust(order), from_rust(scope))); } extern "C" void LLVMRustSetDebug(int Enabled) { #ifndef NDEBUG DebugFlag = Enabled; #endif } enum class LLVMRustAsmDialect { Other, Att, Intel, }; static InlineAsm::AsmDialect from_rust(LLVMRustAsmDialect dialect) { switch (dialect) { case LLVMRustAsmDialect::Att: return InlineAsm::AD_ATT; case LLVMRustAsmDialect::Intel: return InlineAsm::AD_Intel; default: llvm_unreachable("bad AsmDialect."); } } extern "C" LLVMValueRef LLVMRustInlineAsm(LLVMTypeRef Ty, char *AsmString, char *Constraints, LLVMBool HasSideEffects, LLVMBool IsAlignStack, LLVMRustAsmDialect Dialect) { return wrap(InlineAsm::get(unwrap(Ty), AsmString, Constraints, HasSideEffects, IsAlignStack, from_rust(Dialect))); } typedef DIBuilder* LLVMRustDIBuilderRef; typedef struct LLVMOpaqueMetadata *LLVMRustMetadataRef; namespace llvm { DEFINE_ISA_CONVERSION_FUNCTIONS(Metadata, LLVMRustMetadataRef) inline Metadata **unwrap(LLVMRustMetadataRef *Vals) { return reinterpret_cast(Vals); } } template DIT* unwrapDIptr(LLVMRustMetadataRef ref) { return (DIT*) (ref ? unwrap(ref) : NULL); } #define DIDescriptor DIScope #define DIArray DINodeArray #define unwrapDI unwrapDIptr extern "C" uint32_t LLVMRustDebugMetadataVersion() { return DEBUG_METADATA_VERSION; } extern "C" uint32_t LLVMRustVersionMinor() { return LLVM_VERSION_MINOR; } extern "C" uint32_t LLVMRustVersionMajor() { return LLVM_VERSION_MAJOR; } extern "C" void LLVMRustAddModuleFlag(LLVMModuleRef M, const char *name, uint32_t value) { unwrap(M)->addModuleFlag(Module::Warning, name, value); } extern "C" LLVMRustDIBuilderRef LLVMRustDIBuilderCreate(LLVMModuleRef M) { return new DIBuilder(*unwrap(M)); } extern "C" void LLVMRustDIBuilderDispose(LLVMRustDIBuilderRef Builder) { delete Builder; } extern "C" void LLVMRustDIBuilderFinalize(LLVMRustDIBuilderRef Builder) { Builder->finalize(); } extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateCompileUnit( LLVMRustDIBuilderRef 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)); } extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateFile( LLVMRustDIBuilderRef Builder, const char* Filename, const char* Directory) { return wrap(Builder->createFile(Filename, Directory)); } extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateSubroutineType( LLVMRustDIBuilderRef Builder, LLVMRustMetadataRef File, LLVMRustMetadataRef ParameterTypes) { return wrap(Builder->createSubroutineType( #if LLVM_VERSION_MINOR == 7 unwrapDI(File), #endif DITypeRefArray(unwrap(ParameterTypes)))); } extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateFunction( LLVMRustDIBuilderRef Builder, LLVMRustMetadataRef Scope, const char* Name, const char* LinkageName, LLVMRustMetadataRef File, unsigned LineNo, LLVMRustMetadataRef Ty, bool isLocalToUnit, bool isDefinition, unsigned ScopeLine, unsigned Flags, bool isOptimized, LLVMValueRef Fn, LLVMRustMetadataRef TParam, LLVMRustMetadataRef Decl) { #if LLVM_VERSION_MINOR >= 8 DITemplateParameterArray TParams = DITemplateParameterArray(unwrap(TParam)); DISubprogram *Sub = Builder->createFunction( unwrapDI(Scope), Name, LinkageName, unwrapDI(File), LineNo, unwrapDI(Ty), isLocalToUnit, isDefinition, ScopeLine, Flags, isOptimized, TParams, unwrapDIptr(Decl)); unwrap(Fn)->setSubprogram(Sub); return wrap(Sub); #else return wrap(Builder->createFunction( unwrapDI(Scope), Name, LinkageName, unwrapDI(File), LineNo, unwrapDI(Ty), isLocalToUnit, isDefinition, ScopeLine, Flags, isOptimized, unwrap(Fn), unwrapDIptr(TParam), unwrapDIptr(Decl))); #endif } extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateBasicType( LLVMRustDIBuilderRef Builder, const char* Name, uint64_t SizeInBits, uint64_t AlignInBits, unsigned Encoding) { return wrap(Builder->createBasicType( Name, SizeInBits, AlignInBits, Encoding)); } extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreatePointerType( LLVMRustDIBuilderRef Builder, LLVMRustMetadataRef PointeeTy, uint64_t SizeInBits, uint64_t AlignInBits, const char* Name) { return wrap(Builder->createPointerType( unwrapDI(PointeeTy), SizeInBits, AlignInBits, Name)); } extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateStructType( LLVMRustDIBuilderRef Builder, LLVMRustMetadataRef Scope, const char* Name, LLVMRustMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, uint64_t AlignInBits, unsigned Flags, LLVMRustMetadataRef DerivedFrom, LLVMRustMetadataRef Elements, unsigned RunTimeLang, LLVMRustMetadataRef VTableHolder, const char *UniqueId) { return wrap(Builder->createStructType( unwrapDI(Scope), Name, unwrapDI(File), LineNumber, SizeInBits, AlignInBits, Flags, unwrapDI(DerivedFrom), DINodeArray(unwrapDI(Elements)), RunTimeLang, unwrapDI(VTableHolder), UniqueId )); } extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateMemberType( LLVMRustDIBuilderRef Builder, LLVMRustMetadataRef Scope, const char* Name, LLVMRustMetadataRef File, unsigned LineNo, uint64_t SizeInBits, uint64_t AlignInBits, uint64_t OffsetInBits, unsigned Flags, LLVMRustMetadataRef Ty) { return wrap(Builder->createMemberType( unwrapDI(Scope), Name, unwrapDI(File), LineNo, SizeInBits, AlignInBits, OffsetInBits, Flags, unwrapDI(Ty))); } extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateLexicalBlock( LLVMRustDIBuilderRef Builder, LLVMRustMetadataRef Scope, LLVMRustMetadataRef File, unsigned Line, unsigned Col) { return wrap(Builder->createLexicalBlock( unwrapDI(Scope), unwrapDI(File), Line, Col )); } extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateStaticVariable( LLVMRustDIBuilderRef Builder, LLVMRustMetadataRef Context, const char* Name, const char* LinkageName, LLVMRustMetadataRef File, unsigned LineNo, LLVMRustMetadataRef Ty, bool isLocalToUnit, LLVMValueRef Val, LLVMRustMetadataRef Decl = NULL) { return wrap(Builder->createGlobalVariable(unwrapDI(Context), Name, LinkageName, unwrapDI(File), LineNo, unwrapDI(Ty), isLocalToUnit, cast(unwrap(Val)), unwrapDIptr(Decl))); } extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateVariable( LLVMRustDIBuilderRef Builder, unsigned Tag, LLVMRustMetadataRef Scope, const char* Name, LLVMRustMetadataRef File, unsigned LineNo, LLVMRustMetadataRef Ty, bool AlwaysPreserve, unsigned Flags, int64_t* AddrOps, unsigned AddrOpsCount, unsigned ArgNo) { #if LLVM_VERSION_MINOR >= 8 if (Tag == 0x100) { // DW_TAG_auto_variable return wrap(Builder->createAutoVariable( unwrapDI(Scope), Name, unwrapDI(File), LineNo, unwrapDI(Ty), AlwaysPreserve, Flags)); } else { return wrap(Builder->createParameterVariable( unwrapDI(Scope), Name, ArgNo, unwrapDI(File), LineNo, unwrapDI(Ty), AlwaysPreserve, Flags)); } #else return wrap(Builder->createLocalVariable(Tag, unwrapDI(Scope), Name, unwrapDI(File), LineNo, unwrapDI(Ty), AlwaysPreserve, Flags, ArgNo)); #endif } extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateArrayType( LLVMRustDIBuilderRef Builder, uint64_t Size, uint64_t AlignInBits, LLVMRustMetadataRef Ty, LLVMRustMetadataRef Subscripts) { return wrap(Builder->createArrayType(Size, AlignInBits, unwrapDI(Ty), DINodeArray(unwrapDI(Subscripts)) )); } extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateVectorType( LLVMRustDIBuilderRef Builder, uint64_t Size, uint64_t AlignInBits, LLVMRustMetadataRef Ty, LLVMRustMetadataRef Subscripts) { return wrap(Builder->createVectorType(Size, AlignInBits, unwrapDI(Ty), DINodeArray(unwrapDI(Subscripts)) )); } extern "C" LLVMRustMetadataRef LLVMRustDIBuilderGetOrCreateSubrange( LLVMRustDIBuilderRef Builder, int64_t Lo, int64_t Count) { return wrap(Builder->getOrCreateSubrange(Lo, Count)); } extern "C" LLVMRustMetadataRef LLVMRustDIBuilderGetOrCreateArray( LLVMRustDIBuilderRef Builder, LLVMRustMetadataRef* Ptr, unsigned Count) { Metadata **DataValue = unwrap(Ptr); return wrap(Builder->getOrCreateArray( ArrayRef(DataValue, Count)).get()); } extern "C" LLVMValueRef LLVMRustDIBuilderInsertDeclareAtEnd( LLVMRustDIBuilderRef Builder, LLVMValueRef Val, LLVMRustMetadataRef VarInfo, int64_t* AddrOps, unsigned AddrOpsCount, LLVMValueRef DL, LLVMBasicBlockRef InsertAtEnd) { return wrap(Builder->insertDeclare( unwrap(Val), unwrap(VarInfo), Builder->createExpression( llvm::ArrayRef(AddrOps, AddrOpsCount)), DebugLoc(cast(unwrap(DL)->getMetadata())), unwrap(InsertAtEnd))); } extern "C" LLVMValueRef LLVMRustDIBuilderInsertDeclareBefore( LLVMRustDIBuilderRef Builder, LLVMValueRef Val, LLVMRustMetadataRef VarInfo, int64_t* AddrOps, unsigned AddrOpsCount, LLVMValueRef DL, LLVMValueRef InsertBefore) { return wrap(Builder->insertDeclare( unwrap(Val), unwrap(VarInfo), Builder->createExpression( llvm::ArrayRef(AddrOps, AddrOpsCount)), DebugLoc(cast(unwrap(DL)->getMetadata())), unwrap(InsertBefore))); } extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateEnumerator( LLVMRustDIBuilderRef Builder, const char* Name, uint64_t Val) { return wrap(Builder->createEnumerator(Name, Val)); } extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateEnumerationType( LLVMRustDIBuilderRef Builder, LLVMRustMetadataRef Scope, const char* Name, LLVMRustMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, uint64_t AlignInBits, LLVMRustMetadataRef Elements, LLVMRustMetadataRef ClassType) { return wrap(Builder->createEnumerationType( unwrapDI(Scope), Name, unwrapDI(File), LineNumber, SizeInBits, AlignInBits, DINodeArray(unwrapDI(Elements)), unwrapDI(ClassType))); } extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateUnionType( LLVMRustDIBuilderRef Builder, LLVMRustMetadataRef Scope, const char* Name, LLVMRustMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, uint64_t AlignInBits, unsigned Flags, LLVMRustMetadataRef Elements, unsigned RunTimeLang, const char* UniqueId) { return wrap(Builder->createUnionType( unwrapDI(Scope), Name, unwrapDI(File), LineNumber, SizeInBits, AlignInBits, Flags, DINodeArray(unwrapDI(Elements)), RunTimeLang, UniqueId )); } extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateTemplateTypeParameter( LLVMRustDIBuilderRef Builder, LLVMRustMetadataRef Scope, const char* Name, LLVMRustMetadataRef Ty, LLVMRustMetadataRef File, unsigned LineNo, unsigned ColumnNo) { return wrap(Builder->createTemplateTypeParameter( unwrapDI(Scope), Name, unwrapDI(Ty) )); } extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateNameSpace( LLVMRustDIBuilderRef Builder, LLVMRustMetadataRef Scope, const char* Name, LLVMRustMetadataRef File, unsigned LineNo) { return wrap(Builder->createNameSpace( unwrapDI(Scope), Name, unwrapDI(File), LineNo)); } extern "C" void LLVMRustDICompositeTypeSetTypeArray( LLVMRustDIBuilderRef Builder, LLVMRustMetadataRef CompositeType, LLVMRustMetadataRef TypeArray) { DICompositeType *tmp = unwrapDI(CompositeType); Builder->replaceArrays(tmp, DINodeArray(unwrap(TypeArray))); } extern "C" LLVMValueRef LLVMRustDIBuilderCreateDebugLocation( LLVMContextRef Context, unsigned Line, unsigned Column, LLVMRustMetadataRef Scope, LLVMRustMetadataRef InlinedAt) { LLVMContext& context = *unwrap(Context); DebugLoc debug_loc = DebugLoc::get(Line, Column, unwrapDIptr(Scope), unwrapDIptr(InlinedAt)); return wrap(MetadataAsValue::get(context, debug_loc.getAsMDNode())); } extern "C" int64_t LLVMRustDIBuilderCreateOpDeref() { return dwarf::DW_OP_deref; } extern "C" int64_t LLVMRustDIBuilderCreateOpPlus() { return dwarf::DW_OP_plus; } extern "C" void LLVMRustWriteTypeToString(LLVMTypeRef Type, RustStringRef str) { raw_rust_string_ostream os(str); unwrap(Type)->print(os); } extern "C" void LLVMRustWriteValueToString(LLVMValueRef Value, RustStringRef str) { raw_rust_string_ostream os(str); os << "("; unwrap(Value)->getType()->print(os); os << ":"; unwrap(Value)->print(os); os << ")"; } extern "C" bool LLVMRustLinkInExternalBitcode(LLVMModuleRef dst, char *bc, size_t len) { Module *Dst = unwrap(dst); std::unique_ptr buf = MemoryBuffer::getMemBufferCopy(StringRef(bc, len)); ErrorOr> Src = llvm::getLazyBitcodeModule(std::move(buf), Dst->getContext()); if (!Src) { LLVMRustSetLastError(Src.getError().message().c_str()); return false; } std::string Err; raw_string_ostream Stream(Err); DiagnosticPrinterRawOStream DP(Stream); #if LLVM_VERSION_MINOR >= 8 if (Linker::linkModules(*Dst, std::move(Src.get()))) { #else if (Linker::LinkModules(Dst, Src->get(), [&](const DiagnosticInfo &DI) { DI.print(DP); })) { #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 // 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" size_t LLVMRustGetSectionName(LLVMSectionIteratorRef SI, const char **ptr) { StringRef ret; if (std::error_code ec = (*unwrap(SI))->getName(ret)) 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 LLVMRustWriteTwineToString(LLVMTwineRef T, RustStringRef str) { raw_rust_string_ostream os(str); unwrap(T)->print(os); } extern "C" void LLVMRustUnpackOptimizationDiagnostic( 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(unwrap(di)); *pass_name_out = opt->getPassName(); *function_out = wrap(&opt->getFunction()); *debugloc_out = wrap(&opt->getDebugLoc()); *message_out = wrap(&opt->getMsg()); } extern "C" void LLVMRustUnpackInlineAsmDiagnostic( 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(unwrap(di)); *cookie_out = ia->getLocCookie(); *message_out = wrap(&ia->getMsgStr()); *instruction_out = wrap(ia->getInstruction()); } extern "C" void LLVMRustWriteDiagnosticInfoToString(LLVMDiagnosticInfoRef di, RustStringRef str) { raw_rust_string_ostream os(str); DiagnosticPrinterRawOStream dp(os); unwrap(di)->print(dp); } enum class LLVMRustDiagnosticKind { Other, InlineAsm, StackSize, DebugMetadataVersion, SampleProfile, OptimizationRemark, OptimizationRemarkMissed, OptimizationRemarkAnalysis, OptimizationRemarkAnalysisFPCommute, OptimizationRemarkAnalysisAliasing, OptimizationRemarkOther, OptimizationFailure, }; static LLVMRustDiagnosticKind to_rust(DiagnosticKind kind) { switch (kind) { case DK_InlineAsm: return LLVMRustDiagnosticKind::InlineAsm; case DK_StackSize: return LLVMRustDiagnosticKind::StackSize; case DK_DebugMetadataVersion: return LLVMRustDiagnosticKind::DebugMetadataVersion; case DK_SampleProfile: return LLVMRustDiagnosticKind::SampleProfile; case DK_OptimizationRemark: return LLVMRustDiagnosticKind::OptimizationRemark; case DK_OptimizationRemarkMissed: return LLVMRustDiagnosticKind::OptimizationRemarkMissed; case DK_OptimizationRemarkAnalysis: return LLVMRustDiagnosticKind::OptimizationRemarkAnalysis; #if LLVM_VERSION_MINOR >= 8 case DK_OptimizationRemarkAnalysisFPCommute: return LLVMRustDiagnosticKind::OptimizationRemarkAnalysisFPCommute; case DK_OptimizationRemarkAnalysisAliasing: return LLVMRustDiagnosticKind::OptimizationRemarkAnalysisAliasing; #endif default: #if LLVM_VERSION_MINOR >= 9 return (kind >= DK_FirstRemark && kind <= DK_LastRemark) ? LLVMRustDiagnosticKind::OptimizationRemarkOther : LLVMRustDiagnosticKind::Other; #else return LLVMRustDiagnosticKind::Other; #endif } } extern "C" LLVMRustDiagnosticKind LLVMRustGetDiagInfoKind(LLVMDiagnosticInfoRef di) { return to_rust((DiagnosticKind) unwrap(di)->getKind()); } // This is kept distinct from LLVMGetTypeKind, because when // a new type kind is added, the Rust-side enum must be // updated or UB will result. extern "C" LLVMTypeKind LLVMRustGetTypeKind(LLVMTypeRef Ty) { switch (unwrap(Ty)->getTypeID()) { case Type::VoidTyID: return LLVMVoidTypeKind; case Type::HalfTyID: return LLVMHalfTypeKind; case Type::FloatTyID: return LLVMFloatTypeKind; case Type::DoubleTyID: return LLVMDoubleTypeKind; case Type::X86_FP80TyID: return LLVMX86_FP80TypeKind; case Type::FP128TyID: return LLVMFP128TypeKind; case Type::PPC_FP128TyID: return LLVMPPC_FP128TypeKind; case Type::LabelTyID: return LLVMLabelTypeKind; case Type::MetadataTyID: return LLVMMetadataTypeKind; case Type::IntegerTyID: return LLVMIntegerTypeKind; case Type::FunctionTyID: return LLVMFunctionTypeKind; case Type::StructTyID: return LLVMStructTypeKind; case Type::ArrayTyID: return LLVMArrayTypeKind; case Type::PointerTyID: return LLVMPointerTypeKind; case Type::VectorTyID: return LLVMVectorTypeKind; case Type::X86_MMXTyID: return LLVMX86_MMXTypeKind; #if LLVM_VERSION_MINOR >= 8 case Type::TokenTyID: return LLVMTokenTypeKind; #endif } llvm_unreachable("Unhandled TypeID."); } extern "C" void LLVMRustWriteDebugLocToString( LLVMContextRef C, LLVMDebugLocRef dl, RustStringRef str) { raw_rust_string_ostream os(str); unwrap(dl)->print(os); } DEFINE_SIMPLE_CONVERSION_FUNCTIONS(SMDiagnostic, LLVMSMDiagnosticRef) extern "C" void LLVMRustSetInlineAsmDiagnosticHandler( LLVMContextRef C, LLVMContext::InlineAsmDiagHandlerTy H, void *CX) { unwrap(C)->setInlineAsmDiagnosticHandler(H, CX); } extern "C" void LLVMRustWriteSMDiagnosticToString(LLVMSMDiagnosticRef d, RustStringRef str) { raw_rust_string_ostream os(str); unwrap(d)->print("", os); } extern "C" LLVMValueRef LLVMRustBuildLandingPad(LLVMBuilderRef Builder, LLVMTypeRef Ty, LLVMValueRef PersFn, unsigned NumClauses, const char* Name, LLVMValueRef F) { return LLVMBuildLandingPad(Builder, Ty, PersFn, NumClauses, Name); } extern "C" LLVMValueRef LLVMRustBuildCleanupPad(LLVMBuilderRef Builder, LLVMValueRef ParentPad, unsigned ArgCnt, LLVMValueRef *LLArgs, const char *Name) { #if LLVM_VERSION_MINOR >= 8 Value **Args = unwrap(LLArgs); if (ParentPad == NULL) { Type *Ty = Type::getTokenTy(unwrap(Builder)->getContext()); ParentPad = wrap(Constant::getNullValue(Ty)); } return wrap(unwrap(Builder)->CreateCleanupPad(unwrap(ParentPad), ArrayRef(Args, ArgCnt), Name)); #else return NULL; #endif } extern "C" LLVMValueRef LLVMRustBuildCleanupRet(LLVMBuilderRef Builder, LLVMValueRef CleanupPad, LLVMBasicBlockRef UnwindBB) { #if LLVM_VERSION_MINOR >= 8 CleanupPadInst *Inst = cast(unwrap(CleanupPad)); return wrap(unwrap(Builder)->CreateCleanupRet(Inst, unwrap(UnwindBB))); #else return NULL; #endif } extern "C" LLVMValueRef LLVMRustBuildCatchPad(LLVMBuilderRef Builder, LLVMValueRef ParentPad, unsigned ArgCnt, LLVMValueRef *LLArgs, const char *Name) { #if LLVM_VERSION_MINOR >= 8 Value **Args = unwrap(LLArgs); return wrap(unwrap(Builder)->CreateCatchPad(unwrap(ParentPad), ArrayRef(Args, ArgCnt), Name)); #else return NULL; #endif } extern "C" LLVMValueRef LLVMRustBuildCatchRet(LLVMBuilderRef Builder, LLVMValueRef Pad, LLVMBasicBlockRef BB) { #if LLVM_VERSION_MINOR >= 8 return wrap(unwrap(Builder)->CreateCatchRet(cast(unwrap(Pad)), unwrap(BB))); #else return NULL; #endif } extern "C" LLVMValueRef LLVMRustBuildCatchSwitch(LLVMBuilderRef Builder, LLVMValueRef ParentPad, LLVMBasicBlockRef BB, unsigned NumHandlers, const char *Name) { #if LLVM_VERSION_MINOR >= 8 if (ParentPad == NULL) { Type *Ty = Type::getTokenTy(unwrap(Builder)->getContext()); ParentPad = wrap(Constant::getNullValue(Ty)); } return wrap(unwrap(Builder)->CreateCatchSwitch(unwrap(ParentPad), unwrap(BB), NumHandlers, Name)); #else return NULL; #endif } extern "C" void LLVMRustAddHandler(LLVMValueRef CatchSwitchRef, LLVMBasicBlockRef Handler) { #if LLVM_VERSION_MINOR >= 8 Value *CatchSwitch = unwrap(CatchSwitchRef); cast(CatchSwitch)->addHandler(unwrap(Handler)); #endif } extern "C" void LLVMRustSetPersonalityFn(LLVMBuilderRef B, LLVMValueRef Personality) { #if LLVM_VERSION_MINOR >= 8 unwrap(B)->GetInsertBlock() ->getParent() ->setPersonalityFn(cast(unwrap(Personality))); #endif } #if LLVM_VERSION_MINOR >= 8 extern "C" OperandBundleDef* LLVMRustBuildOperandBundleDef(const char *Name, LLVMValueRef *Inputs, unsigned NumInputs) { return new OperandBundleDef(Name, makeArrayRef(unwrap(Inputs), NumInputs)); } extern "C" void LLVMRustFreeOperandBundleDef(OperandBundleDef* Bundle) { delete Bundle; } extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args, unsigned NumArgs, OperandBundleDef *Bundle, const char *Name) { unsigned len = Bundle ? 1 : 0; ArrayRef Bundles = makeArrayRef(Bundle, len); return wrap(unwrap(B)->CreateCall(unwrap(Fn), makeArrayRef(unwrap(Args), NumArgs), Bundles, Name)); } extern "C" LLVMValueRef LLVMRustBuildInvoke(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args, unsigned NumArgs, LLVMBasicBlockRef Then, LLVMBasicBlockRef Catch, OperandBundleDef *Bundle, const char *Name) { unsigned len = Bundle ? 1 : 0; ArrayRef Bundles = makeArrayRef(Bundle, len); return wrap(unwrap(B)->CreateInvoke(unwrap(Fn), unwrap(Then), unwrap(Catch), makeArrayRef(unwrap(Args), NumArgs), Bundles, Name)); } #else extern "C" void* LLVMRustBuildOperandBundleDef(const char *Name, LLVMValueRef *Inputs, unsigned NumInputs) { return NULL; } extern "C" void LLVMRustFreeOperandBundleDef(void* Bundle) { } extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args, unsigned NumArgs, void *Bundle, const char *Name) { return LLVMBuildCall(B, Fn, Args, NumArgs, Name); } extern "C" LLVMValueRef LLVMRustBuildInvoke(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args, unsigned NumArgs, LLVMBasicBlockRef Then, LLVMBasicBlockRef Catch, void *Bundle, const char *Name) { return LLVMBuildInvoke(B, Fn, Args, NumArgs, Then, Catch, Name); } #endif extern "C" void LLVMRustPositionBuilderAtStart(LLVMBuilderRef B, LLVMBasicBlockRef BB) { auto point = unwrap(BB)->getFirstInsertionPt(); unwrap(B)->SetInsertPoint(unwrap(BB), point); } extern "C" void LLVMRustSetComdat(LLVMModuleRef M, LLVMValueRef V, const char *Name) { Triple TargetTriple(unwrap(M)->getTargetTriple()); GlobalObject *GV = unwrap(V); if (!TargetTriple.isOSBinFormatMachO()) { GV->setComdat(unwrap(M)->getOrInsertComdat(Name)); } } extern "C" void LLVMRustUnsetComdat(LLVMValueRef V) { GlobalObject *GV = unwrap(V); GV->setComdat(nullptr); }