You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GCC -O3优化级别下,'%2'与'&1'未生成相同汇编指令的原因探究

Why doesn't GCC optimize x % 2 to x & 1?

First, let's recap the code and assembly you provided to set the context:

Bitwise AND implementation

int main(int argc, char **argv){ return argc & 1; }

Corresponding assembly:

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)

Modulo implementation

int main(int argc, char **argv){ return argc % 2; }

Corresponding assembly:

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

Great question! The core reason GCC doesn't optimize argc % 2 to argc & 1 is that these operations produce different results when argc is negative—and the compiler must strictly adhere to the C standard's rules for integer modulus.

The C Standard Difference

In C, the result of a % b must share the same sign as a. Let's compare for negative values:

  • For an odd negative number like -1:
    • argc & 1 returns 1 (since the least significant bit of any odd two's-complement integer is 1)
    • argc % 2 returns -1 (per C standard, because -1 / 2 truncates to 0, so -1 - (2 * 0) = -1)
  • For an even negative number like -2:
    • argc & 1 returns 0
    • argc % 2 returns 0 (this matches, but the odd case breaks equivalence)

Since the compiler can't assume argc is always non-negative (even though it's rare in practice), it has to generate code that handles negative inputs correctly.

Breaking Down the Modulo Assembly

Let's walk through each instruction in the modulo implementation to see how it enforces the C standard:

  1. mov %edi,%edx: Copies argc (from %edi) into %edx.
  2. shr $0x1f,%edx: Logically shifts %edx right by 31 bits. For a 32-bit integer:
    • Positive argc → result is 0
    • Negative argc → result is 1 (the highest sign bit is isolated)
  3. lea (%rdi,%rdx,1),%eax: Calculates argc + %edx. For negative argc, this is argc + 1; for positive, it's just argc.
  4. and $0x1,%eax: Takes the least significant bit of the previous result—this gives us a value equivalent to (argc + 1) & 1 for negatives, or argc & 1 for positives.
  5. sub %edx,%eax: Subtracts the sign bit. For negative argc, this turns 0 (from step 4 for odd values) into -1, which matches the required modulus result.

Optional: Force the Optimization

If you want GCC to optimize %2 to &1, you can explicitly tell the compiler that argc is non-negative using a built-in assumption:

int main(int argc, char **argv){
    __builtin_assume(argc >= 0);
    return argc % 2;
}

This will generate the same assembly as the bitwise AND version, since GCC now knows it doesn't need to handle negative inputs.

内容的提问来源于stack exchange,提问作者Stypox

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 17:57:46