Rust 高效的SIMD点状积

Rust 高效的SIMD点状积,rust,simd,convolution,avx,dot-product,Rust,Simd,Convolution,Avx,Dot Product,我正在尝试创建高效的点积SIMD版本,以实现FIR滤波器i16类型的2D卷积 #[cfg(target_arch=“x86_64”)] 使用std::arch::x86_64::*; #[目标功能(enable=“avx2”)] 不安全的fn dot_产品(a:&[i16],b:&[i16]){ 设a=a.as_ptr()as*const[i16;16]; 设b=b.as_ptr()as*const[i16;16]; 设a=std::mem::transmute(*a); 设b=std::mem

我正在尝试创建高效的点积SIMD版本,以实现FIR滤波器i16类型的2D卷积

#[cfg(target_arch=“x86_64”)]
使用std::arch::x86_64::*;
#[目标功能(enable=“avx2”)]
不安全的fn dot_产品(a:&[i16],b:&[i16]){
设a=a.as_ptr()as*const[i16;16];
设b=b.as_ptr()as*const[i16;16];
设a=std::mem::transmute(*a);
设b=std::mem::transmute(*b);
设ms_256=_mm256_mullo_epi16(a,b);
dbg!(std::mem::transmute:(ms_256));
设hi_128=_mm256_castsi256_si128(ms_256);
设lo_128=_mm256_extracti128_si256(ms_256,1);
dbg!(std::mem::transmute:(hi_128));
dbg!(std::mem::transmute:(lou 128));
让温度=毫米加上16(高128,低128);
}
fn main(){
设a=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
设b=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
不安全{
dot_产品(a&b);
}
}
I]~/c/simd(master |…)$env RUSTFLAGS=“-c target cpu=native”货物运行—发布| wl拷贝
警告:未使用的变量:`temp`
-->src/main.rs:16:9
|
16 |让温度=_mm_add_epi16(高128,低128);
|^^^^^^帮助:如果这是有意的,请在其前面加下划线:`\u temp`
|
=注意:`#[警告(未使用的_变量)]`默认打开
警告:发出1个警告
在0.00s内完成发布[优化]目标
运行`目标/发布/simd`
[src/main.rs:11]std::mem::transmute:(ms_256)=[
0,
1.
4.
9,
16,
25,
36,
49,
64,
81,
100,
121,
144,
169,
196,
225,
]
[src/main.rs:14]std::mem::transmute:(hi_128)=[
0,
1.
4.
9,
16,
25,
36,
49,
]
[src/main.rs:15]std::mem::transmute:(lou 128)=[
64,
81,
100,
121,
144,
169,
196,
225,
]
虽然我从概念上理解SIMD,但我不熟悉确切的指令和内部函数

我知道我需要将两个向量相乘,然后水平求和,然后将它们减半,并使用指令将两个较小的减半向量垂直相加

我发现madd指令应该在乘法后立即进行一次这样的求和,但不确定如何处理结果

如果使用mul而不是madd,我不确定应该使用哪些指令来进一步减少结果

欢迎任何帮助

PS
我尝试过压缩simd,但它似乎对稳定的rust不起作用。

对于大型阵列,您可以使用
\u mm256\u add\u epi32将结果“垂直”相加到向量累加器中,并且只在最后进行最后的水平相加(一个或两个向量)。(请参阅,假设您可以使C/C++内部函数适应Rust)。如果需要避免32位和溢出,则需要在循环内
pmaddwd
之后再次加宽。@PeterCordes,正如我所说,我在FIR滤波器中为2D卷积做点积。其中一个序列是滤波器内核,大约是16或32个抽头。我对SIMD和AVX的经验没有包括FIR滤波器或那种信号处理,所以这并没有告诉我我们要处理的点积的长度。我想你是在暗示有16或32个元素要求和,所以这比1个SIMD向量还多,所以我所说的仍然适用(除非你不需要循环,只需要完全展开):垂直添加
vpmaddwdwd
结果,直到你有一个向量,然后水平减少。或者,如果您需要避免16位乘积的32位和溢出,请在某个点加宽到64位。@PeterCordes
as*const[i16;16]这表示它是向量或16位整数。我不知道为什么要对16位向量进行水平求和,我需要多于1个SIMD向量。你能详细说明一下吗?也许在rust游乐场写些代码?我不太了解rust,我是来找[simd]标签的。另外,我认为这可能是一个单向量函数,你将在循环中重复调用。无论如何,是的,只有16x2=32字节的输入数据,如果可以使用AVX2,那么只有一个vpmaddwd结果。hsum通过反复提取高半部并添加,就像我第一次评论中的链接问答一样。