In che modo le lingue hanno influenzato la progettazione della CPU? [chiuso]

44

Siamo spesso detto che all'hardware non interessa il linguaggio in cui è scritto un programma come solo vede il codice binario compilato, tuttavia questa non è l'intera verità. Ad esempio, considera l'umile Z80; le sue estensioni al set di istruzioni 8080 includono istruzioni come CPIR che è utile per la scansione di stringhe in stile C (con terminazione NULL), ad es. per eseguire strlen() . I progettisti devono aver identificato che l'esecuzione di programmi C (al contrario di Pascal, in cui la lunghezza di una stringa è nell'intestazione) era qualcosa per cui il loro progetto era probabilmente destinato. Un altro classico esempio è la Lisp Machine .

Quali altri esempi ci sono? Per esempio. istruzioni, numero e tipo di registri , modalità di indirizzamento, che fanno sì che un particolare processore favorisca le convenzioni di un particolare linguaggio? Sono particolarmente interessato alle revisioni della stessa famiglia.

    
posta Gaius 30.07.2012 - 22:34
fonte

15 risposte

20

Le risposte esistenti si concentrano sulle ISA modifiche. Ci sono anche altri cambiamenti hardware. Ad esempio, C ++ usa comunemente vtables per le chiamate virtuali. A partire dal Pentium M , Intel ha un componente "predittore di rami indiretti" che accelera le chiamate alle funzioni virtuali.

    
risposta data 31.07.2012 - 14:04
fonte
14

Il set di istruzioni Intel 8086 include una variazione di "ret" che aggiunge un valore al puntatore dello stack dopo facendo scattare l'indirizzo di ritorno. Ciò è utile per molte implementazioni Pascal in cui il chiamante di una funzione spingerà gli argomenti in pila prima di effettuare una chiamata di funzione e li farà scattare in seguito. Se una routine accetterebbe ad es. valore di quattro byte di parametri, potrebbe terminare con "RET 0004" per ripulire lo stack. In assenza di tale istruzione, una tale convenzione di chiamata probabilmente avrebbe richiesto che il codice inserisse l'indirizzo di ritorno in un registro, aggiornasse il puntatore dello stack e poi saltasse su quel registro.

È interessante notare che la maggior parte del codice (incluse le routine del sistema operativo) sul Macintosh originale utilizzava la convenzione di chiamata Pascal nonostante la mancanza di un'istruzione di facilitazione nel 68000. L'uso di questa convenzione di chiamata salvava 2-4 byte di codice in un tipico sito di chiamata, ma richiesto un extra di 4-6 byte di codice nel sito di ritorno di ogni funzione che ha preso i parametri.

    
risposta data 31.07.2012 - 01:21
fonte
10

Un esempio è MIPS, che ha sia add che addu per il trapping e ignorando l'overflow rispettivamente. (Anche sub e subu .) Aveva bisogno del primo tipo di istruzione per linguaggi come Ada (penso - non ho mai usato effettivamente Ada) che trattano gli overflow esplicitamente e il secondo tipo per linguaggi come C che ignora gli overflow.

Se ricordo male, la CPU attuale ha alcuni circuiti aggiuntivi nell'ALU per tenere traccia degli overflow. Se l'unica lingua interessata alla gente fosse C, non avrebbe bisogno di questo.

    
risposta data 30.07.2012 - 22:45
fonte
8

La serie Burroughs 5000 è stata progettata per supportare in modo efficiente ALGOL e l'iAPX-432 di Intel è stato progettato per eseguire in modo efficiente Ada. L'Inmos Transputer aveva la sua lingua, Occam. Penso che il processore Parallax "Propeller" sia stato progettato per essere programmato usando la sua variante di BASIC.

Non è un linguaggio, ma il set di istruzioni VAX-11 ha una singola istruzione per caricare un contesto di processo, che è stato progettato dopo una richiesta dal team di progettazione VMS. Non ricordo i dettagli, ma ISTR ci ha messo così tante istruzioni per implementare che ha messo un serio limite superiore al numero di processi che potevano pianificare.

    
risposta data 30.07.2012 - 22:48
fonte
7

Una cosa che nessuno sembra aver menzionato finora è che i progressi nell'ottimizzazione del compilatore (in cui il linguaggio di base è in gran parte irrilevante) hanno spinto il passaggio dai set di istruzioni CISC (che erano in gran parte progettati per essere codificati dagli umani) ai set di istruzioni RISC ( che erano in gran parte progettati per essere codificati dai compilatori.)

    
risposta data 04.08.2012 - 17:52
fonte
5

La famiglia Motorola 68000 ha introdotto alcuni autoinserimento adressmode che ha reso la copia dei dati attraverso la CPU molto efficiente e compatto.

[Esempio aggiornato]

questo era un codice c ++ che influenzava 68000 assemblatori

while(someCondition)
    destination[destinationOffset++] = source[sourceOffset++]

implementato nell'assembler convenzionale (pseudocodice, ho dimenticato i comandi dell'assemblatore 68000)

