Kompilator generuje takiego assemblera, że traktuje jako consta 1/2 pierwsze wyrażenie i zaokrągla w dół, czyli masz 1/2, to 0.5 zaokraglone w dół przy castowaniu na inta czyli wartość 0 w tym przypadku i zapisuje tą wartość w .rodata, jest to wykonane w czasie kompilacji.
To oznacza, że jak uruchomisz program to już nie jest liczona ta stała.
Jak by to był float to w czasie kompilacji kompilator w .rodata ustawiłby wartość floata jako stałą.
Czyli zamiast literałów intowskich 1, 2, 3. to trzeba floatowe 1.0, 2.5, 3.0.
Wtedy stała odłożona do .rodata będzie floatem, gdyż uda wtedy się kompilatorowi typ wydedukować na podstawie literału.
A jako, że jest zero, to w tym przypadku kompilator pxor xmm0, xmm0
xoruje rejestr xmm0, robi to tak bo jest to prostsze niż wczytywanie z pamięć wartości zero.
Jeśli będzie jakaś stała to zamiast xorować, to wczytuje ją movss xmm0, DWORD PTR .LC0
, z .rodata
Potem mnoży mulss xmm0, xmm1
, gdzie
I zapisujemy wynik do zmiennej na stosie.
Ale to w przypadku jeśli 1/2 policzył jako stałą, jeśli a*1
policzył jako stałą to będzie
dzielenie divss xmm0, xmm1
Jak zamienisz miejscami 1/2*a
, na a*1/2
to kompilator, nie liczy tej stałej przy kompilacji gdyż nie może wykonać a/2
dzielenia(może w ekstremalnej optymalizacji od razu wynik w .rodata zapisać jak stwierdzi, że nigdzie nie jest zmienna modyfikowana), gdyż jest to tożsame z zapisem 1*a/2
lub a*1/2
, jest to równoznaczny zapis matematyczny po skróceniu.
W takim wypadku kompilator odkłada jako stałą 2
w .rodata i wykonuje dzielenie bo inaczej nie da się tego rozwiązać.
W jednym wypadku liczysz 1/2 = stała
i potem w uruchomionym programie stała * a
, a w drugim a*1 = stała
i w dynamicznie wyliczone stała / 2