IR 构建器

IRBuilder 是 LLVM 中间表示 (IR) 生成的主力。它允许您用 LLVM 指令填充函数的基本块

一个 IRBuilder 内部维护一个当前基本块以及块指令列表中的一个指针。当添加新指令时,它会插入到该点,然后指针会前进到新指令之后。

一个 IRBuilder 也维护一个描述当前源位置的元数据引用,该元数据会附加到所有插入的指令上。

实例化

class llvmlite.ir.IRBuilder(block=None)

创建一个新的 IR 构建器。如果给出了 block(一个 Block),则构建器将从这个基本块的末尾开始。

属性

IRBuilder 具有以下属性

  • IRBuilder.block

    构建器正在操作的基本块。

  • IRBuilder.function

    构建器正在操作的函数。

  • IRBuilder.module

    构建器函数定义的模块。

  • IRBuilder.debug_metadata

    如果不是 None,则这是作为 !dbg 附加到任何插入指令的元数据,除非指令已经设置了 !dbg

实用工具

IRBuilder.append_basic_block(name='')

将一个基本块(带有给定的可选 name)附加到当前函数。当前块不会改变。返回一个 Block

定位

以下 IRBuilder 方法帮助您移动当前指令指针

  • IRBuilder.position_before(instruction)

    定位到给定 instruction 的正前方。当前块也会更改为该指令的基本块。

  • IRBuilder.position_after(instruction)

    定位到给定 instruction 的正后方。当前块也会更改为该指令的基本块。

  • IRBuilder.position_at_start(block)

    定位到基本 block 的开头。

  • IRBuilder.position_at_end(block)

    定位到基本 block 的末尾。

以下上下文管理器允许您临时切换到另一个基本块,然后返回到您之前的位置。

  • IRBuilder.goto_block(block)

    将构建器定位在基本 block 的末尾(如果它未终止),或者在其终结符之前。

    new_block = builder.append_basic_block('foo')
    with builder.goto_block(new_block):
       # Now the builder is at the end of *new_block*
       # ... add instructions
    
    # Now the builder has returned to its previous position
    
  • IRBuilder.goto_entry_block()

    goto_block() 相同,但使用当前函数的入口块。

流程控制辅助函数

以下上下文管理器使创建条件代码变得更容易。

  • IRBuilder.if_then(pred, likely=None)

    创建一个基本块,其执行取决于谓词 pred(一个 IntType(1) 类型的值)。为条件块之后的指令创建另一个基本块。当前基本块以基于 pred 的条件分支终止。

    当进入上下文管理器时,构建器定位在条件块的末尾。当退出上下文管理器时,构建器定位在延续块的开头。

    如果 likely 不是 None,它表示 pred 是否很可能为 True,并相应地发出元数据以指定分支权重。

  • IRBuilder.if_else(pred, likely=None)

    设置两个基本块,其执行取决于谓词 pred(一个 IntType(1) 类型的值)。likely 的含义与 if_then() 中的相同。

    产生一对上下文管理器。它们中的每一个都充当一个 if_then() 上下文管理器——第一个用于 predTrue 时执行的块,第二个用于 predFalse 时执行的块。

    当退出上下文管理器时,构建器定位在一个新的延续块上,两个条件块都将跳转到该延续块。

    典型用法

    with builder.if_else(pred) as (then, otherwise):
        with then:
            # emit instructions for when the predicate is true
        with otherwise:
            # emit instructions for when the predicate is false
    # emit instructions following the if-else block
    

指令构建

以下方法在当前块的当前索引处插入一个新指令——一个 Instruction 实例。返回新指令。

指令的操作数几乎总是

这些方法中的许多还接受一个可选的 name 参数,指定结果值的局部 name。如果未给出,则自动生成唯一名称。

算术运算

在以下方法中,flags 参数是一个可选的字符串序列,用于修改指令的语义。示例包括浮点运算的快速数学标志,以及整数运算中溢出时的环绕是否可以忽略。

