203 changes: 138 additions & 65 deletions ffi/custom_passes.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

#include "core.h"
#include "ffi_types.h"

#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Function.h"
Expand All @@ -26,10 +26,11 @@
using namespace llvm;

namespace llvm {
void initializeRefNormalizePassPass(PassRegistry &Registry);
void initializeRefPrunePassPass(PassRegistry &Registry);
void initializeRefNormalizeLegacyPassPass(PassRegistry &Registry);
void initializeRefPruneLegacyPassPass(PassRegistry &Registry);
} // namespace llvm

namespace {
/**
* Checks if a call instruction is an incref
*
Expand Down Expand Up @@ -104,13 +105,9 @@ template <class Tstack> struct raiiStack {
* A FunctionPass to reorder incref/decref instructions such that decrefs occur
* logically after increfs. This is a pre-requisite pass to the pruner passes.
*/
struct RefNormalizePass : public FunctionPass {
static char ID;
RefNormalizePass() : FunctionPass(ID) {
initializeRefNormalizePassPass(*PassRegistry::getPassRegistry());
}
struct RefNormalize {

bool runOnFunction(Function &F) override {
bool runOnFunction(Function &F) {
bool mutated = false;
// For each basic block in F
for (BasicBlock &bb : F) {
Expand Down Expand Up @@ -158,7 +155,16 @@ struct RefNormalizePass : public FunctionPass {
}
};

struct RefPrunePass : public FunctionPass {
typedef enum {
None = 0b0000,
PerBasicBlock = 0b0001,
Diamond = 0b0010,
Fanout = 0b0100,
FanoutRaise = 0b1000,
All = PerBasicBlock | Diamond | Fanout | FanoutRaise
} Subpasses;

struct RefPrune {
static char ID;
static size_t stats_per_bb;
static size_t stats_diamond;
Expand All @@ -175,25 +181,21 @@ struct RefPrunePass : public FunctionPass {
/**
* Enum for setting which subpasses to run, there is no interdependence.
*/
enum Subpasses {
None = 0b0000,
PerBasicBlock = 0b0001,
Diamond = 0b0010,
Fanout = 0b0100,
FanoutRaise = 0b1000,
All = PerBasicBlock | Diamond | Fanout | FanoutRaise
} flags;

RefPrunePass(Subpasses flags = Subpasses::All, size_t subgraph_limit = -1)
: FunctionPass(ID), flags(flags), subgraph_limit(subgraph_limit) {
initializeRefPrunePassPass(*PassRegistry::getPassRegistry());
}
Subpasses flags;

DominatorTree &DT;
PostDominatorTree &PDT;

RefPrune(DominatorTree &DT, PostDominatorTree &PDT,
Subpasses flags = Subpasses::All, size_t subgraph_limit = -1)
: DT(DT), PDT(PDT), flags(flags), subgraph_limit(subgraph_limit) {}

bool isSubpassEnabledFor(Subpasses expected) {
return (flags & expected) == expected;
}

bool runOnFunction(Function &F) override {
bool runOnFunction(Function &F) {
// state for LLVM function pass mutated IR
bool mutated = false;

Expand Down Expand Up @@ -361,12 +363,6 @@ struct RefPrunePass : public FunctionPass {
*/
bool runDiamondPrune(Function &F) {
bool mutated = false;
// gets the dominator tree
auto &domtree = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
// gets the post-dominator tree
auto &postdomtree =
getAnalysis<PostDominatorTreeWrapperPass>().getPostDomTree();

// Find all increfs and decrefs in the Function and store them in
// incref_list and decref_list respectively.
std::vector<CallInst *> incref_list, decref_list;
Expand Down Expand Up @@ -394,8 +390,8 @@ struct RefPrunePass : public FunctionPass {
continue;

// incref DOM decref && decref POSTDOM incref
if (domtree.dominates(incref, decref) &&
postdomtree.dominates(decref, incref)) {
if (DT.dominates(incref, decref) &&
PDT.dominates(decref, incref)) {
// check that the decref cannot be executed multiple times
SmallBBSet tail_nodes;
tail_nodes.insert(decref->getParent());
Expand Down Expand Up @@ -1028,14 +1024,6 @@ struct RefPrunePass : public FunctionPass {
return NULL;
}

/**
* getAnalysisUsage() LLVM plumbing for the pass
*/
void getAnalysisUsage(AnalysisUsage &Info) const override {
Info.addRequired<DominatorTreeWrapperPass>();
Info.addRequired<PostDominatorTreeWrapperPass>();
}

/**
* Checks if the first argument to the supplied call_inst is NULL and
* returns true if so, false otherwise.
Expand Down Expand Up @@ -1163,34 +1151,119 @@ struct RefPrunePass : public FunctionPass {
}
}
}
}; // end of struct RefPrunePass
}; // end of struct RefPrune

} // namespace

class RefPrunePass : public PassInfoMixin<RefPrunePass> {

public:
Subpasses flags;
size_t subgraph_limit;
RefPrunePass(Subpasses flags = Subpasses::All, size_t subgraph_limit = -1)
: flags(flags), subgraph_limit(subgraph_limit) {}

PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {
auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
auto &PDT = AM.getResult<PostDominatorTreeAnalysis>(F);
if (RefPrune(DT, PDT, flags, subgraph_limit).runOnFunction(F)) {
return PreservedAnalyses::none();
}

return PreservedAnalyses::all();
}
};

class RefNormalizePass : public PassInfoMixin<RefNormalizePass> {

public:
RefNormalizePass() = default;

PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {
RefNormalize().runOnFunction(F);

return PreservedAnalyses::all();
}
};

class RefNormalizeLegacyPass : public FunctionPass {
public:
static char ID;
RefNormalizeLegacyPass() : FunctionPass(ID) {
initializeRefNormalizeLegacyPassPass(*PassRegistry::getPassRegistry());
}

bool runOnFunction(Function &F) override {
return RefNormalize().runOnFunction(F);
};
};

class RefPruneLegacyPass : public FunctionPass {

char RefNormalizePass::ID = 0;
char RefPrunePass::ID = 0;
public:
static char ID; // Pass identification, replacement for typeid
// The maximum number of nodes that the fanout pruners will look at.
size_t subgraph_limit;
Subpasses flags;
RefPruneLegacyPass(Subpasses flags = Subpasses::All,
size_t subgraph_limit = -1)
: FunctionPass(ID), flags(flags), subgraph_limit(subgraph_limit) {
initializeRefPruneLegacyPassPass(*PassRegistry::getPassRegistry());
}

size_t RefPrunePass::stats_per_bb = 0;
size_t RefPrunePass::stats_diamond = 0;
size_t RefPrunePass::stats_fanout = 0;
size_t RefPrunePass::stats_fanout_raise = 0;
bool runOnFunction(Function &F) override {
auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();

INITIALIZE_PASS(RefNormalizePass, "nrtrefnormalizepass", "Normalize NRT refops",
false, false)
auto &PDT =
getAnalysis<PostDominatorTreeWrapperPass>().getPostDomTree();

return RefPrune(DT, PDT, flags, subgraph_limit).runOnFunction(F);
};

INITIALIZE_PASS_BEGIN(RefPrunePass, "nrtrefprunepass", "Prune NRT refops",
false, false)
/**
* getAnalysisUsage() LLVM plumbing for the pass
*/
void getAnalysisUsage(AnalysisUsage &Info) const override {
Info.addRequired<DominatorTreeWrapperPass>();
Info.addRequired<PostDominatorTreeWrapperPass>();
}
};

char RefNormalizeLegacyPass::ID = 0;
char RefPruneLegacyPass::ID = 0;

size_t RefPrune::stats_per_bb = 0;
size_t RefPrune::stats_diamond = 0;
size_t RefPrune::stats_fanout = 0;
size_t RefPrune::stats_fanout_raise = 0;

INITIALIZE_PASS(RefNormalizeLegacyPass, "nrtRefNormalize",
"Normalize NRT refops", false, false)

INITIALIZE_PASS_BEGIN(RefPruneLegacyPass, "nrtRefPruneLegacyPass",
"Prune NRT refops", false, false)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(PostDominatorTreeWrapperPass)

INITIALIZE_PASS_END(RefPrunePass, "refprunepass", "Prune NRT refops", false,
false)
INITIALIZE_PASS_END(RefPruneLegacyPass, "RefPruneLegacyPass",
"Prune NRT refops", false, false)

extern "C" {

API_EXPORT(void)
LLVMPY_AddRefPrunePass(LLVMPassManagerRef PM, int subpasses,
size_t subgraph_limit) {
unwrap(PM)->add(new RefNormalizePass());
LLVMPY_AddLegacyRefPrunePass(LLVMPassManagerRef PM, int subpasses,
size_t subgraph_limit) {
unwrap(PM)->add(new RefNormalizeLegacyPass());
unwrap(PM)->add(
new RefPrunePass((RefPrunePass::Subpasses)subpasses, subgraph_limit));
new RefPruneLegacyPass((Subpasses)subpasses, subgraph_limit));
}

API_EXPORT(void)
LLVMPY_AddRefPrunePass(LLVMModulePassManager MPM, int subpasses,
size_t subgraph_limit) {
MPM->addPass(createModuleToFunctionPassAdaptor(RefNormalizePass()));
MPM->addPass(createModuleToFunctionPassAdaptor(
RefPrunePass((Subpasses)subpasses, subgraph_limit)));
}

/**
Expand All @@ -1207,24 +1280,24 @@ typedef struct PruneStats {
API_EXPORT(void)
LLVMPY_DumpRefPruneStats(PRUNESTATS *buf, bool do_print) {
/* PRUNESTATS is updated with the statistics about what has been pruned from
* the RefPrunePass static state vars. This isn't threadsafe but neither is
* the RefPrune static state vars. This isn't threadsafe but neither is
* the LLVM pass infrastructure so it's all done under a python thread lock.
*
* do_print if set will print the stats to stderr.
*/
if (do_print) {
errs() << "refprune stats "
<< "per-BB " << RefPrunePass::stats_per_bb << " "
<< "diamond " << RefPrunePass::stats_diamond << " "
<< "fanout " << RefPrunePass::stats_fanout << " "
<< "fanout+raise " << RefPrunePass::stats_fanout_raise << " "
<< "per-BB " << RefPrune::stats_per_bb << " "
<< "diamond " << RefPrune::stats_diamond << " "
<< "fanout " << RefPrune::stats_fanout << " "
<< "fanout+raise " << RefPrune::stats_fanout_raise << " "
<< "\n";
};

buf->basicblock = RefPrunePass::stats_per_bb;
buf->diamond = RefPrunePass::stats_diamond;
buf->fanout = RefPrunePass::stats_fanout;
buf->fanout_raise = RefPrunePass::stats_fanout_raise;
buf->basicblock = RefPrune::stats_per_bb;
buf->diamond = RefPrune::stats_diamond;
buf->fanout = RefPrune::stats_fanout;
buf->fanout_raise = RefPrune::stats_fanout_raise;
}

} // extern "C"
28 changes: 28 additions & 0 deletions ffi/ffi_types.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@

#pragma once

#include "core.h"

#include "llvm/IR/PassManager.h"
#include "llvm/IR/PassTimingInfo.h"
#include "llvm/Passes/PassBuilder.h"

typedef llvm::PassBuilder *LLVMPassBuilder;

typedef llvm::FunctionPassManager *LLVMFunctionPassManager;

typedef llvm::ModulePassManager *LLVMModulePassManager;

typedef llvm::FunctionAnalysisManager *LLVMFunctionAnalysisManager;

typedef llvm::ModuleAnalysisManager *LLVMModuleAnalysisManager;

typedef llvm::CGSCCAnalysisManager *LLVMCGSCCAnalysisManager;

typedef llvm::LoopAnalysisManager *LLVMLoopAnalysisManager;

typedef llvm::PassInstrumentationCallbacks *LLVMPassInstrumentationCallbacks;

typedef llvm::TimePassesHandler *LLVMTimePassesHandler;

typedef llvm::OptimizationLevel const *LLVMOptimizationLevel;
23 changes: 2 additions & 21 deletions ffi/initfini.cpp
Original file line number Diff line number Diff line change
@@ -1,32 +1,13 @@
#include "llvm-c/Core.h"
#include "llvm-c/Initialization.h"
#include "llvm-c/Target.h"

#include "core.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/InitializePasses.h"
#include "llvm/PassRegistry.h"

extern "C" {

#define INIT(F) \
API_EXPORT(void) LLVMPY_Initialize##F() { \
LLVMInitialize##F(LLVMGetGlobalPassRegistry()); \
}

INIT(Core)
INIT(TransformUtils)
INIT(ScalarOpts)
INIT(ObjCARCOpts)
INIT(Vectorization)
INIT(InstCombine)
INIT(IPO)
// INIT(Instrumentation)
INIT(Analysis)
INIT(IPA)
INIT(CodeGen)
INIT(Target)

#undef INIT

API_EXPORT(void)
LLVMPY_Shutdown() { LLVMShutdown(); }

Expand Down
40 changes: 23 additions & 17 deletions ffi/memorymanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,19 +130,24 @@ bool LlvmliteMemoryManager::hasSpace(const MemoryGroup &MemGroup,
}

void LlvmliteMemoryManager::reserveAllocationSpace(
uintptr_t CodeSize, uint32_t CodeAlign, uintptr_t RODataSize,
uint32_t RODataAlign, uintptr_t RWDataSize, uint32_t RWDataAlign) {
uintptr_t CodeSize, Align CodeAlign, uintptr_t RODataSize,
Align RODataAlign, uintptr_t RWDataSize, Align RWDataAlign) {

uint64_t CodeAlignValue = CodeAlign.value();
uint64_t RODataAlignValue = RODataAlign.value();
uint64_t RWDataAlignValue = RWDataAlign.value();

LLVM_DEBUG(
dbgs()
<< "\nLlvmliteMemoryManager::reserveAllocationSpace() request:\n\n");
LLVM_DEBUG(dbgs() << "Code size / align: " << format_hex(CodeSize, 2, true)
<< " / " << CodeAlign << "\n");
<< " / " << CodeAlignValue << "\n");
LLVM_DEBUG(dbgs() << "ROData size / align: "
<< format_hex(RODataSize, 2, true) << " / " << RODataAlign
<< "\n");
<< format_hex(RODataSize, 2, true) << " / "
<< RODataAlignValue << "\n");
LLVM_DEBUG(dbgs() << "RWData size / align: "
<< format_hex(RWDataSize, 2, true) << " / " << RWDataAlign
<< "\n");
<< format_hex(RWDataSize, 2, true) << " / "
<< RWDataAlignValue << "\n");

if (CodeSize == 0 && RODataSize == 0 && RWDataSize == 0) {
LLVM_DEBUG(dbgs() << "No memory requested - returning early.\n");
Expand All @@ -152,23 +157,24 @@ void LlvmliteMemoryManager::reserveAllocationSpace(
// Code alignment needs to be at least the stub alignment - however, we
// don't have an easy way to get that here so as a workaround, we assume
// it's 8, which is the largest value I observed across all platforms.
constexpr uint32_t StubAlign = 8;
CodeAlign = std::max(CodeAlign, StubAlign);
constexpr uint64_t StubAlign = 8;
CodeAlignValue = std::max(CodeAlignValue, StubAlign);

// ROData and RWData may not need to be aligned to the StubAlign, but the
// stub alignment seems like a reasonable (if slightly arbitrary) minimum
// alignment for them that should not cause any issues on all (i.e. 64-bit)
// platforms.
RODataAlign = std::max(RODataAlign, StubAlign);
RWDataAlign = std::max(RWDataAlign, StubAlign);
RODataAlignValue = std::max(RODataAlignValue, StubAlign);
RWDataAlignValue = std::max(RWDataAlignValue, StubAlign);

// Get space required for each section. Use the same calculation as
// allocateSection because we need to be able to satisfy it.
uintptr_t RequiredCodeSize = alignTo(CodeSize, CodeAlign) + CodeAlign;
uintptr_t RequiredCodeSize =
alignTo(CodeSize, CodeAlignValue) + CodeAlignValue;
uintptr_t RequiredRODataSize =
alignTo(RODataSize, RODataAlign) + RODataAlign;
alignTo(RODataSize, RODataAlignValue) + RODataAlignValue;
uintptr_t RequiredRWDataSize =
alignTo(RWDataSize, RWDataAlign) + RWDataAlign;
alignTo(RWDataSize, RWDataAlignValue) + RWDataAlignValue;
uint64_t TotalSize =
RequiredCodeSize + RequiredRODataSize + RequiredRWDataSize;

Expand Down Expand Up @@ -222,7 +228,7 @@ void LlvmliteMemoryManager::reserveAllocationSpace(
LLVM_DEBUG(dbgs() << "Code mem starts at " << format_hex(Addr, 18, true)
<< ", size " << format_hex(RequiredCodeSize, 2, true)
<< "\n");
assert(isAddrAligned(Align(CodeAlign), (void *)Addr));
assert(isAddrAligned(Align(CodeAlignValue), (void *)Addr));
FreeMB.Free = sys::MemoryBlock((void *)Addr, RequiredCodeSize);
CodeMem.FreeMem.push_back(FreeMB);
Addr += RequiredCodeSize;
Expand All @@ -232,7 +238,7 @@ void LlvmliteMemoryManager::reserveAllocationSpace(
LLVM_DEBUG(dbgs() << "ROData mem starts at "
<< format_hex(Addr, 18, true) << ", size "
<< format_hex(RequiredRODataSize, 2, true) << "\n");
assert(isAddrAligned(Align(RODataAlign), (void *)Addr));
assert(isAddrAligned(Align(RODataAlignValue), (void *)Addr));
FreeMB.Free = sys::MemoryBlock((void *)Addr, RequiredRODataSize);
RODataMem.FreeMem.push_back(FreeMB);
Addr += RequiredRODataSize;
Expand All @@ -242,7 +248,7 @@ void LlvmliteMemoryManager::reserveAllocationSpace(
LLVM_DEBUG(dbgs() << "RWData mem starts at "
<< format_hex(Addr, 18, true) << ", size "
<< format_hex(RequiredRWDataSize, 2, true) << "\n");
assert(isAddrAligned(Align(RWDataAlign), (void *)Addr));
assert(isAddrAligned(Align(RWDataAlignValue), (void *)Addr));
FreeMB.Free = sys::MemoryBlock((void *)Addr, RequiredRWDataSize);
RWDataMem.FreeMem.push_back(FreeMB);
}
Expand Down
7 changes: 3 additions & 4 deletions ffi/memorymanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,11 +174,10 @@ class API_EXPORT(LlvmliteMemoryManager : public RTDyldMemoryManager) {

virtual bool needsToReserveAllocationSpace() override { return true; }

virtual void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign,
uintptr_t RODataSize,
uint32_t RODataAlign,
virtual void reserveAllocationSpace(uintptr_t CodeSize, Align CodeAlign,
uintptr_t RODataSize, Align RODataAlign,
uintptr_t RWDataSize,
uint32_t RWDataAlign) override;
Align RWDataAlign) override;

private:
struct FreeMemBlock {
Expand Down
4 changes: 2 additions & 2 deletions ffi/orcjit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,8 @@ LLVMPY_LLJIT_Link(std::shared_ptr<LLJIT> *lljit, const char *libraryName,
for (size_t import_idx = 0; import_idx < imports_length; import_idx++) {
SymbolStringPtr mangled =
(*lljit)->mangleAndIntern(imports[import_idx].name);
JITEvaluatedSymbol symbol(imports[import_idx].address,
JITSymbolFlags::Exported);
ExecutorSymbolDef symbol(ExecutorAddr(imports[import_idx].address),
JITSymbolFlags::Exported);
auto error = dylib->define(absoluteSymbols({{mangled, symbol}}));

if (error) {
Expand Down
593 changes: 440 additions & 153 deletions ffi/passmanagers.cpp

Large diffs are not rendered by default.

25 changes: 16 additions & 9 deletions ffi/targets.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
#include "core.h"
#include "ffi_types.h"
#include "llvm-c/Target.h"
#include "llvm-c/TargetMachine.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Type.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/Host.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/TargetParser/Host.h"
#include "llvm/TargetParser/Triple.h"

#include <cstdio>
#include <cstring>
Expand Down Expand Up @@ -102,7 +102,6 @@ LLVMPY_ABISizeOfElementType(LLVMTargetDataRef TD, LLVMTypeRef Ty) {
llvm::Type *tp = llvm::unwrap(Ty);
if (!tp->isPointerTy())
return -1;
tp = tp->getPointerElementType();
return (long long)LLVMABISizeOfType(TD, llvm::wrap(tp));
}

Expand All @@ -111,7 +110,12 @@ LLVMPY_ABIAlignmentOfElementType(LLVMTargetDataRef TD, LLVMTypeRef Ty) {
llvm::Type *tp = llvm::unwrap(Ty);
if (!tp->isPointerTy())
return -1;
tp = tp->getPointerElementType();
return (long long)LLVMABIAlignmentOfType(TD, llvm::wrap(tp));
}

API_EXPORT(long long)
LLVMPY_ABIAlignmentOfType(LLVMTargetDataRef TD, LLVMTypeRef Ty) {
llvm::Type *tp = llvm::unwrap(Ty);
return (long long)LLVMABIAlignmentOfType(TD, llvm::wrap(tp));
}

Expand Down Expand Up @@ -178,7 +182,7 @@ LLVMPY_CreateTargetMachine(LLVMTargetRef T, const char *Triple, const char *CPU,
cm = CodeModel::Large;
}

Optional<Reloc::Model> rm;
std::optional<Reloc::Model> rm;
std::string rms(RelocModel);
if (rms == "static")
rm = Reloc::Static;
Expand Down Expand Up @@ -241,7 +245,7 @@ LLVMPY_CreateTargetMachineData(LLVMTargetMachineRef TM) {

API_EXPORT(void)
LLVMPY_AddAnalysisPasses(LLVMTargetMachineRef TM, LLVMPassManagerRef PM) {
LLVMAddAnalysisPasses(TM, PM);
assert(0 && "Legacy Pass Manager only");
}

API_EXPORT(const void *)
Expand All @@ -265,9 +269,12 @@ LLVMPY_HasSVMLSupport(void) {
}

API_EXPORT(void)
LLVMPY_AddTargetLibraryInfoPass(LLVMPassManagerRef PM, const char *TripleStr) {
LLVMPY_AddTargetLibraryInfoPass(LLVMFunctionAnalysisManager FAM,
const char *TripleStr) {
using namespace llvm;
unwrap(PM)->add(new TargetLibraryInfoWrapperPass(Triple(TripleStr)));
Triple T(TripleStr);
TargetLibraryInfoImpl *TLII = new TargetLibraryInfoImpl(T);
FAM->registerPass([&] { return TargetLibraryAnalysis(*TLII); });
}

} // end extern "C"
277 changes: 229 additions & 48 deletions ffi/transforms.cpp
Original file line number Diff line number Diff line change
@@ -1,96 +1,277 @@
#include "core.h"
#include "ffi_types.h"
#include "llvm-c/Target.h"
#include "llvm-c/Transforms/PassManagerBuilder.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm-c/Transforms/PassBuilder.h"

#include "llvm/IR/Verifier.h"
#include "llvm/Passes/StandardInstrumentations.h"
#include "llvm/Support/CBindingWrapping.h"

/// Helper struct for holding a set of builder options for LLVMRunPasses. This
/// structure is used to keep LLVMRunPasses backwards compatible with future
/// versions in case we modify the options the new Pass Manager utilizes.
class LLVMPassBuilderOptions {
public:
explicit LLVMPassBuilderOptions(
bool DebugLogging = false, bool VerifyEach = false,
llvm::PipelineTuningOptions PTO = llvm::PipelineTuningOptions())
: DebugLogging(DebugLogging), VerifyEach(VerifyEach), PTO(PTO) {}

bool DebugLogging;
bool VerifyEach;
llvm::PipelineTuningOptions PTO;
};

static llvm::TargetMachine *unwrap(LLVMTargetMachineRef P) {
return reinterpret_cast<llvm::TargetMachine *>(P);
}

DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLVMPassBuilderOptions,
LLVMPassBuilderOptionsRef)

static const LLVMOptimizationLevel mapToLevel(unsigned OptLevel,
unsigned SizeLevel) {
switch (OptLevel) {
default:
llvm_unreachable("Invalid optimization level!");

case 0:
return &llvm::OptimizationLevel::O0;

case 1:
return &llvm::OptimizationLevel::O1;

case 2:
switch (SizeLevel) {
default:
llvm_unreachable("Invalid optimization level for size!");

case 0:
return &llvm::OptimizationLevel::O2;

case 1:
return &llvm::OptimizationLevel::Os;

case 2:
return &llvm::OptimizationLevel::Oz;
}

case 3:
return &llvm::OptimizationLevel::O3;
}
}

extern "C" {

API_EXPORT(LLVMPassManagerBuilderRef)
LLVMPY_PassManagerBuilderCreate() { return LLVMPassManagerBuilderCreate(); }
API_EXPORT(LLVMPassBuilder)
LLVMPY_PassManagerBuilderCreate() { return new llvm::PassBuilder(); }

API_EXPORT(LLVMPassBuilderOptionsRef)
LLVMPY_PassManagerBuilderOptionsCreate() {
return LLVMCreatePassBuilderOptions();
}

API_EXPORT(LLVMModuleAnalysisManager)
LLVMPY_LLVMModuleAnalysisManagerCreate() {
return new llvm::ModuleAnalysisManager;
}

API_EXPORT(void)
LLVMPY_PassManagerBuilderDispose(LLVMPassManagerBuilderRef PMB) {
LLVMPassManagerBuilderDispose(PMB);
LLVMPY_LLVMModuleAnalysisManagerDispose(LLVMModuleAnalysisManager MAM) {
delete (MAM);
}

API_EXPORT(LLVMLoopAnalysisManager)
LLVMPY_LLVMLoopAnalysisManagerCreate() { return new llvm::LoopAnalysisManager; }

API_EXPORT(void)
LLVMPY_PassManagerBuilderPopulateModulePassManager(
LLVMPassManagerBuilderRef PMB, LLVMPassManagerRef PM) {
LLVMPassManagerBuilderPopulateModulePassManager(PMB, PM);
LLVMPY_LLVMLoopAnalysisManagerDispose(LLVMLoopAnalysisManager LAM) {
delete (LAM);
}

API_EXPORT(unsigned)
LLVMPY_PassManagerBuilderGetOptLevel(LLVMPassManagerBuilderRef PMB) {
llvm::PassManagerBuilder *pmb = llvm::unwrap(PMB);
return pmb->OptLevel;
API_EXPORT(LLVMFunctionAnalysisManager)
LLVMPY_LLVMFunctionAnalysisManagerCreate() {
return new llvm::FunctionAnalysisManager;
}

API_EXPORT(void)
LLVMPY_PassManagerBuilderSetOptLevel(LLVMPassManagerBuilderRef PMB,
unsigned OptLevel) {
LLVMPassManagerBuilderSetOptLevel(PMB, OptLevel);
LLVMPY_LLVMFunctionAnalysisManagerDispose(LLVMFunctionAnalysisManager FAM) {
delete (FAM);
}

API_EXPORT(unsigned)
LLVMPY_PassManagerBuilderGetSizeLevel(LLVMPassManagerBuilderRef PMB) {
llvm::PassManagerBuilder *pmb = llvm::unwrap(PMB);
return pmb->SizeLevel;
API_EXPORT(LLVMCGSCCAnalysisManager)
LLVMPY_LLVMCGSCCAnalysisManagerCreate() {
return new llvm::CGSCCAnalysisManager;
}

API_EXPORT(void)
LLVMPY_PassManagerBuilderSetSizeLevel(LLVMPassManagerBuilderRef PMB,
unsigned SizeLevel) {
LLVMPassManagerBuilderSetSizeLevel(PMB, SizeLevel);
LLVMPY_LLVMCGSCCAnalysisManagerDispose(LLVMCGSCCAnalysisManager CGAM) {
delete (CGAM);
}

API_EXPORT(int)
LLVMPY_PassManagerBuilderGetDisableUnrollLoops(LLVMPassManagerBuilderRef PMB) {
llvm::PassManagerBuilder *pmb = llvm::unwrap(PMB);
return pmb->DisableUnrollLoops;
API_EXPORT(LLVMPassInstrumentationCallbacks)
LLVMPY_LLVMPassInstrumentationCallbacksCreate() {
return new llvm::PassInstrumentationCallbacks;
}

API_EXPORT(void)
LLVMPY_LLVMPassInstrumentationCallbacksDispose(
LLVMPassInstrumentationCallbacks PIC) {
delete (PIC);
}

API_EXPORT(void)
LLVMPY_PassManagerBuilderSetDisableUnrollLoops(LLVMPassManagerBuilderRef PMB,
LLVMBool Value) {
LLVMPassManagerBuilderSetDisableUnrollLoops(PMB, Value);
LLVMPY_PassManagerBuilderDispose(LLVMPassBuilder PB,
LLVMPassBuilderOptionsRef Options) {
if (PB) {
delete (PB);
PB = nullptr;
}
LLVMDisposePassBuilderOptions(Options);
}

API_EXPORT(LLVMModulePassManager)
LLVMPY_PassManagerBuilderPopulateModulePassManager(
LLVMPassBuilder PB, LLVMPassBuilderOptionsRef Options,
LLVMOptimizationLevel Level, LLVMModulePassManager MPM,
LLVMModuleAnalysisManager MAM, LLVMLoopAnalysisManager LAM,
LLVMFunctionAnalysisManager FAM, LLVMCGSCCAnalysisManager CGAM,
LLVMPassInstrumentationCallbacks PIC) {
// TODO handle PB memory better
if (PB) {
delete (PB);
PB = nullptr;
}

PB = new llvm::PassBuilder(nullptr, unwrap(Options)->PTO,
/*Optional<PGOOptions> PGOOpt =*/{}, PIC);

// Register all the basic analyses with the managers.
PB->registerModuleAnalyses(*MAM);
PB->registerCGSCCAnalyses(*CGAM);
PB->registerFunctionAnalyses(*FAM);
PB->registerLoopAnalyses(*LAM);
PB->crossRegisterProxies(*LAM, *FAM, *CGAM, *MAM);

MPM = new llvm::ModulePassManager(
PB->buildPerModuleDefaultPipeline(*Level, false));

return MPM;
}

API_EXPORT(LLVMOptimizationLevel)
LLVMPY_PassManagerCreateOptimizationLevel(unsigned OptLevel,
unsigned SizeLevel) {
return mapToLevel(OptLevel, SizeLevel);
}

API_EXPORT(unsigned)
LLVMPY_PassManagerBuilderGetOptLevel(LLVMOptimizationLevel Level) {
return Level->getSpeedupLevel();
}

API_EXPORT(unsigned)
LLVMPY_PassManagerBuilderGetSizeLevel(LLVMOptimizationLevel Level) {
return Level->getSizeLevel();
}

API_EXPORT(int)
LLVMPY_PassManagerBuilderGetDisableUnrollLoops(
LLVMPassBuilderOptionsRef Options) {
return unwrap(Options)->PTO.LoopUnrolling;
}

API_EXPORT(void)
LLVMPY_PassManagerBuilderUseInlinerWithThreshold(LLVMPassManagerBuilderRef PMB,
unsigned Threshold) {
LLVMPassManagerBuilderUseInlinerWithThreshold(PMB, Threshold);
LLVMPY_PassManagerBuilderSetDisableUnrollLoops(
LLVMPassBuilderOptionsRef Options, LLVMBool Value) {
LLVMPassBuilderOptionsSetLoopUnrolling(Options, Value);
}

API_EXPORT(void)
LLVMPY_PassManagerBuilderUseInlinerWithThreshold(
LLVMPassBuilderOptionsRef Options, unsigned Threshold) {
LLVMPassBuilderOptionsSetInlinerThreshold(Options, Threshold);
}

API_EXPORT(LLVMFunctionPassManager)
LLVMPY_PassManagerBuilderPopulateFunctionPassManager(
LLVMPassManagerBuilderRef PMB, LLVMPassManagerRef PM) {
LLVMPassManagerBuilderPopulateFunctionPassManager(PMB, PM);
LLVMPassBuilder PB, LLVMPassBuilderOptionsRef Options,
LLVMOptimizationLevel Level, LLVMFunctionPassManager FPM,
LLVMModuleAnalysisManager MAM, LLVMLoopAnalysisManager LAM,
LLVMFunctionAnalysisManager FAM, LLVMCGSCCAnalysisManager CGAM,
LLVMPassInstrumentationCallbacks PIC) {
// TODO handle PB memory better
if (PB) {
delete (PB);
PB = nullptr;
}

PB = new llvm::PassBuilder(nullptr, unwrap(Options)->PTO,
/*Optional<PGOOptions> PGOOpt =*/{}, PIC);

// Register all the basic analyses with the managers.
PB->registerModuleAnalyses(*MAM);
PB->registerCGSCCAnalyses(*CGAM);
PB->registerFunctionAnalyses(*FAM);
PB->registerLoopAnalyses(*LAM);
PB->crossRegisterProxies(*LAM, *FAM, *CGAM, *MAM);

// O0 maps to now passes
if (*Level != llvm::OptimizationLevel::O0)
FPM->addPass(PB->buildFunctionSimplificationPipeline(
*Level, llvm::ThinOrFullLTOPhase::None));

return FPM;
}

API_EXPORT(void)
LLVMPY_PassManagerBuilderSetLoopVectorize(LLVMPassManagerBuilderRef PMB,
LLVMPY_PassManagerBuilderSetLoopVectorize(LLVMPassBuilderOptionsRef Options,
int Value) {
llvm::PassManagerBuilder *pmb = llvm::unwrap(PMB);
pmb->LoopVectorize = Value;
LLVMPassBuilderOptionsSetLoopVectorization(Options, Value);
}

API_EXPORT(int)
LLVMPY_PassManagerBuilderGetLoopVectorize(LLVMPassManagerBuilderRef PMB) {
llvm::PassManagerBuilder *pmb = llvm::unwrap(PMB);
return pmb->LoopVectorize;
LLVMPY_PassManagerBuilderGetLoopVectorize(LLVMPassBuilderOptionsRef Options) {
return unwrap(Options)->PTO.LoopVectorization;
}

API_EXPORT(void)
LLVMPY_PassManagerBuilderSetSLPVectorize(LLVMPassManagerBuilderRef PMB,
LLVMPY_PassManagerBuilderSetSLPVectorize(LLVMPassBuilderOptionsRef Options,
int Value) {
llvm::PassManagerBuilder *pmb = llvm::unwrap(PMB);
pmb->SLPVectorize = Value;
LLVMPassBuilderOptionsSetSLPVectorization(Options, Value);
}

API_EXPORT(int)
LLVMPY_PassManagerBuilderGetSLPVectorize(LLVMPassManagerBuilderRef PMB) {
llvm::PassManagerBuilder *pmb = llvm::unwrap(PMB);
return pmb->SLPVectorize;
LLVMPY_PassManagerBuilderGetSLPVectorize(LLVMPassBuilderOptionsRef Options) {
return unwrap(Options)->PTO.SLPVectorization;
}

// TODO: Expose additional new options?
// llvm-project/llvm/include/llvm-c/Transforms/PassBuilder.h
/*
void LLVMPassBuilderOptionsSetVerifyEach(LLVMPassBuilderOptionsRef Options,
LLVMBool VerifyEach);
void LLVMPassBuilderOptionsSetDebugLogging(LLVMPassBuilderOptionsRef Options,
LLVMBool DebugLogging);
void LLVMPassBuilderOptionsSetLoopInterleaving(
LLVMPassBuilderOptionsRef Options, LLVMBool LoopInterleaving);
void LLVMPassBuilderOptionsSetForgetAllSCEVInLoopUnroll(
LLVMPassBuilderOptionsRef Options, LLVMBool ForgetAllSCEVInLoopUnroll);
void LLVMPassBuilderOptionsSetLicmMssaOptCap(LLVMPassBuilderOptionsRef Options,
unsigned LicmMssaOptCap);
void LLVMPassBuilderOptionsSetLicmMssaNoAccForPromotionCap(
LLVMPassBuilderOptionsRef Options, unsigned LicmMssaNoAccForPromotionCap);
void LLVMPassBuilderOptionsSetCallGraphProfile(
LLVMPassBuilderOptionsRef Options, LLVMBool CallGraphProfile);
void LLVMPassBuilderOptionsSetMergeFunctions(LLVMPassBuilderOptionsRef Options,
LLVMBool MergeFunctions);
*/

} // end extern "C"
27 changes: 16 additions & 11 deletions ffi/type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <iostream>

#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Type.h"

struct ElementIterator {
Expand Down Expand Up @@ -62,6 +63,11 @@ LLVMPY_GetTypeKind(LLVMTypeRef Val) { return (int)LLVMGetTypeKind(Val); }
API_EXPORT(LLVMTypeRef)
LLVMPY_TypeOf(LLVMValueRef Val) { return LLVMTypeOf(Val); }

API_EXPORT(LLVMTypeRef)
LLVMPY_GlobalGetValueType(LLVMValueRef Val) {
return LLVMGlobalGetValueType(Val);
}

API_EXPORT(const char *)
LLVMPY_PrintType(LLVMTypeRef type) {
char *str = LLVMPrintTypeToString(type);
Expand Down Expand Up @@ -100,16 +106,6 @@ LLVMPY_TypeIsStruct(LLVMTypeRef type) {
return llvm::unwrap(type)->isStructTy();
}

API_EXPORT(bool)
LLVMPY_IsFunctionVararg(LLVMTypeRef type) {
llvm::Type *unwrapped = llvm::unwrap(type);
llvm::FunctionType *ty = llvm::dyn_cast<llvm::FunctionType>(unwrapped);
if (ty != nullptr) {
return ty->isVarArg();
}
return false;
}

API_EXPORT(int)
LLVMPY_GetTypeElementCount(LLVMTypeRef type) {
llvm::Type *unwrapped = llvm::unwrap(type);
Expand Down Expand Up @@ -139,9 +135,11 @@ API_EXPORT(uint64_t)
LLVMPY_GetTypeBitWidth(LLVMTypeRef type) {
llvm::Type *unwrapped = llvm::unwrap(type);
auto size = unwrapped->getPrimitiveSizeInBits();
return size.getFixedSize();
return size.getFixedValue();
}

// All pointers are opaque, no types
#if LLVM_VERSION_MAJOR < 17
API_EXPORT(LLVMTypeRef)
LLVMPY_GetElementType(LLVMTypeRef type) {
llvm::Type *unwrapped = llvm::unwrap(type);
Expand All @@ -155,5 +153,12 @@ LLVMPY_GetElementType(LLVMTypeRef type) {
}
return nullptr;
}
#else
API_EXPORT(LLVMTypeRef)
LLVMPY_GetElementType(LLVMTypeRef type) {
assert(false && "No element types with opaque pointers");
return nullptr;
}
#endif

} // end extern "C"
10 changes: 10 additions & 0 deletions ffi/value.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -471,4 +471,14 @@ LLVMPY_GetOpcodeName(LLVMValueRef Val) {
return LLVMPY_CreateString("");
}

API_EXPORT(bool)
LLVMPY_IsFunctionVararg(LLVMValueRef F) {
using namespace llvm;
Function *func = unwrap<Function>(F);
if (func != nullptr) {
return func->isVarArg();
}
return false;
}

} // end extern "C"
15 changes: 15 additions & 0 deletions llvmlite/binding/ffi.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,21 @@ def _make_opaque_ref(name):
LLVMSectionIteratorRef = _make_opaque_ref("LLVMSectionIterator")
LLVMOrcLLJITRef = _make_opaque_ref("LLVMOrcLLJITRef")
LLVMOrcDylibTrackerRef = _make_opaque_ref("LLVMOrcDylibTrackerRef")
LLVMPassBuilderOptionsRef = _make_opaque_ref("LLVMPassBuilderOptions")
LLVMOptimizationLevel = _make_opaque_ref("LLVMOptimizationLevel")
LLVMFunctionPassManager = _make_opaque_ref("LLVMFunctionPassManager")
LLVMPassBuilder = _make_opaque_ref("LLVMPassBuilder")
LLVMModulePassManager = _make_opaque_ref("LLVMModulePassManager")

LLVMModuleAnalysisManager = _make_opaque_ref("LLVMModuleAnalysisManager")
LLVMCGSCCAnalysisManager = _make_opaque_ref("LLVMCGSCCAnalysisManager")
LLVMFunctionAnalysisManager = _make_opaque_ref("LLVMFunctionAnalysisManager")
LLVMLoopAnalysisManager = _make_opaque_ref("LLVMLoopAnalysisManager")
LLVMLoopAnalysisManager = _make_opaque_ref("LLVMLoopAnalysisManager")
LLVMPassInstrumentationCallbacks = _make_opaque_ref(
"LLVMPassInstrumentationCallbacks"
)
LLVMTimePassesHandler = _make_opaque_ref("LLVMTimePassesHandler")


class _LLVMLock:
Expand Down
3 changes: 2 additions & 1 deletion llvmlite/binding/initfini.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ def initialize():
"""
Initialize the LLVM core.
"""
ffi.lib.LLVMPY_InitializeCore()
# No longer necessary with NPM
# ffi.lib.LLVMPY_InitializeCore()


def initialize_all_targets():
Expand Down
251 changes: 177 additions & 74 deletions llvmlite/binding/passmanagers.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,34 +60,6 @@ def dump_refprune_stats(printout=False):
stats.fanout_raise)


def set_time_passes(enable):
"""Enable or disable the pass timers.
Parameters
----------
enable : bool
Set to True to enable the pass timers.
Set to False to disable the pass timers.
"""
ffi.lib.LLVMPY_SetTimePasses(c_bool(enable))


def report_and_reset_timings():
"""Returns the pass timings report and resets the LLVM internal timers.
Pass timers are enabled by ``set_time_passes()``. If the timers are not
enabled, this function will return an empty string.
Returns
-------
res : str
LLVM generated timing report.
"""
with ffi.OutputString() as buf:
ffi.lib.LLVMPY_ReportAndResetTimings(buf)
return str(buf)


def create_module_pass_manager():
return ModulePassManager()

Expand Down Expand Up @@ -651,6 +623,49 @@ def add_instruction_namer_pass(self):
""" # noqa E501
ffi.lib.LLVMPY_AddInstructionNamerPass(self)


class ModulePassManager(PassManager):

__MAM__ = ffi.LLVMModuleAnalysisManager
__PIC__ = ffi.LLVMPassInstrumentationCallbacks
__TimePasses__ = ffi.LLVMTimePassesHandler

def __init__(self, ptr=None):
if ptr is None:
ptr = ffi.lib.LLVMPY_CreatePassManager()
PassManager.__init__(self, ptr)
self.__MAM__ = ffi.lib.LLVMPY_LLVMModuleAnalysisManagerCreate()
self.__TimePasses__ = ffi.lib.LLVMPY_CreateLLVMTimePassesHandler()

def update(self, ptr):
PassManager.__init__(self, ptr)

def set_time_passes(self, enable):
"""Enable or disable the pass timers.
Parameters
----------
enable : bool
Set to True to enable the pass timers.
Set to False to disable the pass timers.
"""
ffi.lib.LLVMPY_SetTimePasses(self.__TimePasses__, self.__PIC__)

def report_and_reset_timings(self):
"""Returns the pass timings report and resets the LLVM internal timers.
Pass timers are enabled by ``set_time_passes()``. If the timers are not
enabled, this function will return an empty string.
Returns
-------
res : str
LLVM generated timing report.
"""
with ffi.OutputString() as buf:
ffi.lib.LLVMPY_ReportAndResetTimings(self.__TimePasses__, buf)
return str(buf)

# Non-standard LLVM passes

def add_refprune_pass(self, subpasses_flags=RefPruneSubpasses.ALL,
Expand All @@ -670,14 +685,6 @@ def add_refprune_pass(self, subpasses_flags=RefPruneSubpasses.ALL,
iflags = RefPruneSubpasses(subpasses_flags)
ffi.lib.LLVMPY_AddRefPrunePass(self, iflags, subgraph_limit)


class ModulePassManager(PassManager):

def __init__(self, ptr=None):
if ptr is None:
ptr = ffi.lib.LLVMPY_CreatePassManager()
PassManager.__init__(self, ptr)

def run(self, module, remarks_file=None, remarks_format='yaml',
remarks_filter=''):
"""
Expand All @@ -695,10 +702,10 @@ def run(self, module, remarks_file=None, remarks_format='yaml',
The filter that should be applied to the remarks output.
"""
if remarks_file is None:
return ffi.lib.LLVMPY_RunPassManager(self, module)
return ffi.lib.LLVMPY_RunPassManager(self, module, self.__MAM__)
else:
r = ffi.lib.LLVMPY_RunPassManagerWithRemarks(
self, module, _encode_string(remarks_format),
self, module, self.__MAM__, _encode_string(remarks_format),
_encode_string(remarks_filter),
_encode_string(remarks_file))
if r == -1:
Expand Down Expand Up @@ -734,12 +741,23 @@ def run_with_remarks(self, module, remarks_format='yaml',


class FunctionPassManager(PassManager):
__FAM__ = ffi.LLVMFunctionAnalysisManager
__PIC__ = ffi.LLVMPassInstrumentationCallbacks
__TimePasses__ = ffi.LLVMTimePassesHandler

def _dispose(self):
ffi.lib.LLVMPY_DisposeFunctionPassManager(self)

def __init__(self, module):
ptr = ffi.lib.LLVMPY_CreateFunctionPassManager(module)
ptr = ffi.lib.LLVMPY_CreateFunctionPassManager()
self._module = module
module._owned = True
PassManager.__init__(self, ptr)
self.__FAM__ = ffi.lib.LLVMPY_LLVMFunctionAnalysisManagerCreate()
self.__TimePasses__ = ffi.lib.LLVMPY_CreateLLVMTimePassesHandler()

def update(self, ptr):
PassManager.__init__(self, ptr)

def initialize(self):
"""
Expand All @@ -755,6 +773,32 @@ def finalize(self):
"""
return ffi.lib.LLVMPY_FinalizeFunctionPassManager(self)

def set_time_passes(self, enable):
"""Enable or disable the pass timers.
Parameters
----------
enable : bool
Set to True to enable the pass timers.
Set to False to disable the pass timers.
"""
ffi.lib.LLVMPY_SetTimePasses(self.__TimePasses__, self.__PIC__)

def report_and_reset_timings(self):
"""Returns the pass timings report and resets the LLVM internal timers.
Pass timers are enabled by ``set_time_passes()``. If the timers are not
enabled, this function will return an empty string.
Returns
-------
res : str
LLVM generated timing report.
"""
with ffi.OutputString() as buf:
ffi.lib.LLVMPY_ReportAndResetTimings(self.__TimePasses__, buf)
return str(buf)

def run(self, function, remarks_file=None, remarks_format='yaml',
remarks_filter=''):
"""
Expand All @@ -772,10 +816,12 @@ def run(self, function, remarks_file=None, remarks_format='yaml',
The filter that should be applied to the remarks output.
"""
if remarks_file is None:
return ffi.lib.LLVMPY_RunFunctionPassManager(self, function)
return ffi.lib.LLVMPY_RunFunctionPassManager(
self, function, self.__FAM__
)
else:
r = ffi.lib.LLVMPY_RunFunctionPassManagerWithRemarks(
self, function, _encode_string(remarks_format),
self, function, self.__FAM__, _encode_string(remarks_format),
_encode_string(remarks_filter),
_encode_string(remarks_file))
if r == -1:
Expand Down Expand Up @@ -813,40 +859,80 @@ def run_with_remarks(self, function, remarks_format='yaml',
finally:
os.unlink(remarkfile)

def add_target_library_info(self, triple):
ffi.lib.LLVMPY_AddTargetLibraryInfoPass(
self.__FAM__, _encode_string(triple)
)


# ============================================================================
# FFI

ffi.lib.LLVMPY_CreatePassManager.restype = ffi.LLVMPassManagerRef
ffi.lib.LLVMPY_LLVMFunctionAnalysisManagerCreate.restype = (
ffi.LLVMFunctionAnalysisManager
)

ffi.lib.LLVMPY_LLVMModuleAnalysisManagerCreate.restype = (
ffi.LLVMModuleAnalysisManager
)

ffi.lib.LLVMPY_CreateLLVMTimePassesHandler.restype = ffi.LLVMTimePassesHandler

ffi.lib.LLVMPY_CreatePassManager.restype = ffi.LLVMModulePassManager

ffi.lib.LLVMPY_CreateFunctionPassManager.argtypes = []
ffi.lib.LLVMPY_CreateFunctionPassManager.restype = ffi.LLVMFunctionPassManager

ffi.lib.LLVMPY_CreateFunctionPassManager.argtypes = [ffi.LLVMModuleRef]
ffi.lib.LLVMPY_CreateFunctionPassManager.restype = ffi.LLVMPassManagerRef
ffi.lib.LLVMPY_DisposePassManager.argtypes = [ffi.LLVMModulePassManager]

ffi.lib.LLVMPY_DisposePassManager.argtypes = [ffi.LLVMPassManagerRef]
ffi.lib.LLVMPY_DisposeFunctionPassManager.argtypes = [
ffi.LLVMFunctionPassManager
]

ffi.lib.LLVMPY_DisposeLLVMTimePassesHandler.argtypes = [
ffi.LLVMTimePassesHandler
]

ffi.lib.LLVMPY_RunPassManager.argtypes = [ffi.LLVMPassManagerRef,
ffi.LLVMModuleRef]
ffi.lib.LLVMPY_RunPassManager.argtypes = [
ffi.LLVMModulePassManager,
ffi.LLVMModuleRef,
ffi.LLVMModuleAnalysisManager,
]
ffi.lib.LLVMPY_RunPassManager.restype = c_bool

ffi.lib.LLVMPY_RunPassManagerWithRemarks.argtypes = [ffi.LLVMPassManagerRef,
ffi.LLVMModuleRef,
c_char_p,
c_char_p,
c_char_p]
ffi.lib.LLVMPY_RunPassManagerWithRemarks.argtypes = [
ffi.LLVMModulePassManager,
ffi.LLVMModuleRef,
ffi.LLVMModuleAnalysisManager,
c_char_p,
c_char_p,
c_char_p,
]
ffi.lib.LLVMPY_RunPassManagerWithRemarks.restype = c_int

ffi.lib.LLVMPY_InitializeFunctionPassManager.argtypes = [ffi.LLVMPassManagerRef]
ffi.lib.LLVMPY_InitializeFunctionPassManager.argtypes = [
ffi.LLVMFunctionPassManager
]
ffi.lib.LLVMPY_InitializeFunctionPassManager.restype = c_bool

ffi.lib.LLVMPY_FinalizeFunctionPassManager.argtypes = [ffi.LLVMPassManagerRef]
ffi.lib.LLVMPY_FinalizeFunctionPassManager.argtypes = [
ffi.LLVMFunctionPassManager
]
ffi.lib.LLVMPY_FinalizeFunctionPassManager.restype = c_bool

ffi.lib.LLVMPY_RunFunctionPassManager.argtypes = [ffi.LLVMPassManagerRef,
ffi.LLVMValueRef]
ffi.lib.LLVMPY_RunFunctionPassManager.argtypes = [
ffi.LLVMFunctionPassManager,
ffi.LLVMValueRef,
]
ffi.lib.LLVMPY_RunFunctionPassManager.restype = c_bool

ffi.lib.LLVMPY_RunFunctionPassManagerWithRemarks.argtypes = [
ffi.LLVMPassManagerRef, ffi.LLVMValueRef, c_char_p, c_char_p, c_char_p
ffi.LLVMFunctionPassManager,
ffi.LLVMValueRef,
ffi.LLVMFunctionAnalysisManager,
c_char_p,
c_char_p,
c_char_p,
]
ffi.lib.LLVMPY_RunFunctionPassManagerWithRemarks.restype = c_int

Expand All @@ -860,7 +946,8 @@ def run_with_remarks(self, function, remarks_format='yaml',
ffi.lib.LLVMPY_AddDotDomPrinterPass.argtypes = [ffi.LLVMPassManagerRef, c_bool]
ffi.lib.LLVMPY_AddDotPostDomPrinterPass.argtypes = [
ffi.LLVMPassManagerRef,
c_bool]
c_bool,
]
ffi.lib.LLVMPY_AddGlobalsModRefAAPass.argtypes = [ffi.LLVMPassManagerRef]
ffi.lib.LLVMPY_AddInstructionCountPass.argtypes = [ffi.LLVMPassManagerRef]
ffi.lib.LLVMPY_AddIVUsersPass.argtypes = [ffi.LLVMPassManagerRef]
Expand All @@ -874,15 +961,18 @@ def run_with_remarks(self, function, remarks_format='yaml',

if llvm_version_major < 15:
ffi.lib.LLVMPY_AddArgPromotionPass.argtypes = [
ffi.LLVMPassManagerRef, c_uint]
ffi.LLVMPassManagerRef,
c_uint,
]

ffi.lib.LLVMPY_AddBreakCriticalEdgesPass.argtypes = [ffi.LLVMPassManagerRef]
ffi.lib.LLVMPY_AddDeadStoreEliminationPass.argtypes = [
ffi.LLVMPassManagerRef]
ffi.lib.LLVMPY_AddDeadStoreEliminationPass.argtypes = [ffi.LLVMPassManagerRef]
ffi.lib.LLVMPY_AddReversePostOrderFunctionAttrsPass.argtypes = [
ffi.LLVMPassManagerRef]
ffi.LLVMPassManagerRef
]
ffi.lib.LLVMPY_AddAggressiveInstructionCombiningPass.argtypes = [
ffi.LLVMPassManagerRef]
ffi.LLVMPassManagerRef
]
ffi.lib.LLVMPY_AddInternalizePass.argtypes = [ffi.LLVMPassManagerRef]
ffi.lib.LLVMPY_AddLCSSAPass.argtypes = [ffi.LLVMPassManagerRef]
ffi.lib.LLVMPY_AddLoopDeletionPass.argtypes = [ffi.LLVMPassManagerRef]
Expand All @@ -892,8 +982,11 @@ def run_with_remarks(self, function, remarks_format='yaml',
ffi.lib.LLVMPY_AddLoopSimplificationPass.argtypes = [ffi.LLVMPassManagerRef]
ffi.lib.LLVMPY_AddLoopUnrollPass.argtypes = [ffi.LLVMPassManagerRef]
ffi.lib.LLVMPY_AddLoopUnrollAndJamPass.argtypes = [ffi.LLVMPassManagerRef]
ffi.lib.LLVMPY_AddLoopUnswitchPass.argtypes = [ffi.LLVMPassManagerRef, c_bool,
c_bool]
ffi.lib.LLVMPY_AddLoopUnswitchPass.argtypes = [
ffi.LLVMPassManagerRef,
c_bool,
c_bool,
]
ffi.lib.LLVMPY_AddLowerAtomicPass.argtypes = [ffi.LLVMPassManagerRef]
ffi.lib.LLVMPY_AddLowerInvokePass.argtypes = [ffi.LLVMPassManagerRef]
ffi.lib.LLVMPY_AddLowerSwitchPass.argtypes = [ffi.LLVMPassManagerRef]
Expand All @@ -909,31 +1002,41 @@ def run_with_remarks(self, function, remarks_format='yaml',
ffi.lib.LLVMPY_AddStripDeadDebugInfoPass.argtypes = [ffi.LLVMPassManagerRef]
ffi.lib.LLVMPY_AddStripDeadPrototypesPass.argtypes = [ffi.LLVMPassManagerRef]
ffi.lib.LLVMPY_AddStripDebugDeclarePrototypesPass.argtypes = [
ffi.LLVMPassManagerRef]
ffi.LLVMPassManagerRef
]
ffi.lib.LLVMPY_AddStripNondebugSymbolsPass.argtypes = [ffi.LLVMPassManagerRef]
ffi.lib.LLVMPY_AddTailCallEliminationPass.argtypes = [ffi.LLVMPassManagerRef]
ffi.lib.LLVMPY_AddJumpThreadingPass.argtypes = [ffi.LLVMPassManagerRef, c_int]
ffi.lib.LLVMPY_AddFunctionAttrsPass.argtypes = [ffi.LLVMPassManagerRef]
ffi.lib.LLVMPY_AddFunctionInliningPass.argtypes = [
ffi.LLVMPassManagerRef, c_int]
ffi.LLVMModulePassManager,
c_int,
]
ffi.lib.LLVMPY_AddGlobalDCEPass.argtypes = [ffi.LLVMPassManagerRef]
ffi.lib.LLVMPY_AddGlobalOptimizerPass.argtypes = [ffi.LLVMPassManagerRef]
ffi.lib.LLVMPY_AddIPSCCPPass.argtypes = [ffi.LLVMPassManagerRef]

ffi.lib.LLVMPY_AddDeadCodeEliminationPass.argtypes = [ffi.LLVMPassManagerRef]
ffi.lib.LLVMPY_AddCFGSimplificationPass.argtypes = [ffi.LLVMPassManagerRef]
ffi.lib.LLVMPY_AddGVNPass.argtypes = [ffi.LLVMPassManagerRef]
ffi.lib.LLVMPY_AddInstructionCombiningPass.argtypes = [ffi.LLVMPassManagerRef]
ffi.lib.LLVMPY_AddLICMPass.argtypes = [ffi.LLVMPassManagerRef]
ffi.lib.LLVMPY_AddInstructionCombiningPass.argtypes = [
ffi.LLVMModulePassManager
]
ffi.lib.LLVMPY_AddLICMPass.argtypes = [ffi.LLVMFunctionPassManager]
ffi.lib.LLVMPY_AddSCCPPass.argtypes = [ffi.LLVMPassManagerRef]
ffi.lib.LLVMPY_AddSROAPass.argtypes = [ffi.LLVMPassManagerRef]
ffi.lib.LLVMPY_AddTypeBasedAliasAnalysisPass.argtypes = [ffi.LLVMPassManagerRef]
ffi.lib.LLVMPY_AddBasicAliasAnalysisPass.argtypes = [ffi.LLVMPassManagerRef]
ffi.lib.LLVMPY_AddTargetLibraryInfoPass.argtypes = [ffi.LLVMPassManagerRef,
c_char_p]
ffi.lib.LLVMPY_AddInstructionNamerPass.argtypes = [ffi.LLVMPassManagerRef]
ffi.lib.LLVMPY_AddTargetLibraryInfoPass.argtypes = [
ffi.LLVMFunctionAnalysisManager,
c_char_p,
]
ffi.lib.LLVMPY_AddInstructionNamerPass.argtypes = [ffi.LLVMModulePassManager]

ffi.lib.LLVMPY_AddRefPrunePass.argtypes = [ffi.LLVMPassManagerRef, c_int,
c_size_t]
ffi.lib.LLVMPY_AddRefPrunePass.argtypes = [
ffi.LLVMModulePassManager,
c_int,
c_size_t,
]

ffi.lib.LLVMPY_DumpRefPruneStats.argtypes = [POINTER(_c_PruneStats), c_bool]
16 changes: 15 additions & 1 deletion llvmlite/binding/targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ def get_pointee_abi_size(self, ty):
"""
Get ABI size of pointee type of LLVM pointer type *ty*.
"""
raise RuntimeError("Opaque pointers means pointee "
"information cannot be queried")
size = ffi.lib.LLVMPY_ABISizeOfElementType(self, ty)
if size == -1:
raise RuntimeError("Not a pointer type: %s" % (ty,))
Expand All @@ -160,11 +162,19 @@ def get_pointee_abi_alignment(self, ty):
"""
Get minimum ABI alignment of pointee type of LLVM pointer type *ty*.
"""
raise RuntimeError("Opaque pointers means pointee "
"information cannot be queried")
size = ffi.lib.LLVMPY_ABIAlignmentOfElementType(self, ty)
if size == -1:
raise RuntimeError("Not a pointer type: %s" % (ty,))
return size

def get_abi_alignment(self, ty):
"""
Get minimum ABI alignment of pointee type of LLVM pointer type *ty*.
"""
return ffi.lib.LLVMPY_ABIAlignmentOfType(self, ty)


RELOC = frozenset(['default', 'static', 'pic', 'dynamicnopic'])
CODEMODEL = frozenset(['default', 'jitdefault', 'small', 'kernel', 'medium',
Expand Down Expand Up @@ -380,6 +390,10 @@ def has_svml():
ffi.LLVMTypeRef]
ffi.lib.LLVMPY_ABIAlignmentOfElementType.restype = c_longlong

ffi.lib.LLVMPY_ABIAlignmentOfType.argtypes = [ffi.LLVMTargetDataRef,
ffi.LLVMTypeRef]
ffi.lib.LLVMPY_ABIAlignmentOfType.restype = c_longlong

ffi.lib.LLVMPY_GetTargetFromTriple.argtypes = [c_char_p, POINTER(c_char_p)]
ffi.lib.LLVMPY_GetTargetFromTriple.restype = ffi.LLVMTargetRef

Expand Down Expand Up @@ -422,7 +436,7 @@ def has_svml():

ffi.lib.LLVMPY_AddAnalysisPasses.argtypes = [
ffi.LLVMTargetMachineRef,
ffi.LLVMPassManagerRef,
ffi.LLVMModulePassManager,
]

ffi.lib.LLVMPY_TargetMachineEmitToMemory.argtypes = [
Expand Down
206 changes: 165 additions & 41 deletions llvmlite/binding/transforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,58 @@ def create_pass_manager_builder():
return PassManagerBuilder()


class OptimizationLevel(ffi.ObjectRef):
def __init__(self, ptr=None):
if ptr is None:
ptr = ffi.lib.LLVMPY_PassManagerCreateOptimizationLevel(0, 0)
ffi.ObjectRef.__init__(self, ptr)


class PassManagerBuilder(ffi.ObjectRef):
__slots__ = ()
__opt_level__ = 0
__size_level__ = 0
__MAM__ = ffi.LLVMModuleAnalysisManager
__LAM__ = ffi.LLVMLoopAnalysisManager
__FAM__ = ffi.LLVMFunctionAnalysisManager
__CGAM__ = ffi.LLVMCGSCCAnalysisManager
__PIC__ = ffi.LLVMPassInstrumentationCallbacks
__pipeline_options__ = ffi.LLVMPassBuilderOptionsRef

def __init__(self, ptr=None):
if ptr is None:
ptr = ffi.lib.LLVMPY_PassManagerBuilderCreate()
ffi.ObjectRef.__init__(self, ptr)

self.__MAM__ = ffi.lib.LLVMPY_LLVMModuleAnalysisManagerCreate()
self.__LAM__ = ffi.lib.LLVMPY_LLVMLoopAnalysisManagerCreate()
self.__FAM__ = ffi.lib.LLVMPY_LLVMFunctionAnalysisManagerCreate()
self.__CGAM__ = ffi.lib.LLVMPY_LLVMCGSCCAnalysisManagerCreate()
self.__PIC__ = ffi.lib.LLVMPY_LLVMPassInstrumentationCallbacksCreate()
self.__pipeline_options__ = (
ffi.lib.LLVMPY_PassManagerBuilderOptionsCreate()
)

@property
def opt_level(self):
"""
The general optimization level as an integer between 0 and 3.
"""
return ffi.lib.LLVMPY_PassManagerBuilderGetOptLevel(self)
return self.__opt_level__

@opt_level.setter
def opt_level(self, level):
ffi.lib.LLVMPY_PassManagerBuilderSetOptLevel(self, level)
self.__opt_level__ = level

@property
def size_level(self):
"""
Whether and how much to optimize for size. An integer between 0 and 2.
"""
return ffi.lib.LLVMPY_PassManagerBuilderGetSizeLevel(self)
return self.__size_level__

@size_level.setter
def size_level(self, size):
ffi.lib.LLVMPY_PassManagerBuilderSetSizeLevel(self, size)
self.__size_level__ = size

@property
def inlining_threshold(self):
Expand All @@ -48,47 +71,96 @@ def inlining_threshold(self):
@inlining_threshold.setter
def inlining_threshold(self, threshold):
ffi.lib.LLVMPY_PassManagerBuilderUseInlinerWithThreshold(
self, threshold)
self.__pipeline_options__, threshold
)

@property
def disable_unroll_loops(self):
"""
If true, disable loop unrolling.
"""
return ffi.lib.LLVMPY_PassManagerBuilderGetDisableUnrollLoops(self)
return ffi.lib.LLVMPY_PassManagerBuilderGetDisableUnrollLoops(
self.__pipeline_options__
)

@disable_unroll_loops.setter
def disable_unroll_loops(self, disable=True):
ffi.lib.LLVMPY_PassManagerBuilderSetDisableUnrollLoops(self, disable)
ffi.lib.LLVMPY_PassManagerBuilderSetDisableUnrollLoops(
self.__pipeline_options__, disable
)

@property
def loop_vectorize(self):
"""
If true, allow vectorizing loops.
"""
return ffi.lib.LLVMPY_PassManagerBuilderGetLoopVectorize(self)
return ffi.lib.LLVMPY_PassManagerBuilderGetLoopVectorize(
self.__pipeline_options__
)

@loop_vectorize.setter
def loop_vectorize(self, enable=True):
return ffi.lib.LLVMPY_PassManagerBuilderSetLoopVectorize(self, enable)
return ffi.lib.LLVMPY_PassManagerBuilderSetLoopVectorize(
self.__pipeline_options__, enable
)

@property
def slp_vectorize(self):
"""
If true, enable the "SLP vectorizer", which uses a different algorithm
from the loop vectorizer. Both may be enabled at the same time.
"""
return ffi.lib.LLVMPY_PassManagerBuilderGetSLPVectorize(self)
return ffi.lib.LLVMPY_PassManagerBuilderGetSLPVectorize(
self.__pipeline_options__
)

@slp_vectorize.setter
def slp_vectorize(self, enable=True):
return ffi.lib.LLVMPY_PassManagerBuilderSetSLPVectorize(self, enable)
return ffi.lib.LLVMPY_PassManagerBuilderSetSLPVectorize(
self.__pipeline_options__, enable
)

def _populate_module_pm(self, pm):
ffi.lib.LLVMPY_PassManagerBuilderPopulateModulePassManager(self, pm)
opt_level = OptimizationLevel(
ffi.lib.LLVMPY_PassManagerCreateOptimizationLevel(
c_uint(self.__opt_level__), c_uint(self.__size_level__)
)
)
pm.update(
ffi.lib.LLVMPY_PassManagerBuilderPopulateModulePassManager(
self,
self.__pipeline_options__,
opt_level,
pm,
pm.__MAM__,
self.__LAM__,
self.__FAM__,
self.__CGAM__,
self.__PIC__,
)
)
pm.__PIC__ = self.__PIC__

def _populate_function_pm(self, pm):
ffi.lib.LLVMPY_PassManagerBuilderPopulateFunctionPassManager(self, pm)
opt_level = OptimizationLevel(
ffi.lib.LLVMPY_PassManagerCreateOptimizationLevel(
c_uint(self.__opt_level__), c_uint(self.__size_level__)
)
)
pm.update(
ffi.lib.LLVMPY_PassManagerBuilderPopulateFunctionPassManager(
self,
self.__pipeline_options__,
opt_level,
pm,
self.__MAM__,
self.__LAM__,
pm.__FAM__,
self.__CGAM__,
self.__PIC__,
)
)
pm.__PIC__ = self.__PIC__

def populate(self, pm):
if isinstance(pm, passmanagers.ModulePassManager):
Expand All @@ -99,53 +171,105 @@ def populate(self, pm):
raise TypeError(pm)

def _dispose(self):
self._capi.LLVMPY_PassManagerBuilderDispose(self)
self._capi.LLVMPY_PassManagerBuilderDispose(
self, self.__pipeline_options__
)


# ============================================================================
# FFI

ffi.lib.LLVMPY_PassManagerBuilderCreate.restype = ffi.LLVMPassManagerBuilderRef
ffi.lib.LLVMPY_PassManagerBuilderCreate.restype = ffi.LLVMPassBuilder

ffi.lib.LLVMPY_LLVMModuleAnalysisManagerCreate.restype = (
ffi.LLVMModuleAnalysisManager
)
ffi.lib.LLVMPY_LLVMLoopAnalysisManagerCreate.restype = (
ffi.LLVMLoopAnalysisManager
)
ffi.lib.LLVMPY_LLVMFunctionAnalysisManagerCreate.restype = (
ffi.LLVMFunctionAnalysisManager
)
ffi.lib.LLVMPY_LLVMCGSCCAnalysisManagerCreate.restype = (
ffi.LLVMCGSCCAnalysisManager
)
ffi.lib.LLVMPY_LLVMPassInstrumentationCallbacksCreate.restype = (
ffi.LLVMPassInstrumentationCallbacks
)


ffi.lib.LLVMPY_PassManagerBuilderOptionsCreate.restype = (
ffi.LLVMPassBuilderOptionsRef
)

ffi.lib.LLVMPY_PassManagerBuilderDispose.argtypes = [
ffi.LLVMPassManagerBuilderRef,
ffi.LLVMPassBuilder,
ffi.LLVMPassBuilderOptionsRef,
]

ffi.lib.LLVMPY_PassManagerBuilderPopulateModulePassManager.argtypes = [
ffi.LLVMPassManagerBuilderRef,
ffi.LLVMPassManagerRef,
ffi.LLVMPassBuilder,
ffi.LLVMPassBuilderOptionsRef,
ffi.LLVMOptimizationLevel,
ffi.LLVMModulePassManager,
ffi.LLVMModuleAnalysisManager,
ffi.LLVMLoopAnalysisManager,
ffi.LLVMFunctionAnalysisManager,
ffi.LLVMCGSCCAnalysisManager,
ffi.LLVMPassInstrumentationCallbacks,
]

ffi.lib.LLVMPY_PassManagerBuilderPopulateModulePassManager.restype = (
ffi.LLVMModulePassManager
)

ffi.lib.LLVMPY_PassManagerBuilderPopulateFunctionPassManager.argtypes = [
ffi.LLVMPassManagerBuilderRef,
ffi.LLVMPassManagerRef,
ffi.LLVMPassBuilder,
ffi.LLVMPassBuilderOptionsRef,
ffi.LLVMOptimizationLevel,
ffi.LLVMFunctionPassManager,
ffi.LLVMModuleAnalysisManager,
ffi.LLVMLoopAnalysisManager,
ffi.LLVMFunctionAnalysisManager,
ffi.LLVMCGSCCAnalysisManager,
ffi.LLVMPassInstrumentationCallbacks,
]

ffi.lib.LLVMPY_PassManagerBuilderPopulateFunctionPassManager.restype = (
ffi.LLVMFunctionPassManager
)

ffi.lib.LLVMPY_PassManagerCreateOptimizationLevel.restype = (
ffi.LLVMOptimizationLevel
)
ffi.lib.LLVMPY_PassManagerCreateOptimizationLevel.argtypes = [c_uint, c_uint]

# Unsigned int PassManagerBuilder properties

for _func in (ffi.lib.LLVMPY_PassManagerBuilderSetOptLevel,
ffi.lib.LLVMPY_PassManagerBuilderSetSizeLevel,
ffi.lib.LLVMPY_PassManagerBuilderUseInlinerWithThreshold,
):
_func.argtypes = [ffi.LLVMPassManagerBuilderRef, c_uint]
for _func in (ffi.lib.LLVMPY_PassManagerBuilderUseInlinerWithThreshold,):
_func.argtypes = [ffi.LLVMPassBuilderOptionsRef, c_uint]


for _func in (ffi.lib.LLVMPY_PassManagerBuilderGetOptLevel,
ffi.lib.LLVMPY_PassManagerBuilderGetSizeLevel,
):
_func.argtypes = [ffi.LLVMPassManagerBuilderRef]
for _func in (
ffi.lib.LLVMPY_PassManagerBuilderGetOptLevel,
ffi.lib.LLVMPY_PassManagerBuilderGetSizeLevel,
):
_func.argtypes = [ffi.LLVMOptimizationLevel]
_func.restype = c_uint

# Boolean PassManagerBuilder properties

for _func in (ffi.lib.LLVMPY_PassManagerBuilderSetDisableUnrollLoops,
ffi.lib.LLVMPY_PassManagerBuilderSetLoopVectorize,
ffi.lib.LLVMPY_PassManagerBuilderSetSLPVectorize,
):
_func.argtypes = [ffi.LLVMPassManagerBuilderRef, c_bool]

for _func in (ffi.lib.LLVMPY_PassManagerBuilderGetDisableUnrollLoops,
ffi.lib.LLVMPY_PassManagerBuilderGetLoopVectorize,
ffi.lib.LLVMPY_PassManagerBuilderGetSLPVectorize,
):
_func.argtypes = [ffi.LLVMPassManagerBuilderRef]
for _func in (
ffi.lib.LLVMPY_PassManagerBuilderSetDisableUnrollLoops,
ffi.lib.LLVMPY_PassManagerBuilderSetLoopVectorize,
ffi.lib.LLVMPY_PassManagerBuilderSetSLPVectorize,
):
_func.argtypes = [ffi.LLVMPassBuilderOptionsRef, c_bool]

for _func in (
ffi.lib.LLVMPY_PassManagerBuilderGetDisableUnrollLoops,
ffi.lib.LLVMPY_PassManagerBuilderGetLoopVectorize,
ffi.lib.LLVMPY_PassManagerBuilderGetSLPVectorize,
):
_func.argtypes = [ffi.LLVMPassBuilderOptionsRef]
_func.restype = c_bool
16 changes: 2 additions & 14 deletions llvmlite/binding/typeref.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,16 +67,6 @@ def is_vector(self):
"""
return ffi.lib.LLVMPY_TypeIsVector(self)

@property
def is_function_vararg(self):
"""
Returns true if a function type accepts a variable number of arguments.
When the type is not a function, raises exception.
"""
if self.type_kind != TypeKind.function:
raise ValueError("Type {} is not a function".format(self))
return ffi.lib.LLVMPY_IsFunctionVararg(self)

@property
def elements(self):
"""
Expand All @@ -92,7 +82,8 @@ def element_type(self):
"""
if not self.is_pointer:
raise ValueError("Type {} is not a pointer".format(self))
return TypeRef(ffi.lib.LLVMPY_GetElementType(self))
raise ValueError("LLVM uses opaque pointers, "
"so this operation is no longer supported")

@property
def element_count(self):
Expand Down Expand Up @@ -177,9 +168,6 @@ def _next(self):
ffi.lib.LLVMPY_TypeIsStruct.argtypes = [ffi.LLVMTypeRef]
ffi.lib.LLVMPY_TypeIsStruct.restype = c_bool

ffi.lib.LLVMPY_IsFunctionVararg.argtypes = [ffi.LLVMTypeRef]
ffi.lib.LLVMPY_IsFunctionVararg.restype = c_bool

ffi.lib.LLVMPY_GetTypeKind.argtypes = [ffi.LLVMTypeRef]
ffi.lib.LLVMPY_GetTypeKind.restype = c_int

Expand Down
25 changes: 25 additions & 0 deletions llvmlite/binding/value.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,14 @@ def type(self):
# XXX what does this return?
return TypeRef(ffi.lib.LLVMPY_TypeOf(self))

@property
def global_value_type(self):
"""
This value's LLVM type.
"""
# XXX what does this return?
return TypeRef(ffi.lib.LLVMPY_GlobalGetValueType(self))

@property
def is_declaration(self):
"""
Expand Down Expand Up @@ -313,6 +321,17 @@ def opcode(self):
% (self._kind,))
return ffi.ret_string(ffi.lib.LLVMPY_GetOpcodeName(self))

@property
def is_function_vararg(self):
"""
Returns true if a function type accepts a variable number of arguments.
When the type is not a function, raises exception.
"""
if not self.is_function:
raise ValueError('expected function value, got %s'
% (self._kind,))
return ffi.lib.LLVMPY_IsFunctionVararg(self)

@property
def incoming_blocks(self):
"""
Expand Down Expand Up @@ -505,6 +524,9 @@ def _next(self):
ffi.lib.LLVMPY_TypeOf.argtypes = [ffi.LLVMValueRef]
ffi.lib.LLVMPY_TypeOf.restype = ffi.LLVMTypeRef

ffi.lib.LLVMPY_GlobalGetValueType.argtypes = [ffi.LLVMValueRef]
ffi.lib.LLVMPY_GlobalGetValueType.restype = ffi.LLVMTypeRef

ffi.lib.LLVMPY_GetTypeName.argtypes = [ffi.LLVMTypeRef]
ffi.lib.LLVMPY_GetTypeName.restype = c_void_p

Expand Down Expand Up @@ -616,3 +638,6 @@ def _next(self):
ffi.lib.LLVMPY_GetConstantFPValue.argtypes = [ffi.LLVMValueRef,
POINTER(c_bool)]
ffi.lib.LLVMPY_GetConstantFPValue.restype = c_double

ffi.lib.LLVMPY_IsFunctionVararg.argtypes = [ffi.LLVMValueRef]
ffi.lib.LLVMPY_IsFunctionVararg.restype = c_bool
6 changes: 3 additions & 3 deletions llvmlite/ir/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,22 +43,22 @@ def _get_ll_pointer_type(self, target_data, context=None):
m = Module(context=context)
foo = GlobalVariable(m, self, name="foo")
with parse_assembly(str(m)) as llmod:
return llmod.get_global_variable(foo.name).type
return llmod.get_global_variable(foo.name).global_value_type

def get_abi_size(self, target_data, context=None):
"""
Get the ABI size of this type according to data layout *target_data*.
"""
llty = self._get_ll_pointer_type(target_data, context)
return target_data.get_pointee_abi_size(llty)
return target_data.get_abi_size(llty)

def get_abi_alignment(self, target_data, context=None):
"""
Get the minimum ABI alignment of this type according to data layout
*target_data*.
"""
llty = self._get_ll_pointer_type(target_data, context)
return target_data.get_pointee_abi_alignment(llty)
return target_data.get_abi_alignment(llty)

def format_constant(self, value):
"""
Expand Down
150 changes: 76 additions & 74 deletions llvmlite/tests/test_binding.py

Large diffs are not rendered by default.

178 changes: 91 additions & 87 deletions llvmlite/tests/test_refprune.py

Large diffs are not rendered by default.