.. _deprecation:

===================
Deprecation Notices
===================

This section contains information about deprecation of behaviours, features and
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``
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
`llvmpy`. As time has passed, that functionality was redesigned and put in
`llvmlite.ir` with `llvmlite.llvmpy` remaining as a compatibility layer. No
continued maintenance has ensured that it provides a matching API to `llvmpy`
and it provides no advantage over the `llvmlite.ir` module.

Reason for deprecation
----------------------
The functionality provided by `llvmlite.llvmpy` and its child modules is now
present in `llvmlite.ir`, so this module will be dropped.

Example(s) of the impact
------------------------
Code that imports `llvmlite.llvmpy`, `llvmlite.llvmpy.core` or
`llvmlite.llvmpy.passes` will break.

Schedule
--------
The feature change was implemented as follows:

* v0.39 module is deprecated
* v0.40 module is removed

Recommendations
---------------
Since similar functionality already exists in `llvmlite.ir`, the transition
path is relatively short:

- replace `llvmlite.llvmpy.core.Builder` with `llvmlite.ir.IRBuilder`
- replace `llvmlite.llvmpy.core.Builder.icmp` with
  `llvmlite.ir.IRBuilder.icmp_signed` and `icmp_unsigned`, as appropriate
- replace `llvmlite.llvmpy.core.Builder.fcmp` with
  `llvmlite.ir.IRBuilder.fcmp_ordered` and `fcmp_unordered`, as appropriate
- replace calls to the static methods of `llvmlite.llvmpy.core.Type` with the
  constructors provided in `llvmlite.ir` (_e.g._, `Type.int(8)` with
  `IntType(8)`)
- Replace calls to the static methods of `llvmlite.llvmpy.core.Constant` with
  calls to the constructor of `llvmlite.ir.Constant` or
  `llvmlite.ir.Constant.literal_struct`, as appropriate. Note that `stringz`
  and `array` have no direct equivalents.
- replace `llvmlite.llvmpy.core.Module`, `Function`, `MetaDataString`,
  `InlineAsm` with the classes of the same name in `llvmlite.ir.`
- replace `llvmlite.llvmpy.core.MetaData.get` with
  `llvmlite.ir.Module.add_metadata`
- replace `llvmlite.llvmpy.core.Function.intrinsic` with
  `llvmlite.ir.Module.declare_intrinsic`
- for `llvmlite.llvmpy.passes`, create the pass manager directly using
  `llvmlite.binding`

Deprecation of use of memset/memcpy llvm intrinsic with specified alignment
===========================================================================
From LLVM 7 onward the `memset <https://releases.llvm.org/7.0.0/docs/LangRef.html#llvm-memset-intrinsics>`_
and `memcpy <https://releases.llvm.org/7.0.0/docs/LangRef.html#llvm-memcpy-intrinsic>`_
intrinsics dropped the use of an alignment, specified as the third argument, and
instead use the alignment of the first argument for this purpose. Specifying
the alignment in third argument continued to work as LLVM auto-updates this use
case.

Reason for deprecation
----------------------
LLVM has changed the behaviour of the previously mentioned intrinsics, and so as
to increase compatibility with future releases of LLVM, llvmlite is adapting to
match.

Example(s) of the impact
------------------------

As of 0.30 the following worked::

    from llvmlite import ir

    bit = ir.IntType(1)
    int8 = ir.IntType(8)
    int32 = ir.IntType(32)
    int64 = ir.IntType(64)
    int8ptr = int8.as_pointer()

    mod = ir.Module()
    fnty = ir.FunctionType(int32, ())
    func = ir.Function(mod, fnty, "some_function")
    block = func.append_basic_block('some_block')
    builder = ir.IRBuilder(block)

    some_address = int64(0xdeaddead)
    dest = builder.bitcast(some_address, int8ptr)
    value = int8(0xa5)
    memset = mod.declare_intrinsic('llvm.memset', [int8ptr, int32])
    memcpy = mod.declare_intrinsic('llvm.memcpy', [int8ptr, int8ptr, int32])

    # NOTE: 5 argument call site (dest, value, length, align, isvolatile)
    builder.call(memset, [dest, value, int32(10), int32(0), bit(0)])

    some_other_address = int64(0xcafecafe)
    src = builder.bitcast(some_other_address, int8ptr)

    # NOTE: 5 argument call site (dest, src, length, align, isvolatile)
    builder.call(memcpy, [dest, src, int32(10), int32(0), bit(0)])

    builder.ret(int32(0))
    print(str(mod))


From 0.31 onwards only the following works::

    from llvmlite import ir

    bit = ir.IntType(1)
    int8 = ir.IntType(8)
    int32 = ir.IntType(32)
    int64 = ir.IntType(64)
    int8ptr = int8.as_pointer()

    mod = ir.Module()
    fnty = ir.FunctionType(int32, ())
    func = ir.Function(mod, fnty, "some_function")
    block = func.append_basic_block('some_block')
    builder = ir.IRBuilder(block)

    some_address = int64(0xdeaddead)
    dest = builder.bitcast(some_address, int8ptr)
    value = int8(0xa5)
    memset = mod.declare_intrinsic('llvm.memset', [int8ptr, int32])
    memcpy = mod.declare_intrinsic('llvm.memcpy', [int8ptr, int8ptr, int32])

    # NOTE: 4 argument call site (dest, value, length, isvolatile)
    builder.call(memset, [dest, value, int32(10), bit(0)])

    some_other_address = int64(0xcafecafe)
    src = builder.bitcast(some_other_address, int8ptr)

    # NOTE: 4 argument call site (dest, src, length, isvolatile)
    builder.call(memcpy, [dest, src, int32(10), bit(0)])

    builder.ret(int32(0))
    print(str(mod))


Schedule
--------
The feature change was implemented as follows:

* v0.30 was the last release to support an alignment specified as the third
  argument (5 argument style).
* v0.31 onwards supports the 4 argument style call only.


Recommendations
---------------
Projects that need/rely on the deprecated behaviour should pin their dependency
on llvmlite to a version prior to removal of this behaviour.
