Does gcc/g++ have flags to enable or disable arithmetic optimisations, e.g. where a+a+...+a
is replaced by n*a
when a
is an integer? In particular, can this be disabled when using -O2
or -O3
?
In the example below even with -O0
the add operations are replaced by a single multiplication:
$ cat add1.cpp
unsigned int multiply_by_22(unsigned int a)
{
return a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a;
}
$ g++ -S -masm=intel -O0 add1.cpp
$ cat add1.s
...
imul eax, edi, 22
Even disabling all the flags used in -O0
(see g++ -c -Q -O0 --help=optimizers | grep enabled
) still produces the imul
operation.
When adding loops, it requires -O1
to simplify the repeated addition to a single multiplication:
$ cat add2.cpp
unsigned int multiply(unsigned int a, unsigned int b)
{
unsigned int sum=0;
for(unsigned int i=0; i<b; i++)
sum += a;
return sum;
}
$ g++ -S -masm=intel -O1 add2.cpp
$ cat add2.s
...
mov eax, 0
.L3:
add eax, 1
cmp esi, eax
jne .L3
imul eax, edi
ret
I.e. -O1
has moved the sum += a;
outside the loop and replaced it by a single multiplication. With -O2
it will also remove the dead loop.
I'm just asking out of interest as I was trying to time some basic integer operations and noticed that the compiler optimised my loops away and I couldn't find any flags to disable this.
I do not know such compiler flag.
Maybe you can try to use volatile
as a substitute:
unsigned int multiply_by_22(volatile unsigned int a)
{
return a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a;
}
with -O0 you get:
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], edi
mov edx, DWORD PTR [rbp-4]
mov eax, DWORD PTR [rbp-4]
add edx, eax
mov eax, DWORD PTR [rbp-4]
add edx, eax
mov eax, DWORD PTR [rbp-4]
add edx, eax
mov eax, DWORD PTR [rbp-4]
add edx, eax
mov eax, DWORD PTR [rbp-4]
add edx, eax
mov eax, DWORD PTR [rbp-4]
add edx, eax
mov eax, DWORD PTR [rbp-4]
add edx, eax
mov eax, DWORD PTR [rbp-4]
add edx, eax
mov eax, DWORD PTR [rbp-4]
add edx, eax
mov eax, DWORD PTR [rbp-4]
add edx, eax
etc...
For -O2 or -O3 generated code, you can visit: https://godbolt.org/z/Bk2b6Z
In the absence of any compiler flags I see only two options to enforce add
:
$ cat fibonacci.cpp
unsigned int fibonacci(unsigned int ops)
{
unsigned int a=1;
unsigned int b=1;
for(unsigned int i=0; i<ops/2; i++) {
a+=b;
b+=a;
}
return b;
}
$ g++ -Wall -S -masm=intel -O3 --unroll-loops fibonacci.cpp
$ cat fibonacci.s
...
.L3:
add edx, eax
add ecx, 8
add eax, edx
add edx, eax
add eax, edx
add edx, eax
add eax, edx
add edx, eax
add eax, edx
add edx, eax
add eax, edx
add edx, eax
add eax, edx
add edx, eax
add eax, edx
add edx, eax
add eax, edx
cmp ecx, edi
jne .L3
add
operations:unsigned int multiply_by_5(unsigned int a)
{
unsigned int sum = 0;
asm ( "# start multiply_by_5\n\t"
"movl %1, %%ebx\n\t" // ebx = a
"movl $0, %%eax\n\t" // eax = 0 (sum = 0)
"addl %%ebx, %%eax\n\t" // eax += ebx (sum+=a)
"addl %%ebx, %%eax\n\t" // eax += ebx (sum+=a)
"addl %%ebx, %%eax\n\t" // eax += ebx (sum+=a)
"addl %%ebx, %%eax\n\t" // eax += ebx (sum+=a)
"addl %%ebx, %%eax\n\t" // eax += ebx (sum+=a)
"movl %%eax, %0\n\t" // sum = eax
"# end multiply_by_5\n"
: "=m" (sum) : "m" (a) : "%eax", "%ebx");
return sum;
}
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