【问题标题】:Subtraction over ranges of bits位范围内的减法
【发布时间】:2017-10-09 13:20:29
【问题描述】:

我有一组 22 个 5 位值 (0-31),它们作为 110 位打包在一起,形成两个 64 位无符号整数(即最后 18 位始终为零)。我想设计一个函数,对于每个 5 位段,执行绝对值差。

我知道对单个数字使用按位运算符的减法方法,但在这里我不想担心 5 位段之间的溢出。我正在寻找使用按位运算符和/或 x86 汇编操作的解决方案,最好没有任何循环。

编辑:为了澄清,我将有一对这 110 位我想对它们进行差异操作。欢迎提出任何建议。

解决方案:感谢 @EOF 建议 VPSADBW 指令。我将使用 8 位数字来代替更快(更易读)的代码。

【问题讨论】:

  • 你能澄清一下 - 单个值的绝对值差异是多少? (我只知道 两个 值之间的区别。)
  • 它看起来像一个“我的代码”请求。
  • 我怀疑最讨厌的部分将是跨越两个 uint64_ts 的 5 位数字。
  • @EOF 我有一个非常好的方案,但我的 1 正好是 1 位。我在考虑给每个 6 位并使用 1 位进行进位。这样在减法之前我们可以设置所有进位和减法。但这将需要 66 位。我们只有 64 + 1(实际进位)= 65 位。​​
  • @WillCunningham:嗯,x86 上有 [V]PSADBW,它为您提供了uint8_ts 的两个向量之间绝对差的总和。我认为 x86 本身没有绝对差异的指令,但 ARM NEON 有:VABD。在 x86 上,您可能需要两条指令,[V]PSUBB[V]PABSB

标签: c optimization x86 bit-manipulation x86-64


【解决方案1】:

您可以使用 pdep0b000111111000111111... 之类的掩码将 5 位整数分散到 8 位字段中,并使用上面 cmets 中讨论的字节方式 SIMD 内容。

或者,您可以将它们扩展为 6 位字段,并将额外位设置为 1,然后在 64 位字中进行减法,但是您需要找到一些 bit-twiddly 方式以 SWAR 方式完成“abs”部分。不过我怀疑 SIMD 会更快。

请记住,pdep 在 AMD CPU 上的性能很差:吞吐量要差 18

【讨论】:

    【解决方案2】:

    我认为您最好的选择可能是在最近的 x86 CPU 上使用 pdep(并行位存款)指令。您可以使用它快速将 5 位值扩展为 8 位值。一旦它们是 8 位值,您可以执行许多 SSE 指令。

    以下内容采用 rdx:rax 中的 128 位值并输出 xmm1:xmm0,并将这些拆分为字节。

    以下是一些我认为可能对您有用的未经测试的代码:

    mov r8, abs 0x1F1F1F1F1F1F1F1F
    
    pdep rcx, rax, r8
    movq xmm0, rcx
    
    shrd rax, rdx, 16
    shr rax, 40 - 16
    pdep rax, rax, r8
    pinsrq xmm0, rax, 1
    
    shr rdx, 16
    pdep rdx, rdx, r8
    movq xmm1, rdx
    

    逆变换类似,用pext代替pdep

    【讨论】:

    • 谢谢!这将很有用。
    猜你喜欢
    • 1970-01-01
    • 2014-03-02
    • 2018-12-30
    • 1970-01-01
    • 2023-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-03
    相关资源
    最近更新 更多