Опция GCC -march=native
Почему в некоторых случаях применение опции -march=native замедляет код, генерируемый GCC?
Вот среднее время работы разных бинарников кода ниже, скомпилированных с разными опциями на моей машине (GCC 10.2.0, Clang 9.0.1, Ryzen 3 3200U):
gcc -O2 0.125 0.088
gcc -Ofast 0.125 0.089
gcc -O2 -march=native 0.126 0.090
gcc -Ofast -march=native 0.187 0.127
clang -O2 0.120 0.081
clang -Ofast 0.116 0.081
clang -O2 -march=native 0.131 0.094
clang -Ofast -march=native 0.084 0.096
Листинг gcc -O2:
Dump of assembler code for function char_bench:
0x0000000000001230 <+0>: push r12
0x0000000000001232 <+2>: push rbp
0x0000000000001233 <+3>: mov rbp,rsi
0x0000000000001236 <+6>: push rbx
0x0000000000001237 <+7>: mov rbx,rdi
0x000000000000123a <+10>: call 0x1030 <clock@plt>
0x000000000000123f <+15>: mov r12,rax
0x0000000000001242 <+18>: xor eax,eax
0x0000000000001244 <+20>: nop DWORD PTR [rax+0x0]
0x0000000000001248 <+24>: cmp BYTE PTR [rbx+rax*1],0x0
0x000000000000124c <+28>: je 0x1253 <char_bench+35>
0x000000000000124e <+30>: mov BYTE PTR [rbp+rax*1+0x0],0x1
0x0000000000001253 <+35>: add rax,0x1
0x0000000000001257 <+39>: cmp rax,0xbebc200
0x000000000000125d <+45>: jne 0x1248 <char_bench+24>
0x000000000000125f <+47>: call 0x1030 <clock@plt>
0x0000000000001264 <+52>: pop rbx
0x0000000000001265 <+53>: pop rbp
0x0000000000001266 <+54>: sub rax,r12
0x0000000000001269 <+57>: pop r12
0x000000000000126b <+59>: ret
End of assembler dump.
Листинг gcc -Ofast -march=native:
Dump of assembler code for function char_bench:
0x0000000000001250 <+0>: push r12
0x0000000000001252 <+2>: push rbp
0x0000000000001253 <+3>: mov rbp,rsi
0x0000000000001256 <+6>: push rbx
0x0000000000001257 <+7>: mov rbx,rdi
0x000000000000125a <+10>: call 0x1030 <clock@plt>
0x000000000000125f <+15>: mov r12,rax
0x0000000000001262 <+18>: xor eax,eax
0x0000000000001264 <+20>: data16 nop WORD PTR cs:[rax+rax*1+0x0]
0x000000000000126f <+31>: nop
0x0000000000001270 <+32>: cmp BYTE PTR [rbx+rax*1],0x0
0x0000000000001274 <+36>: je 0x127b <char_bench+43>
0x0000000000001276 <+38>: mov BYTE PTR [rbp+rax*1+0x0],0x1
0x000000000000127b <+43>: inc rax
0x000000000000127e <+46>: cmp rax,0xbebc200
0x0000000000001284 <+52>: jne 0x1270 <char_bench+32>
0x0000000000001286 <+54>: call 0x1030 <clock@plt>
0x000000000000128b <+59>: pop rbx
0x000000000000128c <+60>: sub rax,r12
0x000000000000128f <+63>: pop rbp
0x0000000000001290 <+64>: pop r12
0x0000000000001292 <+66>: ret
End of assembler dump.
#include <stdio.h>
#include <time.h>
#define SIZE 200000000
char C1[SIZE];
char C2[SIZE];
clock_t char_bench(char * const source, char * const dest)
{
clock_t start = clock();
for(size_t i = 0; i < SIZE; ++i)
if(source[i])
dest[i] = 1;
clock_t end = clock();
return end - start;
}
int main()
{
for(size_t i = 0; i < SIZE; ++i)
{
C1[i] = 0;
C2[i] = 0;
}
printf("%.3lf\n", char_bench(C1, C2) / (float)CLOCKS_PER_SEC);
for(size_t i = 0; i < SIZE; ++i)
{
C1[i] = 1;
C2[i] = 1;
}
printf("%.3lf\n", char_bench(C1, C2) / (float)CLOCKS_PER_SEC);
return 0;
}
Понимаю, что бенчмарк синтетический, но разница во времени выполнения всё же удручает.