Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

gcc flags to disable arithmetic optimisations

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.

like image 675
user1059432 Avatar asked Dec 08 '19 20:12

user1059432


2 Answers

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

like image 154
Picaud Vincent Avatar answered Oct 31 '22 11:10

Picaud Vincent


In the absence of any compiler flags I see only two options to enforce add:

  • Write a more complex series of additions the compiler can't optimise away, e.g. Fibbonaci series (although this will overrun quickly):
$ 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
  • Write an assembly routine which emits 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;
}
like image 21
user1059432 Avatar answered Oct 31 '22 10:10

user1059432