Statistiche su x86 & x64 – parte 4 (numero di operandi)

Le istruzioni, come sappiamo, sono composte dallo mnemonico, che identifica il tipo di azione svolta, accompagnato eventualmente da uno o più operandi che utilizza come sorgente/i e/o come destinazione.

In quest’articolo ci occuperemo delle statistiche relative al numero di operandi, senza tenere conto dello mnemonico per il momento, di cui ci occuperemo nella parte finale della serie.

x86 e x64 condividono buona parte dell’architettura, con leggere differenze a livello di ISA, ma la struttura delle istruzioni rimane sostanzialmente la stessa, come abbiamo in parte avuto modo di vedere dal precedente articolo che ha messo a confronto due spezzoni di codice.

Per questo motivo condividono anche gli stessi limiti. Le istruzioni, infatti, possono avere fino a 4 operandi in totale, per entrambe le architetture, sebbene quest’ultimo caso sia riservato a poche istruzioni dell’estensione AVX che Intel ha introdotto di recente (e che è stata presa in licenza anche dalla rivale AMD).

Il quadro che viene fuori dalla beta pubblica di Adobe Photoshop CS6 a 32 bit non mostra, pertanto, alcuna sorpresa:

Number of operands:
  Num      Count
    2     987717
    1     725509
    0      31565
    3       1778

Non avendo incontrato nessuna istruzione AVX, era prevedibile che dal quadro fosse del tutto assente la voce relativa ai 4 operandi.

Per il resto lo scenario è di facile e ovvia lettura: più del doppio delle istruzioni fa uso di 2 operandi, mentre subito dopo e a poca distanza, con più del 40% del totale, troviamo quelle a cui ne serve soltanto uno.

A spartirsi le briciole troviamo le istruzioni che non fanno uso di alcun operando (magari perché referenziato/i implicitamente) ed estremamente rare sono, invece, quelle che ne impiegano ben tre.

Quest’ultimo dato non desta stupore, poiché l’8086 aveva istruzioni con al più due operandi. Nel corso del tempo ne sono state aggiunte alcune con tre, fra le quali quella di gran lunga più usata è la IMUL (introdotta con l’80186) e, in misura molto minore, le SHLD e SHLR (introdotte con l’80386), alle quali ne sono poi state affiancate poche altre con l’estensione SIMD SSE.

Merce rara dunque (e si vede dai numeri), mentre con l’estensione AVX avere 3 operandi rappresenta la norma (sono quelle più diffuse), ma al momento non ha trovato alcun riscontro dagli eseguibili disassemblati, e dunque queste istruzioni sono, purtroppo, state tagliate fuori dalle analisi condotte. D’altra parte parliamo di una recente novità, arrivata da poco.

Passando alla beta pubblica di Adobe Photoshop CS6 a 64 bit la scaletta non cambia per quanto riguarda l’ordine delle voci, ma muta nella sostanza, cioè nei numeri che vengono fuori:

Number of operands:
  Num      Count
    2    1267956
    1     414178
    0      52816
    3       2381

Il dato che salta subito all’occhio è l’esplosione delle istruzioni che fanno uso di due operandi, le quali adesso rappresentano quasi i 3/4 della totalità, il tutto a discapito di quelle con un solo operando, che scendono a poco meno di 1/4.

La spiegazione è semplice, ed è stata già riportata nei precedenti articoli: il cambio dell’ABI da x86 a x64 prevede che in quest’ultimo caso si faccia ricorso ai registri per passare dati alle routine da chiamare, mentre in precedenza veniva usato lo stack.

La conferma arriva dall’esame delle frequenze delle istruzioni, che con x64 vedono un aumento delle istruzioni di “move” (quindi non soltanto le classiche MOV) e la LEA, e al contestuale crollo delle PUSH e POP, come vedremo meglio in uno dei futuri articoli della serie, il quale discuterà della frequenze delle singole istruzioni.

Se la nuova ABI spiega le variazioni dei primi due risultati, appare, però, anomalo il terzo dato, che non trova alcuna giustificazione dovuta a questo cambiamento. La soluzione va ricercata nel notevole aumento delle istruzioni NOP che, come abbiamo già anticipato, sono molto utilizzate su x64 per allineare il codice ai 16 byte, in modo che i salti siano eseguiti (quasi) sempre a indirizzi multipli di 16, favorendo i decoder, che possono provare a estrarre più istruzioni da una linea di cache per riempire velocemente la pipeline.

Di minore importanza è il quarto e ultimo dato, che mostra un innalzamento della frequenza delle istruzioni dotate di 3 operandi, confermato dallo strano aumento delle IMUL presenti nel codice x64 disassemblato (2163 contro le 1564 di x86, nella forma più comune, quella REG,REG,IMM).

Non è chiaro se il motivo di questo improvviso aumento sia dovuto semplicemente al fatto che siano stati disassemblati pezzi di codice diversi fra x86 e x64, o a qualche altra strategia diversa adoperata dai compilatori. Data la rarità di questa tipologia di opcode, possiamo, a ogni buon conto, trascurare questo caso particolare.

Nel prossimo pezzo della serie verranno analizzate le varie modalità di indirizzamento verso la memoria di queste due architetture.

Press ESC to close