在UINT64到双转换上:为什么右移动后的代码更简单1?

发布于 2025-02-13 05:07:30 字数 857 浏览 1 评论 0原文

为什么asdouble1asdouble0要简单得多?

// AsDouble0(unsigned long):                          # @AsDouble0(unsigned long)
//         movq    xmm1, rdi
//         punpckldq       xmm1, xmmword ptr [rip + .LCPI0_0] # xmm1 = xmm1[0],mem[0],xmm1[1],mem[1]
//         subpd   xmm1, xmmword ptr [rip + .LCPI0_1]
//         movapd  xmm0, xmm1
//         unpckhpd        xmm0, xmm1                      # xmm0 = xmm0[1],xmm1[1]
//         addsd   xmm0, xmm1
//         addsd   xmm0, xmm0
//         ret
double AsDouble0(uint64_t x) { return x * 2.0; }

// AsDouble1(unsigned long):                          # @AsDouble1(unsigned long)
//         shr     rdi
//         cvtsi2sd        xmm0, rdi
//         addsd   xmm0, xmm0
//         ret
double AsDouble1(uint64_t x) { return (x >> 1) * 2.0; }

代码可在:

Why is AsDouble1 much more straightforward than AsDouble0?

// AsDouble0(unsigned long):                          # @AsDouble0(unsigned long)
//         movq    xmm1, rdi
//         punpckldq       xmm1, xmmword ptr [rip + .LCPI0_0] # xmm1 = xmm1[0],mem[0],xmm1[1],mem[1]
//         subpd   xmm1, xmmword ptr [rip + .LCPI0_1]
//         movapd  xmm0, xmm1
//         unpckhpd        xmm0, xmm1                      # xmm0 = xmm0[1],xmm1[1]
//         addsd   xmm0, xmm1
//         addsd   xmm0, xmm0
//         ret
double AsDouble0(uint64_t x) { return x * 2.0; }

// AsDouble1(unsigned long):                          # @AsDouble1(unsigned long)
//         shr     rdi
//         cvtsi2sd        xmm0, rdi
//         addsd   xmm0, xmm0
//         ret
double AsDouble1(uint64_t x) { return (x >> 1) * 2.0; }

Code available at: https://godbolt.org/z/dKc6Pe6M1

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

各自安好 2025-02-20 05:07:30

X86具有在签名的整数和浮子之间转换的指令。未签名的整数转换是AVX512支持的(我认为),大多数编译器默认情况下不假定。如果您向右移动uint64_t一次,则符号位消失,因此您可以将其解释为签名的整数并具有相同的结果。

x86 has an instruction to convert between signed integers and floats. Unsigned integer conversion is (I think) supported by AVX512, which most compilers don't assume by default. If you shift right a uint64_t once, the sign bit is gone, so you can interpret it as a signed integer and have the same result.

南风几经秋 2025-02-20 05:07:30

cvtsi2sd指令作为其源操作数A 签名 Integer(32-或64位宽)。但是,您的功能采用 unsigned 参数。

因此,在第一种情况下,编译器不能直接使用cvtsi2sd指令,因为给定参数中的值可能无法表示为同一尺寸的签名整数 - 因此它会生成执行转换的代码到double“漫长的路”(但安全)。

但是,在您的第二个功能中,最初的右移动保证符号将是清楚的;因此,无论是将其解释为签名还是未签名,结果值将是相同的……因此,编译器可以安全地将其(修改)值作为cvtsi2sd操作的源。

The cvtsi2sd instruction takes, as its source operand, a signed integer (either 32- or 64-bits wide). However, your functions take unsigned arguments.

Thus, in the first case, the compiler cannot directly use the cvtsi2sd instruction, because the value in the given argument may not be representable as a same-size signed integer – so it generates code that does the conversion to double the "long way" (but safely).

However, in your second function, the initial right shift by one bit guarantees that the sign bit will be clear; thus, the resultant value will be identical, whether it is interpreted as signed or unsigned … so the compiler can safely use that (modified) value as the source for the cvtsi2sd operation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文