2010-04-15 12 views
15

Ho cercato di ottenere una buona presa sul linguaggio assembly x86 e mi chiedevo se esistesse un equivalente rapido e breve di movl $1, %eax. In quel momento ho pensato che una lista di idiomi usati frequentemente nella lingua sarebbe stata una buona idea.idiomi di assembly x86

Questo potrebbe includere l'uso preferito di xorl %eax, %eax rispetto a movl $0, %eax o testl %eax, %eax rispetto a cmpl $0, %eax.

Oh, e invia un esempio per post!

+5

'movl $ 1,% eax' è piuttosto veloce e breve. Su alcuni processori, 'xorl% eax,% eax' è in realtà più lento di' movl $ 0,% eax'. Su altri, 'incl% eax' è più lento di' addl $ 1,% eax'. Se hai intenzione di scrivere assembly nel 2010, dovresti sapere per quale architettura stai scrivendo e selezionare il tuo "dialetto" (per mantenere la metafora linguistica) di conseguenza. –

+0

@Pascal Cuoq, potresti spiegare quali fattori influenzano questo tipo di differenza nelle prestazioni? Sono particolarmente sconcertato dal fatto che 'incl% eax' sia più lento di' addl $ 1,% eax'. Inoltre, se potessi indicarmi un link che descrive questo tipo di comportamento, te ne sarò grato! – susmits

+0

Per tutte le architetture x86 nel 2010 xor eax, eax ist più veloce o equivalente, in ogni caso è più breve. Dai un'occhiata a http://stackoverflow.com/questions/1396527/any-reason-to-do-a-xor-eax-eax/1396552#1396552. Questo è più o meno dai tempi di 486. – hirschhornsalz

risposta

5

su x64:

xor eax, eax 

per

xor rax, rax 

(il primo anche cancella implicitamente la metà superiore di rax, ma ha un codice operativo minore)

7

Uso LEA per esempio la moltiplicazione, come:

lea eax, [ecx+ecx*4] 

per EAX = 5 * ECX

+5

BTW: questo è un cane lento su NetBurst, perché Intel ha rimosso il barrel-shifter per poter ottenere velocità di clock più elevate. Ironia della sorte, al momento della pubblicazione del P4, questo era ancora documentato nei manuali di ottimizzazione di Intel. –

+0

Grazie per il commento re. velocità. Mi rendo conto che un idioma non è necessariamente la stessa cosa di un'ottimizzazione. Comunque, come idioma, penso che LEA sia stato usato abbastanza ampiamente (ab). – PhiS

+5

Beh, * è * un'ottimizzazione. Ed è anche ufficialmente raccomandato da Intel.È solo che, dopo averlo raccomandato ufficialmente per 15 anni, improvvisamente rilascia una nuova CPU su cui era lento, richiedendo essenzialmente la ricompilazione * di ogni singolo programma scritto *. Per fortuna, NetBurst è morto per una morte rapida e dolorosa e tutte le attuali microarchitetture sono evoluzioni del Pentium III, non del Pentium4, quindi tutte le attuali CPU hanno ancora un barrel shifter. In sostanza, * tutte le CPU Intel * dal 80385 e tutti gli Athlon ne hanno, solo il Pentium4 no. –

5

si potrebbe anche come il modo per ottimizzare in assemblea. Allora dovresti chiedere per cosa stai ottimizzando: dimensioni o velocità? Ad ogni modo, ecco il mio "linguaggio", una sostituzione per xchg:

xor eax, ebx 
xor ebx, eax 
xor eax, ebx 
+0

** ATTENZIONE: ** Se eax == ebx - Entrambi saranno azzerati! – LiraNuna

+11

Ne sei sicuro? 42^42 = 0; 42^0 = 42; 0^42 = 42 – Sparafusile

2

Utilizzando SHL e SHR per la moltiplicazione/divisione per una potenza di 2

+0

Può essere esteso anche ad altri numeri. Ad esempio, 'y * 320 = (y << 8) + (y << 6)'. Tuttavia, potrebbe non essere sempre più veloce di una semplice moltiplicazione. Dipende dal tuo processore. – csl

2

un altro (a fianco xor) per

mov eax, 0 ; B800000000h 

è

sub eax, eax ; 29C0h 

Motivazione: più piccolo codice operativo

2

Non so se questo conta come un idioma, ma nella maggior parte dei processori prima i7

movq xmm0, [eax] 
movhps xmm0, [eax+8] 

o, se SSE3 è disponibile,

lddqu xmm0, [eax] 

sono più veloci per la lettura da una posizione di memoria non allineato rispetto

movdqu xmm0, [eax] 
4

Ampliando il mio commento:

Per un processore non pertinente come Pentium Pro, xorl %eax, %eax sembra avere una dipendenza su %eax e quindi deve attendere che il valore di tale registro sia disponibile. I processori successivi hanno in realtà una logica aggiuntiva per riconoscere che l'istruzione non ha alcuna dipendenza.

Le istruzioni incl e decl impostano alcuni dei flag ma ne lasciano invariati gli altri.Questa è la situazione peggiore se i flag sono modellati come un unico registro ai fini del riordino delle istruzioni: qualsiasi istruzione che legge un flag dopo un incl o decl deve essere considerata come dipendente dallo incl o dal decl (nel caso in cui stia leggendo uno dei flag che questa istruzione imposta) e anche sull'istruzione precedente che imposta i flag (nel caso in cui stia leggendo uno dei flag che questa istruzione non imposta). Una soluzione sarebbe quella di dividere il registro delle bandiere in due e considerare le dipendenze con questa grana più fine ... ma AMD ha avuto un'idea migliore e ha rimosso completamente queste istruzioni dall'estensione a 64 bit che hanno proposto alcuni anni fa.

Per quanto riguarda i collegamenti, ho trovato questo sia nei manuali di Intel per i quali è inutile fornire un collegamento, perché sono su un sito web aziendale che ha riorganizzato ogni sei mesi, o sul sito di Agner Fog: http://www.agner.org/optimize/#manuals

4

A loop ...

dec  ecx 
    cmp  ecx, -1  
    jnz  Loop    

è

dec  ecx 
    jns  Loop 

Più veloce e più breve.

+0

Il loop non è più semplice? –

+1

@Hasan Saad: È solo che ti è più lento, l'uso del ciclo in x86 è deprecato. –

+0

Grazie mille :) Non ne avevo idea, quindi grazie per l'informazione. Molto apprezzata :) –

10

Ecco un altro "idioma" interessante. Speriamo che tutti sappiano che la divisione è un grosso crollo di tempo, anche rispetto a una moltiplicazione. Usando un po 'di matematica, è possibile moltiplicare per l'inverso della costante invece di dividerci. Questo va al di là degli acuti trucchi. Ad esempio, per dividere per 5:

mov eax, some_number 
mov ebx, 3435973837 // 32-bit inverse of 5 
mul ebx 

Ora eax è stato diviso per 5 senza utilizzare il codice operativo lento div. Ecco un elenco di costanti utili per la divisione spudorata rubato http://blogs.msdn.com/devdev/archive/2005/12/12/502980.aspx

3 2863311531 
5 3435973837 
7 3067833783 
9 954437177 
11 3123612579 
13 3303820997 
15 4008636143 
17 4042322161 

Per i numeri non presenti nell'elenco, potrebbe essere necessario fare un cambiamento in anticipo (di dividere per 6, SHR 1, poi moltiplicare per l'inverso della 3).

Problemi correlati