Perché un processore ha 32 registri?


52

Mi sono sempre chiesto perché i processori si sono fermati a 32 registri. È di gran lunga il pezzo più veloce della macchina, perché non creare processori più grandi con più registri? Non significherebbe meno andare nella RAM?


2
Suppongo che oltre un certo punto tutte le variabili locali si inseriscano nei registri. I dati reali con cui stai lavorando sono probabilmente comunque troppo grandi
Niklas B.

14
Rendimenti decrescenti. Chiaramente, i registri sono "più costosi" (in vari sensi) rispetto alla RAM o avremmo solo 8 GB di registri.
David Richerby,

5
Uno dei motivi per cui è così veloce è perché non ce ne sono molti.
stackErr

5
C'è una differenza tra quanti registri ha la cpu in totale e quanti puoi usare contemporaneamente.
Thorbjørn Ravn Andersen,

CPU e GPU nascondono la latenza principalmente principalmente dalla cache e dal multithreading. Quindi, le CPU hanno pochi registri, mentre le GPU hanno decine di migliaia sui registri. Vedi il mio documento di indagine sul file di registro GPU che discute tutti questi compromessi e fattori.
user984260

Risposte:


82

Innanzitutto, non tutte le architetture di processori si sono fermate a 32 registri. Quasi tutte le architetture RISC che hanno 32 registri esposti nel set di istruzioni in realtà hanno 32 registri interi e altri 32 registri a virgola mobile (quindi 64). (Il virgola mobile "add" utilizza registri diversi rispetto all'intero "add".) L'architettura SPARC ha finestre di registro. Su SPARC puoi accedere solo a 32 registri interi alla volta, ma i registri si comportano come uno stack e puoi spingere e pop i nuovi registri 16 alla volta. L'architettura Itanium di HP / Intel aveva 128 interi e 128 registri a virgola mobile esposti nel set di istruzioni. Le moderne GPU di NVidia, AMD, Intel, ARM e Imagination Technologies, espongono tutti un numero enorme di registri nei loro file di registro. (So ​​che questo vale per le architetture NVidia e Intel, non ho molta familiarità con i set di istruzioni AMD, ARM e Imagination, ma penso che anche i file di registro siano grandi lì.)

In secondo luogo, la maggior parte dei microprocessori moderni implementa la ridenominazione dei registri per eliminare la serializzazione non necessaria causata dalla necessità di riutilizzare le risorse, quindi i file dei registri fisici sottostanti possono essere più grandi (96, 128 o 192 registri su alcune macchine.) Questo (e la programmazione dinamica) elimina alcuni dei è necessario che il compilatore generi così tanti nomi di registro univoci, pur fornendo allo scheduler un file di registro più grande.

Vi sono due motivi per cui potrebbe essere difficile aumentare ulteriormente il numero di registri esposti nel set di istruzioni. Innanzitutto, devi essere in grado di specificare gli identificatori di registro in ciascuna istruzione. 32 registri richiedono un identificatore di registro a 5 bit, quindi le istruzioni a 3 indirizzi (comuni nelle architetture RISC) impiegano 15 dei 32 bit di istruzione solo per specificare i registri. Se lo aumentassi a 6 o 7 bit, allora avresti meno spazio per specificare i codici operativi e le costanti. Le GPU e Itanium hanno istruzioni molto più grandi. Le istruzioni più grandi hanno un costo: è necessario utilizzare più memoria delle istruzioni, quindi il comportamento della cache delle istruzioni è meno ideale.

Il secondo motivo è il tempo di accesso. Più grande è la memoria, più lenta è l'accesso ai dati da essa. (Solo in termini di fisica di base: i dati sono memorizzati in uno spazio bidimensionale, quindi se si memorizzano bit, la distanza media da un bit specifico è .) Un file di registro è solo un piccola memoria multi-portata e uno dei vincoli per ingrandirla è che alla fine dovresti iniziare a rallentare la macchina per contenere il file di registro più grande. Di solito, in termini di prestazioni totali, questa è una perdita. nO(n)


1
Avrei menzionato i 256 FPR SPARC64 VIIIfx e i 32 GPR extra-finestra extra, realizzati aggiungendo un'istruzione Set XAR che fornisce 13 bit ciascuno per la successiva o due istruzioni. È stato scelto come target HPC, quindi il conteggio dei registri è più comprensibile. Sarei stato anche tentato di esporre alcuni dei compromessi e delle tecniche associate a più registri; ma hai mostrato la saggezza per evitare una risposta più estenuante (e anche allora non esaustiva).
Paul A. Clayton,

2
Aggiungere un po 'al vantaggio decrescente di più registri per il codice "di uso generale" potrebbe essere utile, anche se non è facile trovare misurazioni significative. Penso che Mitch Alsup abbia menzionato su comp.arch che l'estensione di x86 a 32 registri anziché 16 avrebbe guadagnato circa il 3% in termini di prestazioni rispetto al (ISTR) del 10-15% per l'estensione da 8 a 16 che è stata scelta. Anche per un ISA con load-store, andare a 64 probabilmente offre pochi vantaggi (almeno per l'attuale codice GP). (A proposito, le GPU spesso condividono i registri tra i thread: ad esempio, un thread con 250 lasciando il 16 in totale privato per altri thread.)
Paul A. Clayton

