[[假设]] 属性对代码没有影响

问题描述 投票:0回答:1

我希望下面的

multiply_by_pow_of_2
函数有一个更优化的乘法代码,因为我使用了
[[ assume( std::has_single_bit( multiplier ) ) ]];
,它应该告诉编译器第二个参数
multiplier
始终是2的幂。所以也许它可以生成更快代码。然而它生成相同的代码(使用
imul
):

multiply_by_pow_of_2(unsigned int, unsigned int):
        mov     eax, esi
        imul    eax, edi
        ret

话虽如此,在 main 中调用此函数并将其生成的代码与

argc * 8
的代码进行比较表明,两者都更改为通常的
lea
(而不是类似 左移):

        lea     esi, [0+rdi*8]

这里(直播):

#include <bit>
#include <cstdio>


unsigned multiply_by_pow_of_2( unsigned num, unsigned multiplier ) noexcept
{
    [[ assume( std::has_single_bit( multiplier ) ) ]];
    return num * multiplier;
}

int main( int argc, char* argv[ ] )
{
    unsigned result;

    if constexpr ( true )
    {
        result = multiply_by_pow_of_2( argc, 8 );
    }
    else
    {
        result = argc * 8;
    }

    std::printf( "%d\n", result );
}

给出(使用

-O3
):

multiply_by_pow_of_2(unsigned int, unsigned int):
        mov     eax, esi
        imul    eax, edi
        ret
.LC0:
        .string "%d\n"
main:
        sub     rsp, 8
        lea     esi, [0+rdi*8] ; <- here
        xor     eax, eax
        mov     edi, OFFSET FLAT:.LC0
        call    printf
        xor     eax, eax
        add     rsp, 8
        ret

无论有没有假设语句,函数的代码都保持不变。我是否无法让编译器相信

multiplier
是 2 的幂?这怎么办?

c++ x86-64 compiler-optimization c++23
1个回答
0
投票

首先,乘法指令在当前的 CPU 上速度非常快,因此使用移位而不是乘法不一定会取得很大的胜利。

其次,要用移位代替乘法,仅知道操作数有一个位是不够的 - 您需要知道该位实际放置在哪个位位置(例如 b),以便您可以执行左移移动 b 个位置。如果编译器无法推断出该信息,则需要例如发出计数尾随零指令来查找 b,然后进行移位。这几乎肯定比单纯的乘法更昂贵。

另一方面,如果输入是常量,则编译器可以在编译时计算 b 并发出您所见证的无乘法代码。

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