更改向量LLVM

时间:2018-05-20 23:30:47

标签: compiler-construction llvm llvm-ir

我正在尝试使用LLVM IR代码更改向量的元素。以下代码:

extern printd(num);

array a [1 2 3];

printd(a[1]); # 2.0

a[1] = 10;

printd(a[1]); # 2.0

生成此IR代码:

declare double @printd(double)

define <4 x double> @a() {
entry:
  %0 = insertelement <4 x double> undef, double 1.000000e+00, i32 0
  %1 = insertelement <4 x double> %0, double 2.000000e+00, i32 1
  %2 = insertelement <4 x double> %1, double 3.000000e+00, i32 2
  ret <4 x double> %2
}

define double @__anon_expr0() {
entry:
  %calltmp = call <4 x double> @a()
  %0 = extractelement <4 x double> %calltmp, i32 1
  %calltmp1 = call double @printd(double %0)
  ret double %calltmp1
}

define double @__anon_expr1() {
entry:
  %calltmp = call <4 x double> @a()
  %0 = insertelement <4 x double> %calltmp, double 1.000000e+00, i32 1
  ret double 0.000000e+00
}

那部分没关系,问题出在这里(__anon_expr1):

define double @__anon_expr1() {
entry:
  %calltmp = call <4 x double> @a()
  %0 = insertelement <4 x double> %calltmp, double 1.000000e+00, i32 1
  ret double 0.000000e+00
}

我要做的是将值重新插入向量 - 这不起作用。我怀疑这是两个问题之一:

  1. 我无法重新设置元素
  2. 我实际上是在变量%calltmp中重新设置一个元素,而不是实际的矢量。
  3. 我很想知道如何解决这个问题。

1 个答案:

答案 0 :(得分:3)

您的第一个问题是您已将@a定义为函数,特别是始终返回值<1.0, 2.0, 3.0>的函数。所以无论你在别的地方做什么,你都永远不能打电话给@a()并取回除了那个价值以外的任何东西。因此,您要做的第一件事就是将@a转换为全局变量,这样您就可以更改其值。

现在您的下一个问题是insertelement不会更改给定的向量。它不能,因为向量存储在寄存器中,您无法重新分配寄存器(LLVM使用静态单一赋值形式)。因此,insertelement生成一个新的向量,其中给定的索引已更改。在您的代码中,您将新的向量存储在%0中,然后对其执行任何操作。在您@a成为全局变量之后,您可以将%0的值存储在@a中。这将解决您当前的问题。

但是,正如我们已经在评论中讨论的那样,由于以下几个原因,向量并不适合您正在做的事情:

  1. 由于您无法指向向量,因此您无法轻松编写迭代任意大小向量的函数。
  2. 正如我已经指出的那样,insertelement创建了一个更改了一个元素的新向量。这意味着整个矢量被复制。如果你创建大型向量,那可能会花费很多。
  3. 你似乎并没有真正利用矢量的任何好处。向量允许您对相同大小的数字向量执行逐点算术,这将在适当的情况下编译为SIMD指令。这就是他们意图使用的方式 - 而不是通用的阵列替换。
  4. 如果使@a成为数组,则可以获得指向其第二个元素的指针并将新值直接存储到其中。因此,您只需更改要更改的一个元素,而不是创建一个全新的数组并用它替换@a。这就是你真正想要的。