Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add IR layer typed pointers mode #1159

Merged
merged 11 commits into from
Mar 4, 2025
12 changes: 8 additions & 4 deletions llvmlite/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@
del get_versions

# FIXME: Remove me once typed pointers are no longer supported.
def _opaque_pointers_enabled():
# Let's enable opaque pointers unconditionally.
opaque_pointers_enabled = True
# Note: We should probably default to lazy opaque pointers disabled, but I want
# us to be able to test with Numba directly.
def _lazy_opaque_pointers_enabled():
import os
return os.environ.get('LLVMLITE_ENABLE_OPAQUE_POINTERS', '0') == '1'
opaque_pointers_enabled = _opaque_pointers_enabled()
del _opaque_pointers_enabled
return os.environ.get('LLVMLITE_ENABLE_LAZY_OPAQUE_POINTERS', '1') == '1'
lazy_opaque_pointers_enabled = _lazy_opaque_pointers_enabled()
del _lazy_opaque_pointers_enabled
19 changes: 2 additions & 17 deletions llvmlite/ir/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@

import struct

from llvmlite import lazy_opaque_pointers_enabled
from llvmlite.ir._utils import _StrCaching

# FIXME: Remove me once typed pointers are no longer supported.
from llvmlite import opaque_pointers_enabled


def _wrapname(x):
return '"{0}"'.format(x.replace('\\', '\\5c').replace('"', '\\22'))
Expand Down Expand Up @@ -145,8 +143,6 @@ def from_llvm(cls, typeref, ir_ctx):
"""
Create from a llvmlite.binding.TypeRef
"""
if not opaque_pointers_enabled:
return _TypedPointerType.from_llvm(typeref, ir_ctx)
return cls()


Expand All @@ -163,7 +159,7 @@ def __init__(self, pointee, addrspace=0):
self.is_opaque = False

def _to_string(self):
if not opaque_pointers_enabled:
if lazy_opaque_pointers_enabled:
return "{0}*".format(self.pointee) if self.addrspace == 0 else \
"{0} addrspace({1})*".format(self.pointee, self.addrspace)
return super(_TypedPointerType, self)._to_string()
Expand All @@ -190,17 +186,6 @@ def gep(self, i):
def intrinsic_name(self):
return 'p%d%s' % (self.addrspace, self.pointee.intrinsic_name)

@classmethod
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was added by @sklam in #1051. I think there's no way this can survive the transition to opaque pointers anyway (and the fact it doesn't seem to have an effect on tests is also somewhat reassuring), but I want to check if @sklam has any thoughts here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The opaque pointer version of this shouldn't be affected by this patch (which is why the tests aren't affected either).
I think the typed version can't survive, but my understanding from #1064 (comment) was that this was okay.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok to remove.

def from_llvm(cls, typeref, ir_ctx):
"""
Create from a llvmlite.binding.TypeRef
"""
assert not opaque_pointers_enabled
# opaque pointer will change this
[pointee] = typeref.elements
# addrspace is not handled
return cls(pointee.as_ir(ir_ctx=ir_ctx))


