rust/src/rustllvm/PassWrapper.cpp
Jan-Erik Rediger 6ed5db8d35 [LLVM-3.9] Specify that we are using the legacy interface
LLVM pass manager infrastructure is currently getting rewritten to be
more flexible, but the rewrite isn't complete yet.
2016-07-29 10:29:44 +02:00

399 lines
12 KiB
C++

// 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 <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 <stdio.h>
#include "rustllvm.h"
#include "llvm/Support/CBindingWrapping.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetSubtargetInfo.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm-c/Transforms/PassManagerBuilder.h"
using namespace llvm;
using namespace llvm::legacy;
extern cl::opt<bool> EnableARMEHABI;
typedef struct LLVMOpaquePass *LLVMPassRef;
typedef struct LLVMOpaqueTargetMachine *LLVMTargetMachineRef;
DEFINE_STDCXX_CONVERSION_FUNCTIONS(Pass, LLVMPassRef)
DEFINE_STDCXX_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef)
DEFINE_STDCXX_CONVERSION_FUNCTIONS(PassManagerBuilder, LLVMPassManagerBuilderRef)
extern "C" void
LLVMInitializePasses() {
PassRegistry &Registry = *PassRegistry::getPassRegistry();
initializeCore(Registry);
initializeCodeGen(Registry);
initializeScalarOpts(Registry);
initializeVectorization(Registry);
initializeIPO(Registry);
initializeAnalysis(Registry);
#if LLVM_VERSION_MINOR == 7
initializeIPA(Registry);
#endif
initializeTransformUtils(Registry);
initializeInstCombine(Registry);
initializeInstrumentation(Registry);
initializeTarget(Registry);
}
enum class SupportedPassKind {
Function,
Module,
Unsupported
};
extern "C" Pass*
LLVMRustFindAndCreatePass(const char *PassName) {
StringRef SR(PassName);
PassRegistry *PR = PassRegistry::getPassRegistry();
const PassInfo *PI = PR->getPassInfo(SR);
if (PI) {
return PI->createPass();
}
return NULL;
}
extern "C" SupportedPassKind
LLVMRustPassKind(Pass *pass) {
assert(pass);
PassKind passKind = pass->getPassKind();
if (passKind == PT_Module) {
return SupportedPassKind::Module;
} else if (passKind == PT_Function) {
return SupportedPassKind::Function;
} else {
return SupportedPassKind::Unsupported;
}
}
extern "C" void
LLVMRustAddPass(LLVMPassManagerRef PM, Pass *pass) {
assert(pass);
PassManagerBase *pm = unwrap(PM);
pm->add(pass);
}
#ifdef LLVM_COMPONENT_X86
#define SUBTARGET_X86 SUBTARGET(X86)
#else
#define SUBTARGET_X86
#endif
#ifdef LLVM_COMPONENT_ARM
#define SUBTARGET_ARM SUBTARGET(ARM)
#else
#define SUBTARGET_ARM
#endif
#ifdef LLVM_COMPONENT_AARCH64
#define SUBTARGET_AARCH64 SUBTARGET(AArch64)
#else
#define SUBTARGET_AARCH64
#endif
#ifdef LLVM_COMPONENT_MIPS
#define SUBTARGET_MIPS SUBTARGET(Mips)
#else
#define SUBTARGET_MIPS
#endif
#ifdef LLVM_COMPONENT_POWERPC
#define SUBTARGET_PPC SUBTARGET(PPC)
#else
#define SUBTARGET_PPC
#endif
#define GEN_SUBTARGETS \
SUBTARGET_X86 \
SUBTARGET_ARM \
SUBTARGET_AARCH64 \
SUBTARGET_MIPS \
SUBTARGET_PPC
#define SUBTARGET(x) namespace llvm { \
extern const SubtargetFeatureKV x##FeatureKV[]; \
extern const SubtargetFeatureKV x##SubTypeKV[]; \
}
GEN_SUBTARGETS
#undef SUBTARGET
extern "C" bool
LLVMRustHasFeature(LLVMTargetMachineRef TM,
const char *feature) {
TargetMachine *Target = unwrap(TM);
const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo();
const FeatureBitset &Bits = MCInfo->getFeatureBits();
const llvm::SubtargetFeatureKV *FeatureEntry;
#define SUBTARGET(x) \
if (MCInfo->isCPUStringValid(x##SubTypeKV[0].Key)) { \
FeatureEntry = x##FeatureKV; \
} else
GEN_SUBTARGETS {
return false;
}
#undef SUBTARGET
while (strcmp(feature, FeatureEntry->Key) != 0)
FeatureEntry++;
return (Bits & FeatureEntry->Value) == FeatureEntry->Value;
}
extern "C" LLVMTargetMachineRef
LLVMRustCreateTargetMachine(const char *triple,
const char *cpu,
const char *feature,
CodeModel::Model CM,
Reloc::Model RM,
CodeGenOpt::Level OptLevel,
bool UseSoftFloat,
bool PositionIndependentExecutable,
bool FunctionSections,
bool DataSections) {
std::string Error;
Triple Trip(Triple::normalize(triple));
const llvm::Target *TheTarget = TargetRegistry::lookupTarget(Trip.getTriple(),
Error);
if (TheTarget == NULL) {
LLVMRustSetLastError(Error.c_str());
return NULL;
}
StringRef real_cpu = cpu;
if (real_cpu == "native") {
real_cpu = sys::getHostCPUName();
}
TargetOptions Options;
Options.PositionIndependentExecutable = PositionIndependentExecutable;
Options.FloatABIType = FloatABI::Default;
if (UseSoftFloat) {
Options.FloatABIType = FloatABI::Soft;
}
Options.DataSections = DataSections;
Options.FunctionSections = FunctionSections;
TargetMachine *TM = TheTarget->createTargetMachine(Trip.getTriple(),
real_cpu,
feature,
Options,
RM,
CM,
OptLevel);
return wrap(TM);
}
extern "C" void
LLVMRustDisposeTargetMachine(LLVMTargetMachineRef TM) {
delete unwrap(TM);
}
// Unfortunately, LLVM doesn't expose a C API to add the corresponding analysis
// passes for a target to a pass manager. We export that functionality through
// this function.
extern "C" void
LLVMRustAddAnalysisPasses(LLVMTargetMachineRef TM,
LLVMPassManagerRef PMR,
LLVMModuleRef M) {
PassManagerBase *PM = unwrap(PMR);
PM->add(createTargetTransformInfoWrapperPass(
unwrap(TM)->getTargetIRAnalysis()));
}
extern "C" void
LLVMRustConfigurePassManagerBuilder(LLVMPassManagerBuilderRef PMB,
CodeGenOpt::Level OptLevel,
bool MergeFunctions,
bool SLPVectorize,
bool LoopVectorize) {
// Ignore mergefunc for now as enabling it causes crashes.
//unwrap(PMB)->MergeFunctions = MergeFunctions;
unwrap(PMB)->SLPVectorize = SLPVectorize;
unwrap(PMB)->OptLevel = OptLevel;
unwrap(PMB)->LoopVectorize = LoopVectorize;
}
// Unfortunately, the LLVM C API doesn't provide a way to set the `LibraryInfo`
// field of a PassManagerBuilder, we expose our own method of doing so.
extern "C" void
LLVMRustAddBuilderLibraryInfo(LLVMPassManagerBuilderRef PMB,
LLVMModuleRef M,
bool DisableSimplifyLibCalls) {
Triple TargetTriple(unwrap(M)->getTargetTriple());
TargetLibraryInfoImpl *TLI = new TargetLibraryInfoImpl(TargetTriple);
if (DisableSimplifyLibCalls)
TLI->disableAllFunctions();
unwrap(PMB)->LibraryInfo = TLI;
}
// Unfortunately, the LLVM C API doesn't provide a way to create the
// TargetLibraryInfo pass, so we use this method to do so.
extern "C" void
LLVMRustAddLibraryInfo(LLVMPassManagerRef PMB,
LLVMModuleRef M,
bool DisableSimplifyLibCalls) {
Triple TargetTriple(unwrap(M)->getTargetTriple());
TargetLibraryInfoImpl TLII(TargetTriple);
if (DisableSimplifyLibCalls)
TLII.disableAllFunctions();
unwrap(PMB)->add(new TargetLibraryInfoWrapperPass(TLII));
}
// Unfortunately, the LLVM C API doesn't provide an easy way of iterating over
// all the functions in a module, so we do that manually here. You'll find
// similar code in clang's BackendUtil.cpp file.
extern "C" void
LLVMRustRunFunctionPassManager(LLVMPassManagerRef PM, LLVMModuleRef M) {
llvm::legacy::FunctionPassManager *P = unwrap<llvm::legacy::FunctionPassManager>(PM);
P->doInitialization();
for (Module::iterator I = unwrap(M)->begin(),
E = unwrap(M)->end(); I != E; ++I)
if (!I->isDeclaration())
P->run(*I);
P->doFinalization();
}
extern "C" void
LLVMRustSetLLVMOptions(int Argc, char **Argv) {
// Initializing the command-line options more than once is not allowed. So,
// check if they've already been initialized. (This could happen if we're
// being called from rustpkg, for example). If the arguments change, then
// that's just kinda unfortunate.
static bool initialized = false;
if (initialized) return;
initialized = true;
cl::ParseCommandLineOptions(Argc, Argv);
}
extern "C" bool
LLVMRustWriteOutputFile(LLVMTargetMachineRef Target,
LLVMPassManagerRef PMR,
LLVMModuleRef M,
const char *path,
TargetMachine::CodeGenFileType FileType) {
llvm::legacy::PassManager *PM = unwrap<llvm::legacy::PassManager>(PMR);
std::string ErrorInfo;
std::error_code EC;
raw_fd_ostream OS(path, EC, sys::fs::F_None);
if (EC)
ErrorInfo = EC.message();
if (ErrorInfo != "") {
LLVMRustSetLastError(ErrorInfo.c_str());
return false;
}
unwrap(Target)->addPassesToEmitFile(*PM, OS, FileType, false);
PM->run(*unwrap(M));
// Apparently `addPassesToEmitFile` adds a pointer to our on-the-stack output
// stream (OS), so the only real safe place to delete this is here? Don't we
// wish this was written in Rust?
delete PM;
return true;
}
extern "C" void
LLVMRustPrintModule(LLVMPassManagerRef PMR,
LLVMModuleRef M,
const char* path) {
llvm::legacy::PassManager *PM = unwrap<llvm::legacy::PassManager>(PMR);
std::string ErrorInfo;
std::error_code EC;
raw_fd_ostream OS(path, EC, sys::fs::F_None);
if (EC)
ErrorInfo = EC.message();
formatted_raw_ostream FOS(OS);
PM->add(createPrintModulePass(FOS));
PM->run(*unwrap(M));
}
extern "C" void
LLVMRustPrintPasses() {
LLVMInitializePasses();
struct MyListener : PassRegistrationListener {
void passEnumerate(const PassInfo *info) {
if (info->getPassArgument() && *info->getPassArgument()) {
printf("%15s - %s\n", info->getPassArgument(),
info->getPassName());
}
}
} listener;
PassRegistry *PR = PassRegistry::getPassRegistry();
PR->enumerateWith(&listener);
}
extern "C" void
LLVMRustAddAlwaysInlinePass(LLVMPassManagerBuilderRef PMB, bool AddLifetimes) {
unwrap(PMB)->Inliner = createAlwaysInlinerPass(AddLifetimes);
}
extern "C" void
LLVMRustRunRestrictionPass(LLVMModuleRef M, char **symbols, size_t len) {
PassManager passes;
ArrayRef<const char*> ref(symbols, len);
passes.add(llvm::createInternalizePass(ref));
passes.run(*unwrap(M));
}
extern "C" void
LLVMRustMarkAllFunctionsNounwind(LLVMModuleRef M) {
for (Module::iterator GV = unwrap(M)->begin(),
E = unwrap(M)->end(); GV != E; ++GV) {
GV->setDoesNotThrow();
Function *F = dyn_cast<Function>(GV);
if (F == NULL)
continue;
for (Function::iterator B = F->begin(), BE = F->end(); B != BE; ++B) {
for (BasicBlock::iterator I = B->begin(), IE = B->end();
I != IE; ++I) {
if (isa<InvokeInst>(I)) {
InvokeInst *CI = cast<InvokeInst>(I);
CI->setDoesNotThrow();
}
}
}
}
}
extern "C" void
LLVMRustSetDataLayoutFromTargetMachine(LLVMModuleRef Module,
LLVMTargetMachineRef TMR) {
TargetMachine *Target = unwrap(TMR);
unwrap(Module)->setDataLayout(Target->createDataLayout());
}
extern "C" LLVMTargetDataRef
LLVMRustGetModuleDataLayout(LLVMModuleRef M) {
return wrap(&unwrap(M)->getDataLayout());
}