Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions ffi/core.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "core.h"

#include "llvm-c/Support.h"
#include "llvm/IR/LLVMContext.h"

extern "C" {

Expand All @@ -21,10 +22,33 @@ API_EXPORT(void)
LLVMPY_DisposeString(const char *msg) { free(const_cast<char *>(msg)); }

API_EXPORT(LLVMContextRef)
LLVMPY_GetGlobalContext() { return LLVMGetGlobalContext(); }
LLVMPY_GetGlobalContext(bool enable_opaque_pointers) {
LLVMContextRef ctx = LLVMGetGlobalContext();
#if LLVM_VERSION_MAJOR >= 14
if (enable_opaque_pointers)
llvm::unwrap(ctx)->enableOpaquePointers();
#endif
return ctx;
}

API_EXPORT(LLVMContextRef)
LLVMPY_ContextCreate() { return LLVMContextCreate(); }
LLVMPY_ContextCreate(bool enable_opaque_pointers) {
LLVMContextRef ctx = LLVMContextCreate();
#if LLVM_VERSION_MAJOR >= 14
if (enable_opaque_pointers)
llvm::unwrap(ctx)->enableOpaquePointers();
#endif
return ctx;
}

API_EXPORT(bool)
LLVMPY_SupportsTypedPointers(LLVMContextRef ctx) {
#if LLVM_VERSION_MAJOR >= 13
return llvm::unwrap(ctx)->supportsTypedPointers();
#else
return true;
#endif
}

API_EXPORT(void)
LLVMPY_ContextDispose(LLVMContextRef context) {
Expand Down
7 changes: 5 additions & 2 deletions ffi/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,13 @@ API_EXPORT(void)
LLVMPY_DisposeString(const char *msg);

API_EXPORT(LLVMContextRef)
LLVMPY_GetGlobalContext();
LLVMPY_GetGlobalContext(bool enable_opaque_pointers);

API_EXPORT(LLVMContextRef)
LLVMPY_ContextCreate();
LLVMPY_ContextCreate(bool enable_opaque_pointers);

API_EXPORT(bool)
LLVMPY_SupportsTypedPointers(LLVMContextRef ctx);

} /* end extern "C" */

Expand Down
5 changes: 5 additions & 0 deletions ffi/targets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,11 @@ LLVMPY_CopyStringRepOfTargetData(LLVMTargetDataRef TD, char **Out) {
API_EXPORT(void)
LLVMPY_DisposeTargetData(LLVMTargetDataRef TD) { LLVMDisposeTargetData(TD); }

API_EXPORT(long long)
LLVMPY_ABIAlignmentOfType(LLVMTargetDataRef TD, LLVMTypeRef Ty) {
return (long long)LLVMABIAlignmentOfType(TD, Ty);
}

API_EXPORT(long long)
LLVMPY_ABISizeOfType(LLVMTargetDataRef TD, LLVMTypeRef Ty) {
return (long long)LLVMABISizeOfType(TD, Ty);
Expand Down
10 changes: 10 additions & 0 deletions ffi/value.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,16 @@ LLVMPY_SetValueName(LLVMValueRef Val, const char *Name) {
API_EXPORT(LLVMModuleRef)
LLVMPY_GetGlobalParent(LLVMValueRef Val) { return LLVMGetGlobalParent(Val); }

API_EXPORT(LLVMTypeRef)
LLVMPY_GlobalGetValueType(LLVMValueRef Val) {
llvm::Value *unwrapped = llvm::unwrap(Val);
llvm::GlobalValue *gv = llvm::dyn_cast<llvm::GlobalValue>(unwrapped);
if (!gv) {
return nullptr;
}
return llvm::wrap(gv->getValueType());
}

API_EXPORT(LLVMTypeRef)
LLVMPY_TypeOf(LLVMValueRef Val) { return LLVMTypeOf(Val); }

Expand Down
14 changes: 12 additions & 2 deletions llvmlite/binding/context.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
from ctypes import c_bool

from llvmlite.binding import ffi


def create_context():
return ContextRef(ffi.lib.LLVMPY_ContextCreate())
return ContextRef(ffi.lib.LLVMPY_ContextCreate(True))


def get_global_context():
return GlobalContextRef(ffi.lib.LLVMPY_GetGlobalContext())
return GlobalContextRef(ffi.lib.LLVMPY_GetGlobalContext(True))


class ContextRef(ffi.ObjectRef):
def __init__(self, context_ptr):
super(ContextRef, self).__init__(context_ptr)

def supports_typed_pointers(self):
return ffi.lib.LLVMPY_SupportsTypedPointers(self)

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

Expand All @@ -22,8 +27,13 @@ def _dispose(self):
pass


ffi.lib.LLVMPY_GetGlobalContext.argtypes = [c_bool]
ffi.lib.LLVMPY_GetGlobalContext.restype = ffi.LLVMContextRef

ffi.lib.LLVMPY_ContextCreate.argtypes = [c_bool]
ffi.lib.LLVMPY_ContextCreate.restype = ffi.LLVMContextRef

ffi.lib.LLVMPY_SupportsTypedPointers.argtypes = [ffi.LLVMContextRef]
ffi.lib.LLVMPY_SupportsTypedPointers.restype = c_bool

ffi.lib.LLVMPY_ContextDispose.argtypes = [ffi.LLVMContextRef]
10 changes: 10 additions & 0 deletions llvmlite/binding/targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,12 @@ def get_abi_size(self, ty):
"""
return ffi.lib.LLVMPY_ABISizeOfType(self, ty)

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

def get_element_offset(self, ty, position):
"""
Get byte offset of type's ty element at the given position
Expand Down Expand Up @@ -363,6 +369,10 @@ def has_svml():
ffi.LLVMTargetDataRef,
]

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

ffi.lib.LLVMPY_ABISizeOfType.argtypes = [ffi.LLVMTargetDataRef,
ffi.LLVMTypeRef]
ffi.lib.LLVMPY_ABISizeOfType.restype = c_longlong
Expand Down
10 changes: 10 additions & 0 deletions llvmlite/binding/value.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,13 @@ def add_function_attribute(self, attr):
raise ValueError('no such attribute {!r}'.format(attrname))
ffi.lib.LLVMPY_AddFunctionAttr(self, attrval)

@property
def global_value_type(self):
"""
This value's LLVM type, if it is a global value.
"""
return TypeRef(ffi.lib.LLVMPY_GlobalGetValueType(self))

@property
def type(self):
"""
Expand Down Expand Up @@ -418,6 +425,9 @@ def _next(self):

ffi.lib.LLVMPY_SetValueName.argtypes = [ffi.LLVMValueRef, c_char_p]

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

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

Expand Down
12 changes: 6 additions & 6 deletions llvmlite/ir/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def as_pointer(self, addrspace=0):
def __ne__(self, other):
return not (self == other)

def _get_ll_pointer_type(self, target_data, context=None):
def _get_ll_global_value_type(self, target_data, context=None):
"""
Convert this type object to an LLVM type.
"""
Expand All @@ -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)
llty = self._get_ll_global_value_type(target_data, context)
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)
llty = self._get_ll_global_value_type(target_data, context)
return target_data.get_abi_alignment(llty)

def format_constant(self, value):
"""
Expand Down
65 changes: 50 additions & 15 deletions llvmlite/tests/test_binding.py
Original file line number Diff line number Diff line change
Expand Up @@ -969,14 +969,30 @@ def test_target_data_abi_enquiries(self):
for g in (gv_i32, gv_i8, gv_struct):
self.assertEqual(td.get_abi_size(g.type), pointer_size)

self.assertEqual(td.get_pointee_abi_size(gv_i32.type), 4)
self.assertEqual(td.get_pointee_abi_alignment(gv_i32.type), 4)
if llvm.context.get_global_context().supports_typed_pointers():
with self.subTest('pointee_types'):
self.assertEqual(td.get_pointee_abi_size(gv_i32.type), 4)
self.assertEqual(td.get_pointee_abi_alignment(gv_i32.type), 4)

self.assertEqual(td.get_pointee_abi_size(gv_i8.type), 1)
self.assertIn(td.get_pointee_abi_alignment(gv_i8.type), (1, 2, 4))
self.assertEqual(td.get_pointee_abi_size(gv_i8.type), 1)
self.assertIn(td.get_pointee_abi_alignment(
gv_i8.type), (1, 2, 4))

self.assertEqual(td.get_pointee_abi_size(gv_struct.type), 24)
self.assertIn(td.get_pointee_abi_alignment(gv_struct.type), (4, 8))
self.assertEqual(td.get_pointee_abi_size(gv_struct.type), 24)
self.assertIn(td.get_pointee_abi_alignment(
gv_struct.type), (4, 8))

with self.subTest('global_value_types'):
self.assertEqual(td.get_abi_size(gv_i32.global_value_type), 4)
self.assertEqual(td.get_abi_alignment(gv_i32.global_value_type), 4)

self.assertEqual(td.get_abi_size(gv_i8.global_value_type), 1)
self.assertIn(td.get_abi_alignment(
gv_i8.global_value_type), (1, 2, 4))

self.assertEqual(td.get_abi_size(gv_struct.global_value_type), 24)
self.assertIn(td.get_abi_alignment(
gv_struct.global_value_type), (4, 8))

def test_object_cache_notify(self):
notifies = []
Expand Down Expand Up @@ -1163,28 +1179,33 @@ def test_type_name(self):
self.assertEqual(tp.name, "")
st = mod.get_global_variable("glob_struct")
self.assertIsNotNone(re.match(r"struct\.glob_type(\.[\d]+)?",
st.type.element_type.name))
st.global_value_type.name))

def test_type_printing_variable(self):
mod = self.module()
glob = mod.get_global_variable("glob")
tp = glob.type
self.assertEqual(str(tp), 'i32*')
if llvm.context.get_global_context().supports_typed_pointers():
self.assertEqual(str(tp), 'i32*')
else:
self.assertEqual(str(tp), 'ptr')

def test_type_printing_function(self):
mod = self.module()
fn = mod.get_function("sum")
self.assertEqual(str(fn.type), "i32 (i32, i32)*")
self.assertRegex(str(fn.global_value_type), r"i32 \(i32, i32\)")
self.assertRegex(str(fn.type), r"(ptr|i32 \(i32, i32\)\*)")

def test_type_printing_struct(self):
mod = self.module()
st = mod.get_global_variable("glob_struct")
self.assertTrue(st.type.is_pointer)
self.assertIsNotNone(re.match(r'%struct\.glob_type(\.[\d]+)?\*',
str(st.type)))
self.assertIsNotNone(re.match(
r"%struct\.glob_type(\.[\d]+)? = type { i64, \[2 x i64\] }",
str(st.type.element_type)))
self.assertRegex(
str(st.type),
r'(ptr|%struct\.glob_type(\.[\d]+)?\*)')
self.assertRegex(
str(st.global_value_type),
r"%struct\.glob_type(\.[\d]+)? = type { i64, \[2 x i64\] }")

def test_close(self):
glob = self.glob()
Expand Down Expand Up @@ -1331,6 +1352,20 @@ def test_get_abi_size(self):
glob = self.glob()
self.assertEqual(td.get_abi_size(glob.type), 8)

def test_get_global_value_abi_size(self):
td = self.target_data()

glob = self.glob()
self.assertIsNotNone(glob.global_value_type)
self.assertEqual(td.get_abi_size(glob.global_value_type), 4)

glob = self.glob("glob_struct")
self.assertIsNotNone(glob.global_value_type)
self.assertEqual(td.get_abi_size(glob.global_value_type), 24)

@unittest.skipUnless(
llvm.context.get_global_context().supports_typed_pointers(),
"No typed pointer support")
def test_get_pointee_abi_size(self):
td = self.target_data()

Expand All @@ -1347,7 +1382,7 @@ def test_get_struct_element_offset(self):
with self.assertRaises(ValueError):
td.get_element_offset(glob.type, 0)

struct_type = glob.type.element_type
struct_type = glob.global_value_type
self.assertEqual(td.get_element_offset(struct_type, 0), 0)
self.assertEqual(td.get_element_offset(struct_type, 1), 8)

Expand Down
8 changes: 5 additions & 3 deletions llvmlite/tests/test_refprune.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ def test_per_bb_2(self):
mod, stats = self.check(self.per_bb_ir_2)
self.assertEqual(stats.basicblock, 4)
# not pruned
self.assertIn("call void @NRT_incref(i8* %ptr)", str(mod))
self.assertRegex(str(mod), r"call void @NRT_incref\((ptr|i8\*) %ptr\)")

per_bb_ir_3 = r"""
define void @main(i8* %ptr, i8* %other) {
Expand All @@ -226,7 +226,8 @@ def test_per_bb_3(self):
mod, stats = self.check(self.per_bb_ir_3)
self.assertEqual(stats.basicblock, 2)
# not pruned
self.assertIn("call void @NRT_decref(i8* %other)", str(mod))
self.assertRegex(
str(mod), r"call void @NRT_decref\((ptr|i8\*) %other\)")

per_bb_ir_4 = r"""
; reordered
Expand All @@ -244,7 +245,8 @@ def test_per_bb_4(self):
mod, stats = self.check(self.per_bb_ir_4)
self.assertEqual(stats.basicblock, 4)
# not pruned
self.assertIn("call void @NRT_decref(i8* %other)", str(mod))
self.assertRegex(
str(mod), r"call void @NRT_decref\((ptr|i8\*) %other\)")


class TestDiamond(BaseTestByIR):
Expand Down