整数

  • IRBuilder.shl(lhs, rhs, name='', flags=())

    lhs 左移 rhs 位。

  • IRBuilder.lshr(lhs, rhs, name=(), flags=())

    lhs 逻辑右移 rhs 位。

  • IRBuilder.ashr(lhs, rhs, name='', flags=())

    lhs 算术(有符号)右移 rhs 位。

  • IRBuilder.cttz(value, flag)

    计算 value 中的尾随零位数。布尔型 flag 指示结果对 0 是否有定义。

  • IRBuilder.ctlz(value, flag)

    计算 value 中的前导零位数。布尔型 flag 指示结果对 0 是否有定义。

  • IRBuilder.add(lhs, rhs, name='', flags=())

    整数加法 lhsrhs

  • IRBuilder.sadd_with_overflow(lhs, rhs, name='', flags=())

    整数加法 lhsrhs。返回一个 { 结果, 溢出位 } 结构。

  • IRBuilder.sub(lhs, rhs, name='', flags=())

    整数减法 lhs 减去 rhs

  • IRBuilder.ssub_with_overflow(lhs, rhs, name='', flags=())

    整数减法 lhs 减去 rhs。返回一个 { 结果, 溢出位 } 结构。

  • IRBuilder.mul(lhs, rhs, name='', flags=())

    整数乘法 lhs 乘以 rhs

  • IRBuilder.smul_with_overflow(lhs, rhs, name='', flags=())

    整数乘法 lhs 乘以 rhs。返回一个 { 结果, 溢出位 } 结构。

  • IRBuilder.sdiv(lhs, rhs, name='', flags=())

    有符号整数除法 lhs 除以 rhs

  • IRBuilder.udiv(lhs, rhs, name='', flags=())

    无符号整数除法 lhs 除以 rhs

  • IRBuilder.srem(lhs, rhs, name='', flags=())

    有符号整数 lhs 除以 rhs 的余数。

  • IRBuilder.urem(lhs, rhs, name='', flags=())

    无符号整数 lhs 除以 rhs 的余数。

  • IRBuilder.and_(lhs, rhs, name='', flags=())

    位与 lhsrhs

  • IRBuilder.or_(lhs, rhs, name='', flags=())

    位或 lhsrhs

  • IRBuilder.xor(lhs, rhs, name='', flags=())

    位异或 lhsrhs

  • IRBuilder.not_(value, name='')

    位补 value

  • IRBuilder.neg(value, name='')

    value 取反。

浮点数

  • IRBuilder.fadd(lhs, rhs, name='', flags=())

    浮点数加法 lhsrhs

  • IRBuilder.fsub(lhs, rhs, name='', flags=())

    浮点数减法 lhs 减去 rhs

  • IRBuilder.fmul(lhs, rhs, name='', flags=())

    浮点数乘法 lhs 乘以 rhs

  • IRBuilder.fdiv(lhs, rhs, name='', flags=())

    浮点数除法 lhs 除以 rhs

  • IRBuilder.frem(lhs, rhs, name='', flags=())

    浮点数 lhs 除以 rhs 的余数。

  • IRBuilder.fneg(arg, name='', flags=())

    浮点数 arg 的取反。

类型转换

  • IRBuilder.trunc(value, typ, name='')

    将整数 value 截断为整数类型 typ

  • IRBuilder.zext(value, typ, name='')

    将整数 value 零扩展到整数类型 typ

  • IRBuilder.sext(value, typ, name='')

    将整数 value 符号扩展到整数类型 typ

  • IRBuilder.fptrunc(value, typ, name='')

    将浮点数 value 截断(近似)为浮点类型 typ

  • IRBuilder.fpext(value, typ, name='')

    将浮点数 value 扩展到浮点类型 typ

  • IRBuilder.fptosi(value, typ, name='')

    将浮点数 value 转换为有符号整数类型 typ

  • IRBuilder.fptoui(value, typ, name='')

    将浮点数 value 转换为无符号整数类型 typ

  • IRBuilder.sitofp(value, typ, name='')

    将有符号整数 value 转换为浮点类型 typ

  • IRBuilder.uitofp(value, typ, name='')

    将无符号整数 value 转换为浮点类型 typ

  • IRBuilder.ptrtoint(value, typ, name='')

    将指针 value 转换为整数类型 typ

  • IRBuilder.inttoptr(value, typ, name='')

    将整数 value 转换为指针类型 typ

  • IRBuilder.bitcast(value, typ, name='')

    将指针 value 转换为指针类型 typ

  • IRBuilder.addrspacecast(value, typ, name='')

    将指针 value 转换为不同地址空间的指针类型 typ

比较

  • IRBuilder.icmp_signed(cmpop, lhs, rhs, name='')

    有符号整数 lhsrhs 比较。字符串 cmpop 可以是 <<===!=>=> 之一。

  • IRBuilder.icmp_unsigned(cmpop, lhs, rhs, name='')

    无符号整数 lhsrhs 比较。字符串 cmpop 可以是 <<===!=>=> 之一。

  • IRBuilder.fcmp_ordered(cmpop, lhs, rhs, name='', flags=[])

    浮点数 lhsrhs 有序比较。

    • 字符串 cmpop 可以是 <<===!=>=>orduno 之一。

    • flags 列表可以包含 nnanninfnszarcpfast 中的任何一个,其中 fast 暗示所有之前的标志。

  • IRBuilder.fcmp_unordered(cmpop, lhs, rhs, name='', flags=[])

    浮点数 lhsrhs 无序比较。

    • 字符串 cmpop 可以是 <<===!=>=>orduno 之一。

    • flags 列表可以包含 nnanninfnszarcpfast 中的任何一个,其中 fast 暗示所有之前的标志。

