2016-04-05 12 views
5

Sto lavorando su tecniche di ottimizzazione eseguite dal compilatore Native .Net. Ho creato un loop del campione:Perché. Native compile loop in ordine inverso?

 for (int i = 0; i < 100; i++) 
     { 
      Function(); 
     } 

E ho compilato con nativo. Quindi ho disassemblato il file .dll con codice macchina all'interno di IDA. Come risultato, ho:

enter image description here

(ho rimosso poche righe non necessarie, quindi non preoccupatevi che le linee indirizzo sono inconsistant)

Capisco che add esi, 0FFFFFFFFh significa veramente subtract one from esi and alter Zero Flag if needed, così possiamo saltare all'inizio se zero non è stato ancora raggiunto.

Quello che non capisco è perché il compilatore ha eseguito il ciclo?

Sono venuto a conclusione che

LOOP: 
add esi, 0FFFFFFFFh 
jnz LOOP 

è solo più veloce rispetto ad esempio

LOOP: 
inc esi 
cmp esi, 064h 
jl LOOP 

Ma è proprio a causa di questo ed è la differenza di velocità davvero significativo?

+0

AGGIUNGI con un valore immediato è più veloce di INC e salti anche CMP ... tutto in 3 righe di codice. Allora sì, la differenza è DAVVERO significativa (sia per dimensioni che per velocità). Immagina di farlo in ~ 30000 posti in un programma del mondo reale ... –

+0

Sì, è più veloce, e in generale gli ottimizzatori applicheranno qualsiasi ottimizzazione possibile che renda il tuo codice più veloce senza cambiare la semantica del tuo programma. –

+0

Per quanto riguarda la direzione invertita, forse il confronto con lo zero è più veloce del confronto con un valore specifico? – user5226582

risposta

3

inc might be slower than add because of the partial flag update. Inoltre, add influisce sullo zero flag, quindi non è necessario utilizzare un'altra istruzione cmp. Basta saltare direttamente.

Questo è un tipo noto di loop optimization

inversione: inversione Loop inverte l'ordine in cui vengono assegnati valori alla variabile di indice. Questa è una sottile ottimizzazione che può aiutare a eliminare le dipendenze e quindi a consentire altre ottimizzazioni. Inoltre, alcune architetture utilizzano costrutti di loop a livello di linguaggio Assembly che contano solo in un'unica direzione (ad es. Decrement-jump-if-not-zero (DJNZ)).

È possibile vedere il risultato per gli altri compilatori here.

+0

' inc' è più lento di allora 'aggiungi' di un ciclo di clock. Confrontali in [Manuale di riferimento dell'ottimizzazione delle architetture Intel® 64 e IA-32] (http://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures- optimization-manual.html). Scorri verso il basso fino all'Appendice C e puoi vedere i tempi di latenza e di throughput di ogni x86/x6 4 istruzioni. 1 ciclo di clock potrebbe non sembrare significativo, ma se hai centinaia o migliaia di cicli, si sommerà velocemente. – Icemanind

1

tua conclusione è corretta: invertita ciclo si rivolgerà 0 (ciclo termina quando il valore di registro raggiungere 0), in modo che si Add azzerare bandiera usata nel ramo condizionale.

In questo modo non è necessario lo Cmp dedicato che porta a: 1) ottimizzazione della dimensione 2) è anche più veloce (conclusione della decisione dei programmatori del compilatore e un altro answer).

Questo è piuttosto comune trucco di assemblatore per scrivere il ciclo di targeting 0. Sono sorpreso che capisca l'assemblatore, ma non lo so (chiedendo) a riguardo.

Problemi correlati