2011-10-22 02:35:52 +02:00
|
|
|
//===- RustWrapper.cpp - Rust wrapper for core functions --------*- C++ -*-===
|
2011-03-15 22:57:26 +01:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
2011-10-22 02:35:52 +02:00
|
|
|
//===----------------------------------------------------------------------===
|
2011-03-15 22:57:26 +01:00
|
|
|
//
|
|
|
|
// This file defines alternate interfaces to core functions that are more
|
|
|
|
// readily callable by Rust's FFI.
|
|
|
|
//
|
2011-10-22 02:35:52 +02:00
|
|
|
//===----------------------------------------------------------------------===
|
2011-03-15 22:57:26 +01:00
|
|
|
|
2011-11-26 07:00:43 +01:00
|
|
|
#include "llvm/LLVMContext.h"
|
2011-05-05 06:27:00 +02:00
|
|
|
#include "llvm/Linker.h"
|
2011-04-15 23:35:46 +02:00
|
|
|
#include "llvm/PassManager.h"
|
2012-08-28 03:39:34 +02:00
|
|
|
#include "llvm/Analysis/Verifier.h"
|
|
|
|
#include "llvm/Analysis/Passes.h"
|
|
|
|
#include "llvm/Transforms/Scalar.h"
|
2012-08-28 03:42:14 +02:00
|
|
|
#include "llvm/Transforms/IPO.h"
|
2011-04-15 23:35:46 +02:00
|
|
|
#include "llvm/ADT/Triple.h"
|
2011-11-26 07:00:43 +01:00
|
|
|
#include "llvm/Assembly/Parser.h"
|
2011-11-07 14:32:13 +01:00
|
|
|
#include "llvm/Assembly/PrintModulePass.h"
|
2011-04-15 23:35:46 +02:00
|
|
|
#include "llvm/Support/FormattedStream.h"
|
2011-05-11 01:10:08 +02:00
|
|
|
#include "llvm/Support/Timer.h"
|
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2011-04-15 23:35:46 +02:00
|
|
|
#include "llvm/Target/TargetMachine.h"
|
2011-08-28 20:58:10 +02:00
|
|
|
#include "llvm/Support/TargetSelect.h"
|
|
|
|
#include "llvm/Support/TargetRegistry.h"
|
2011-11-26 07:00:43 +01:00
|
|
|
#include "llvm/Support/SourceMgr.h"
|
2011-04-27 00:21:20 +02:00
|
|
|
#include "llvm/Target/TargetOptions.h"
|
2011-05-06 15:59:33 +02:00
|
|
|
#include "llvm/Support/Host.h"
|
2012-07-25 21:06:03 +02:00
|
|
|
#include "llvm/Support/Debug.h"
|
2012-08-25 06:54:30 +02:00
|
|
|
#include "llvm/Support/DynamicLibrary.h"
|
2012-08-26 14:40:21 +02:00
|
|
|
#include "llvm/Support/Memory.h"
|
2012-08-25 06:54:30 +02:00
|
|
|
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
|
|
|
#include "llvm/ExecutionEngine/JIT.h"
|
2012-08-26 14:40:21 +02:00
|
|
|
#include "llvm/ExecutionEngine/JITMemoryManager.h"
|
|
|
|
#include "llvm/ExecutionEngine/MCJIT.h"
|
2012-08-25 06:54:30 +02:00
|
|
|
#include "llvm/ExecutionEngine/Interpreter.h"
|
2011-03-15 22:57:26 +01:00
|
|
|
#include "llvm-c/Core.h"
|
2011-05-05 20:34:15 +02:00
|
|
|
#include "llvm-c/BitReader.h"
|
2011-03-15 22:57:26 +01:00
|
|
|
#include "llvm-c/Object.h"
|
|
|
|
#include <cstdlib>
|
|
|
|
|
2012-08-26 14:40:21 +02:00
|
|
|
// Used by RustMCJITMemoryManager::getPointerToNamedFunction()
|
|
|
|
// to get around glibc issues. See the function for more information.
|
|
|
|
#ifdef __linux__
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
2011-04-15 23:35:46 +02:00
|
|
|
using namespace llvm;
|
|
|
|
|
2011-05-05 06:27:00 +02:00
|
|
|
static const char *LLVMRustError;
|
2011-03-15 22:57:26 +01:00
|
|
|
|
|
|
|
extern "C" LLVMMemoryBufferRef
|
|
|
|
LLVMRustCreateMemoryBufferWithContentsOfFile(const char *Path) {
|
|
|
|
LLVMMemoryBufferRef MemBuf = NULL;
|
2011-05-05 06:27:00 +02:00
|
|
|
LLVMCreateMemoryBufferWithContentsOfFile(Path, &MemBuf,
|
|
|
|
const_cast<char **>(&LLVMRustError));
|
2011-03-15 22:57:26 +01:00
|
|
|
return MemBuf;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" const char *LLVMRustGetLastError(void) {
|
|
|
|
return LLVMRustError;
|
|
|
|
}
|
|
|
|
|
2011-04-13 19:53:19 +02:00
|
|
|
extern "C" void LLVMAddBasicAliasAnalysisPass(LLVMPassManagerRef PM);
|
2011-04-18 16:02:34 +02:00
|
|
|
|
2011-11-07 14:32:13 +01:00
|
|
|
extern "C" void LLVMRustAddPrintModulePass(LLVMPassManagerRef PMR,
|
|
|
|
LLVMModuleRef M,
|
|
|
|
const char* path) {
|
|
|
|
PassManager *PM = unwrap<PassManager>(PMR);
|
|
|
|
std::string ErrorInfo;
|
|
|
|
raw_fd_ostream OS(path, ErrorInfo, raw_fd_ostream::F_Binary);
|
|
|
|
formatted_raw_ostream FOS(OS);
|
|
|
|
PM->add(createPrintModulePass(&FOS));
|
|
|
|
PM->run(*unwrap(M));
|
|
|
|
}
|
|
|
|
|
2012-07-21 09:20:45 +02:00
|
|
|
void LLVMInitializeX86TargetInfo();
|
|
|
|
void LLVMInitializeX86Target();
|
|
|
|
void LLVMInitializeX86TargetMC();
|
|
|
|
void LLVMInitializeX86AsmPrinter();
|
|
|
|
void LLVMInitializeX86AsmParser();
|
|
|
|
|
2012-08-25 06:54:30 +02:00
|
|
|
// Only initialize the platforms supported by Rust here,
|
|
|
|
// because using --llvm-root will have multiple platforms
|
|
|
|
// that rustllvm doesn't actually link to and it's pointless to put target info
|
|
|
|
// into the registry that Rust can not generate machine code for.
|
|
|
|
|
2012-08-29 07:49:35 +02:00
|
|
|
void LLVMRustInitializeTargets() {
|
|
|
|
LLVMInitializeX86TargetInfo();
|
|
|
|
LLVMInitializeX86Target();
|
|
|
|
LLVMInitializeX86TargetMC();
|
|
|
|
LLVMInitializeX86AsmPrinter();
|
|
|
|
LLVMInitializeX86AsmParser();
|
|
|
|
}
|
2012-08-25 06:54:30 +02:00
|
|
|
|
|
|
|
extern "C" bool
|
2012-08-26 14:40:21 +02:00
|
|
|
LLVMRustLoadLibrary(const char* file) {
|
|
|
|
std::string err;
|
|
|
|
|
|
|
|
if(llvm::sys::DynamicLibrary::LoadLibraryPermanently(file, &err)) {
|
|
|
|
LLVMRustError = err.c_str();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Custom memory manager for MCJITting. It needs special features
|
|
|
|
// that the generic JIT memory manager doesn't entail. Based on
|
|
|
|
// code from LLI, change where needed for Rust.
|
|
|
|
class RustMCJITMemoryManager : public JITMemoryManager {
|
|
|
|
public:
|
|
|
|
SmallVector<sys::MemoryBlock, 16> AllocatedDataMem;
|
|
|
|
SmallVector<sys::MemoryBlock, 16> AllocatedCodeMem;
|
|
|
|
SmallVector<sys::MemoryBlock, 16> FreeCodeMem;
|
2012-08-29 07:49:35 +02:00
|
|
|
void* __morestack;
|
2012-08-26 14:40:21 +02:00
|
|
|
|
2012-08-29 07:49:35 +02:00
|
|
|
RustMCJITMemoryManager(void* sym) : __morestack(sym) { }
|
2012-08-26 14:40:21 +02:00
|
|
|
~RustMCJITMemoryManager();
|
|
|
|
|
|
|
|
virtual uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
|
|
|
|
unsigned SectionID);
|
|
|
|
|
|
|
|
virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
|
|
|
|
unsigned SectionID);
|
|
|
|
|
|
|
|
virtual void *getPointerToNamedFunction(const std::string &Name,
|
|
|
|
bool AbortOnFailure = true);
|
|
|
|
|
|
|
|
// Invalidate instruction cache for code sections. Some platforms with
|
|
|
|
// separate data cache and instruction cache require explicit cache flush,
|
|
|
|
// otherwise JIT code manipulations (like resolved relocations) will get to
|
|
|
|
// the data cache but not to the instruction cache.
|
|
|
|
virtual void invalidateInstructionCache();
|
|
|
|
|
|
|
|
// The MCJITMemoryManager doesn't use the following functions, so we don't
|
|
|
|
// need implement them.
|
|
|
|
virtual void setMemoryWritable() {
|
|
|
|
llvm_unreachable("Unimplemented call");
|
|
|
|
}
|
|
|
|
virtual void setMemoryExecutable() {
|
|
|
|
llvm_unreachable("Unimplemented call");
|
|
|
|
}
|
|
|
|
virtual void setPoisonMemory(bool poison) {
|
|
|
|
llvm_unreachable("Unimplemented call");
|
|
|
|
}
|
|
|
|
virtual void AllocateGOT() {
|
|
|
|
llvm_unreachable("Unimplemented call");
|
|
|
|
}
|
|
|
|
virtual uint8_t *getGOTBase() const {
|
|
|
|
llvm_unreachable("Unimplemented call");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
virtual uint8_t *startFunctionBody(const Function *F,
|
|
|
|
uintptr_t &ActualSize){
|
|
|
|
llvm_unreachable("Unimplemented call");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
virtual uint8_t *allocateStub(const GlobalValue* F, unsigned StubSize,
|
|
|
|
unsigned Alignment) {
|
|
|
|
llvm_unreachable("Unimplemented call");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
virtual void endFunctionBody(const Function *F, uint8_t *FunctionStart,
|
|
|
|
uint8_t *FunctionEnd) {
|
|
|
|
llvm_unreachable("Unimplemented call");
|
|
|
|
}
|
|
|
|
virtual uint8_t *allocateSpace(intptr_t Size, unsigned Alignment) {
|
|
|
|
llvm_unreachable("Unimplemented call");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
virtual uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment) {
|
|
|
|
llvm_unreachable("Unimplemented call");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
virtual void deallocateFunctionBody(void *Body) {
|
|
|
|
llvm_unreachable("Unimplemented call");
|
|
|
|
}
|
|
|
|
virtual uint8_t* startExceptionTable(const Function* F,
|
|
|
|
uintptr_t &ActualSize) {
|
|
|
|
llvm_unreachable("Unimplemented call");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
virtual void endExceptionTable(const Function *F, uint8_t *TableStart,
|
|
|
|
uint8_t *TableEnd, uint8_t* FrameRegister) {
|
|
|
|
llvm_unreachable("Unimplemented call");
|
|
|
|
}
|
|
|
|
virtual void deallocateExceptionTable(void *ET) {
|
|
|
|
llvm_unreachable("Unimplemented call");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
uint8_t *RustMCJITMemoryManager::allocateDataSection(uintptr_t Size,
|
|
|
|
unsigned Alignment,
|
|
|
|
unsigned SectionID) {
|
|
|
|
if (!Alignment)
|
|
|
|
Alignment = 16;
|
|
|
|
uint8_t *Addr = (uint8_t*)calloc((Size + Alignment - 1)/Alignment, Alignment);
|
|
|
|
AllocatedDataMem.push_back(sys::MemoryBlock(Addr, Size));
|
|
|
|
return Addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t *RustMCJITMemoryManager::allocateCodeSection(uintptr_t Size,
|
|
|
|
unsigned Alignment,
|
|
|
|
unsigned SectionID) {
|
|
|
|
if (!Alignment)
|
|
|
|
Alignment = 16;
|
|
|
|
unsigned NeedAllocate = Alignment * ((Size + Alignment - 1)/Alignment + 1);
|
|
|
|
uintptr_t Addr = 0;
|
|
|
|
// Look in the list of free code memory regions and use a block there if one
|
|
|
|
// is available.
|
|
|
|
for (int i = 0, e = FreeCodeMem.size(); i != e; ++i) {
|
|
|
|
sys::MemoryBlock &MB = FreeCodeMem[i];
|
|
|
|
if (MB.size() >= NeedAllocate) {
|
|
|
|
Addr = (uintptr_t)MB.base();
|
|
|
|
uintptr_t EndOfBlock = Addr + MB.size();
|
|
|
|
// Align the address.
|
|
|
|
Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1);
|
|
|
|
// Store cutted free memory block.
|
|
|
|
FreeCodeMem[i] = sys::MemoryBlock((void*)(Addr + Size),
|
|
|
|
EndOfBlock - Addr - Size);
|
|
|
|
return (uint8_t*)Addr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// No pre-allocated free block was large enough. Allocate a new memory region.
|
|
|
|
sys::MemoryBlock MB = sys::Memory::AllocateRWX(NeedAllocate, 0, 0);
|
|
|
|
|
|
|
|
AllocatedCodeMem.push_back(MB);
|
|
|
|
Addr = (uintptr_t)MB.base();
|
|
|
|
uintptr_t EndOfBlock = Addr + MB.size();
|
|
|
|
// Align the address.
|
|
|
|
Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1);
|
|
|
|
// The AllocateRWX may allocate much more memory than we need. In this case,
|
|
|
|
// we store the unused memory as a free memory block.
|
|
|
|
unsigned FreeSize = EndOfBlock-Addr-Size;
|
|
|
|
if (FreeSize > 16)
|
|
|
|
FreeCodeMem.push_back(sys::MemoryBlock((void*)(Addr + Size), FreeSize));
|
|
|
|
|
|
|
|
// Return aligned address
|
|
|
|
return (uint8_t*)Addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void RustMCJITMemoryManager::invalidateInstructionCache() {
|
|
|
|
for (int i = 0, e = AllocatedCodeMem.size(); i != e; ++i)
|
|
|
|
sys::Memory::InvalidateInstructionCache(AllocatedCodeMem[i].base(),
|
|
|
|
AllocatedCodeMem[i].size());
|
|
|
|
}
|
|
|
|
|
|
|
|
void *RustMCJITMemoryManager::getPointerToNamedFunction(const std::string &Name,
|
|
|
|
bool AbortOnFailure) {
|
|
|
|
#ifdef __linux__
|
|
|
|
// Force the following functions to be linked in to anything that uses the
|
|
|
|
// JIT. This is a hack designed to work around the all-too-clever Glibc
|
|
|
|
// strategy of making these functions work differently when inlined vs. when
|
|
|
|
// not inlined, and hiding their real definitions in a separate archive file
|
|
|
|
// that the dynamic linker can't see. For more info, search for
|
|
|
|
// 'libc_nonshared.a' on Google, or read http://llvm.org/PR274.
|
|
|
|
if (Name == "stat") return (void*)(intptr_t)&stat;
|
|
|
|
if (Name == "fstat") return (void*)(intptr_t)&fstat;
|
|
|
|
if (Name == "lstat") return (void*)(intptr_t)&lstat;
|
|
|
|
if (Name == "stat64") return (void*)(intptr_t)&stat64;
|
|
|
|
if (Name == "fstat64") return (void*)(intptr_t)&fstat64;
|
|
|
|
if (Name == "lstat64") return (void*)(intptr_t)&lstat64;
|
|
|
|
if (Name == "atexit") return (void*)(intptr_t)&atexit;
|
|
|
|
if (Name == "mknod") return (void*)(intptr_t)&mknod;
|
|
|
|
#endif
|
|
|
|
|
2012-08-29 07:49:35 +02:00
|
|
|
if (Name == "__morestack") return &__morestack;
|
2012-08-28 01:51:30 +02:00
|
|
|
|
2012-08-26 14:40:21 +02:00
|
|
|
const char *NameStr = Name.c_str();
|
|
|
|
void *Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr);
|
|
|
|
if (Ptr) return Ptr;
|
|
|
|
|
|
|
|
if (AbortOnFailure)
|
|
|
|
report_fatal_error("Program used external function '" + Name +
|
|
|
|
"' which could not be resolved!");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
RustMCJITMemoryManager::~RustMCJITMemoryManager() {
|
|
|
|
for (unsigned i = 0, e = AllocatedCodeMem.size(); i != e; ++i)
|
|
|
|
sys::Memory::ReleaseRWX(AllocatedCodeMem[i]);
|
|
|
|
for (unsigned i = 0, e = AllocatedDataMem.size(); i != e; ++i)
|
|
|
|
free(AllocatedDataMem[i].base());
|
|
|
|
}
|
|
|
|
|
2012-08-29 07:49:35 +02:00
|
|
|
extern "C" void*
|
|
|
|
LLVMRustJIT(void* __morestack,
|
|
|
|
LLVMPassManagerRef PMR,
|
2012-08-25 06:54:30 +02:00
|
|
|
LLVMModuleRef M,
|
|
|
|
CodeGenOpt::Level OptLevel,
|
|
|
|
bool EnableSegmentedStacks) {
|
|
|
|
|
|
|
|
InitializeNativeTarget();
|
|
|
|
InitializeNativeTargetAsmPrinter();
|
|
|
|
|
|
|
|
std::string Err;
|
|
|
|
TargetOptions Options;
|
2012-08-26 14:40:21 +02:00
|
|
|
Options.JITEmitDebugInfo = true;
|
2012-08-28 01:51:30 +02:00
|
|
|
Options.NoFramePointerElim = true;
|
|
|
|
Options.EnableSegmentedStacks = EnableSegmentedStacks;
|
2012-08-28 03:39:34 +02:00
|
|
|
PassManager *PM = unwrap<PassManager>(PMR);
|
2012-08-25 06:54:30 +02:00
|
|
|
|
2012-08-28 03:39:34 +02:00
|
|
|
PM->add(createBasicAliasAnalysisPass());
|
|
|
|
PM->add(createInstructionCombiningPass());
|
|
|
|
PM->add(createReassociatePass());
|
|
|
|
PM->add(createGVNPass());
|
|
|
|
PM->add(createCFGSimplificationPass());
|
|
|
|
PM->add(createFunctionInliningPass());
|
2012-08-29 07:49:35 +02:00
|
|
|
PM->add(createPromoteMemoryToRegisterPass());
|
2012-08-28 03:39:34 +02:00
|
|
|
PM->run(*unwrap(M));
|
2012-08-25 06:54:30 +02:00
|
|
|
|
2012-08-29 07:49:35 +02:00
|
|
|
RustMCJITMemoryManager* MM = new RustMCJITMemoryManager(__morestack);
|
|
|
|
ExecutionEngine* EE = EngineBuilder(unwrap(M))
|
2012-08-25 06:54:30 +02:00
|
|
|
.setTargetOptions(Options)
|
2012-08-26 14:40:21 +02:00
|
|
|
.setJITMemoryManager(MM)
|
2012-08-25 06:54:30 +02:00
|
|
|
.setOptLevel(OptLevel)
|
|
|
|
.setUseMCJIT(true)
|
2012-08-29 07:49:35 +02:00
|
|
|
.setAllocateGVsWithCode(false)
|
2012-08-25 06:54:30 +02:00
|
|
|
.create();
|
|
|
|
|
|
|
|
if(!EE || Err != "") {
|
|
|
|
LLVMRustError = Err.c_str();
|
2012-08-29 07:49:35 +02:00
|
|
|
return 0;
|
2012-08-25 06:54:30 +02:00
|
|
|
}
|
|
|
|
|
2012-08-26 14:40:21 +02:00
|
|
|
MM->invalidateInstructionCache();
|
2012-08-29 07:49:35 +02:00
|
|
|
Function* func = EE->FindFunctionNamed("_rust_main");
|
2012-08-25 06:54:30 +02:00
|
|
|
|
|
|
|
if(!func || Err != "") {
|
|
|
|
LLVMRustError = Err.c_str();
|
2012-08-29 07:49:35 +02:00
|
|
|
return 0;
|
2012-08-25 06:54:30 +02:00
|
|
|
}
|
|
|
|
|
2012-08-29 07:49:35 +02:00
|
|
|
void* entry = EE->getPointerToFunction(func);
|
2012-08-26 14:40:21 +02:00
|
|
|
assert(entry);
|
2012-08-25 06:54:30 +02:00
|
|
|
|
2012-08-29 07:49:35 +02:00
|
|
|
return entry;
|
2012-08-25 06:54:30 +02:00
|
|
|
}
|
|
|
|
|
2012-07-13 23:06:30 +02:00
|
|
|
extern "C" bool
|
2011-10-22 02:35:52 +02:00
|
|
|
LLVMRustWriteOutputFile(LLVMPassManagerRef PMR,
|
|
|
|
LLVMModuleRef M,
|
|
|
|
const char *triple,
|
|
|
|
const char *path,
|
|
|
|
TargetMachine::CodeGenFileType FileType,
|
2011-11-27 07:38:36 +01:00
|
|
|
CodeGenOpt::Level OptLevel,
|
|
|
|
bool EnableSegmentedStacks) {
|
2011-04-27 00:21:20 +02:00
|
|
|
|
2012-08-29 07:49:35 +02:00
|
|
|
LLVMRustInitializeTargets();
|
2011-11-27 07:38:36 +01:00
|
|
|
|
|
|
|
TargetOptions Options;
|
|
|
|
Options.NoFramePointerElim = true;
|
|
|
|
Options.EnableSegmentedStacks = EnableSegmentedStacks;
|
|
|
|
|
2011-04-15 23:35:46 +02:00
|
|
|
std::string Err;
|
|
|
|
const Target *TheTarget = TargetRegistry::lookupTarget(triple, Err);
|
|
|
|
std::string FeaturesStr;
|
2011-07-01 08:56:49 +02:00
|
|
|
std::string Trip(triple);
|
2012-05-01 00:40:04 +02:00
|
|
|
std::string CPUStr("generic");
|
2011-07-25 17:11:24 +02:00
|
|
|
TargetMachine *Target =
|
2011-11-27 07:38:36 +01:00
|
|
|
TheTarget->createTargetMachine(Trip, CPUStr, FeaturesStr,
|
|
|
|
Options, Reloc::PIC_,
|
|
|
|
CodeModel::Default, OptLevel);
|
2011-04-15 23:35:46 +02:00
|
|
|
bool NoVerify = false;
|
|
|
|
PassManager *PM = unwrap<PassManager>(PMR);
|
|
|
|
std::string ErrorInfo;
|
|
|
|
raw_fd_ostream OS(path, ErrorInfo,
|
|
|
|
raw_fd_ostream::F_Binary);
|
2012-07-13 23:06:30 +02:00
|
|
|
if (ErrorInfo != "") {
|
|
|
|
LLVMRustError = ErrorInfo.c_str();
|
|
|
|
return false;
|
|
|
|
}
|
2011-04-15 23:35:46 +02:00
|
|
|
formatted_raw_ostream FOS(OS);
|
2011-04-18 16:02:34 +02:00
|
|
|
|
2011-11-27 07:38:36 +01:00
|
|
|
bool foo = Target->addPassesToEmitFile(*PM, FOS, FileType, NoVerify);
|
2011-04-15 23:35:46 +02:00
|
|
|
assert(!foo);
|
2011-04-22 18:01:45 +02:00
|
|
|
(void)foo;
|
2011-04-15 23:35:46 +02:00
|
|
|
PM->run(*unwrap(M));
|
2011-05-14 06:48:51 +02:00
|
|
|
delete Target;
|
2012-07-13 23:06:30 +02:00
|
|
|
return true;
|
2011-04-15 23:35:46 +02:00
|
|
|
}
|
2011-05-05 20:34:15 +02:00
|
|
|
|
2011-11-26 07:00:43 +01:00
|
|
|
extern "C" LLVMModuleRef LLVMRustParseAssemblyFile(const char *Filename) {
|
|
|
|
|
|
|
|
SMDiagnostic d;
|
|
|
|
Module *m = ParseAssemblyFile(Filename, d, getGlobalContext());
|
|
|
|
if (m) {
|
|
|
|
return wrap(m);
|
|
|
|
} else {
|
|
|
|
LLVMRustError = d.getMessage().c_str();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-05 20:34:15 +02:00
|
|
|
extern "C" LLVMModuleRef LLVMRustParseBitcode(LLVMMemoryBufferRef MemBuf) {
|
|
|
|
LLVMModuleRef M;
|
|
|
|
return LLVMParseBitcode(MemBuf, &M, const_cast<char **>(&LLVMRustError))
|
|
|
|
? NULL : M;
|
|
|
|
}
|
|
|
|
|
2011-05-07 20:54:23 +02:00
|
|
|
extern "C" LLVMValueRef LLVMRustConstSmallInt(LLVMTypeRef IntTy, unsigned N,
|
|
|
|
LLVMBool SignExtend) {
|
|
|
|
return LLVMConstInt(IntTy, (unsigned long long)N, SignExtend);
|
|
|
|
}
|
2011-05-11 01:10:08 +02:00
|
|
|
|
2011-11-16 21:15:54 +01: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-11 01:10:08 +02:00
|
|
|
extern bool llvm::TimePassesIsEnabled;
|
|
|
|
extern "C" void LLVMRustEnableTimePasses() {
|
|
|
|
TimePassesIsEnabled = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" void LLVMRustPrintPassTimings() {
|
|
|
|
raw_fd_ostream OS (2, false); // stderr.
|
|
|
|
TimerGroup::printAll(OS);
|
|
|
|
}
|
2011-10-31 22:42:17 +01:00
|
|
|
|
2011-11-14 17:32:31 +01:00
|
|
|
extern "C" LLVMValueRef LLVMGetOrInsertFunction(LLVMModuleRef M,
|
|
|
|
const char* Name,
|
|
|
|
LLVMTypeRef FunctionTy) {
|
|
|
|
return wrap(unwrap(M)->getOrInsertFunction(Name,
|
|
|
|
unwrap<FunctionType>(FunctionTy)));
|
|
|
|
}
|
2011-11-10 06:55:09 +01:00
|
|
|
|
|
|
|
extern "C" LLVMTypeRef LLVMMetadataTypeInContext(LLVMContextRef C) {
|
|
|
|
return wrap(Type::getMetadataTy(*unwrap(C)));
|
|
|
|
}
|
|
|
|
extern "C" LLVMTypeRef LLVMMetadataType(void) {
|
|
|
|
return LLVMMetadataTypeInContext(LLVMGetGlobalContext());
|
|
|
|
}
|
2012-06-22 00:01:32 +02:00
|
|
|
|
|
|
|
extern "C" LLVMValueRef LLVMBuildAtomicRMW(LLVMBuilderRef B,
|
|
|
|
AtomicRMWInst::BinOp op,
|
|
|
|
LLVMValueRef target,
|
|
|
|
LLVMValueRef source,
|
|
|
|
AtomicOrdering order) {
|
|
|
|
return wrap(unwrap(B)->CreateAtomicRMW(op,
|
|
|
|
unwrap(target), unwrap(source),
|
|
|
|
order));
|
|
|
|
}
|
2012-07-25 21:06:03 +02:00
|
|
|
|
|
|
|
extern "C" void LLVMSetDebug(int Enabled) {
|
|
|
|
DebugFlag = Enabled;
|
|
|
|
}
|