Interessante vedere che la gestione dell'ambiente (quindi la conversione alfa), spesso associata a linguaggi di alto livello, viene effettivamente utilizzata a livello di registro.
babou,

@ PaulA.Clayton Ho sempre pensato che IA-64 sia l'architettura che ha il maggior numero di registri ISA
phuclv,

@ LưuVĩnhPhúc SPARC64 VIIIfx era specifico per HPC. Cordiali saluti, l' Am29k (introdotto intorno al 1987-8 ) aveva 64 GPR globali e 128 con finestre che sono più GPR di Itanium (che ha 8 registri di diramazione e un registro di conteggio di loop la cui funzione sarebbe in GPR in alcuni altri ISA).
Paul A. Clayton,

16

Solo altri due motivi per limitare il numero di registri:

  • Poco guadagno prevedibile: CPU come gli attuali modelli Intel / AMD x64 hanno 32kByte e più cache L1-D e l'accesso alla cache L1 di solito richiede solo un ciclo di clock (rispetto a circa un centinaio di cicli di clock per una singola RAM completa accesso). Quindi c'è poco da guadagnare dall'avere più dati nei registri rispetto ad avere dati nella cache L1
  • Costi computazionali aggiuntivi: avere più registri crea un sovraccarico che può effettivamente rallentare un computer:
    • Negli ambienti multitasking, uno switch di attività di solito deve salvare il contenuto di tutti i registri del processo che viene lasciato in memoria e deve caricare quelli del processo da inserire. Più registri hai, più tempo ci vorrà.
    • Analogamente, nelle architetture senza finestre di registro, le chiamate di funzione in cascata utilizzano lo stesso set di registri. Quindi una funzione A che chiama una funzione B utilizza lo stesso set di registri di B stesso. Pertanto, B deve salvare il contenuto di tutti i registri che utilizza (che contengono ancora i valori di A) e deve riscriverli prima di tornare (in alcune convenzioni di chiamata è compito di A salvare i contenuti del registro prima di chiamare B, ma il le spese generali sono simili). Maggiore è il numero di registri, maggiore è il tempo necessario per il salvataggio e quindi diventa più costosa una chiamata di funzione.

Come funziona per la cache L1 in modo da non avere lo stesso problema dei registri?
babou,

4
Sui processori ad alte prestazioni, la latenza Dcache L1 è in genere più di 3 o 4 cicli (inclusa la generazione di indirizzi), ad es. Intel Haswell ha una latenza di 4 cicli (la latenza del registro di dipendenza dei dati è anche più facile da nascondere nella pipeline). Dcache tende inoltre a supportare un minor numero di accessi per ciclo (ad es. 2 letti, 1 scrittura per Haswell) rispetto a un file di registro (ad esempio 4 letti, 6 scritti per Alpha 21264 che ha replicato il file, 2 file con 4 letture sono più veloci di 1 con 8).
Paul A. Clayton,

