Optimization 为什么此代码生成的程序集比等效的C++/叮当声? 我编写了一个简单的C++函数来检查编译器优化: bool f1(bool a,bool b){ 返回!a | |(a&b); }

Optimization 为什么此代码生成的程序集比等效的C++/叮当声? 我编写了一个简单的C++函数来检查编译器优化: bool f1(bool a,bool b){ 返回!a | |(a&b); },optimization,rust,llvm-codegen,Optimization,Rust,Llvm Codegen,在那之后,我检查了锈蚀的等效物: fn f1(a: bool, b: bool) -> bool { !a || (a && b) } 我过去经常检查汇编程序的输出 C++代码(由-O3标记为CLAN编译)的结果如下: f1(bool, bool): # @f1(bool, bool) xor dil, 1 or dil, sil mov eax, e

在那之后,我检查了锈蚀的等效物:

fn f1(a: bool, b: bool) -> bool {
    !a || (a && b)
}
我过去经常检查汇编程序的输出

C++代码(由-O3标记为CLAN编译)的结果如下:

f1(bool, bool):                                # @f1(bool, bool)
    xor     dil, 1
    or      dil, sil
    mov     eax, edi
    ret
锈当量的结果要长得多:

example::f1:
  push rbp
  mov rbp, rsp
  mov al, sil
  mov cl, dil
  mov dl, cl
  xor dl, -1
  test dl, 1
  mov byte ptr [rbp - 3], al
  mov byte ptr [rbp - 4], cl
  jne .LBB0_1
  jmp .LBB0_3
.LBB0_1:
  mov byte ptr [rbp - 2], 1
  jmp .LBB0_4
.LBB0_2:
  mov byte ptr [rbp - 2], 0
  jmp .LBB0_4
.LBB0_3:
  mov al, byte ptr [rbp - 4]
  test al, 1
  jne .LBB0_7
  jmp .LBB0_6
.LBB0_4:
  mov al, byte ptr [rbp - 2]
  and al, 1
  movzx eax, al
  pop rbp
  ret
.LBB0_5:
  mov byte ptr [rbp - 1], 1
  jmp .LBB0_8
.LBB0_6:
  mov byte ptr [rbp - 1], 0
  jmp .LBB0_8
.LBB0_7:
  mov al, byte ptr [rbp - 3]
  test al, 1
  jne .LBB0_5
  jmp .LBB0_6
.LBB0_8:
  test byte ptr [rbp - 1], 1
  jne .LBB0_1
  jmp .LBB0_2
我还尝试了
-O
选项,但输出为空(已删除未使用的函数)


我故意不使用任何库来保持输出干净。请注意,
clang
rustc
都使用LLVM作为后端。是什么解释了这种巨大的产出差异?如果它只是禁用了优化开关问题,我如何才能看到来自
rustc
的优化输出?

在godbolt中使用
-C opt level=3
编译时给出:

example::f1:
  push rbp
  mov rbp, rsp
  xor dil, 1
  or dil, sil
  mov eax, edi
  pop rbp
  ret

它看起来与C++版本相当。有关更多解释,请参阅


注意:我必须使函数
pub extern
停止编译器对其进行优化,因为它没有使用。

使用编译器标志
-O
()编译,我得到以下输出():

有几件事:

    <> >强>为什么它仍然比C++版本长?< /强>

    生锈版本正好有三个说明:

    push    rbp
    mov     rbp, rsp
    [...]
    pop     rbp
    
    这些是管理所谓的帧指针或基指针(
    rbp
    )的说明。这主要是为了获得好的堆栈跟踪。如果通过C++ > -fNO省略帧指针< /代码>禁用C++版本。注意,这使用了
    g++
    而不是
    clang++
    ,因为

  • 为什么不忽略帧指针?

    事实上,的确如此。但是Godbolt向编译器添加了一个选项来保留帧指针。您可以阅读更多有关为什么这样做的信息。如果使用
    rustc-O--cratetype=lib foo.rs--emit asm-C“llvm args=-x86 asm syntax=intel”
    在本地编译代码,则会得到以下输出:

    f1:
        xor dil, 1
        or  dil, sil
        mov eax, edi
        ret
    

    这正是C++版本的输出。

    你可以“撤销”Godbolt所做的事情

  • 为什么
    -O
    而不是
    -release

    锁销直接使用
    rustc
    而不是
    货物
    --release
    标志是
    货物的标志。要在
    rustc
    上启用优化,您需要通过
    -O
    -C opt level=3
    (或0和3之间的任何其他级别)


要获得相同的asm代码,需要禁用调试信息-这将删除帧指针


-C opt level=3-C debuginfo=0
()

它不(实际差异比问题中显示的要小得多)。我很惊讶没有人检查C++输出:


是否使用
-O
(在发布模式下)进行编译?@Boiethios是的,但它删除了整个代码(未使用)。使函数
pub-extern
起作用:)哦,所以
-C
就是通过
opt-level
的方式。我尝试了
-O
,但那只是完全删除了
f1
。看起来仍然有一个毫无意义的堆栈框架创建简单
-O
,而不是
选择级别
,也可以工作,但只有当您使函数
发布外部
:)请强调您将
发布
添加到函数签名中的事实。Godbolt产生的空输出没有这个。@jaskmar有。我的意思是为这篇文章的未来读者提供信息,以防止混淆。谢谢
f1:
    xor dil, 1
    or  dil, sil
    mov eax, edi
    ret