Perché Intel nasconde il core RISC interno nei propri processori?


89

A partire da Pentium Pro (microarchitettura P6), Intel ha riprogettato i suoi microprocessori e ha utilizzato il core RISC interno secondo le vecchie istruzioni CISC. Dal momento che Pentium Pro tutte le istruzioni CISC sono divise in parti più piccole (uops) e quindi eseguite dal core RISC.

All'inizio era chiaro per me che Intel avesse deciso di nascondere la nuova architettura interna e costringere i programmatori a utilizzare la "shell CISC". Grazie a questa decisione Intel potrebbe riprogettare completamente l'architettura dei microprocessori senza compromettere la compatibilità, è ragionevole.

Tuttavia non capisco una cosa, perché Intel mantiene ancora nascosto un set di istruzioni RISC interno per così tanti anni? Perché non consentirebbero ai programmatori di utilizzare le istruzioni RISC come il vecchio set di istruzioni CISC x86?

Se Intel mantiene la compatibilità con le versioni precedenti per così tanto tempo (abbiamo ancora la modalità 8086 virtuale accanto alla modalità a 64 bit), perché non ci consentono di compilare programmi in modo che ignorino le istruzioni CISC e utilizzino direttamente il core RISC? Questo aprirà un modo naturale per abbandonare lentamente il set di istruzioni x86, che al giorno d'oggi è deprecato (questo è il motivo principale per cui Intel ha deciso di utilizzare il core RISC all'interno, giusto?).

Guardando la nuova serie Intel "Core i" vedo che estendono solo il set di istruzioni CISC aggiungendo AVX, SSE4 e altri.


1
notare che ci sono alcune CPU x86 in cui è esposto il set di istruzioni RISC interno
phuclv

Risposte:


90

No, il set di istruzioni x86 non è certamente deprecato. È più popolare che mai. Il motivo per cui Intel utilizza internamente una serie di microistruzioni simili a RISC è perché possono essere elaborate in modo più efficiente.

Quindi una CPU x86 funziona avendo un decoder piuttosto pesante nel frontend, che accetta le istruzioni x86 e le converte in un formato interno ottimizzato, che il backend può elaborare.

Per quanto riguarda l'esposizione di questo formato a programmi "esterni", ci sono due punti:

  • non è un formato stabile. Intel può cambiarlo tra i modelli di CPU per adattarsi al meglio all'architettura specifica. Ciò consente loro di massimizzare l'efficienza e questo vantaggio andrebbe perso se dovessero accontentarsi di un formato di istruzioni fisso e stabile per uso interno e per uso esterno.
  • non c'è proprio nulla da guadagnare facendolo. Con le CPU enormi e complesse di oggi, il decoder è una parte relativamente piccola della CPU. Dover decodificare le istruzioni x86 lo rende più complesso, ma il resto della CPU non è influenzato, quindi nel complesso c'è davvero poco da guadagnare, soprattutto perché il frontend x86 dovrebbe essere ancora lì per eseguire codice "legacy" . Quindi non salveresti nemmeno i transistor attualmente utilizzati sul frontend x86.

