从联合中提取值

时间:2013-10-23 18:48:04

标签: llvm

从一组联合中提取值的LLVM方法是什么? 工会没有直接支持,这似乎使事情变得复杂。

背景: 我正在调用JIT执行机器返回的函数 并传递1个参数,即数组的基址 含有论据的工会。

数据结构是从C开始设置的:

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

编码intfloat*的出现顺序 在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到它的第一个元素?

1 个答案:

答案 0 :(得分: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对工会一无所知。从这一点开始,它作用于结构聚合。
  • 使用GEP获取LLVM中的数组成员,获取两个数字索引。有关其工作原理的深入解释,请参阅http://llvm.org/docs/GetElementPtr.html
  • 获得该成员后,只需从中加载该值即可。 Clang知道如何在枚举中布置成员,因此它直接从成员加载i32*