adressRegister1 = source
adressRegister2 = destination
while(someCondition) {
    move akku,(adressRegister1)
    move (adressRegister2), akku
    increment(adressRegister1, 1)
    increment(adressRegister2, 1)
}

con il nuovo indirizzo è diventato qualcosa di simile a

adressRegister1 = source
adressRegister2 = destination
while(someCondition) {
    move akku,(adressRegister1++)
    move (adressRegister2++), akku
}

solo due istruzioni per ciclo invece di 4.

    
risposta data 31.07.2012 - 13:27
fonte
5

Il mainframe della serie Z di IBM, è il discendente di IBM 360 degli anni '60.

Ci sono state diverse istruzioni che sono state inserite appositamente per velocizzare i programmi COBOL e Fortran. L'esempio classico è BXLE - "Branch on Index Low or Equal" che è la maggior parte di un ciclo Fortran for o COBOL PERFORM VARYING x from 1 by 1 until x > n incapsulato in una singola istruzione.

Esiste anche un'intera famiglia di istruzioni decimali impaccate per supportare il calcolo dell'aritmetica decimale a virgola fissa nei programmi COBOL.

    
risposta data 31.07.2012 - 08:23
fonte
3

Le prime CPU Intel avevano le seguenti caratteristiche, molte delle quali ora obsolete in modalità 64-bit:

  • ENTER, LEAVE e RET nn istruzioni [i primi manuali dicevano esplicitamente che erano stati introdotti per i linguaggi strutturati a blocchi, ad esempio, Pascal, che supporta le procedure annidate]
  • istruzioni per accelerare l'aritmetica dei BCD (AAA, AAM, ecc.); anche il supporto BCD in x87
  • Istruzioni JCXZ e LOOP per l'implementazione di cicli conteggiati
  • INTO, per generare una trappola su overflow aritmetico (ad es. in Ada)
  • XLAT per ricerche tabella
  • BOUND per il controllo dei limiti degli array

Il flag di segno, presente nel registro di stato di molte CPU, esiste per eseguire facilmente l'aritmetica firmata AND senza segno.

Il set di istruzioni SSE 4.1 introduce istruzioni per l'elaborazione delle stringhe, sia conteggiate che con terminazione a zero (PCMPESTR, ecc.)

Inoltre, potrei immaginare che un numero di funzionalità a livello di sistema siano state progettate per supportare sicurezza del codice compilato (controllo del limite del segmento, cancelli di chiamata con copia dei parametri, ecc.)

    
risposta data 01.08.2012 - 17:41
fonte
3

Alcuni processori ARM, principalmente quelli nei dispositivi mobili, includono (d) l'estensione Jazelle, che è l'interprete hardware JVM; interpreta direttamente il bytecode Java. JVM Jazelle-aware può utilizzare l'hardware per accelerare l'esecuzione ed eliminare gran parte di JIT, ma il fallback al software VM è ancora garantito se il bytecode non può essere interpretato su chip.

