Compiler construction 向量LLVM的变更元素

Compiler construction 向量LLVM的变更元素,compiler-construction,llvm,llvm-ir,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> unde

我正在尝试使用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
}
我试图做的是在向量中重新插入一个值-这不起作用。我怀疑这是两个问题之一:

  • 我无法重新设置元素
  • 实际上,我正在重新设置变量
    %calltmp
    中的一个元素,而不是实际的向量

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

    您的第一个问题是您已经将
    @a
    定义为一个函数,特别是一个总是返回值的函数。因此,无论您在其他地方做什么,您都无法调用
    @a()
    ,并返回除该值以外的任何内容。因此,您要做的第一件事是将
    @a
    转换为全局变量,以便可以更改其值

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

    然而,正如我们在评论中已经讨论的,向量并不是你所做的事情的合适选择,原因有几个:

  • 由于无法将指针指向向量,因此无法轻松编写迭代任意大小向量的函数
  • 正如我已经指出的,
    insertelement
    创建了一个新的向量,其中一个元素发生了更改。这意味着整个向量被复制。如果创建大型向量,那么成本可能会很高
  • 你似乎没有真正利用向量的任何好处。向量允许您对大小相同的数字向量执行逐点运算,并在适当的情况下编译为SIMD指令。这就是它们的用途——而不是作为通用阵列的替代品

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

    您的第一个问题是,您已经将
    @a
    定义为一个函数,特别是一个始终返回值
    的函数。因此,无论您在其他地方做什么,您都无法调用
    @a()
    ,并返回除该值以外的任何内容。因此,您要做的第一件事是将
    @a
    转换为全局变量,以便可以更改其值

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

    然而,正如我们在评论中已经讨论的,向量并不是你所做的事情的合适选择,原因有几个:

  • 由于无法将指针指向向量,因此无法轻松编写迭代任意大小向量的函数
  • 正如我已经指出的,
    insertelement
    创建了一个新的向量,其中一个元素发生了更改。这意味着整个向量被复制。如果创建大型向量,那么成本可能会很高
  • 你似乎没有真正利用向量的任何好处。向量允许您对大小相同的数字向量执行逐点运算,并在适当的情况下编译为SIMD指令。这就是它们的用途——而不是作为通用阵列的替代品

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

    您确定要在此处使用向量吗?您的源程序显示“数组”<代码>插入元件不是就地操作;它会生成一个新的向量(由于您不触摸包含新向量的
    %0
    ),因此您永远不会使用该向量)。您永远不能更改现有寄存器的内容(这就是SSA的意思)。还有,为什么
    a
    a函数?@sepp2k我想使用向量,因为我认为向量更具动态性(不是固定大小,等等)。我想最好的办法是创建一个变量,而不是一个返回向量的函数,并将其更改为
    %0
    。谢谢你的帮助和洞察力。向量不是这样的。就像数组一样,向量的大小也是其类型的一部分,所以它们的大小是固定的。向量与数组的区别在于:它们只能包含数字,因为它们是元素类型。它们是一级值,这意味着它们可以存储在寄存器中,并作为参数传递给函数(无需通过指针)等。您可以对它们使用数值操作,如
    fadd
    ,然后在适用的情况下编译为SIMD指令(这是它们的主要用途)。你不能在它们上面使用
    getelementptr
    ,所以你不能得到指向它们元素的指针。所以在某种意义上,它们的大小甚至比数组更固定,因为使用数组,你至少可以得到指向它们内容的指针,然后将它传递给一个可以dea的函数
    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
    }