Skip to content
Merged
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
10 changes: 10 additions & 0 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ jobs:
CONDA_ENV: cienv
LLVM: '16'

opaque_pointers:
PYTHON: '3.12'
CONDA_ENV: cienv
OPAQUE_POINTERS: yes

- template: buildscripts/azure/azure-linux-macos.yml
parameters:
name: Linux
Expand Down Expand Up @@ -72,6 +77,11 @@ jobs:
CONDA_ENV: cienv
LLVM: '16'

opaque_pointers:
PYTHON: '3.12'
CONDA_ENV: cienv
OPAQUE_POINTERS: yes

- template: buildscripts/azure/azure-windows.yml
parameters:
name: Windows
Expand Down
5 changes: 5 additions & 0 deletions buildscripts/azure/azure-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ jobs:
CONDA_ENV: cienv
LLVM: '16'

opaque_pointers:
PYTHON: '3.12'
CONDA_ENV: cienv
OPAQUE_POINTERS: yes

steps:

- powershell: |
Expand Down
7 changes: 7 additions & 0 deletions buildscripts/incremental/test.cmd
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@

call activate %CONDA_ENV%

if "%OPAQUE_POINTERS%"=="yes" (
set LLVMLITE_ENABLE_OPAQUE_POINTERS=1
echo "Testing with opaque pointers enabled"
) else (
echo "Testing with opaque pointers disabled"
)

python runtests.py -v
8 changes: 8 additions & 0 deletions buildscripts/incremental/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,18 @@ set -v -e

python --version

if [ "$OPAQUE_POINTERS" == "yes" ]; then
export LLVMLITE_ENABLE_OPAQUE_POINTERS=1
echo "Testing with opaque pointers enabled"
else
echo "Testing with opaque pointers disabled"
fi

if [ "$WHEEL" == "yes" ]; then
cd dist
python -m llvmlite.tests -v
else
python runtests.py -v
fi

if [ "$RUN_COVERAGE" == "yes" ]; then coverage run runtests.py; fi
5 changes: 5 additions & 0 deletions docs/source/user-guide/binding/target-information.rst
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ Classes
Get the ABI-mandated size of a :class:`TypeRef` object.
Returns an integer.

* .. method:: get_abi_alignment(type)

Similar to :meth:`get_abi_size`, but returns the ABI-mandated alignment
rather that the ABI size.

* .. method:: get_pointee_abi_size(type)

Similar to :meth:`get_abi_size`, but assumes that *type* is
Expand Down
121 changes: 121 additions & 0 deletions docs/source/user-guide/deprecation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,127 @@ APIs that have become undesirable/obsolete. Any information about the schedule
for their deprecation and reasoning behind the changes, along with examples, is
provided.


.. _deprecation-of-typed-pointers:

Deprecation of Typed Pointers
=============================

The use of Typed Pointers is deprecated, and :ref:`Opaque Pointers
<pointer-types>` will be the default (and eventually required) in a future
llvmlite version.

Reason for deprecation
----------------------

llvmlite aims to move forward to newer LLVM versions, which will necessitate
switching to `Opaque Pointers <https://llvm.org/docs/OpaquePointers.html>`_:

- In LLVM 15, Opaque Pointers are the default.
- In LLVM 16, Typed Pointers are only supported on a best-effort basis (and
therefore may have bugs that go unfixed).
- In LLVM 17, support for Typed Pointers is removed.

Although Opaque Pointers are already the default in LLVM 15, llvmlite still uses
Typed Pointers by default with LLVM 15.

Examples(s) of the impact
-------------------------

Code that uses llvmlite to work with pointers or to parse assembly that uses
pointers will break if not modified to use opaque pointers.

Schedule
--------

- In llvmlite 0.44, Opaque Pointers will be the default pointer kind.
- In llvmlite 0.45, support for Typed Pointers will be removed.

Recommendations
---------------

Code using llvmlite should be updated as follows when switching to Opaque
Pointers.

IR layer
~~~~~~~~

Modify uses of ``.type.pointee`` of instructions to use ``.allocated_type``
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe it's worth noting this is only valid for alloca instructions since they have a clear "allocated type" (https://llvm.org/docs/doxygen/Instructions_8h_source.html#l00115).

instead. For example:

.. code:: python

# Allocating an integer on the stack and storing a value to it
stackint = builder.alloca(ir.IntType(32))
builder.store(ir.Constant(stackint.type.pointee, 123), stackint)

becomes:

.. code:: python

# Allocating an integer on the stack and storing a value to it
stackint = builder.alloca(ir.IntType(32))
builder.store(ir.Constant(stackint.allocated_type, 123), stackint)


Replace the use of ``.as_pointer()`` of types with the ``PointerType`` class.
For example:

.. code:: python

# Declaring a function of type i32(i32*, i32)
fnty = ir.FunctionType(ir.IntType(32), [ir.IntType(32).as_pointer(),
ir.IntType(32)])


becomes:

.. code:: python

# Declaring a function of type i32(ptr, i32)
fnty = ir.FunctionType(ir.IntType(32), [ir.PointerType(),
ir.IntType(32)])


