SSE指令在哪里优于正常指令

x86-64的SSE指令(向量指令)在哪里优于正常指令。 因为我所看到的是,执行SSE指令所需的频繁加载和存储会使由于向量计算而获得的任何增益无效。 那么有人可以给我一个示例SSE代码,它比普通代码表现更好。

它可能是因为我分别传递每个参数,像这样…

__m128i a = _mm_set_epi32(pa[0], pa[1], pa[2], pa[3]); __m128i b = _mm_set_epi32(pb[0], pb[1], pb[2], pb[3]); __m128i res = _mm_add_epi32(a, b); for( i = 0; i < 4; i++ ) po[i] = res.m128i_i32[i]; 

有没有办法我可以一次性传递所有4个整数,我的意思是一次性传递整个128字节的pa ? 并res.m128i_i32res.m128i_i32分配给po

总结评论的答案:

你基本上陷入了捕获大多数初次使用者的陷阱。 基本上你的例子有两个问题:

  1. 你在滥用_mm_set_epi32()
  2. 您的计算/负载存储比率非常低。 (在您的示例中为1到3)

_mm_set_epi32()是一种非常昂贵的内在函数。 虽然使用起来很方便,但它不能编译成单个指令。 使用_mm_set_epi32()时,某些编译器(如VS2010)可能会生成性能很差的代码。

相反,由于您正在加载连续的内存块,因此应使用_mm_load_si128() 。 这要求指针对齐16个字节。 如果你不能保证这种对齐方式,你可以使用_mm_loadu_si128() – 但性能会受到影响。 理想情况下,您应该正确对齐数据,以便不需要使用_mm_loadu_si128()


使用SSE真正高效,您还需要最大化计算/负载存储比率。 我拍摄的目标是每个内存访问3-4个算术指令。 这是一个相当高的比例。 通常,您必须重构代码或重新设计算法以增加它。 结合数据传递是一种常见的方法。

当您拥有具有长依赖关系链的大型循环体时,通常需要循环展开以最大化性能。


成功使用SSE实现加速的SO问题的一些示例。

  • C代码循环性能 (非矢量化)
  • C代码循环性能[续] (矢量化)
  • 如何实现每个周期4个FLOP的理论最大值? (实现峰值处理器性能的设计示例)