class VoidType(Type):
"""
Expand Down
99 changes: 33 additions & 66 deletions llvmlite/tests/test_ir.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@
from . import TestCase
from llvmlite import ir
from llvmlite import binding as llvm

# FIXME: Remove me once typed pointers are no longer supported.
from llvmlite import opaque_pointers_enabled
from llvmlite import lazy_opaque_pointers_enabled


int1 = ir.IntType(1)
Expand Down Expand Up @@ -123,10 +121,9 @@ def check_func_body(self, func, asm):

class TestFunction(TestBase):

# FIXME: Remove `else' once TP are no longer supported.
proto = \
"""i32 @"my_func"(i32 %".1", i32 %".2", double %".3", ptr %".4")""" \
if opaque_pointers_enabled else \
if not lazy_opaque_pointers_enabled else \
"""i32 @"my_func"(i32 %".1", i32 %".2", double %".3", i32* %".4")"""

def test_declare(self):
Expand All @@ -146,8 +143,7 @@ def test_declare_attributes(self):
pers = ir.Function(self.module(), tp_pers, '__gxx_personality_v0')
func.attributes.personality = pers
asm = self.descr(func).strip()
# FIXME: Remove `else' once TP are no longer supported.
if opaque_pointers_enabled:
if not lazy_opaque_pointers_enabled:
self.assertEqual(asm,
("declare %s alwaysinline convergent optsize "
"alignstack(16) "
Expand All @@ -172,8 +168,7 @@ def test_function_attributes(self):
func.args[3].add_attribute("nonnull")
func.return_value.add_attribute("noalias")
asm = self.descr(func).strip()
# FIXME: Remove `else' once TP are no longer supported.
if opaque_pointers_enabled:
if not lazy_opaque_pointers_enabled:
self.assertEqual(asm,
"""declare noalias i32 @"my_func"(i32 zeroext %".1", i32 dereferenceable(5) dereferenceable_or_null(10) %".2", double %".3", ptr nonnull align 4 %".4")""" # noqa E501
)
Expand Down Expand Up @@ -284,8 +279,7 @@ def test_declare_intrinsics(self):
assume = module.declare_intrinsic('llvm.assume')
self.check_descr(self.descr(powi).strip(), """\
declare double @"llvm.powi.f64"(double %".1", i32 %".2")""")
# FIXME: Remove `else' once TP are no longer supported.
if opaque_pointers_enabled:
if not lazy_opaque_pointers_enabled:
self.check_descr(self.descr(memset).strip(), """\
declare void @"llvm.memset.p0i8.i32"(ptr %".1", i8 %".2", i32 %".3", i1 %".4")""") # noqa E501
self.check_descr(self.descr(memcpy).strip(), """\
Expand Down Expand Up @@ -402,8 +396,7 @@ def test_metadata_null(self):
# A null metadata (typed) value
mod = self.module()
mod.add_metadata([int32.as_pointer()(None)])
# FIXME: Remove `else' once TP are no longer supported.
if opaque_pointers_enabled:
if not lazy_opaque_pointers_enabled:
self.assert_ir_line("!0 = !{ ptr null }", mod)
else:
self.assert_ir_line("!0 = !{ i32* null }", mod)
Expand Down Expand Up @@ -623,8 +616,7 @@ def test_globals_access(self):
with self.assertRaises(KeyError):
mod.get_global('kkk')
# Globals should have a useful repr()
# FIXME: Remove `else' once TP are no longer supported.
if opaque_pointers_enabled:
if not lazy_opaque_pointers_enabled:
self.assertEqual(repr(globdouble),
"<ir.GlobalVariable 'globdouble' of type 'ptr'>")
else:
Expand Down Expand Up @@ -1027,7 +1019,7 @@ def test_mem_ops(self):
self.assertEqual(j.type, ir.VoidType())
k = builder.load_atomic(c, ordering="seq_cst", align=4, name='k')
self.assertEqual(k.type, int32)
if opaque_pointers_enabled:
if not lazy_opaque_pointers_enabled:
ptr = ir.Constant(ir.PointerType(), None)
else:
ptr = ir.Constant(ir.PointerType(int32), None)
Expand All @@ -1041,8 +1033,7 @@ def test_mem_ops(self):
with self.assertRaises(TypeError) as cm:
builder.store(b, e)

