废弃通知

本节包含有关已不再适用/过时的行为、功能和 API 废弃的信息。其中提供了关于其废弃计划、变更原因以及示例的详细信息。

类型指针的废弃

类型指针的使用已被废弃,在未来的 llvmlite 版本中,不透明指针将成为默认(并最终成为强制)选项。

废弃原因

llvmlite 旨在向前兼容更新的 LLVM 版本,这将需要切换到不透明指针

  • 在 LLVM 15 中,不透明指针是默认设置。

  • 在 LLVM 16 中,类型指针仅提供尽力而为的支持(因此可能存在未修复的错误)。

  • 在 LLVM 17 中,已移除对类型指针的支持。

尽管不透明指针在 LLVM 15 中已是默认设置,但 llvmlite 0.44 在使用 LLVM 15 时仍默认使用类型指针。

绑定层将转向使用不透明指针。IR 层仍将支持类型指针和不透明指针,在提供指针目标类型时默认使用类型指针。这使得 llvmlite 能够继续与使用旧版 LLVM 的基于 LLVM 的项目(例如 NVVM)一起使用。

影响示例

在未来的版本中,如果未修改为使用不透明指针,则使用 llvmlite 处理类型指针或生成带有类型指针的 IR 的代码将无法运行。

同时,IR 层生成的并由绑定层解析的 IR 将自动透明地升级为使用不透明指针;用户无需采取任何操作。

计划

  • 在 llvmlite 0.45 中,将移除绑定层中对类型指针的支持。IR 层仍将默认使用类型指针。

  • 在 llvmlite 的未来版本(>= 0.46)中,IR 层将默认使用不透明指针。

  • 在 llvmlite 的后续版本(>= 0.47)中,将移除 IR 层对类型指针的支持。

此计划可能会更新,以将类型指针支持的废弃/移除推迟到更晚的 llvmlite 版本。

建议

在使用 llvmlite 的代码切换到不透明指针时,应按如下方式更新。

IR 层

修改指令中对 .type.pointee 的使用,改为使用 .allocated_type。例如

# 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)

变为

# 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)

将类型中 .as_pointer() 的使用替换为 PointerType 类。例如

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

变为

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

修改对 ir.loadir.load_atomicir.gep 指令的调用,以传入指针类型。例如

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

变为

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

绑定层

在使用 TargetData 实例时

在使用全局变量和函数时(它们将是 ValueRef 实例)

  • 对于任何作为全局变量或函数的 valueref,将其对 valueref.type 的使用替换为 valueref.global_value_type

在将汇编代码传递给 llvmlite.binding.parse_assembly()

  • 传递给 parse_assembly() 的 IR 可以自由使用类型指针或不透明指针。

废弃 llvmlite.llvmpy 模块

llvmlite.llvmpy 模块最初是为了与 llvmpy 兼容而创建的。随着时间的推移,该功能被重新设计并放入 llvmlite.ir 中,而 llvmlite.llvmpy 仍然作为兼容层存在。由于未继续维护,它无法确保提供与 llvmpy 匹配的 API,并且与 llvmlite.ir 模块相比,它不提供任何优势。

废弃原因

llvmlite.llvmpy 及其子模块提供的功能现在已存在于 llvmlite.ir 中,因此该模块将被移除。

影响示例

导入 llvmlite.llvmpyllvmlite.llvmpy.corellvmlite.llvmpy.passes 的代码将无法运行。

计划

功能变更已按以下方式实现

  • v0.39 模块已废弃

  • v0.40 模块已移除

建议

由于 llvmlite.ir 中已存在类似功能,因此迁移路径相对较短

  • llvmlite.llvmpy.core.Builder 替换为 llvmlite.ir.IRBuilder

  • 根据需要将 llvmlite.llvmpy.core.Builder.icmp 替换为 llvmlite.ir.IRBuilder.icmp_signedicmp_unsigned

  • 根据需要将 llvmlite.llvmpy.core.Builder.fcmp 替换为 llvmlite.ir.IRBuilder.fcmp_orderedfcmp_unordered

  • 将对 llvmlite.llvmpy.core.Type 静态方法的调用替换为 llvmlite.ir 中提供的构造函数(例如,将 Type.int(8) 替换为 IntType(8)

  • 根据需要将对 llvmlite.llvmpy.core.Constant 静态方法的调用替换为对 llvmlite.ir.Constant 构造函数或 llvmlite.ir.Constant.literal_struct 的调用。请注意,stringzarray 没有直接的对应项。

  • llvmlite.llvmpy.core.ModuleFunctionMetaDataStringInlineAsm 替换为 llvmlite.ir. 中同名的类

  • llvmlite.llvmpy.core.MetaData.get 替换为 llvmlite.ir.Module.add_metadata

  • llvmlite.llvmpy.core.Function.intrinsic 替换为 llvmlite.ir.Module.declare_intrinsic

  • 对于 llvmlite.llvmpy.passes,请直接使用 llvmlite.binding 创建 pass manager

废弃使用指定对齐方式的 memset/memcpy llvm 内置函数

从 LLVM 7 开始,memsetmemcpy 内置函数不再使用指定为第三个参数的对齐方式,而是使用第一个参数的对齐方式。在第三个参数中指定对齐方式仍然有效,因为 LLVM 会自动更新此用例。

废弃原因

LLVM 已经改变了前面提到的内置函数的行为,为了增强与未来 LLVM 版本的兼容性,llvmlite 正在进行相应的调整。

影响示例

在 0.30 版本中,以下代码有效

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))

从 0.31 版本开始,只有以下代码有效

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))

计划

功能变更已按以下方式实现

  • v0.30 是最后一个支持将对齐方式指定为第三个参数(5参数样式)的版本。

  • 从 v0.31 开始,仅支持 4 参数样式调用。

建议

需要/依赖此废弃行为的项目应将其对 llvmlite 的依赖固定到此行为被移除之前的版本。