@ PaulA.Clayton: se la cache L1 ha una latenza di 3-4 cicli, ciò suggerirebbe che potrebbe esserci qualche vantaggio nell'avere ad esempio alcuni insiemi di 64 parole di memoria a ciclo singolo con un proprio spazio di indirizzi di 64 parole e istruzioni dedicate "load / store direct", in particolare se ci fosse un modo per spingere tutti i valori diversi da zero seguito da una parola che diceva quali parole erano diverse da zero, e quindi un modo per ripristinarle (azzerando tutti i registri non spuntati) . Molti metodi hanno tra le 16 e le 60 parole di variabili locali, quindi ridurre il tempo di accesso per quelli da 3-4 cicli a uno sembrerebbe utile.
supercat

@supercat Diverse idee cache stack (e global / TLS [es. Knapsack]) sono state presentate in documenti accademici e meccanismi come il buffer delle firme ( PDF ) Uso effettivo, non tanto (sembra). Questo sta diventando loquace (quindi probabilmente dovrebbe finire o andare altrove).
Paul A. Clayton,

4

Un sacco di codice ha molti accessi alla memoria (il 30% è una cifra tipica). Di conseguenza, in genere circa 2/3 sono accessi in lettura e 1/3 sono accessi in scrittura. Ciò non è dovuto all'esaurimento dei registri quanto all'accesso alle matrici, all'accesso alle variabili dei membri dell'oggetto, ecc.

Questo deve essere fatto in memoria (o cache di dati) a causa di come viene creato C / C ++ (tutto ciò a cui è possibile ottenere un puntatore deve avere un indirizzo a cui deve essere potenzialmente memorizzato in memoria). Se il compilatore può indovinare che non scriverai su variabili volenti o nolenti usando trucchi puntatori indiretti pazzi, li metterà nei registri e questo funziona alla grande per le variabili di funzione ma non per quelle accessibili a livello globale (in genere, tutto ciò che viene fuori da malloc ()) perché è sostanzialmente impossibile indovinare come cambierà lo stato globale.

Per questo motivo, non è comune che il compilatore sarà in grado di fare comunque qualcosa con più di circa 16 registri di utilizzo generale. Ecco perché tutti gli architetti popolari ne hanno così tanti (ARM ne ha 16).