Modify calls to ``ir.load``, ``ir.load_atomic``, and ``ir.gep`` instructions to
pass in pointer types. For example:

.. code:: python

ptr = builder.gep(func.args[0], [index])
value = builder.load(ptr)

becomes:

.. code:: python

ptr = builder.gep(func.args[0], [index], source_etype=ll.IntType(32))
value = builder.load(ptr, typ=ll.IntType(32))


Binding layer
~~~~~~~~~~~~~

When working with :class:`TargetData <llvmlite.binding.TargetData>` instances:

- Replace calls to :meth:`get_pointee_abi_size()
<llvmlite.binding.TargetData.get_pointee_abi_size>` with calls to
:meth:`get_abi_size() <llvmlite.binding.TargetData.get_abi_size>`.
- Replace calls to :meth:`get_pointee_abi_alignment()
<llvmlite.binding.TargetData.get_pointee_abi_alignment>` with calls to
:meth:`get_abi_alignment() <llvmlite.binding.TargetData.get_abi_alignment>`.

When working with global variables and functions (which will be :class:`ValueRef
<llvmlite.binding.ValueRef>` instances):

- Replace any use of ``valueref.type`` with ``valueref.global_value_type`` for
any ``valueref`` that is a global variable or function.

When passing assembly to :func:`llvmlite.binding.parse_assembly`:

- Ensure that any IR passed to ``parse_assembly()`` uses Opaque Pointers.


Deprecation of `llvmlite.llvmpy` module
=======================================
The `llvmlite.llvmpy` module was originally created for compatibility with
Expand Down
80 changes: 64 additions & 16 deletions docs/source/user-guide/ir/types.rst
Original file line number Diff line number Diff line change
Expand Up @@ -58,22 +58,6 @@ instantiated, a type should be considered immutable.
Atomic types
=============

.. class:: PointerType(pointee, addrspace=0)

The type of pointers to another type.

Pointer types expose the following attributes:

* .. attribute:: addrspace

The pointer's address space number. This optional integer
allows you to choose a non-default address space---the
meaning is platform dependent.

* .. attribute:: pointee

The type pointed to.


.. class:: IntType(bits)

Expand Down Expand Up @@ -105,6 +89,70 @@ Atomic types
function without a return value.


.. _pointer-types:

Pointer Types
=============

llvmlite presently supports both *Typed Pointers* and *Opaque Pointers*. Typed
Pointers are currently the default; Opaque Pointers will become the default in
future, and support for Typed Pointers will be eventually be removed.

.. note::
Further details of the migration to Opaque Pointers are outlined in the
section on :ref:`deprecation-of-typed-pointers`.

When Typed Pointers are enabled, the pointer type is represented using:

.. class:: PointerType(pointee, addrspace=0)

The type of pointers to another type.

Pointer types expose the following attributes:

* .. attribute:: addrspace

The pointer's address space number. This optional integer
allows you to choose a non-default address space---the
meaning is platform dependent.

* .. attribute:: pointee

The type pointed to.

Opaque pointers can be enabled by setting the environment variable:

.. code:: bash

LLVMLITE_ENABLE_OPAQUE_POINTERS=1

or by setting the ``opaque_pointers_enabled`` attribute after importing
llvmlite, but prior to using any of its functionality. For example:

.. code:: python

import llvmlite
llvmlite.opaque_pointers_enabled = True

# ... continue using llvmlite ...

When Opaque Pointers are enabled, the pointer type is represented using:

.. class:: PointerType(addrspace=0)
:no-index:

The type of pointers.

Pointer types expose the following attribute:

* .. attribute:: addrspace
:no-index:

The pointer's address space number. This optional integer
allows you to choose a non-default address space---the
meaning is platform dependent.


.. _aggregate-types:

Aggregate types
Expand Down
38 changes: 38 additions & 0 deletions examples/opaque_pointers/llvmir.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import llvmlite
llvmlite.opaque_pointers_enabled = True

import llvmlite.ir as ll

fntype = ll.FunctionType(ll.IntType(32), [ll.IntType(32), ll.IntType(32)])

module = ll.Module()

func = ll.Function(module, fntype, name='foo')
bb_entry = func.append_basic_block()

builder = ll.IRBuilder()
builder.position_at_end(bb_entry)

stackint = builder.alloca(ll.IntType(32))
# Instead of stackint.type.pointee we can access stackint.allocated_type
# directly.
builder.store(ll.Constant(stackint.allocated_type, 123), stackint)
myint = builder.load(stackint)

addinstr = builder.add(func.args[0], func.args[1])
mulinstr = builder.mul(addinstr, ll.Constant(ll.IntType(32), 123))
pred = builder.icmp_signed('<', addinstr, mulinstr)
builder.ret(mulinstr)

bb_block = func.append_basic_block()
builder.position_at_end(bb_block)

bb_exit = func.append_basic_block()

pred = builder.trunc(addinstr, ll.IntType(1))
builder.cbranch(pred, bb_block, bb_exit)

builder.position_at_end(bb_exit)
builder.ret(myint)

print(module)
Loading