Questa non è una soluzione perfetta, ma il costo è piuttosto contenuto ed è una scelta molto migliore rispetto alla progettazione della CPU per supportare due set di istruzioni completamente diversi. (In tal caso, probabilmente finirebbero per inventare una terza serie di micro-operazioni per uso interno, solo perché queste possono essere modificate liberamente per adattarsi al meglio all'architettura interna della CPU)


1
Punti buoni. RISC è una buona architettura di base, dove GOOD significa velocità di esecuzione e possibile implementazione correttamente, e x86 ISA che ha una storia architettonica CISC, è solo ora, un layout di set di istruzioni con una storia enorme e una favolosa ricchezza di software binario disponibile per esso , oltre ad essere efficiente per l'archiviazione e l'elaborazione. Non è una shell CISC, è lo standard ISA di fatto.
Warren P

2
@ Warren: nell'ultima parte, in realtà non la penso così. Un set di istruzioni CISC ben progettato è più efficiente in termini di archiviazione, sì, ma dai pochi test che ho visto, l'istruzione x86 "media" è larga qualcosa come 4,3 byte, che è più di quanto sarebbe tipicamente in un'architettura RISC. x86 perde molta efficienza di archiviazione perché è stato progettato ed esteso in modo così casuale nel corso degli anni. Ma come dici tu, il suo principale punto di forza è la storia e l'enorme quantità di codice binario esistente.
jalf

1
Non ho detto che fosse "CISC ben progettato", solo "enorme storia". Le parti BUONE sono le parti di progettazione del chip RISC.
Warren P

2
@jalf - Dall'ispezione dei binari effettivi, la dimensione delle istruzioni in x86 è in media di circa 3 byte ciascuna. Ci sono ovviamente istruzioni molto più lunghe, ma quelle più piccole tendono a dominare nell'uso effettivo.
srking

1
La lunghezza media dell'istruzione non è una buona misura della densità del codice: il tipo più comune di istruzione x86 nel codice tipico è il caricamento e l'archiviazione (spostando semplicemente i dati dove possono essere elaborati e di nuovo in memoria, i processori RISC e circa la metà del CISC hanno molti registri quindi non è necessario fare così tanto. Anche quanto può fare un'istruzione (le istruzioni per il braccio possono fare circa 3 cose).
ctrl-alt-delor

20

La vera risposta è semplice.

Il fattore principale alla base dell'implementazione dei processori RISC era ridurre la complessità e aumentare la velocità. Lo svantaggio di RISC è la ridotta densità di istruzioni, il che significa che lo stesso codice espresso in formato simile a RISC necessita di più istruzioni rispetto al codice CISC equivalente.

Questo effetto collaterale non significa molto se la tua CPU funziona alla stessa velocità della memoria, o almeno se entrambe funzionano a velocità ragionevolmente simili.

Attualmente la velocità della memoria rispetto alla velocità della CPU mostra una grande differenza nei clock. Le CPU attuali a volte sono cinque volte o più veloci della memoria principale.

Questo stato della tecnologia favorisce un codice più denso, qualcosa che CISC fornisce.

Si può sostenere che le cache potrebbero accelerare le CPU RISC. Ma lo stesso si può dire delle cpu CISC.

Si ottiene un miglioramento della velocità maggiore utilizzando CISC e cache rispetto a RISC e cache, poiché la cache della stessa dimensione ha un effetto maggiore sul codice ad alta densità fornito da CISC.

Un altro effetto collaterale è che RISC è più difficile per l'implementazione del compilatore. È più facile ottimizzare i compilatori per cpus CISC. eccetera.

Intel sa cosa stanno facendo.

Questo è così vero che ARM ha una modalità di densità del codice più elevata chiamata Thumb.


1
Anche un core RISC interno riduce il numero di transistor su una CPU CISC. Invece di cablare ogni istruzione CISC, puoi usare il microcodice per eseguirle. Ciò porta a riutilizzare le istruzioni del microcodice RISC per diverse istruzioni CISC, quindi utilizzando meno area dello stampo.
Sil

16

Se Intel mantiene la compatibilità con le versioni precedenti per così tanto tempo (abbiamo ancora la modalità 8086 virtuale accanto alla modalità a 64 bit), perché non ci consentono di compilare programmi in modo che ignorino le istruzioni CISC e utilizzino direttamente il core RISC? Questo aprirà un modo naturale per abbandonare lentamente il set di istruzioni x86, che al giorno d'oggi è deprecato (questo è il motivo principale per cui Intel ha deciso di utilizzare il core RISC all'interno, giusto?).

È necessario esaminare l'angolo di affari di questo. Intel ha effettivamente provato ad allontanarsi da x86, ma è l'oca che fa le uova d'oro per l'azienda. XScale e Itanium non si sono mai avvicinati al livello di successo che ha il loro core business x86.

Quello che stai sostanzialmente chiedendo è che Intel si tagli i polsi in cambio di caldi fuzzies da parte degli sviluppatori. Minare x86 non è nel loro interesse. Tutto ciò che fa sì che più sviluppatori non debbano scegliere di prendere di mira x86 mina x86. Questo, a sua volta, li indebolisce.


6
Sì, quando Intel ha provato a farlo (Itanium), il mercato ha risposto semplicemente con un'alzata di spalle.
Warren P

Va notato che c'erano una varietà di fattori durante il fallimento di Itanium, e non solo perché si trattava di una nuova architettura. Ad esempio, scaricare la pianificazione della CPU su un compilatore che non ha mai effettivamente raggiunto il suo obiettivo. Se l'Itanium fosse 10 o 100 volte più veloce delle CPU x86, si sarebbe venduto come una torta. Ma non è stato più veloce.
Viaggio Katastico

5

La risposta è semplice. Intel non sta sviluppando CPU per sviluppatori ! Li stanno sviluppando per le persone che prendono le decisioni di acquisto , che a proposito, è ciò che fa ogni azienda al mondo!

Intel si è impegnata molto tempo fa a fare in modo che (entro limiti ragionevoli, ovviamente) le loro CPU sarebbero rimaste compatibili con le versioni precedenti. Le persone vogliono sapere che, quando acquistano un nuovo computer basato su Intel, tutto il loro software attuale funzionerà esattamente allo stesso modo del loro vecchio computer. (Anche se, si spera, più veloce!)

Inoltre, Intel sa esattamente quanto sia importante questo impegno, perché una volta hanno cercato di andare in modo diverso. Esattamente quante persone si sa con una CPU Itanium?!?

Potrebbe non piacerti, ma quella decisione, rimanere con x86, è ciò che ha reso Intel uno dei nomi aziendali più riconoscibili al mondo!


2
Non sono d'accordo con l'insinuazione che i processori Intel non siano facili da usare per gli sviluppatori. Avendo programmato PowerPC e x86 per molti anni, sono arrivato a credere che CISC sia molto più facile da programmare. (Ora lavoro per Intel, ma ho deciso su questo problema prima di essere assunto.)
Jeff

1
@ Jeff Non era affatto mia intenzione! La domanda era: perché Intel non ha aperto il set di istruzioni RISC in modo che gli sviluppatori possano usarlo. Non ho detto nulla sul fatto che x86 non sia amichevole per gli sviluppatori. Quello che ho detto è che decisioni come questa non sono state prese pensando agli sviluppatori , ma, piuttosto, erano strettamente decisioni aziendali.
geo

5

La risposta di @jalf copre la maggior parte dei motivi, ma c'è un dettaglio interessante che non menziona: il core interno simile a RISC non è progettato per eseguire un set di istruzioni qualcosa come ARM / PPC / MIPS. L'imposta x86 non viene pagata solo nei decoder assetati di energia, ma in una certa misura in tutto il core. cioè non è solo la codifica delle istruzioni x86; è ogni istruzione con una semantica strana.

Facciamo finta che Intel abbia creato una modalità operativa in cui il flusso di istruzioni fosse qualcosa di diverso da x86, con istruzioni che si mappavano più direttamente su uops. Facciamo anche finta che ogni modello di CPU abbia il proprio ISA per questa modalità, quindi sono ancora liberi di cambiare gli interni quando vogliono ed esporli con una quantità minima di transistor per la decodifica delle istruzioni di questo formato alternativo.

Presumibilmente avresti ancora solo lo stesso numero di registri, mappati allo stato dell'architettura x86, quindi i sistemi operativi x86 possono salvarlo / ripristinarlo sui cambi di contesto senza utilizzare il set di istruzioni specifico della CPU. Ma se eliminiamo quella limitazione pratica, sì, potremmo avere qualche altro registro perché possiamo usare i registri temporanei nascosti normalmente riservati al microcodice 1 .


Se avessimo solo decoder alternativi senza modifiche alle fasi successive della pipeline (unità di esecuzione), questo ISA avrebbe ancora molte eccentricità x86. Non sarebbe un'architettura RISC molto bella. Nessuna singola istruzione sarebbe molto complessa, ma alcune delle altre follie di x86 sarebbero ancora lì.

Ad esempio: gli spostamenti sinistra / destra lasciano il flag Overflow indefinito, a meno che il conteggio degli spostamenti non sia uno, nel qual caso OF = il solito rilevamento di overflow con segno. Follia simile per le rotazioni. Tuttavia, le istruzioni RISC esposte potrebbero fornire spostamenti senza flag e così via (consentendo l'uso di solo uno o due dei multipli uops che di solito vanno in alcune complesse istruzioni x86). Quindi questo non regge davvero come il principale contro-argomento.

Se hai intenzione di creare un decoder completamente nuovo per un ISA RISC, puoi farlo scegliere e scegliere parti delle istruzioni x86 da esporre come istruzioni RISC. Questo mitiga in qualche modo la specializzazione x86 del core.


La codifica delle istruzioni probabilmente non sarebbe di dimensioni fisse, dal momento che i singoli utenti possono contenere molti dati. Molti più dati di quanti abbiano senso se tutti gli insns hanno la stessa dimensione. Un singolo uop microfuso può aggiungere un immediato a 32 bit e un operando di memoria che utilizza una modalità di indirizzamento con 2 registri e uno spostamento a 32 bit. (In SnB e versioni successive, solo le modalità di indirizzamento a registro singolo possono micro-fusibili con le operazioni ALU).

uops sono molto grandi e non molto simili alle istruzioni ARM a larghezza fissa. Un set di istruzioni a 32 bit a larghezza fissa può caricare solo 16 bit immediati alla volta, quindi il caricamento di un indirizzo a 32 bit richiede una coppia di caricamento immediato basso metà / carico alto-immediato. x86 non deve farlo, il che aiuta a non essere terribile con solo 15 registri GP che limitano la capacità di mantenere costanti nei registri. (15 è un grande aiuto su 7 registri, ma raddoppiare di nuovo a 31 aiuta molto meno, penso che sia stata trovata qualche simulazione. RSP di solito non è di uso generale, quindi è più come 15 registri GP e uno stack.)


TL; Riepilogo DR:

Ad ogni modo, questa risposta si riduce a "il set di istruzioni x86 è probabilmente il modo migliore per programmare una CPU che deve essere in grado di eseguire rapidamente le istruzioni x86", ma si spera che faccia luce sui motivi.


Formati UOP interni nel front-end vs back-end

Vedi anche Micro fusione e modalità di indirizzamento per un caso di differenze in ciò che i formati uop front-end e back-end possono rappresentare sulle CPU Intel.

Nota 1 : ci sono alcuni registri "nascosti" da utilizzare come provvisori per microcodice. Questi registri vengono rinominati proprio come i registri architetturali x86, quindi le istruzioni multi-up possono essere eseguite fuori ordine.

ad es. xchg eax, ecxsu CPU Intel decodifica come 3 uops ( perché? ), e la nostra ipotesi migliore è che si tratti di uops MOV-like che lo fanno tmp = eax; ecx=eax ; eax=tmp;. In quest'ordine, perché misuro la latenza della direzione dst-> src a ~ 1 ciclo, contro 2 per l'altro modo. E queste mosse non sono come le normali movistruzioni; non sembrano essere candidati per l'eliminazione dei movimenti a latenza zero.

Vedere anche http://blog.stuffedcow.net/2013/05/measuring-rob-capacity/ per un accenno al tentativo di misurare sperimentalmente la dimensione della PRF e al dover tenere conto dei registri fisici utilizzati per contenere lo stato dell'architettura, inclusi i registri nascosti.

Nel front-end dopo i decodificatori, ma prima della fase di emissione / rinomina che rinomina i registri sul file di registro fisico, il formato UOP interno utilizza numeri di registro simili ai numeri di registro x86, ma con spazio per indirizzare questi registri nascosti.

Il formato uop è leggermente diverso all'interno del core out-of-order (ROB e RS), noto anche come back-end (dopo la fase di emissione / rinomina). I file di registro fisico int / FP hanno ciascuno 168 voci in Haswell , quindi ogni campo di registro in un uop deve essere sufficientemente ampio da indirizzarne molti.

Dato che il renamer è presente nell'HW, probabilmente sarebbe meglio usarlo, invece di fornire istruzioni programmate staticamente direttamente al back-end. Quindi potremmo lavorare con un set di registri grande quanto i registri architetturali x86 + i provvisori del microcodice, non di più.

Il back-end è progettato per funzionare con un renamer front-end che evita i pericoli WAW / WAR, quindi non potremmo usarlo come una CPU in ordine anche se lo volessimo. Non dispone di interblocchi per rilevare tali dipendenze; che viene gestito da problema / rinomina.

Potrebbe essere carino se potessimo alimentare gli uops nel back-end senza il collo di bottiglia della fase di emissione / rinomina (il punto più stretto nelle moderne pipeline Intel, ad esempio 4-wide su Skylake contro 4 ALU + 2 load + 1 store port in il back-end). Ma se lo hai fatto, non penso che tu possa programmare staticamente il codice per evitare il riutilizzo del registro e calpestare un risultato che è ancora necessario se un errore nella cache ha bloccato un carico per molto tempo.

Quindi abbiamo praticamente bisogno di alimentare gli uop nella fase di rilascio / rinomina, probabilmente bypassando solo la decodifica, non la cache uop o IDQ. Quindi otteniamo un normale dirigente OoO con una sana rilevazione dei rischi. La tabella di allocazione dei registri è progettata solo per rinominare 16 + alcuni registri interi nella PRF intera da 168 voci. Non ci si poteva aspettare che l'HW rinominasse un insieme più grande di registri logici sullo stesso numero di registri fisici; ciò richiederebbe un RAT più grande.


-3

Perché non ci consentono di compilare programmi in modo che ignorino le istruzioni CISC e utilizzino direttamente il core RISC?

Oltre alle risposte precedenti, l'altro motivo è la segmentazione del mercato. Si pensa che alcune istruzioni siano implementate nel microcodice piuttosto che nell'hardware, quindi consentire a chiunque di eseguire microoperazioni arbitrarie può minare le vendite di nuove CPU con "nuove" istruzioni CISC più performanti.


1
Non credo che abbia senso. Un RISC può utilizzare il microcodice, soprattutto se si tratta di aggiungere solo decoder RISC a un frontend x86.
Peter Cordes

2
È ancora sbagliato. Le nuove istruzioni AES (e le imminenti istruzioni SHA) e altre cose come PCLMULQDQ hanno hardware dedicato. Su Haswell, AESENC si decodifica in un unico uop ( agner.org/optimize ), quindi non è assolutamente microcodificato. (I decoder devono solo attivare il sequencer ROM del microcodice per le istruzioni che decodificano a più di 4 uops .)
Peter Cordes

1
Hai ragione sul fatto che alcune nuove istruzioni usano semplicemente le funzionalità esistenti in un modo che non è disponibile con le istruzioni x86. Un buon esempio potrebbe essere BMI2 SHLX , che consente di eseguire turni di conteggio variabili senza mettere il conteggio in CL e senza incorrere negli Uops aggiuntivi necessari per gestire la pessima semantica delle flag x86 (i flag non vengono modificati se il conteggio degli spostamenti è zero, così SHL r/m32, clha una dipendenza di input da FLAGS e decodifica a 3 uop su Skylake. Era solo 1 uop su Core2 / Nehalem, tuttavia, secondo i test di Agner Fog.)
Peter Cordes

Grazie per i vostri commenti.
KOLANICH
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.