C/C++:“mod 2”不会产生与“and 1”相同的指令(gcc -O3)

Sty*_*pox -1 c assembly gcc compiler-optimization

当使用 gcc 和最大优化(GCC 11.1.0,gcc -std=c11 -O3)编译这两个片段时,我希望获得完全相同的可执行文件,因为%2&1操作是等效的objdump但是,在用 反汇编之后,两个目标文件有所不同。输出如下所示。

int main(int argc, char **argv){
   return argc & 1;
}
Run Code Online (Sandbox Code Playgroud)
0000000000001020 <main>:
    1020:       89 f8                   mov    %edi,%eax
    1022:       83 e0 01                and    $0x1,%eax
    1025:       c3                      ret    
    1026:       66 2e 0f 1f 84 00 00    cs nopw 0x0(%rax,%rax,1) 
Run Code Online (Sandbox Code Playgroud)

模数

0000000000001020 <main>:
    1020:       89 f8                   mov    %edi,%eax
    1022:       83 e0 01                and    $0x1,%eax
    1025:       c3                      ret    
    1026:       66 2e 0f 1f 84 00 00    cs nopw 0x0(%rax,%rax,1) 
Run Code Online (Sandbox Code Playgroud)
0000000000001020 <main>:
    1020:       89 fa                   mov    %edi,%edx
    1022:       c1 ea 1f                shr    $0x1f,%edx
    1025:       8d 04 17                lea    (%rdi,%rdx,1),%eax
    1028:       83 e0 01                and    $0x1,%eax
    102b:       29 d0                   sub    %edx,%eax
    102d:       c3                      ret    
    102e:       66 90                   xchg   %ax,%ax
Run Code Online (Sandbox Code Playgroud)

我理解第一个程序中的说明,但我不太明白第二个程序的某些行的目的。

  • shr $0x1f,%edx应该表示“右移 31 位%edx
  • lea (%rdi,%rdx,1),%eax应该意味着“保存在%eax地址中保存的值%rdi + %rdx * 1

为什么这两个程序不同?为什么编译器不优化%2&1,据说它更快并且使用更少的指令?

P__*_*J__ 5

val % 2如果val为负,则可能具有负值。val & 1将只有一个正值(或零)。所以这些操作并不相同——因此不同的编译代码。