Skip to content

Commit

Permalink
Add lazy opaque pointers mode
Browse files Browse the repository at this point in the history
  • Loading branch information
rj-jesus committed Feb 20, 2025
1 parent 75ebdf6 commit f8b24e1
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 87 deletions.
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
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

0 comments on commit f8b24e1

Please sign in to comment.