3

从联合数组中提取值的 LLVM 方法是什么?不直接支持联合,这似乎使事情复杂化。

背景:我正在调用由 JIT 执行机器返回的函数并传递给它 1 个参数,即包含参数的联合数组的基地址。

数据结构是从 C 中设置的,例如:

std::array<union{int,float*}> arguments(5);

int和的出现序列float*被编码在 a 中vector<llvm::Type*>

i32
i32
float*
float*
float*

现在我正在尝试这个(这是jitted函数):

define void @main([8 x i8]* %arg_ptr) {
entrypoint:
   %0 = getelementptr [8 x i8]* %arg_ptr, i32 0
   %1 = getelementptr [8 x i8]* %arg_ptr, i32 1
   %2 = getelementptr [8 x i8]* %arg_ptr, i32 2
   %3 = getelementptr [8 x i8]* %arg_ptr, i32 3
   %4 = getelementptr [8 x i8]* %arg_ptr, i32 4
}

首先,函数的签名是否正确(假设指针大小为 8 个字节)?

如何从存储在 %0 中的第一个i32中取出?[8 x i8]

我是否需要[8 x i8]先将数组转换为指针i32*,然后为其第一个元素创建另一个 GEP?

4

1 回答 1

4

请注意,LLVM IR 并没有真正的联合。在实践中发生的是 Clang(它知道目标三元组,因此细节是特定于平台/ABI 的)将创建一个struct足够大的单个元素来包含您的联合并对其采取行动。这是一些C代码:

typedef union {
  double dnum;
  int inum;
  float* fptr;
} my_union;

int bar(my_union* mu) {
  return mu[4].inum;
}

使用 clang 将其转换为 LLVM IR(使用 x86-64 机器上的默认目标,我们得到这个(优化代码,以减少混乱):

%union.my_union = type { double }

define i32 @bar(%union.my_union* nocapture readonly %mu) #0 {
entry:
  %arrayidx = getelementptr inbounds %union.my_union* %mu, i64 4
  %inum = bitcast %union.my_union* %arrayidx to i32*
  %0 = load i32* %inum, align 4
  ret i32 %0
}

这里需要注意一些事项,并回答您问题中嵌入的一些子问题:

  • 联合被 C 类型取代,struct {double}因为它大到足以包含所有联合成员,并且它还提供正确的对齐约束。LLVM 对联合一无所知。从这一点开始,它作用于结构聚合。
  • 对 LLVM 中的数组成员的访问是通过一个 GEP 完成的,该 GEP 获得两个数字索引。有关它为何以这种方式工作的深入解释,请参阅http://llvm.org/docs/GetElementPtr.html
  • 拥有成员后,您只需从中加载值。Clang 知道成员在枚举中的布局方式,因此它i32*直接从成员中加载。
于 2013-10-23T19:23:30.753 回答