向量 LLVM 的变化元素

Change element of vector LLVM

我正在尝试使用 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 中的一个元素,而不是实际的向量。

我很想知道我能做些什么来解决这个问题。

您的第一个问题是您已将 @a 定义为函数,特别是始终 returns 值 <1.0, 2.0, 3.0> 的函数。因此,无论您在其他地方做什么,您将永远无法调用 @a() 并取回该值以外的任何内容。所以你要做的第一件事就是把 @a 变成一个全局变量,这样你就可以改变它的值。

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

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

  1. 由于无法将指针指向向量,因此无法轻松编写迭代任意大小向量的函数。
  2. 正如我已经指出的那样,insertelement 创建了一个新的矢量,其中一个元素发生了变化。这意味着整个向量都被复制了。如果您创建大向量,那可能会变得非常昂贵。
  3. 您似乎并没有真正利用向量的任何好处。向量允许您对相同大小的数字向量执行逐点算术,这些向量将在适当的地方编译为 SIMD 指令。这就是它们的用途 - 而不是作为通用数组替换。

如果你使 @a 成为一个数组,你就可以获得指向它的第二个元素的指针并将新值直接存储到其中。因此,无需创建一个全新的数组并用它替换 @a,您只需更改要更改的一个元素即可。这才是你真正想要的。