我正在编写一个生成 LLVM IR 指令的编译器。我正在广泛使用向量。
我希望能够对向量中的所有元素求和。现在我只是单独提取每个元素并手动添加它们,但令我震惊的是,这正是硬件应该能够提供帮助的事情(因为这听起来像是一个非常常见的操作)。但似乎没有内在的做到这一点。
最好的方法是什么?我正在使用 LLVM 3.2。
首先,即使不使用内在函数,您也可以生成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 问题: