2014-07-08 16 views
8

Non capisco cosa sta succedendo in questo codice. Il codice C è:Comprensione delle ottimizzazioni del compilatore C++ MSVS

#include <stdio.h> 

int main() 
{ 
    const int mul = 100; 
    int x; 
    printf_s("Input a number\r\n"); 
    scanf_s("%i", &x); 
    printf_s("%i/%i = %i\r\n", x, mul, x/mul); 
    return 0; 
} 

Mi aspettavo che l'assembly risultante saranno alcuni cambiamenti semplici e aggiungere/operazioni di sub, ma ci sono alcune costanti magici come 51EB851Fh, moltiplicazioni, ecc Che cosa sta succedendo qui?

; int __cdecl main() 
_main proc near 

x= dword ptr -8 
var_4= dword ptr -4 

push ebp 
mov  ebp, esp 
sub  esp, 8 
mov  eax, ___security_cookie 
xor  eax, ebp 
mov  [ebp+var_4], eax 
push offset Format ; "Input a number\r\n" 
call ds:__imp__printf_s 
lea  eax, [ebp+x] 
push eax 
push offset aI  ; "%i" 
call ds:__imp__scanf_s 
mov  ecx, [ebp+x] 
mov  eax, 51EB851Fh 
imul ecx 
sar  edx, 5 
mov  eax, edx 
shr  eax, 1Fh 
add  eax, edx 
push eax 
push 64h 
push ecx 
push offset aIII  ; "%i/%i = %i\r\n" 
call ds:__imp__printf_s 
mov  ecx, [ebp+var_4] 
add  esp, 1Ch 
xor  ecx, ebp  ; cookie 
xor  eax, eax 
call @[email protected] ; __security_check_cookie(x) 
mov  esp, ebp 
pop  ebp 
retn 
_main endp 
+0

Come hai ottenuto l'assemblaggio risultante? –

+1

ida, ma puoi usare qualsiasi utilità gratuita di google usando la frase segreta 'free disassembler' –

risposta

11

processori non sono molto buone a dividere, un idiv può prendere tra 11 e 18 cicli . Al contrario di turni e si moltiplica, di solito prendono solo un singolo ciclo.

Quindi l'ottimizzatore ha sostituito la divisione con una moltiplicazione utilizzando la matematica a virgola fissa, sfruttando un moltiplicatore a 32 bit che produce un risultato a 64 bit in edx: eax. Back-of-the-envelope: n/100 == n * 0,32/32 == n * (0,32 * pow (2,32))/32/pow (2,32). Quelle divisioni sono molto economiche, solo una svolta giusta. E il moltiplicatore diventa 0,32 * pow (2,32) ~ = 1374389535 == 0x51EB851F

+0

Secondo le specifiche di Intel, imul richiede 3 cicli, vuoi dire che ci vuole anche 1 ciclo o si riferisce solo all'aggiunta? –

+3

Ci vuole 1 ciclo su Sandy Bridge. Utilizzare le tabelle di istruzioni di Agner Fog per ottenerne l'analisi in base all'architettura e alla modalità di indirizzamento. –

Problemi correlati