C 为什么这个表达式本身比它的一个组件快?

C 为什么这个表达式本身比它的一个组件快?,c,performance,gcc,C,Performance,Gcc,为什么三个变量都是整数的(i&1)|((i&mostSig)?onesComp:0),在GCC上编译时比i&1本身更快 第一个表达式显然必须计算i&1,然后用((i&shift)?one或two:0)计算它,因此我希望它比i%2快,但比i&1慢,而在Clang(3.8及更新版本)上则慢:(我的是(i&shift)|((i&mostSig)

为什么三个变量都是整数的
(i&1)|((i&mostSig)?onesComp:0)
,在GCC上编译时比
i&1
本身更快

第一个表达式显然必须计算
i&1
,然后用
((i&shift)?one或two:0)计算它,因此我希望它比
i%2
快,但比
i&1
慢,而在Clang(3.8及更新版本)上则慢:(我的是
(i&shift)|((i&mostSig)i&1
(因为它会破坏一个使用补码的系统)和天真的
i%2

但是在GCC(5.5-8.1)中,我的表达式比其他两个表达式都没有优化:(如上所述)

第一个表达式的完整代码为:

  int i = -3;                                // Number to test
  int onesComp = !((-1) & 1);                // Check if machine uses One's complement
  int mostSig = 1<<(sizeof(i)*8-1);          // Represents the most significant bit (Should be unsigned, but serves for demonstration) 
  int odd = (i&1) | ((i&mostSig)?onesComp:0);// The bit being benchmarked
这是针对
i&1

   push   %rbp
   mov    %rsp,%rbp
   sub    $0x90,%rsp
   mov    %rdi,-0x88(%rbp)
   movl   $0x0,-0x54(%rbp)
   movl   $0xfffffffd,-0x4(%rbp)
   mov    -0x88(%rbp),%rax
   mov    %rax,-0x10(%rbp)
   mov    -0x10(%rbp),%rax
   mov    %rax,-0x20(%rbp)
   mov    -0x20(%rbp),%rax
   mov    %rax,-0x28(%rbp)
   mov    -0x28(%rbp),%rax
   movzbl 0x3c(%rax),%eax
   test   %al,%al
   je     4076e4 <broken(benchmark::State&)+0x4e>
   mov    $0x0,%eax
   jmp    4076ec <broken(benchmark::State&)+0x56>
   mov    -0x28(%rbp),%rax
   mov    0x78(%rax),%rax
   mov    %rax,-0x40(%rbp)
   mov    -0x28(%rbp),%rax
   mov    %rax,-0x38(%rbp)
   mov    -0x40(%rbp),%rax
   mov    -0x38(%rbp),%rdx
   mov    %rax,-0x70(%rbp)
   mov    %rdx,-0x68(%rbp)
   mov    -0x10(%rbp),%rax
   mov    %rax,-0x18(%rbp)
   mov    -0x18(%rbp),%rax
   mov    %rax,%rdi
   callq  416b60 <benchmark::State::StartKeepRunning()>
   movq   $0x0,-0x50(%rbp)
   movq   $0x0,-0x48(%rbp)
   mov    -0x50(%rbp),%rax
   mov    -0x48(%rbp),%rdx
   mov    %rax,-0x80(%rbp)
   mov    %rdx,-0x78(%rbp)
   mov    -0x70(%rbp),%rax
   test   %rax,%rax
   setne  %al
   movzbl %al,%eax
   test   %rax,%rax
   je     407755 <broken(benchmark::State&)+0xbf>
   mov    $0x1,%eax
   jmp    407766 <broken(benchmark::State&)+0xd0>
   mov    -0x68(%rbp),%rax
   mov    %rax,%rdi
   callq  4168e0 <benchmark::State::FinishKeepRunning()>
   mov    $0x0,%eax
   test   %al,%al
   je     4077ae <broken(benchmark::State&)+0x118>
   mov    -0x4(%rbp),%eax
   and    $0x1,%eax
   mov    %eax,-0x54(%rbp)
   mov    -0x54(%rbp),%eax
   mov    -0x70(%rbp),%rax
   test   %rax,%rax
   jne    407798 <broken(benchmark::State&)+0x102>
   mov    $0x426ca0,%ecx
   mov    $0x274,%edx
   mov    $0x426c40,%esi
   mov    $0x426c69,%edi
   callq  404240 <__assert_fail@plt>
   mov    -0x70(%rbp),%rax
   sub    $0x1,%rax
   mov    %rax,-0x70(%rbp)
   jmp    40773c <broken(benchmark::State&)+0xa6>
   mov    %rax,%rdi
   callq  404790 <_Unwind_Resume@plt>
   nop
   leaveq 
   retq   
推送%rbp
mov%rsp,%rbp
低于$0x90,%rsp
mov%rdi,-0x88(%rbp)
movl$0x0,-0x54(%rbp)
movl$0xFFFFFD,-0x4(%rbp)
mov-0x88(%rbp),%rax
mov%rax,-0x10(%rbp)
mov-0x10(%rbp),%rax
mov%rax,-0x20(%rbp)
mov-0x20(%rbp),%rax
mov%rax,-0x28(%rbp)
mov-0x28(%rbp),%rax
movzbl 0x3c(%rax),%eax
测试%al,%al
je 4076e4
mov$0x0,%eax
JMP4076EC
mov-0x28(%rbp),%rax
mov 0x78(%rax),%rax
mov%rax,-0x40(%rbp)
mov-0x28(%rbp),%rax
mov%rax,-0x38(%rbp)
mov-0x40(%rbp),%rax
mov-0x38(%rbp),%rdx
mov%rax,-0x70(%rbp)
mov%rdx,-0x68(%rbp)
mov-0x10(%rbp),%rax
mov%rax,-0x18(%rbp)
mov-0x18(%rbp),%rax
mov%rax,%rdi
callq 416b60
movq$0x0,-0x50(%rbp)
movq$0x0,-0x48(%rbp)
mov-0x50(%rbp),%rax
mov-0x48(%rbp),%rdx
mov%rax,-0x80(%rbp)
mov%rdx,-0x78(%rbp)
mov-0x70(%rbp),%rax
测试%rax,%rax
setne%al
movzbl%al,%eax
测试%rax,%rax
je 407755
mov$0x1,%eax
jmp 407766
mov-0x68(%rbp),%rax
mov%rax,%rdi
callq 4168e0
mov$0x0,%eax
测试%al,%al
日本脑炎4077ae
mov-0x4(%rbp),%eax
和$0x1,%eax
mov%eax,-0x54(%rbp)
mov-0x54(%rbp),%eax
mov-0x70(%rbp),%rax
测试%rax,%rax
jne 407798
mov$0x426ca0,%ecx
mov$0x274,%edx
mov$0x426c40,%esi
mov$0x426c69,%edi
callq 404240
mov-0x70(%rbp),%rax
低于$0x1,%rax
mov%rax,-0x70(%rbp)
jmp 40773c
mov%rax,%rdi
callq 404790
不
利沃克
retq

评论不是为了进行深入讨论;本次对话一直是。您为什么对此感兴趣?差异非常小。根本没有必要找出导致未优化版本中1.5%差异的原因。可能是任何原因。如跳转地址未正确对齐等。我们唯一能说的是,发出叮当声s
idiv
用于naive情况,而gcc没有,这导致naive情况下的差异更大。顺便说一句,我很好奇,现在哪个平台没有两个补码整数?
   push   %rbp
   mov    %rsp,%rbp
   sub    $0x90,%rsp
   mov    %rdi,-0x88(%rbp)
   movl   $0x0,-0x54(%rbp)
   movl   $0xfffffffd,-0x4(%rbp)
   mov    -0x88(%rbp),%rax
   mov    %rax,-0x10(%rbp)
   mov    -0x10(%rbp),%rax
   mov    %rax,-0x20(%rbp)
   mov    -0x20(%rbp),%rax
   mov    %rax,-0x28(%rbp)
   mov    -0x28(%rbp),%rax
   movzbl 0x3c(%rax),%eax
   test   %al,%al
   je     4076e4 <broken(benchmark::State&)+0x4e>
   mov    $0x0,%eax
   jmp    4076ec <broken(benchmark::State&)+0x56>
   mov    -0x28(%rbp),%rax
   mov    0x78(%rax),%rax
   mov    %rax,-0x40(%rbp)
   mov    -0x28(%rbp),%rax
   mov    %rax,-0x38(%rbp)
   mov    -0x40(%rbp),%rax
   mov    -0x38(%rbp),%rdx
   mov    %rax,-0x70(%rbp)
   mov    %rdx,-0x68(%rbp)
   mov    -0x10(%rbp),%rax
   mov    %rax,-0x18(%rbp)
   mov    -0x18(%rbp),%rax
   mov    %rax,%rdi
   callq  416b60 <benchmark::State::StartKeepRunning()>
   movq   $0x0,-0x50(%rbp)
   movq   $0x0,-0x48(%rbp)
   mov    -0x50(%rbp),%rax
   mov    -0x48(%rbp),%rdx
   mov    %rax,-0x80(%rbp)
   mov    %rdx,-0x78(%rbp)
   mov    -0x70(%rbp),%rax
   test   %rax,%rax
   setne  %al
   movzbl %al,%eax
   test   %rax,%rax
   je     407755 <broken(benchmark::State&)+0xbf>
   mov    $0x1,%eax
   jmp    407766 <broken(benchmark::State&)+0xd0>
   mov    -0x68(%rbp),%rax
   mov    %rax,%rdi
   callq  4168e0 <benchmark::State::FinishKeepRunning()>
   mov    $0x0,%eax
   test   %al,%al
   je     4077ae <broken(benchmark::State&)+0x118>
   mov    -0x4(%rbp),%eax
   and    $0x1,%eax
   mov    %eax,-0x54(%rbp)
   mov    -0x54(%rbp),%eax
   mov    -0x70(%rbp),%rax
   test   %rax,%rax
   jne    407798 <broken(benchmark::State&)+0x102>
   mov    $0x426ca0,%ecx
   mov    $0x274,%edx
   mov    $0x426c40,%esi
   mov    $0x426c69,%edi
   callq  404240 <__assert_fail@plt>
   mov    -0x70(%rbp),%rax
   sub    $0x1,%rax
   mov    %rax,-0x70(%rbp)
   jmp    40773c <broken(benchmark::State&)+0xa6>
   mov    %rax,%rdi
   callq  404790 <_Unwind_Resume@plt>
   nop
   leaveq 
   retq