7

我正在编写一个生成 LLVM IR 指令的编译器。我正在广泛使用向量。

我希望能够对向量中的所有元素求和。现在我只是单独提取每个元素并手动添加它们,但令我震惊的是,这正是硬件应该能够提供帮助的事情(因为这听起来像是一个非常常见的操作)。但似乎没有内在的做到这一点。

最好的方法是什么?我正在使用 LLVM 3.2。

4

1 回答 1

5

首先,即使不使用内在函数,您也可以生成log(n)向量加法(n 是向量长度)而不是n标量加法,这里有一个向量大小为 8 的示例:

define i32 @sum(<8 x i32> %a) {
  %v1 = shufflevector <8 x i32> %a, <8 x i32> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
  %v2 = shufflevector <8 x i32> %a, <8 x i32> undef, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
  %sum1 = add <4 x i32> %v1, %v2
  %v3 = shufflevector <4 x i32> %sum1, <4 x i32> undef, <2 x i32> <i32 0, i32 1>
  %v4 = shufflevector <4 x i32> %sum1, <4 x i32> undef, <2 x i32> <i32 2, i32 3>
  %sum2 = add <2 x i32> %v3, %v4
  %v5 = extractelement <2 x i32> %sum2, i32 0
  %v6 = extractelement <2 x i32> %sum2, i32 1
  %sum3 = add i32 %v5, %v6
  ret i32 %sum3
}

如果您的目标支持这些向量添加,那么似乎很可能会降低上述内容以使用这些指令,从而为您提供性能。

关于内在函数,没有与目标无关的内在函数来处理这个问题。但是,如果您正在编译到 x86,您确实可以访问hadd内部函数(例如llvm.x86.int_x86_ssse3_phadd_sw_128,将两个<4 x i32>向量相加)。您仍然需要执行与上述类似的操作,只能add替换说明。

有关这方面的更多信息,您可以搜索“水平和”或“水平向量和”;例如,这里有一些关于 x86 水平总和的相关 stackoverflow 问题:

于 2013-02-07T08:34:14.423 回答