首页 > 解决方案 > 在 C++ 中获取 uint64_t 的上半部分的指令/内在函数?

问题描述

想象以下代码:

在线尝试!

uint64_t x = 0x81C6E3292A71F955ULL;
uint32_t y = (uint32_t) (x >> 32);

y接收 64 位整数的高 32 位部分。我的问题是是否存在任何内在函数或任何 CPU 指令在单个操作中执行此操作而不进行移动和移位?

至少 CLang(在上面的 Try-it-online 中链接)为此创建了两条指令mov rax, rdishr rax, 32因此 CLang 不进行此类优化,或者不存在此类特殊指令。

如果存在像movhi dst_reg, src_reg.

标签: c++cbit-manipulationintrinsicsinstructions

解决方案


如果有更好的方法来为任意 uint64_t 执行此位域提取,编译器将已经使用它。(至少在理论上;编译器确实错过了优化,他们的选择有时有利于延迟,即使它花费更多的微指令。)

您只需要内在函数来处理无法在纯 C 中有效表达的内容,编译器已经可以轻松理解这些内容。 (或者如果你的编译器很笨,无法发现明显的东西。)

您可能会想象输入值来自两个 32 位值的乘积的情况,那么在某些 CPU 上,编译器可能值得使用扩展mul r32来在两个单独的 32 位寄存器中生成结果,而不是imul r64, r64+ shr reg,32,如果它可以轻松使用 EAX/EDX。但是除了gcc -mtune=silvermont其他调整选项之外,您不能编译器那样做。


shr reg, 32具有 1 个周期延迟,并且可以在大多数现代 x86 微架构 ( https://uops.info/ )上的多个执行端口上运行。唯一可能希望的是它可以将结果放在不同的寄存器中,而不会覆盖输入。

大多数现代非 x86 ISA 都与 RISC 类似,带有 3 操作数指令,因此移位指令可以复制和移位,这与 x86 移位不同,x86 移位中编译器需要 amov以及shr以后还需要原始 64 位值,或(在小函数的情况下)需要不同寄存器中的返回值。

并且一些 ISA 具有位域提取指令。PowerPC 甚至有一个有趣的旋转和掩码指令 ( rlwinm)(掩码是立即数指定的位范围),它是与正常移位不同的指令。编译器将酌情使用它 - 不需要内在的。 https://devblogs.microsoft.com/oldnewthing/20180810-00/?p=99465


带有BMI2rorx rax, rdi, 32的 x86 必须复制和旋转,而不是在同一个寄存器中卡住移位。uint32_t在不内联的独立版本中,返回的函数可以/应该使用它而不是 mov+shr,因为调用者已经必须忽略 RAX 中的高垃圾。(x86-64 System V 和 Windows x64 都将返回值定义为仅与 arg 的 C 类型匹配的寄存器宽度;例如,返回uint32_t意味着 RAX 的高 32 位不是返回值的一部分,可以保存任何内容。通常它们为零,因为写入 32 位寄存器隐式地零扩展为 64,但类似return bar()​​where bar 返回 uint64_t 可以让 RAX 保持不变而不必截断它;事实上,优化的尾调用是可能的。)

没有内在的 for rorx; 编译器应该知道何时使用它。(但 gcc/clang-O3 -march=haswell错过了这个优化。) https://godbolt.org/z/ozjhcc8Te

如果编译器在循环中执行此操作,它可以32在寄存器中shrx reg,reg,reg作为复制和移位。或者更愚蠢的是,它可以用作pext面具0xffffffffULL << 32shrx但由于延迟更高,情况更糟。

AMD TBM(仅限 Bulldozer 系列,而非 Zen)具有bextr(bitfield-extract) 的直接形式,它以 1 uop ( https://agner.org/optimize/ ) 高效运行。 https://godbolt.org/z/bn3rfxzch显示 gcc11 -O3 -march=bdver4(Excavator) uses bextr rax, rdi, 0x2020,而 clang 错过了优化。 gcc -march=znver1使用 mov + shr 因为 Zen 删除了 Trailing Bit Manipulation 以及 XOP 扩展。

标准 BMI1bextr需要寄存器中的位置/长度,而在英特尔 CPU 上是 2 微指令,所以它是垃圾。它确实有内在的,但我建议不要使用它。 mov+shr在 Intel CPU 上更快。


推荐阅读