You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用C++构建Store指令存储LLVM Basic Block地址至数组?

问题

我在查看C程序生成的LLVM IR代码时发现,C程序中获取标签地址的行为会被转换为store指令处理,对应的IR代码示例如下:

store i8* blockaddress(@func_name, %label_name), i8** %val_name

查阅LLVM官方文档后,了解到blockaddress的工作机制:

blockaddress(@function, %block)
The 'blockaddress' constant computes the address of the specified basic block in the specified function, and always has an i8* type. Taking the address of the entry block is illegal.
This value only has defined behavior when used as an operand to the 'indirectbr' instruction, or for comparisons against null. Pointer equality tests between labels addresses results in undefined behavior — though, again, comparison against null is ok, and no label is equal to the null pointer. This may be passed around as an opaque pointer sized value as long as the bits are not inspected. This allows ptrtoint and arithmetic to be performed on these values so long as the original value is reconstituted before the indirectbr instruction.
Finally, some targets may provide defined semantics when using the value as the operand to an inline assembly, but that is target specific.

我想了解:

  1. IR层面如何通过store指令将blockaddress存储到类似%5的变量中
  2. 如何用C++构建该store指令,实现将Basic Block的地址存储到数组中

此前我已成功构建indirectbr指令,相关代码如下:

irBuilder.SetInsertPoint(indirectbr_bb);
IndirectBrInst *indirect_br = IndirectBrInst::Create(BlockAddress::get(func, instr2_bb), 0, indirectbr_bb);
indirect_br->addDestination(instr1_bb);
indirect_br->addDestination(instr2_bb);

生成的IR代码:

indirectbr_bb:                                    ; preds = %dispatch_then_bb
  indirectbr i8* blockaddress(@jit_func, %instr2_bb), [label %instr1_bb, label %instr2_bb]

解答

一、IR层面的存储逻辑

要把blockaddress存储到变量中,核心是确保存储的源操作数是blockaddress常量,目标操作数是一个指向i8*的指针(即i8**类型):

  • 源:blockaddress(@func, %bb) 是i8*类型的常量
  • 目标:需要先分配一个i8*类型的变量(比如通过alloca指令),然后取它的地址得到i8**类型的指针

单个变量存储示例IR

  1. 先分配存储标签地址的变量:
    %bb_addr = alloca i8*, align 8
    
  2. 用store指令把blockaddress存入该变量:
    store i8* blockaddress(@target_func, %target_bb), i8** %bb_addr
    

数组存储示例IR

如果要存入数组,需要先分配数组空间,然后计算数组元素的地址(通过getelementptr指令),再执行store:

; 分配一个能存2个i8*的数组
%bb_array = alloca [2 x i8*], align 8
; 计算数组第0个元素的地址(i8**类型)
%array_idx0 = getelementptr inbounds [2 x i8*], [2 x i8*]* %bb_array, i32 0, i32 0
; 存入第一个blockaddress
store i8* blockaddress(@target_func, %bb1), i8** %array_idx0
; 计算数组第1个元素的地址
%array_idx1 = getelementptr inbounds [2 x i8*], [2 x i8*]* %bb_array, i32 0, i32 1
; 存入第二个blockaddress
store i8* blockaddress(@target_func, %bb2), i8** %array_idx1

二、C++代码实现

1. 存储到单个变量

利用LLVM的IRBuilder可以快速构建alloca和store指令:

// 假设已准备好:func(目标函数)、target_bb(要获取地址的BasicBlock)、irBuilder(IRBuilder实例)
// 1. 分配i8*类型的变量,得到i8**类型的指针
Value* bbAddrPtr = irBuilder.CreateAlloca(Type::getInt8PtrTy(irBuilder.getContext()), nullptr, "bb_addr");
// 2. 创建blockaddress常量
Constant* blockAddr = BlockAddress::get(func, target_bb);
// 3. 构建store指令,存入变量
irBuilder.CreateStore(blockAddr, bbAddrPtr);

生成的IR会和单个变量存储示例一致。

2. 存储到数组

要存入数组,需要先创建数组类型,分配空间,再通过CreateGEP计算元素地址,最后执行store:

LLVMContext& ctx = irBuilder.getContext();
// 1. 定义数组类型:2个i8*元素
ArrayType* bbArrayType = ArrayType::get(Type::getInt8PtrTy(ctx), 2);
// 2. 分配数组空间,得到[2 x i8*]*类型的指针
Value* bbArray = irBuilder.CreateAlloca(bbArrayType, nullptr, "bb_array");

// 3. 存储第一个BasicBlock地址到数组索引0
Constant* blockAddr1 = BlockAddress::get(func, bb1);
// 计算数组第0个元素的地址:参数依次是数组指针、数组维度0的索引(0)、元素索引(0)
Value* idx0 = irBuilder.CreateGEP(bbArrayType, bbArray, {
    irBuilder.getInt32(0),  // 数组本身的索引(因为是alloca的单个数组,所以是0)
    irBuilder.getInt32(0)   // 元素索引
}, "array_idx0");
irBuilder.CreateStore(blockAddr1, idx0);

// 4. 存储第二个BasicBlock地址到数组索引1
Constant* blockAddr2 = BlockAddress::get(func, bb2);
Value* idx1 = irBuilder.CreateGEP(bbArrayType, bbArray, {
    irBuilder.getInt32(0),
    irBuilder.getInt32(1)
}, "array_idx1");
irBuilder.CreateStore(blockAddr2, idx1);

这段代码会生成和数组存储示例一致的IR代码。


内容的提问来源于stack exchange,提问作者zevorn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 01:25:20