在 32 位整数中查找最大值

Posted

技术标签:

【中文标题】在 32 位整数中查找最大值【英文标题】:Find max among 32 bit integers 【发布时间】:2016-06-05 00:02:58 【问题描述】:

SSE/SSE2 中是否有指令能够找到 4 个 32 位整数的最大值/最小值? 我试着搜索一些东西,但我只找到了 16/8 位的说明。 提前致谢。

https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=max&expand=4465,4463,3278&techs=SSE,SSE2

【问题讨论】:

您是在寻找横向操作吗?还是并行 4 个打包的最大操作,例如 pmaxsd?如果您需要 SSE2 的水平最大值,只需存储到内存并使用标量即可。使用 SSE4.1,那么像水平总和这样的洗牌可能是最快的。水平操作很慢。如果您的算法需要很多,那么您使用 SIMD 是错误的。请参阅SSE tag wiki 获取指南。 “您在寻找水平操作吗?” 我在寻找并行操作。好的,您建议存储到内存并使用标量操作。 (在水平的情况下)。但是你为什么建议这样做呢?毕竟,使用 SIMD 没有任何优势。您的意思是,水平操作与“存储到内存并以“正常”(标量)方式比较一样快吗? 如果您正好有 4 个号码,而不是 1000 个号码,那么 SIMD 没有太多好处。 (除非你的号码是无符号的 16 位,所以你可以使用专用的PHMINPOSUW)。水平意味着“在单个向量内”,这与 SIMD 擅长的相反(例如,将 a[0] 添加到 b[0],将 a[1] 添加到 b[1] 等)。如果您需要在没有 SSE4.1 的情况下找到 4 个元素的水平最大值,那么您可能无法击败标量。 【参考方案1】:

没有 SSE4.1 的最好方法似乎是 32 位比较,然后使用该掩码进行混合:AND(mask, x) OR ANDN(mask, y)

Agner Fog's vector class library 拥有a function for it:

// function max: a > b ? a : b
static inline Vec4i max(Vec4i const & a, Vec4i const & b) 
#if INSTRSET >= 5   // SSE4.1 supported
    return _mm_max_epi32(a,b);
#else
    __m128i greater = _mm_cmpgt_epi32(a,b);
    return selectb(greater,a,b);
#endif

我对该库 on github 进行了一些大部分未经测试和尚未合并的更改。我的大部分更改都是对我有时间查看的少数函数(整数水平和、四字算术右移、四字乘法)的重大改进。 (欢迎测试/反馈!)

但是很多现有的代码都非常好,所以我肯定会推荐使用那些包装类。当您在启用优化的情况下进行构建时,它们不会增加开销,并且它们使语法变得容易得多。例如a+b 而不是 _mm_add_epi32(a,b)

【讨论】:

也许横向操作是低调的果实。我的意思是它们不是您通常在关键循环中想要的操作,因此优化它们并不是那么重要。您是否在 VCL 中发现任何需要优化的关键函数?我认为 VCL 最困难的部分是置换和混合。参见例如this。我认为这是使用通用类实现最困难的领域。 @Zboson:是的,事实证明,所有的 VCL 总是使用 vpblendvb(2 uop 并且需要来自内存的掩码),即使对于编译时间常数混合也是如此。我列表中的下一个是修复模板以尽可能使用更快的vpblenddpblendw。我还推动了 operator >> (Vec2q) 的加速(模拟缺少的 psarq),我在 128b 版本上的表现要好得多,而不仅仅是将变量混合更改为即时混合。 Here 是另一个有趣的例子。我最终做对了,但问题是在 VCL 生成理想代码而不是错误代码之前,我必须尝试几种变体。 @Zboson:所以有些模式应该变成简单的随机播放,但不是吗?我还没有查看它是否能够识别所有可能的随机播放模式。已经有很多特例模式了!哦,我看到 OP 的代码可能很糟糕,所以这可能是一个测试用例。但是,请记住,VCL 没有希望在单独的语句之间进行优化。因此,即使blend8f<...> 的 VCL 元编程是完美的,您仍然必须知道硬件有哪些可用的 shuffle。单个 blend8fx8 来优化 8 输入 8 输出 shuffle 将是疯狂的......【参考方案2】:

也许PMAXSD 能解决问题?

比较目标操作数(第一个操作数)和源操作数(第二个操作数)中的压缩有符号双字整数,并返回目标操作数中每个压缩值的最大值。

但是,它需要 SSE 4.1 和/或 AVX 支持。

【讨论】:

以上是关于在 32 位整数中查找最大值的主要内容,如果未能解决你的问题,请参考以下文章

int类型最大能存储到哪一位

int 最大值

一维数组求最大子数组的和(首位相邻32位)

最大子数组之和首位相邻32位版

差漏补缺

在无符号 32 位整数中查找位位置