ADD 1 è davvero più veloce di INC? x86

Ho letto varie guide all’ottimizzazione secondo cui ADD 1 è più veloce rispetto all’utilizzo di INC in x86. È proprio vero?

Su alcune micro-architetture, con alcuni flussi di istruzioni, INC incorrerà in uno “stallo di aggiornamento parziale delle bandiere” (poiché aggiorna alcuni dei flag mantenendo gli altri). ADD imposta il valore di tutti i flag e quindi non rischia un tale stallo.

ADD non è sempre più veloce di INC , ma è quasi sempre altrettanto veloce (ci sono alcuni casi d’angolo su alcune vecchie micro-architetture, ma sono estremamente rari) e talvolta molto più veloci.

Per maggiori dettagli, consultare il Manuale di riferimento sull’ottimizzazione di Intel o le note di microarchitettura di Agner Fog .

Mentre non è una risposta definitiva. Scrivi questo file C:

 === inc.c === #include  int main(int argc, char *argv[]) { for (int n = 0; n < 1000; n++) { printf("%d\n", n); } return 0; } 

Quindi esegui:

 clang -march=native -masm=intel -O3 -S -o inc.clang.s inc.c gcc -march=native -masm=intel -O3 -S -o inc.gcc.s inc.c 

Nota il codice assembly generato. Rilevante uscita clang:

 mov esi, ebx call printf inc ebx cmp ebx, 1000 jne .LBB0_1 

Rilevante output gcc:

 mov edi, 1 inc ebx call __printf_chk cmp ebx, 1000 jne .L2 

Ciò dimostra che gli autori di clang e gcc pensano che l' INC sia la scelta migliore rispetto a ADD reg, 1 sulle architetture moderne.

Cosa significherebbe per la tua domanda? Bene, mi fiderei del loro giudizio sulle guide che hai letto e concludo che INC è altrettanto veloce di ADD e che l'un byte salvato a causa della codifica del registro più breve lo rende preferibile. Gli autori di compilatori sono solo persone in modo che possano essere sbagliati, ma è improbabile. 🙂

Qualche altra sperimentazione mi mostra che se non usi l'opzione -march=native , gcc userà invece add ebx, 1 . Clang otoh, gli piace sempre meglio. La mia conclusione è che quando hai chiesto la domanda nel 2012 ADD volte era preferibile, ma ora nel 2016 dovresti sempre andare con INC .

Negli anni ’80 o ’90 i tempi di esecuzione delle istruzioni semplici erano determinati principalmente dal numero di componenti nell’istruzione: aggiungi ascia, 1 contiene un’altra unità decodificabile (l’immediata) rispetto a, inc ax o add ax, bx. E così l’80286 ha trascorso un altro ciclo di clock per decodificare l’istruzione.

Poi c’era / è l’era, quando intel particolarmente ottimizzato la maggior parte delle istruzioni di tipo RISC a spese delle istruzioni di tipo CISC. (ad esempio aggiungi ax, [mem]; aggiungi [mem], ax). Oggi o almeno domani, quelli sono economici … Le sequenze di rami complessi saranno risolte in una pipeline di 30 unità che esegue la ridenominazione automatica dei registri.

Quindi, siamo più probabili ora nell’era, dove inc eax è CISC , aka male e add eax,1 è RISC , che è buono. Ma queste cose possono cambiare durante la notte.