MIPS e altri RISC tendono ad avere 32 perché non è molto difficile avere così tanti registri - il costo è abbastanza basso, quindi è un po 'un "perché no?". Più di 32 sono per lo più inutili e hanno il rovescio della medaglia di rendere più lungo l'accesso al file di registro (ogni raddoppio del numero di registri potenzialmente aggiunge un ulteriore livello di multiplexer che aggiunge un po 'più di ritardo ...). Inoltre, rende le istruzioni leggermente più lunghe in media, il che significa che quando si esegue il tipo di programmi che dipendono dalla larghezza di banda della memoria delle istruzioni, i registri extra in realtà ti rallentano!

Se la tua cpu è in ordine e non rinomina i registri e stai provando a fare molte operazioni per ciclo (più di 3), in teoria hai bisogno di più registri man mano che aumenta il numero di operazioni per ciclo. Questo è il motivo per cui Itanium ha così tanti registri! Ma in pratica, a parte il codice a virgola mobile o orientato al SIMD (in cui Itanium era davvero bravo), la maggior parte del codice avrà molte letture / scritture e salti di memoria che rendono impossibile questo sogno di più di 3 operazioni per ciclo (specialmente nei software orientati al server come database, compilatori, esecuzione di linguaggio di alto livello come javascript, emulazione ecc ...). Questo è ciò che affondò Itanium.

Tutto dipende dalla differenza tra calcolo ed esecuzione!


2

Chi ti dice che il processore ha sempre 32 registri? x86 ha 8, ARM 32-bit e x86_64 ne hanno 16, IA-64 ne ha 128 e molti altri numeri. Puoi dare un'occhiata qui . Anche MIPS, PPC o qualsiasi altra architettura che abbia 32 registri di uso generale nel set di istruzioni, il numero è molto più grande di 32 poiché ci sono sempre registri flag (se presenti), registri di controllo ... esclusi registri rinominati e registri hardware

Tutto ha il suo prezzo. Maggiore è il numero di registri, maggiore è il lavoro svolto durante la commutazione delle attività, maggiore è lo spazio necessario nella codifica delle istruzioni. Se si dispone di meno registri, non è necessario archiviare e ripristinare molto quando si chiama e si ritorna da funzioni o si cambia attività con il compromesso della mancanza di registri in alcuni codici di calcolo

Inoltre, più grande è il file di registro, più costoso e complesso sarà. SRAM è la RAM più veloce e costosa, quindi viene utilizzata solo nella cache della CPU. Ma è ancora molto più economico e occupa meno area di un file di registro con la stessa capacità.


2

Ad esempio, un tipico processore Intel ha "ufficialmente" 16 numeri interi e 16 registri vettoriali. Ma in realtà ce ne sono molti altri: il processore usa "rinomina registro". Se hai un'istruzione reg3 = reg1 + reg2 avresti un problema se un'altra istruzione che utilizza reg3 non fosse ancora terminata - non potresti eseguire la nuova istruzione nel caso in cui sovrascriva reg3 prima che sia stata letta dall'istruzione precedente.

Pertanto ci sono circa 160 registri reali . Quindi la semplice istruzione sopra è cambiata in "regX = reg1 + reg2, e ricorda che regX contiene reg3". Senza i registri di rinomina, l'esecuzione fuori servizio sarebbe assolutamente morta nell'acqua.


1

Non sono un ingegnere elettrico, ma penso che un'altra possibilità per il motivo di limitare il numero di registri sia il routing. Esistono un numero limitato di unità aritmetiche e devono essere in grado di prendere input da ogni registro e output ad ogni registro. Ciò è particolarmente vero quando si dispone di programmi in pipeline che possono eseguire molte istruzioni per ciclo.

Una versione semplice di questo avrebbe complessità, rendendo non scalabile il numero di registri o altrimenti richiederebbe una riprogettazione del routing a qualcosa di molto più complicato per instradare tutto con una complessità migliore.O(n2)

Ho avuto l'idea di questa risposta guardando alcuni dei discorsi di Ivan Godard sulla CPU del mulino. Parte dell'innovazione della CPU Mill è che non è possibile eseguire l'output su registri arbitrari: le uscite sono tutte inserite in uno stack di registro o "cinghia", il che riduce così i problemi di routing, perché si sa sempre dove andrà l'output. Si noti che hanno ancora il problema di routing per ottenere i registri di input per le unità aritmetiche.

Vedere The Mill CPU Architecture - the Belt (2 di 9) per la descrizione del problema e la soluzione di Mill.


"Devono essere in grado di prendere input da ogni registro e output in ogni registro." - Mi aspetto che questo sia tipicamente implementato con un bus, non ci deve essere una connessione separata con gli ALU per ogni registro.
user253751

1
@immibis: se vuoi spostare i dati in circa 300 picosecondi, un autobus non lo farà. E se vuoi spostare molti dati (ad esempio per eseguire tre istruzioni con due operandi e un risultato ciascuno nello stesso ciclo) un bus non funzionerà assolutamente, assolutamente.
gnasher729,

0

Per quanto riguarda il MIPS ISA, Hennessy e Patterson, Computer Organization and Design 4th edition p. 176, risponde direttamente a questa domanda specifica:

Più piccolo è più veloce. Il desiderio di velocità è la ragione per cui MIPS ha 32 registri piuttosto che molti altri.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.