C/C++:"mod 2" 不会产生与 "and 1" 相同的指令 (gcc -O3)
C/C++: "mod 2" not resulting in the same instructions as "and 1" (gcc -O3)
在使用 gcc 和最大优化(GCC 11.1.0,gcc -std=c11 -O3
)编译这两个片段时,我希望获得完全相同的相同的可执行文件,因为 %2
和 &1
运算 等价 。但是,在使用 objdump
进行反汇编后,这两个目标文件有所不同。输出如下所示。
和
int main(int argc, char **argv){
return argc & 1;
}
0000000000001020 <main>:
1020: 89 f8 mov %edi,%eax
1022: 83 e0 01 and [=14=]x1,%eax
1025: c3 ret
1026: 66 2e 0f 1f 84 00 00 cs nopw 0x0(%rax,%rax,1)
模数
int main(int argc, char **argv){
return argc % 2;
}
0000000000001020 <main>:
1020: 89 fa mov %edi,%edx
1022: c1 ea 1f shr [=16=]x1f,%edx
1025: 8d 04 17 lea (%rdi,%rdx,1),%eax
1028: 83 e0 01 and [=16=]x1,%eax
102b: 29 d0 sub %edx,%eax
102d: c3 ret
102e: 66 90 xchg %ax,%ax
我理解第一个程序中的指令,但我不太明白第二个程序中某些行的目的。
shr [=21=]x1f,%edx
应该表示“右移 %edx
的 31 位”
lea (%rdi,%rdx,1),%eax
应该表示“保存在 %eax
地址 %rdi + %rdx * 1
保存的值”
为什么这两个程序不同?为什么编译器不将 %2
优化为 &1
,这应该更快并且使用更少的指令?
如果 val
为负,val % 2
可能有负值。 val & 1
将只有一个正值(或零)。所以这些操作不相同 - 因此编译代码不同。
在使用 gcc 和最大优化(GCC 11.1.0,gcc -std=c11 -O3
)编译这两个片段时,我希望获得完全相同的相同的可执行文件,因为 %2
和 &1
运算 等价 。但是,在使用 objdump
进行反汇编后,这两个目标文件有所不同。输出如下所示。
和
int main(int argc, char **argv){
return argc & 1;
}
0000000000001020 <main>:
1020: 89 f8 mov %edi,%eax
1022: 83 e0 01 and [=14=]x1,%eax
1025: c3 ret
1026: 66 2e 0f 1f 84 00 00 cs nopw 0x0(%rax,%rax,1)
模数
int main(int argc, char **argv){
return argc % 2;
}
0000000000001020 <main>:
1020: 89 fa mov %edi,%edx
1022: c1 ea 1f shr [=16=]x1f,%edx
1025: 8d 04 17 lea (%rdi,%rdx,1),%eax
1028: 83 e0 01 and [=16=]x1,%eax
102b: 29 d0 sub %edx,%eax
102d: c3 ret
102e: 66 90 xchg %ax,%ax
我理解第一个程序中的指令,但我不太明白第二个程序中某些行的目的。
shr [=21=]x1f,%edx
应该表示“右移%edx
的 31 位”lea (%rdi,%rdx,1),%eax
应该表示“保存在%eax
地址%rdi + %rdx * 1
保存的值”
为什么这两个程序不同?为什么编译器不将 %2
优化为 &1
,这应该更快并且使用更少的指令?
val
为负,val % 2
可能有负值。 val & 1
将只有一个正值(或零)。所以这些操作不相同 - 因此编译代码不同。