向量 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
}
我想做的是将一个值重新插入到向量中——这是行不通的。我怀疑这是两个问题之一:
- 我无法重新设置元素
- 我实际上是在重新设置变量
%calltmp
中的一个元素,而不是实际的向量。
我很想知道我能做些什么来解决这个问题。
您的第一个问题是您已将 @a
定义为函数,特别是始终 returns 值 <1.0, 2.0, 3.0>
的函数。因此,无论您在其他地方做什么,您将永远无法调用 @a()
并取回该值以外的任何内容。所以你要做的第一件事就是把 @a
变成一个全局变量,这样你就可以改变它的值。
现在你的下一个问题是 insertelement
不会改变给定的向量。它不能,因为向量存储在寄存器中并且您不能重新分配寄存器(LLVM 使用静态单一分配形式)。因此 insertelement
会生成一个给定索引已更改的新向量。在您的代码中,您将该新向量存储在 %0
中,然后不对其进行任何操作。将 @a
设为全局变量后,即可将 %0
的值存储在 @a
中。这将解决您眼前的问题。
但是,正如我们已经在评论中讨论的那样,出于以下几个原因,向量并不是您正在做的事情的合适选择:
- 由于无法将指针指向向量,因此无法轻松编写迭代任意大小向量的函数。
- 正如我已经指出的那样,
insertelement
创建了一个新的矢量,其中一个元素发生了变化。这意味着整个向量都被复制了。如果您创建大向量,那可能会变得非常昂贵。
- 您似乎并没有真正利用向量的任何好处。向量允许您对相同大小的数字向量执行逐点算术,这些向量将在适当的地方编译为 SIMD 指令。这就是它们的用途 - 而不是作为通用数组替换。
如果你使 @a
成为一个数组,你就可以获得指向它的第二个元素的指针并将新值直接存储到其中。因此,无需创建一个全新的数组并用它替换 @a
,您只需更改要更改的一个元素即可。这才是你真正想要的。
我正在尝试使用 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
}
我想做的是将一个值重新插入到向量中——这是行不通的。我怀疑这是两个问题之一:
- 我无法重新设置元素
- 我实际上是在重新设置变量
%calltmp
中的一个元素,而不是实际的向量。
我很想知道我能做些什么来解决这个问题。
您的第一个问题是您已将 @a
定义为函数,特别是始终 returns 值 <1.0, 2.0, 3.0>
的函数。因此,无论您在其他地方做什么,您将永远无法调用 @a()
并取回该值以外的任何内容。所以你要做的第一件事就是把 @a
变成一个全局变量,这样你就可以改变它的值。
现在你的下一个问题是 insertelement
不会改变给定的向量。它不能,因为向量存储在寄存器中并且您不能重新分配寄存器(LLVM 使用静态单一分配形式)。因此 insertelement
会生成一个给定索引已更改的新向量。在您的代码中,您将该新向量存储在 %0
中,然后不对其进行任何操作。将 @a
设为全局变量后,即可将 %0
的值存储在 @a
中。这将解决您眼前的问题。
但是,正如我们已经在评论中讨论的那样,出于以下几个原因,向量并不是您正在做的事情的合适选择:
- 由于无法将指针指向向量,因此无法轻松编写迭代任意大小向量的函数。
- 正如我已经指出的那样,
insertelement
创建了一个新的矢量,其中一个元素发生了变化。这意味着整个向量都被复制了。如果您创建大向量,那可能会变得非常昂贵。 - 您似乎并没有真正利用向量的任何好处。向量允许您对相同大小的数字向量执行逐点算术,这些向量将在适当的地方编译为 SIMD 指令。这就是它们的用途 - 而不是作为通用数组替换。
如果你使 @a
成为一个数组,你就可以获得指向它的第二个元素的指针并将新值直接存储到其中。因此,无需创建一个全新的数组并用它替换 @a
,您只需更改要更改的一个元素即可。这才是你真正想要的。