While Learning compiler Optimisation, I write codes in C
under Linux
with GCC
version gcc version 4.4.5 (Ubuntu/Linaro 4.4.4-14ubuntu5.1)
To understant not a statement
(nop) in C. I written two codes first y.c
second x.c
and generate their compiled assembly code
using gcc -S
option.
Fist code y.c
desktop:~$ cat y.c
main()
{
int i=0;
}
desktop:~$ gcc -S y.c
desktop:~$
Second code x.c
desktop:~$ cat x.c
main()
{
int i=0;
/* Loops and if*/
while(0);
for(;0;);
if(0);
/* Arithmetic Operations */
i * i;
i / i;
i - i;
i + i;
i % i;
+i;
-i;
/* Comparison operators */
i == i;
i != i;
i < i;
i > i;
i >= i;
i <= i;
/* Bitwise Operations*/
i ^ i;
i | i;
i & i;
~i;
i << i;
i >> i;
/* Address Operatins*/
&i;
*(&i);
(&i)[i];
/* Ternary conditional operation*/
i? i : i;
/* Other Operations*/
sizeof(i);
(char)i;
/* Not-Logical Operation*/
!i;
/* Logical AND , OR Operators */
// i && i; // Commented && operation
// i || i; // Commented || operation
}
desktop:~$ gcc -S x.c
NOTICE: This time Last two lines in x.c
are commented.
And as I was expecting. There is no difference in their generated assembly codes. I compared x.s
and y.s
using diff
command.
desktop:~$ diff x.s y.s
1c1
< .file "x.c"
---
> .file "y.c"
desktop:~$
But When I uncomment last(or say add) two lines in x.c
.
i && i;
i || i;
Again compile x.c with -S option and compared with y.s.
desktop:~$ tail x.c
sizeof(i);
(char)i;
/* Not-Logical Operation*/
!i;
/* Logical AND , OR Operators */
i && i; // unCommented && operation
i || i; // unCommented || operation
}
desktop:~$ gcc -S x.c
desktop:~$ diff x.s y.s
1c1
< .file "x.c"
---
> .file "y.c"
10,21d9
< movl -4(%ebp), %eax
< testl %eax, %eax
< je .L3
< movl -4(%ebp), %eax
< testl %eax, %eax
< .L3:
< movl -4(%ebp), %eax
< testl %eax, %eax
< jne .L8
< movl -4(%ebp), %eax
< testl %eax, %eax
< .L8:
desktop:~$
Question:
I just can not understand why expressions i || i
and i && i
are not equivalent to 'not a statement'
?
Why compiler transfer this two statements into executable( we can disassemble with objdump
will get same code). What is special in this two expression. they do not includes =
operation.
Does they change (set/reset) CPU flag-registers ? I guess no!
Even /
division operation discarded that may cause an divided by zero fault.
EDIT : Added answer
There is nothing special in i || i
and i && i
expressions. Both are equivalent to
NOT A STATEMENT. And can be removed by GCC compiler
with some extra effort.
To remove this: -o2
and -o3
flags are useful:
Here is my Try!!
desktop:~$ gcc -o2 -S y.c
desktop:~$ gcc -o2 -S x.c
desktop:~$ diff x.s y.s -y
.file "x.c" | .file "y.c"
.text .text
.p2align 4,,15 <
.globl main .globl main
.type main, @function .type main, @function
main: main:
pushl %ebp pushl %ebp
movl %esp, %ebp movl %esp, %ebp
popl %ebp | subl $16, %esp
> movl $0, -4(%ebp)
> leave
The extra lines in at RHS are because of misalignment between files.
I also like to add information that JAVA
and C#
compilers discard this expressions without any flags.
Enable optimizations using -O2
, and you should see the extra code disappear.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With