为什么生成不同的汇编代码?哪个更好?

问题描述 投票:0回答:2
#include <cstdint>

uint64_t hr1(const uint64_t x, const bool a, const int n) noexcept
{
    if (a) {
        return x | (a << n);
    }
    return x;
}

uint64_t hr2(const uint64_t x, const bool a, const int n)
{
    return x | ((a ? 1ull : 0) << n);
}

https://godbolt.org/z/gy_65H

hr1(unsigned long, bool, int):
  mov rax, rdi
  test sil, sil
  jne .L4
  ret
.L4:
  mov ecx, edx
  mov esi, 1
  sal esi, cl
  movsx rsi, esi
  or rax, rsi
  ret
hr2(unsigned long, bool, int):
  mov ecx, edx
  movzx esi, sil
  sal rsi, cl
  mov rax, rsi
  or rax, rdi
  ret

为什么clang和gcc无法将第一个功能优化为第二个功能?

c++ assembly optimization
2个回答
0
投票

这些功能没有相同的行为。特别是在第一个中,a将经历整数提升为int中的a << n,因此如果n >= std::numeric_limits<int>::digits(通常为31),则移位将具有不确定的行为。

[在第二个函数中不是这样,其中a ? 1ull : 0将导致产生unsigned long long的通用类型,因此该移位将为所有值n < std::numeric_limits<unsigned long long>::digits(通常为64)定义了明确定义的行为可能大于std::numeric_limits<int>::digits(通常为31)。

您应在两个移位中都将a1强制转换为uint64_t,以使代码在所有明智的输入(即n < 64)中表现良好。


0
投票

这些功能没有相同的行为。特别是在第一个a中,整数将升为int中的a << n,因此,如果n >= std::numeric_limits<int>::digits,则该函数将具有未定义的行为。

[在第二个函数中不是这种情况,它将对所有可能大于n < std::numeric_limits<unsigned long long>::digits(通常为32)的值n >= std::numeric_limits<int>::digits(通常为64)具有明确定义的行为。

© www.soinside.com 2019 - 2024. All rights reserved.