【问题标题】:Divide 8-bit integers by 4 (or shift) using SSE使用 SSE 将 8 位整数除以 4(或移位)
【发布时间】:2017-05-24 03:46:46
【问题描述】:

如何使用 SSE 内在函数将 16 个 8 位整数除以 4(或将它们向右移动 2)?

【问题讨论】:

  • 我认为只要指定正确的 -march 或 -mtune 就会自动发生:godbolt.org/g/jxGyFd
  • 首先,该工具非常适合 StackOverflow 等问答页面。我马上给它加了书签。对于答案的真实内容,谢谢,我会看看程序集,如果编译器在某些情况下自动执行它,我应该能够从程序集中读取它。
  • @RichardHodges 我发现这段代码实际上相当令人失望,不过 Clang 做得很好。
  • @harold 为什么令人失望?请记住,它正在处理未在 SSE 兼容边界上对齐的块的病理情况。一旦它处理了边缘情况,主块就会被矢量化。如果您将指针标记为对齐,我相信您会看到完美的代码。
  • 嗯,不,用 16 字节对齐注释指针对 GCC 没有帮助。事实证明,真正的 区别在于mtune=native 导致 Clang 假设支持 AVX2,而 GCC 假设仅支持 AVX。如果你明确地将-mavx2 传递给 GCC,你会得到更好的输出,类似于 Clang 的输出。当然,Clang 不会改变。关于为什么“本机”对于您无法控制其系统规范的在线编译器没有多大意义的一个很好的教训。 :-) @richard

标签: c++ x86 sse simd intrinsics


【解决方案1】:

不幸的是,没有针对 8 位元素的 SSE 移位指令。如果元素是 8 位 unsigned 那么您可以使用 16 位移位并屏蔽掉不需要的高位,例如

v = _mm_srli_epi16(v, 2);
v = _mm_and_si128(v, _mm_set1_epi8(0x3f));

对于 8 位 signed 元素,它有点复杂,但仍然可能,尽管解压缩为 16 位可能更容易,进行移位,然后再打包回 8 位。

【讨论】:

  • 谢谢,刚刚自己写了一个伪造epi8的宏来解决这个问题:#define _mm_srli_epi8(mm, Imm) _mm_and_si128(_mm_set1_epi8(0xFF >> Imm), _mm_srli_epi32(mm, Imm))
  • @miho:请注意,在这里将其编写为宏而不是内联函数并没有任何优势。
  • @DietrichEpp:实际上,如果_mm_srli_epi32 中的Imm 不是文字常量(尤其是在调试版本中),一些编译器会抱怨,这可能是内联函数的问题,尽管你应该没问题使用当前/最新版本的 gcc、clang、ICC。
  • 是的,这取决于您的代码是否需要可移植并与一堆不同的编译器一起工作,在这种情况下,您必须发挥最低公分母(通常是 MSVC)。如果您只需要使用一个(或几个)编译器版本,那么您可以在这里使用内联函数。
  • @PaulR 我使用的技巧是将移位量作为模板参数。
猜你喜欢
  • 2023-03-09
  • 2012-05-17
  • 1970-01-01
  • 2017-07-12
  • 1970-01-01
  • 1970-01-01
  • 2015-07-29
  • 1970-01-01
  • 2021-01-17
相关资源
最近更新 更多