GCC додає дивні тимчасові змінні

Я створив цей код:

#include 

typedef unsigned int uint;
uint in[2]={1,2},out[2]={3,4};

int main() {

    in[0]=out[0]/10;
}

і компілював його з GCC (v4.4.5, без оптимізації) на Linux, в результаті чого:

0000000000400474 
: 400474: 55 push rbp 400475: 48 89 e5 mov rbp,rsp 400478: 8b 05 ae 03 20 00 mov eax,DWORD PTR [rip+0x2003ae] # 0082c 40047e: 89 45 fc mov DWORD PTR [rbp-0x4],eax 400481: ba cd cc cc cc mov edx,0xcccccccd 400486: 8b 45 fc mov eax,DWORD PTR [rbp-0x4] 400489: f7 e2 mul edx 40048b: 89 d0 mov eax,edx 40048d: c1 e8 03 shr eax,0x3 400490: 89 05 8e 03 20 00 mov DWORD PTR [rip+0x20038e],eax # 600824 400496: c9 leave 400497: c3 ret 400498: 90 nop 400499: 90 nop 40049a: 90 nop 40049b: 90 nop 40049c: 90 nop 40049d: 90 nop 40049e: 90 nop 40049f: 90 nop

Тепер питання: що робить цей код на рядку №5?

40047e:       89 45 fc                mov    DWORD PTR [rbp-0x4],eax

це не зберігає значення, яке він отримав з [0] знову в якомусь місці в пам'яті? Чому так? Я не сказав їй, щоб читати і писати негайно до певного місця.

Тепер ця тимчасова змінна знову з'являється за адресою 400486 у рядку # 7:

400486:       8b 45 fc                mov    eax,DWORD PTR [rbp-0x4]

Схоже, що в цьому прикладі GCC виробляє дуже неефективний код, і він вилучає лінію кешу через цих тимчасових сховищ. Будь ласка, підтвердьте, можливо, є щось, чого я не отримую.

0
Стек не є rbp-0x4 ? Раніше він mov rbp, rsp .
додано Автор K-ballo, джерело
Ну, ви не сказали жодної оптимізації.
додано Автор Fred Larson, джерело
Звичайно, він виробляє неефективний код; Ви сказали йому не оптимізувати.
додано Автор Dave, джерело
Він просто зберігає і відновлює значення % eax зі стека. Ваші масиви знаходяться на % ebx + 0x20038e .
додано Автор Alexandre C., джерело

1 Відповіді

GCC робить дуже неефективний код при компіляції на -O0 - те, що ви бачите, є в основному сирим перекладом його внутрішнього представлення програми. Це внутрішнє уявлення містить ряд тимчасових змінних, і ваша пара завантаження/зберігання - це значення, яке проходить через таке тимчасове. На більш високих рівнях оптимізації такі види непридатних навантажень/магазинів будуть в основному усунені; однак на -O0 вимкнено навіть найпростіший аналіз.

5
додано
спасибі я отримав. Я думав, що оригінальний код, згенерований GCC, буде робити те, про що він сказав, навіть з -O0, не зберігаючи і відновлюючи значення реєстру.
додано Автор Nulik, джерело
@Neil: GCC має кілька різних проміжних представлень: GIMPLE, SSA, RTL, ... Звичайно, форма SSA створює навантаження тимчасових змінних.
додано Автор ninjalj, джерело
Я вважаю, що його ІС повинна бути машиною на основі стека; Я додав return argc; і скопіював argc до стека, перш ніж повернути його. (Я також спробував змінити в і з простих змінних, і він скопіював (1 << 32) * 0.8 в стек.) Порівняння навіть при /Od MSVC компілятор зазвичай видає mov eax, _out xor edx, edx mov ecx, 10 div ecx mov _in , eax . (Він використовує mul на /O2 .)
додано Автор Neil, джерело