条件移动

IRBuilder.select(cond, lhs, rhs, name='')

二选一——如果 cond 为真则为 lhs,否则为 rhs

Phi

IRBuilder.phi(typ, name='')

创建一个 phi 节点。要添加传入边及其值,请在返回值上使用 add_incoming() 方法。

聚合操作

  • IRBuilder.extract_value(agg, index, name='')

    提取聚合 aggindex 位置的元素。

    • index 可以是整数或整数序列。

    • 索引必须是常量。

  • IRBuilder.insert_value(agg, value, index, name='')

    通过在 index 处设置新 value 来构建聚合值 agg 的副本。index 的值类型可以与 extract_value() 中的相同。

向量操作

  • IRBuilder.extract_element(vector, idx, name='')

    返回位置 idx 处的 value

  • IRBuilder.insert_element(vector, value, idx, name='')

    返回向量,其中 vector[idx]value 替换。如果 idx 大于或等于向量长度,则结果未定义。

  • IRBuilder.shuffle_vector(vector1, vector2, mask, name='')

    vector1vector2 构建元素的排列。返回一个与 mask 长度相同的新向量。

    • vector1vector2 必须具有相同的元素类型。

    • mask 必须是整数类型的常量向量。

内存

  • IRBuilder.alloca(typ, size=None, name='')

    typ 类型的大小值静态分配一个栈槽。如果未给出 size,则分配一个用于 1 个值的栈槽。

  • IRBuilder.load(ptr, name='', align=None)

    从指针 ptr 加载值。如果传递了 align,它应该是一个 Python 整数,指定保证的指针对齐。

  • IRBuilder.store(value, ptr, align=None)

    value 存储到指针 ptr。如果传递了 align,它应该是一个 Python 整数,指定保证的指针对齐。

  • IRBuilder.load_atomic(ptr, ordering, align, name='')

    作为给定 ordering 的原子操作,从指针 ptr 加载值。align 必须是一个 Python 整数,指定保证的指针对齐。

  • IRBuilder.store_atomic(value, ptr, ordering, align)

    作为给定 ordering 的原子操作,将 value 存储到指针 ptralign 必须是一个 Python 整数,指定保证的指针对齐。

  • IRBuilder.gep(ptr, indices, inbounds=False, name='')

    getelementptr 指令。给定指向聚合值 ptr 的指针,计算由 indices 序列给出的内部元素的地址。

  • llvmlite.ir.cmpxchg(ptr, cmp, val, ordering, failordering=None, name='')

    在地址 ptr 进行原子比较并交换。

    • cmp 是用于与内容比较的值。

    • val 是要交换进去的新值。

    • 可选的 orderingfailordering 指定了此指令的内存模型。

  • llvmlite.ir.atomic_rmw(op, ptr, val, ordering, name='')

    在地址 ptr 执行原子内存操作 op,操作数为 val

    • 字符串 op 指定操作——例如,addsub

    • 可选的 ordering 指定了此指令的内存模型。

函数调用

IRBuilder.call(fn, args, name='', cconv=None, tail=None, fastmath=(), attrs=(), arg_attrs=None)

调用函数 fn,参数为 args(一个值序列)。

  • cconv 是可选的调用约定。

  • tail 控制尾调用优化行为。它可以是以下之一:

    • None(默认值):表示没有特定的尾调用优化行为。

    • "tail":一个提示,表示调用应该进行尾调用优化,但可能被忽略。

    • "musttail":表示为了程序正确性,调用必须进行尾调用优化。

    • "notail":表示调用不应进行尾调用优化。

    为了向后兼容以前的版本,还接受以下值:

    • False 等同于 None,表示没有特定行为。

    • True 等同于 "tail",表示建议进行尾调用优化。

  • fastmath 是一个字符串或字符串序列,用于指定快速数学标志的名称。

  • attrs 是一个字符串或字符串序列,表示要附加到调用站点的函数属性。

  • arg_attrs 是一个字典,将参数索引(常规整数,从零开始)映射到字符串或字符串序列,给出要附加到此调用站点相应参数的属性。如果字典中不存在某个索引,或者 arg_attrs 完全缺失,则不会为给定参数发出任何属性。

    如果某些属性(例如 sret)在函数声明中指定,则为了正确性,它们也必须在每个调用站点指定。(截至 LLVM 11,LLVM 语言参考中似乎没有明确指定这一点。)