# FIXME: Remove `else' once TP are no longer supported.
if opaque_pointers_enabled:
if not lazy_opaque_pointers_enabled:
self.assertEqual(str(cm.exception),
"cannot store i32 to ptr: mismatching types")
self.check_block(block, """\
Expand Down Expand Up @@ -1084,8 +1075,7 @@ def test_gep(self):
c = builder.alloca(ir.PointerType(int32), name='c')
d = builder.gep(c, [ir.Constant(int32, 5), a], name='d')
self.assertEqual(d.type, ir.PointerType(int32))
# FIXME: Remove `else' once TP are no longer supported.
if opaque_pointers_enabled:
if not lazy_opaque_pointers_enabled:
self.check_block(block, """\
my_block:
%"c" = alloca ptr
Expand All @@ -1110,8 +1100,7 @@ def test_gep_castinstr(self):
d = builder.bitcast(a, ls.as_pointer(), name='d')
e = builder.gep(d, [ir.Constant(int32, x) for x in [0, 3]], name='e')
self.assertEqual(e.type, ir.PointerType(int8ptr))
# FIXME: Remove `else' once TP are no longer supported.
if opaque_pointers_enabled:
if not lazy_opaque_pointers_enabled:
self.check_block(block, """\
my_block:
%"d" = bitcast i32 %".1" to ptr
Expand All @@ -1137,8 +1126,7 @@ def test_gep_castinstr_addrspace(self):
e = builder.gep(d, [ir.Constant(int32, x) for x in [0, 3]], name='e')
self.assertEqual(e.type.addrspace, addrspace)
self.assertEqual(e.type, ir.PointerType(int8ptr, addrspace=addrspace))
# FIXME: Remove `else' once TP are no longer supported.
if opaque_pointers_enabled:
if not lazy_opaque_pointers_enabled:
self.check_block(block, """\
my_block:
%"d" = bitcast i32 %".1" to ptr addrspace(4)
Expand All @@ -1157,8 +1145,7 @@ def test_gep_addrspace(self):
a, b = builder.function.args[:2]
addrspace = 4
c = builder.alloca(ir.PointerType(int32, addrspace=addrspace), name='c')
# FIXME: Remove `else' once TP are no longer supported.
if opaque_pointers_enabled:
if not lazy_opaque_pointers_enabled:
self.assertEqual(str(c.type), 'ptr')
else:
self.assertEqual(str(c.type), 'i32 addrspace(4)**')
Expand All @@ -1167,8 +1154,7 @@ def test_gep_addrspace(self):
self.assertEqual(d.type.addrspace, addrspace)
e = builder.gep(d, [ir.Constant(int32, 10)], name='e')
self.assertEqual(e.type.addrspace, addrspace)
# FIXME: Remove `else' once TP are no longer supported.
if opaque_pointers_enabled:
if not lazy_opaque_pointers_enabled:
self.check_block(block, """\
my_block:
%"c" = alloca ptr addrspace(4)
Expand Down Expand Up @@ -1229,8 +1215,7 @@ def test_extract_insert_value(self):
# Replacement value has the wrong type
builder.insert_value(c_inner, a, 1)

# FIXME: Remove `else' once TP are no longer supported.
if opaque_pointers_enabled:
if not lazy_opaque_pointers_enabled:
self.check_block(block, """\
my_block:
%"c" = extractvalue {i32, i1} {i32 4, i1 true}, 0
Expand Down Expand Up @@ -1278,8 +1263,7 @@ def test_cast_ops(self):
j = builder.inttoptr(i, ir.PointerType(int8), 'j') # noqa F841
k = builder.bitcast(a, flt, "k") # noqa F841
self.assertFalse(block.is_terminated)
# FIXME: Remove `else' once TP are no longer supported.
if opaque_pointers_enabled:
if not lazy_opaque_pointers_enabled:
self.check_block(block, """\
my_block:
%"c" = trunc i32 %".1" to i8
Expand Down Expand Up @@ -1319,8 +1303,7 @@ def test_atomicrmw(self):
c = builder.alloca(int32, name='c')
d = builder.atomic_rmw('add', c, a, 'monotonic', 'd')
self.assertEqual(d.type, int32)
# FIXME: Remove `else' once TP are no longer supported.
if opaque_pointers_enabled:
if not lazy_opaque_pointers_enabled:
self.check_block(block, """\
my_block:
%"c" = alloca i32
Expand Down Expand Up @@ -1382,8 +1365,7 @@ def test_branch_indirect(self):
indirectbr.add_destination(bb_1)
indirectbr.add_destination(bb_2)
self.assertTrue(block.is_terminated)
# FIXME: Remove `else' once TP are no longer supported.
if opaque_pointers_enabled:
if not lazy_opaque_pointers_enabled:
self.check_block(block, """\
my_block:
indirectbr ptr blockaddress(@"my_func", %"b_1"), [label %"b_1", label %"b_2"]
Expand Down Expand Up @@ -1505,8 +1487,7 @@ def test_call_metadata(self):
a = builder.alloca(int32, name="a")
b = builder.module.add_metadata(())
builder.call(dbg_declare, (a, b, b))
# FIXME: Remove `else' once TP are no longer supported.
if opaque_pointers_enabled:
if not lazy_opaque_pointers_enabled:
self.check_block(block, """\
my_block:
%"a" = alloca i32
Expand Down Expand Up @@ -1536,8 +1517,7 @@ def test_call_attributes(self):
2: 'noalias'
}
)
# FIXME: Remove `else' once TP are no longer supported.
if opaque_pointers_enabled:
if not lazy_opaque_pointers_enabled:
self.check_block_regex(block, """\
my_block:
%"retval" = alloca i32
Expand Down Expand Up @@ -1628,8 +1608,7 @@ def test_invoke_attributes(self):
2: 'noalias'
}
)
# FIXME: Remove `else' once TP are no longer supported.
if opaque_pointers_enabled:
if not lazy_opaque_pointers_enabled:
self.check_block_regex(block, """\
my_block:
%"retval" = alloca i32
Expand Down Expand Up @@ -1658,8 +1637,7 @@ def test_landingpad(self):
lp.add_clause(ir.FilterClause(ir.Constant(ir.ArrayType(
int_typeinfo.type, 1), [int_typeinfo])))
builder.resume(lp)
# FIXME: Remove `else' once TP are no longer supported.
if opaque_pointers_enabled:
if not lazy_opaque_pointers_enabled:
self.check_block(block, """\
my_block:
%"lp" = landingpad {i32, ptr}
Expand Down Expand Up @@ -2346,8 +2324,7 @@ def test_metadata(self):
builder = ir.IRBuilder(block)
builder.debug_metadata = builder.module.add_metadata([])
builder.alloca(ir.PointerType(int32), name='c')
# FIXME: Remove `else' once TP are no longer supported.
if opaque_pointers_enabled:
if not lazy_opaque_pointers_enabled:
self.check_block(block, """\
my_block:
%"c" = alloca ptr, !dbg !0
Expand Down Expand Up @@ -2431,17 +2408,15 @@ def test_str(self):
'i1 (float, ...)')
self.assertEqual(str(ir.FunctionType(int1, (flt, dbl), var_arg=True)),
'i1 (float, double, ...)')
# FIXME: Remove `else' once TP are no longer supported.
if opaque_pointers_enabled:
if not lazy_opaque_pointers_enabled:
self.assertEqual(str(ir.PointerType(int32)), 'ptr')
self.assertEqual(str(ir.PointerType(ir.PointerType(int32))), 'ptr')
else:
self.assertEqual(str(ir.PointerType(int32)), 'i32*')
self.assertEqual(str(ir.PointerType(ir.PointerType(int32))),
'i32**')
self.assertEqual(str(ir.ArrayType(int1, 5)), '[5 x i1]')
# FIXME: Remove `else' once TP are no longer supported.
if opaque_pointers_enabled:
if not lazy_opaque_pointers_enabled:
self.assertEqual(str(ir.ArrayType(ir.PointerType(int1), 5)),
'[5 x ptr]')
self.assertEqual(str(ir.PointerType(ir.ArrayType(int1, 5))), 'ptr')
Expand All @@ -2452,8 +2427,7 @@ def test_str(self):
'[5 x i1]*')
self.assertEqual(str(ir.LiteralStructType((int1,))), '{i1}')
self.assertEqual(str(ir.LiteralStructType((int1, flt))), '{i1, float}')
# FIXME: Remove `else' once TP are no longer supported.
if opaque_pointers_enabled:
if not lazy_opaque_pointers_enabled:
self.assertEqual(str(ir.LiteralStructType((
ir.PointerType(int1), ir.LiteralStructType((int32, int8))))),
'{ptr, {i32, i8}}')
Expand Down Expand Up @@ -2751,8 +2725,7 @@ def test_gep(self):
tp = ir.LiteralStructType((flt, int1))
gv = ir.GlobalVariable(m, tp, "myconstant")
c = gv.gep([ir.Constant(int32, x) for x in (0, 1)])
# FIXME: Remove `else' once TP are no longer supported.
if opaque_pointers_enabled:
if not lazy_opaque_pointers_enabled:
self.assertEqual(str(c),
'getelementptr ({float, i1}, ptr @"myconstant", i32 0, i32 1)') # noqa E501
else:
Expand All @@ -2766,8 +2739,7 @@ def test_gep(self):

const_ptr = ir.Constant(tp.as_pointer(), None)
c2 = const_ptr.gep([ir.Constant(int32, 0)])
# FIXME: Remove `else' once TP are no longer supported.
if opaque_pointers_enabled:
if not lazy_opaque_pointers_enabled:
self.assertEqual(str(c2),
'getelementptr ({float, i1}, ptr null, i32 0)') # noqa E501
else:
Expand All @@ -2784,8 +2756,7 @@ def test_gep_addrspace_globalvar(self):
self.assertEqual(gv.addrspace, addrspace)
c = gv.gep([ir.Constant(int32, x) for x in (0, 1)])
self.assertEqual(c.type.addrspace, addrspace)
# FIXME: Remove `else' once TP are no longer supported.
if opaque_pointers_enabled:
if not lazy_opaque_pointers_enabled:
self.assertEqual(str(c),
('getelementptr ({float, i1}, ptr '
'addrspace(4) @"myconstant", i32 0, i32 1)'))
Expand Down Expand Up @@ -2819,8 +2790,7 @@ def test_bitcast(self):
m = self.module()
gv = ir.GlobalVariable(m, int32, "myconstant")
c = gv.bitcast(int64.as_pointer())
# FIXME: Remove `else' once TP are no longer supported.
if opaque_pointers_enabled:
if not lazy_opaque_pointers_enabled:
self.assertEqual(str(c), 'bitcast (ptr @"myconstant" to ptr)')
else:
self.assertEqual(str(c), 'bitcast (i32* @"myconstant" to i64*)')
Expand Down Expand Up @@ -2848,8 +2818,7 @@ def test_ptrtoint_1(self):

self.assertRaises(TypeError, one.ptrtoint, int64)
self.assertRaises(TypeError, ptr.ptrtoint, flt)
# FIXME: Remove `else' once TP are no longer supported.
if opaque_pointers_enabled:
if not lazy_opaque_pointers_enabled:
self.assertEqual(str(c), 'ptrtoint (ptr null to i32)')
else:
self.assertEqual(str(c), 'ptrtoint (i64* null to i32)')
Expand All @@ -2858,8 +2827,7 @@ def test_ptrtoint_2(self):
m = self.module()
gv = ir.GlobalVariable(m, int32, "myconstant")
c = gv.ptrtoint(int64)
# FIXME: Remove `else' once TP are no longer supported.
if opaque_pointers_enabled:
if not lazy_opaque_pointers_enabled:
self.assertEqual(str(c), 'ptrtoint (ptr @"myconstant" to i64)')

self.assertRaisesRegex(
Expand Down Expand Up @@ -2890,8 +2858,7 @@ def test_inttoptr(self):

self.assertRaises(TypeError, one.inttoptr, int64)
self.assertRaises(TypeError, pi.inttoptr, int64.as_pointer())
# FIXME: Remove `else' once TP are no longer supported.
if opaque_pointers_enabled:
if not lazy_opaque_pointers_enabled:
self.assertEqual(str(c), 'inttoptr (i32 1 to ptr)')
else:
self.assertEqual(str(c), 'inttoptr (i32 1 to i64*)')
Expand Down
Loading