I thought since condition is a >= 3, we should use jl
(less).
But gcc used jle
(less or equal).
It make no sense to me; why did the compiler do this?
I thought since condition is a >= 3, we should use jl
(less).
But gcc used jle
(less or equal).
It make no sense to me; why did the compiler do this?
You're getting mixed up by a transformation the compiler made on the way from the C source to the asm implementation. gcc's output implements your function this way:
a = 5;
if (a<=2) goto ret0;
return 1;
ret0:
return 0;
It's all clunky and redundant because you compiled with -O0
, so it stores a
to memory and then reloads it, so you could modify it with a debugger if you set a breakpoint and still have the code "work".
See also How to remove "noise" from GCC/clang assembly output?
Compilers generally prefer to reduce the magnitude of a comparison constant, so it's more likely to fit in a sign-extended 8-bit immediate instead of needing a 32-bit immediate in the machine code.
We can get some nice compact code by writing a function that takes an arg, so it won't optimize away when we enable optimizations.
int cmp(int a) {
return a>=128; // In C, a boolean converts to int as 0 or 1
}
gcc -O3
on Godbolt, targetting the x86-64 ABI (same as your code):
xorl %eax, %eax # whole RAX = 0
cmpl $127, %edi
setg %al # al = (edi>127) : 1 : 0
ret
So it transformed a >=128
into a >127
comparison. This saves 3 bytes of machine code, because cmp $127, %edi
can use the cmp $imm8, r/m32
encoding (cmp r/m32, imm8
in Intel syntax in Intel's manual), but 128 would have to use cmp $imm32, r/m32
.
BTW, comparisons and conditions make sense in Intel syntax, but are backwards in AT&T syntax. For example, cmp edi, 127
/ jg
is taken if edi > 127
.
But in AT&T syntax, it's cmp $127, %edi
, so you have to mentally reverse the operands or think of a >
instead of <