分支

以下方法都是终结符

  • IRBuilder.branch(target)

    无条件跳转到 target(一个 Block)。

  • IRBuilder.cbranch(cond, truebr, falsebr)

    根据 cond(一个 IntType(1) 类型的值),条件跳转到 truebrfalsebr(均为 Block 实例)。此指令是一个 PredictableInstr

  • IRBuilder.ret(value)

    从当前函数返回 value

  • IRBuilder.ret_void()

    从当前函数返回,不带返回值。

  • IRBuilder.switch(value, default)

    根据 value 切换到不同的块。如果未匹配到其他块,则 default 是要切换到的块。

    要添加非默认目标,请在返回值上使用 add_case() 方法。

  • IRBuilder.branch_indirect(address)

    跳转到地址为 address 的基本块,addressIntType(8).as_pointer() 类型的值。

    要获取块地址,请使用 BlockAddress 常量。

    要添加所有可能的跳转目的地,请在返回值上使用 add_destination() 方法。

异常处理

  • IRBuilder.invoke(fn, args, normal_to, unwind_to, name='', cconv=None, fastmath=(), attrs=(), arg_attrs=None)

    调用函数 fn,参数为 args(一个值序列)。

    如果函数 fn 正常返回,控制权将转移到 normal_to。否则,它将转移到 unwind_to,其第一个非 phi 指令必须是 LandingPad

    其余参数给出了在调用站点指定的附加属性;详见 call() 方法的描述。

  • IRBuilder.landingpad(typ, personality, name='', cleanup=False)

    描述此基本块可以处理哪些异常。

    • typ 指定了着陆点的返回类型。它是一个包含 2 个指针大小字段的结构体。

    • personality 指定了异常个性化函数。

    • cleanup 指定是否应始终将控制权转移到此着陆点,即使没有捕获到匹配的异常。

    要添加着陆点子句,请在返回值上使用 add_clause() 方法。

    有两种着陆点子句:

    • 一个 CatchClause,它指定要捕获的单个异常的类型信息。类型信息是一个 IntType(8).as_pointer().as_pointer() 类型的值;

    • 一个 FilterClause,它指定一个类型信息数组。

    每个着陆点必须包含至少一个子句,或者被标记为清理。

    着陆点的语义完全由个性化函数决定。有关 LLVM 优化器中处理着陆点的详细信息,请参阅LLVM 中的异常处理。有关个性化函数实现的详细信息,请参阅Itanium 异常处理 ABI

  • IRBuilder.resume(landingpad)

    恢复由 landingpad 捕获的异常。用于指示着陆点最终未捕获到异常,可能因为它只执行了清理。

内联汇编

  • IRBuilder.asm(ftype, asm, constraint, args, side_effect, name='')

    添加一个内联汇编调用指令。例如,这在 load_reg()store_reg() 中使用。

    参数

    • ftype 是一个函数类型,指定内联汇编调用的输入和输出。

    • asm 是内联汇编片段——例如,"mov $2, $0\nadd $1, $0"。x86 内联汇编使用 AT&T 语法。

    • constraint 定义输入/输出约束——例如 =r,r,r

    • args 是输入列表,作为 IR 值。

    • side_effect 是一个布尔值,指定此指令是否具有约束列表中不可见的副作用。

    • name 是返回的 LLVM 值的可选名称。

    有关这些参数的更多信息,请参阅官方 LLVM 文档

    示例:在 x86 上添加两个 64 位值

    fty = FunctionType(IntType(64), [IntType(64),IntType(64)])
    add = builder.asm(fty, "mov $2, $0\nadd $1, $0", "=r,r,r",
                      (arg_0, arg_1), True, name="asm_add")
    
  • IRBuilder.load_reg(reg_type, reg_name, name='')

    将寄存器值加载到 LLVM 值中。

    示例:获取 rax 寄存器的值

    builder.load_reg(IntType(64), "rax")
    
  • IRBuilder.store_reg(value, reg_type, reg_name, name='')

    将 LLVM 值存储到寄存器中。

    示例:将 0xAAAAAAAAAAAAAAAA 存储到 rax 寄存器中

    builder.store_reg(Constant(IntType(64), 0xAAAAAAAAAAAAAAAA), IntType(64), "rax")
    

杂项

  • IRBuilder.assume(cond)

    让 LLVM 优化器假定 cond(一个 IntType(1) 类型的值)为 True

  • IRBuilder.unreachable()

    标记代码中的一个不可达点。

  • IRBuilder.comment(text)

    在生成的 IR 中插入一行注释。LLVM 将忽略此注释,但它对于调试编译器输出可能很有用。

    参数

    • text 是一个不包含换行符的字符串。