I processori con tale unità includono l'istruzione BXJ, che mette il processore in speciale "modalità Jazelle", o se l'attivazione dell'unità non è riuscita, viene semplicemente interpretata come normale istruzione di salto. L'unità riutilizza i registri ARM per mantenere lo stato JVM.

Il successore della tecnologia Jazelle è ThumbEE

    
risposta data 05.08.2012 - 10:23
fonte
2

Per quanto ne so, questo era più comune in passato.

C'è una sessione di domande in cui James Gosling ha detto che c'erano persone che cercavano di fare hardware che avrebbe potuto gestire meglio il bytecode JVM, ma poi queste persone avrebbero trovato un modo per farlo con un intel x86 "generico" comune (magari compilando il bytecode in modo intelligente).

Ha detto che c'è un vantaggio nell'utilizzo del chip generico popolare (come quello di Intel) perché ha una grossa società che versa enormi somme di denaro al prodotto.

Il video vale la pena di provarlo. Ne parla al minuto 19 o 20.

    
risposta data 02.08.2012 - 21:36
fonte
2

Ho fatto una rapida ricerca di pagine e sembra che nessuno abbia menzionato la CPU sviluppata specificamente per eseguire Forth . Il linguaggio di programmazione Forth è basato sullo stack, compatto e utilizzato nei sistemi di controllo.

    
risposta data 09.08.2012 - 08:30
fonte
2

La CPU Intel iAPX è stata progettata specificamente per i linguaggi OO. Non ha funzionato abbastanza, però.

The iAPX 432 (intel Advanced Processor architecture) was Intel's first 32-bit microprocessor design, introduced in 1981 as a set of three integrated circuits. It was intended to be Intel's major design for the 1980s, implementing many advanced multitasking and memory management features. The design was therefore referred to as a Micromainframe...

The iAPX 432 was "designed to be programmed entirely in high-level languages", with Ada being primary and it supported object-oriented programming and garbage collection directly in hardware and microcode. Direct support for various data structures was also intended to allow modern operating systems for the iAPX 432 to be implemented using far less program code than for ordinary processors. These properties and features resulted in a hardware and microcode design that was much more complex than most processors of the era, especially microprocessors.

Using the semiconductor technology of its day, Intel's engineers weren't able to translate the design into a very efficient first implementation. Along with the lack of optimization in a premature Ada compiler, this contributed to rather slow but expensive computer systems, performing typical benchmarks at roughly 1/4 the speed of the new 80286 chip at the same clock frequency (in early 1982).

This initial performance gap to the rather low profile and low priced 8086-line was probably the main reason why Intel's plan to replace the latter (later known as x86) with the iAPX 432 failed. Although engineers saw ways to improve a next generation design, the iAPX 432 Capability architecture had now started to be regarded more as an implementation overhead rather than as the simplifying support it was intended to be.

The iAPX 432 project was a commercial failure for Intel...

    
risposta data 05.08.2012 - 05:29
fonte
1

Il 68000 aveva MOVEM che era più adatto a spingere più registri sullo stack in una singola istruzione, che è quello che molti linguaggi si aspettavano.

Se hai visto MOVEM (MOVE Multiple) che precede JSR (Jump SubRoutine) in tutto il codice, in genere sapevi che avevi a che fare con il codice C conforme.

MOVEM consentito per l'incremento automatico del registro di destinazione che consente a ciascun utilizzo di continuare a impilare sulla destinazione o di rimuoverlo dallo stack in caso di decremento automatico.

link

    
risposta data 04.08.2012 - 19:09
fonte
1

L'architettura AVR di Atmel è interamente progettata da zero per essere adatta alla programmazione in C. Ad esempio, questa nota applicativa elabora ulteriormente.

IMO questo è strettamente correlato all'eccellente risposta di un rockets4kids, con PIC16-s in fase di sviluppo diretto programmazione assembler (40 istruzioni totali), con famiglie successive che hanno come target C

    
risposta data 27.09.2013 - 10:46
fonte
1

Quando è stato progettato il coprocessore numerico 8087, era abbastanza comune per le lingue eseguire tutti i calcoli matematici a virgola mobile usando il tipo di massima precisione e arrotondare il risultato solo a una precisione inferiore assegnandolo a una variabile di precisione inferiore. Nello standard C originale, ad esempio, la sequenza:

float a = 16777216, b = 0.125, c = -16777216;
float d = a+b+c;

promuovere a e b a double , aggiungerli, promuovere c a double , aggiungerlo e quindi archiviare il risultato arrotondato a float . Anche se in molti casi sarebbe stato più veloce per un compilatore generare codice che eseguisse operazioni direttamente sul tipo float , era più semplice avere un insieme di routine a virgola mobile che operassero solo sul tipo double , lungo con routine da convertire in / da float , che avere serie separate di routine per gestire le operazioni su float e double . L'8087 è stato progettato attorno a questo approccio all'aritmetica, eseguendo tutte le operazioni aritmetiche utilizzando un tipo a virgola mobile a 80 bit [80 bit è stato probabilmente scelto perché:

  1. Su molti processori a 16 e 32 bit, è più veloce lavorare con una mantissa a 64 bit e un esponente separato piuttosto che lavorare con valori che dividono un byte tra la mantissa e l'esponente.

  2. È molto difficile eseguire calcoli accurati alla precisione dei tipi numerici che si stanno utilizzando; se si sta provando ad es. calcola qualcosa come log10 (x), è più facile e veloce calcolare un risultato che sia accurato all'interno di 100ulp di un tipo a 80-bit piuttosto che calcolare un risultato che sia preciso all'interno di 1ulp di un tipo a 64-bit e che arrotonda il primo il risultato della precisione a 64 bit produrrà un valore a 64 bit più accurato del secondo.

Sfortunatamente, le versioni future del linguaggio hanno cambiato la semantica di come dovrebbero funzionare i tipi in virgola mobile; mentre la semantica 8087 sarebbe stata molto carina se le lingue li avessero supportati in modo consistente, se le funzioni f1 (), f2 (), ecc. restituiscono il tipo float , molti autori di compilatori prenderanno su di loro stessi per rendere long double un alias per il doppio tipo a 64 bit anziché il tipo a 80 bit del compilatore (e non fornisce altri mezzi per creare variabili a 80 bit) e per valutare arbitrariamente qualcosa del tipo:

double f = f1()*f2() - f3()*f4();

in uno dei seguenti modi:

double f = (float)(f1()*f2()) - (extended_double)f3()*f4();
double f = (extended_double)f1()*f2() - (float)(f3()*f4());
double f = (float)(f1()*f2()) - (float)(f3()*f4());
double f = (extended_double)f1()*f2() - (extended_double)f3()*f4();

Si noti che se f3 e f4 restituiscono gli stessi valori di f1 e f2, rispettivamente, l'espressione originale dovrebbe restituire chiaramente zero, ma molte delle ultime espressioni potrebbero non esserlo. Ciò ha portato le persone a condannare la "precisione extra" dell'8087 anche se l'ultima formulazione sarebbe generalmente superiore alla terza e - con il codice che utilizzava il doppio tipo esteso in modo appropriato - sarebbe raramente inferiore.

Negli anni successivi, Intel ha risposto alla tendenza del linguaggio (IMHO sfavorevole) a forzare i risultati intermedi ad arrotondare la precisione degli operandi progettando i loro processori successivi in modo da favorire tale comportamento, a scapito del codice che andrebbe a vantaggio dall'uso di maggiore precisione sui calcoli intermedi.

    
risposta data 03.11.2014 - 20:17
fonte

Leggi altre domande sui tag