Le istruzioni: il linguaggio dei calcolatori

Le istruzioni: il linguaggio dei
calcolatori
LuigiPalopoli
Insieme delle Istruzioni
• Perimpartire istruzioni alcomputerbisogna
parlare il suo linguaggio
• Illinguaggio si compone di unvocabolario di
istruzioni detto instructionset(IS)
• Ivari tipidi processore hanno ciascuno il
proprio IS.
• Tuttavia ledifferenze nonsono eccessive
§ Unutileesempio e’quello delle inflessioni
regionali di un’unica radice linguistica
Instruction Set
• Comeosservato da VonNueman leistruzioni:
“certi [insiemi di istruzioni]che inlinea di
principiosi prestano acontrollare l’Hardware”
• Egli stesso osservava che leconsiderazioni
davvero decisivesono di natura pratica:
§ semplicita’dei dispositivi richiesti
§ chiarezza delle applicazioni
§ velocita’di esecuzionei
• Queste considerazioni scritte nel 1947sono
straordinariamente valide anche oggi
In queste lezioni…
• Questaserie di lezioni vuole mostrare degli IS
(inmodo da vedere inseguito larealizzazione)
• Studieremo il concetto di programma
memorizzato:
Istruzioni e dati sono
memorizzati comenumeri
• Studieremo tre IS:
• MIPS
• INTEL
• ARM(cenni)
Perche’ il MIPS
• Ilmotivo percuimostreremo e faremo esercizi
conINTELe’abbastanza chiaro (qualche milione
di PCsono basati su Intelo Intelcompatibili)
• L’architettura MIPSe’invece un’architettura RISC
(inverita’nondiffusissima)
• Tuttavia
§ E’molto simileadaltre architetture RISCdiffusissime
(esempio ARM)
§ L’architettura INTELfa una traduzione ontheflydel
proprio ISche viene tradotta internamente inun
linguaggio RISC
Incominciamo…..
• Inzieremo dall’IS MIPS
• Acominciare daVonNeuman si diceva che
all’interno diunIS:
Devono necessariamente essere
previste istruzioni peril calcolo
delle operazioni aritmetiche
fondamentali
Operazioni artimetiche
• E’dunque naturale che l’architettura MIPS
supporti leoperazioni aritmetiche
• Perprogettare unIScomequello delMIPS
terremo conto di vari principi ispiratori
Principiodi Progettazione n.1:
Lasemplicita’favorisce laregolarita’
Istruzioni aritmetiche
• Ilmodo piu’semplice di immaginare una
istruzione aritmetica e’atre operandi:
a = b + c
• Quindi l’architettura delMIPSprevede
soltanto istruzioni aritmetiche atre operandi
add a, b, c
Istruzioni piu’ complesse
• Istruzioni piu’complesse si ottengono apartire dalla
combinazione di istruzioni semplici.
• Es.
a = b + c;
d = a – e;
• Diventa
add a, b, c
sub d, a, e
Esempio
• Nei linguaggi adaltolivello possiamo scrivere
espressioni complesse apiacimento:
f = (g+h) – (i+j);
• Quando si traduceabassolivello bisogna perforza
usare sequenze di istruzioni elementari
Esempio
• Adesempio lanostraespressione verra’
tradotta come mostrato di seguito
add t0, g, h; #la variabile temp.
# t0 = g + h
add t1, i, j; #la variabile temp.
# t1 = i + j
sub f, t0, t1; # f = t0 – t1
Un po’ di commenti
• Nell’assembler MIPS
§ i commenti iniziano con#e continuano fino alla fine
della linea
§ l’operando “destinatario”dell’operazione e’sempre il
primo
• Questo nonvalepertutti gli assemblatori.
• Adesempio sesi usa gcc comeassemblatore
questo seguelasintassi AT&Tperlaquale:
§ Icommenti si fanno alaC/*commento */
§ L’operando destinatario dell’operazione e’messo in
fondo
Operandi
• Fino adora abbiamo usato gli operandipiuttosto
allegramente (comesefossero “normali”
variabili di unlinguaggio adaltolivello)
• Inrealta’nel MIPSgli operandidi operazioni
aritmetiche sono vincolati adessere registri
• Unregistro e’una particolare locazione di
memoria che e’interna alprocessore e quindi
puo’essere reperita inmaniera velocissima (un
ciclo di clock)
Registri del MIPS
• IlMIPScontiene 32registri a32bit(64nel caso di MIPS
– 64)
• Ilvincolo di operare solotra registri semplifica di molto
il progetto dell’hardware
• Maperche’solo32registri?
Principiodi Progettazione n.2:
minori sono ledimensioni,maggiore lavelocita’
• Avere molti registri obbligherebbe Isegnali aspostarsi
su distanze piu’lunghe all’interno delprocessore
• Quindi pereffettuare uno spostamento all’interno di
unciclo di clocksaremmo costretti arallentare il clock
Esempio (Ripreso)
• Torniamo alnostro esempio:
f = (g+h) – (i+j);
• Ilcodice conI registri diviene:
add $t0, $s1, $s2; #Il registro temporaneo
# t0 viene settato =
# regist. s1+s2
add $t1, $s3, $s4;
sub $s0, $t0, t1; # f = t1 – t0
Osservazioni
• Nell’assembler MIPSperindicare che un
operando e’unregistro losi fa precedere da $
• Comeabbiamo detto leoperazioni aritmetiche e
logiche si effettuano solotra registri
• Ilproblema e’che I registri nonbastano
• Ci occorrono istruzioni di trasferimento che
§ prelevino locazioni di memoria e li mettano nei
registri (load)
§ salvino il contenuto dei registri inmemoria
La memoria
• Lamemoria e’una sequenza di bitorganizzati
ingruppi di 8(byte).
Ciascun bytee’
associato adun
indirizzo lineare
progressivo tramite
il quale e’possibile
prelevarlo
Word
• Perquanto lamaggior partedelle architetture
permettano l’accesso aciascun byte la
maggior partedelle voltesi trasferiscano
parole di dimensioni uguali ai registri
Vincolo di allineamento:
e’possibile accedere
soloaparoleposte
aindirizzi multipli
dell’ampiezza della
parola
Trasferimento
• Percaricare una word(o unbyte)devo
specificarne l’indirizzo
• Nell’assembler MIPS l’indirizzo si specifica
tramite una base(inunregistro)e uno
spiazzamento o offset (costante)
• Comevedremo inaltre architetture (esempio
INTEL)c’e’molta piu’flessibilita’nello
specificare l’indirizzo
Load
• Ilcaricamento di una parola contenuta in
indirizzo inunregistro avviene tramite la
seguente istruzione:
lw $t0, 4($s3)
Sista
operando su
una parola
Registro in
cuisi vuole
caricare
Base
Spiazzamento
• L’effetto di questa istruzione e’di caricare int0
lawordall’indirizzo dato da s3+4
Esempio
• Supponiamo di volere effettuare l’istruzione
A[12] = h + A[8]
• Latraduzione inassemblyMIPS
lw $t0, 32($s3); # La parola 8 comincia
#all’indirizzo 32 e il
#puntatore A e’ in s3
add $t0, $s2, $t0; #h e’ in s2
sw $t0, 48($s3); # memorizzo il contenuto del
# registro temp. in A[12]
Register Spilling
• Tipicamente I programmi contengono piu’variabili che
registri :=)
• Quello che si fa e’caricare levariabili inuso inundato
momento nei registri e scaricare quelle che nonsi
usano piu’inquel momento
• Questaoperazione e’chiamata registerspilling ed e’
eseguita dal compilatore che stima il workingset ed
inserisce nel codice I carichi/scarichi appropriati
• Nell’esempio precedente,magari l’indirizzo di Aserve
ancora ins3nelle istruzioni successivementre forse h
si puo’scaricare da s2
Operandi immediati o
costanti
• Molto spesso nelle operazioni aritmetiche
almeno uno dei dueoperandie’costante
• Unpossibile approccio puo’essere di
memorizzare lacostante inunqualche
indirizzo
• Esempio:
f = f + 4;
lw $t0, IndCost4($s1);# la costante 4
#e’ all’indirizzo s1 + IndCost4
add $s3, $s3, $t0;
Operandi Immediati
• Lasoluzione che abbiamo visto e’piuttosto
inefficiente
Principiodi Progettazione n.3:
rendi piu’veloci possibile leoperazioni comuni
• Perquesto motivo esistono istruzioni che
permettono di operare concostani
f = f + 4;
addi $s3, $s3, 4
Immediate
La costante 0
• Esistono alcune costanti che possono essere di
grande utilita’persemplificare alcune
operazioni
• Adesempio perspostare unregistro inun
altro posso renderlo destinatorio della somma
delsorgente con0
• Perquesto motivo il MIPSdedica unregistro
$zeroacontenere lacostante 0
Numeri
• Primadi parlare delmodo incuileistruzioni sono
codificate attraverso numeri (rappresentate)
ricordiamo:
§ Nei calcolatori l’unita’basedi informazione e’il bit
§ Ungruppo di 4bitpuo’essere associato adun
numero fino a16che rappresenta una cifra nella
notazione esadecimale
§ Quindi unbyteviene rappresentato da duecifre
esadecimali (ciascuna corrispondente a4bit)
§ Adesempio
1001 1101
9D
Cifre esadecimali
Little e big endian
• Quando si memorizza una parola di quattro
byte(o di 8)inuna sequenza di byteposti a
indirizzi progressivi va capito doveva il byte
piu’significativo e quello meno significativo.
• Esempio (esadecimale)
0XEA01BD1C
Bytepiu’
significativo
Bytemeno
significativo
Little e big endian
• Littleendian (Architetture Motorola,Protocolli
Internet)
EA01BD1C
Addr 3
EA
Addr 2
01
Addr 1
BD
Addr 0
1C
• BigEndian (Intel)
EA01BD1C
Addr 3
1C
Addr 2
BD
Addr 1
01
Addr 0
EA
Rappresentazione delle
istruzioni
• ComeI dati,anche unprogramma deve essere
memorizzato informanumerica
• Questo vuol direche leistruzione che
abbiamo introdotto simbolicamente
(assembly)devono essere convertite indei
numeri (codice macchina)
• Cominciamo conunesempio
Esempio
• Consideriamo l’istruzione
add $t0, $s1, $s2
• Perrappresentarla tramite uncodice numerico
univoco ci occorre:
• Uncodice numerico che ci dica che si tratta di un
add
• Altri codici numerici che ci dicano quali sono gli
operandi…
• il tutto in32bit
Risultato
• Ilrisultato rappresentato indecimale e’il
seguente:
6bit
5bit
5bit
5bit
5bit
6bit
000000 10001 10010 01000 00000 100000
(0)
Iprimi e gli ultimi
bitcodificano
l’istruzione
(17)
(18)
Primo
operando
(8)
Secondo
operando
(0)
(32)
Risultato
• Iregistri sono numerati (es.s1=17,s2=18)e
quindi possono essere specificati comeoperandi
all’interno delcodice dell’istruzione
Campi delle istruzioni MIPS
• Ingenerale,e’utiledareunnome ai vari campi
relativealcodice macchina di un’istruzione
6bit
5bit
5bit
5bit
OP
rs
rt
rd
• op:codice operativo dell’istruzione
• rs:primo operando sorgente
• rt:secondo operando sorgente
• rd:operando destinazione
5bit
6bit
shamt funct
• shamt:shiftamount(lo vedremo
peralcune istuzioni)
• funct: definisce lafunzionalita’
specifica dell’istruzione (insieme a
op).Adesempio lasottrazione e’un
particolare tipo di addizione
Tradeoff
Principiodi Progettazione n.4:unbuon progetto
richiede buoni compromessi
• Nel nostro caso il buon compromesso e’di far
stareleistruzioni in32bit
• Ci costa
§ limite alnumero di istruzioni
§ limite alnumero di registri
§ limite alle modalita’di indirizzamento
• …maci permette di guadagnare moltoin
efficienza
Istruzioni Immediate
• Abbiamo visto che ci sono istruzioni di
caricamento/salvataggio e somma con
costanti che nonpossono ovviamente stare
nel formato che abbiamo visto (detto R, da
registro)
• Perquesto motivo esiste anche unformato
perl’indirizzamento immediato (detto I)
Istruzioni Immediate
• Ilformato e’il seguente
6bit
5bit
5bit
OP
rs
rt
16bit
costante o indirizzo
• Adesempio:
35
lw $t0, 32($s3)
$s3
19
$t0
8
32
Esempio
• Supponiamo di voletradurre inlinguaggio
macchina leseguenti istruzioni:
A[300] = h + A[300];
• Latraduzione e’laseguente:
lw $t0, 1200($t1)
add $t0, $s2, $t0
sw $t0, 1200($t1)
in codice macchina….
• Cominciamo conil guardare i codici decimali:
lw
Istruzione
op
rs
rt
$t0, 1200($t1)
35
9
8
0
18
8
43
9
8
add $t0, $s2, $t0
sw
$t0, 1200($t1)
rd
Ind/Shamt
1200
8
0
32
1200
• Inbinario
op
rs
rt
100011
01001
01000
000000
10010
01000
101011
01001
01000
rd
Ind/Shamt
Funct
0000010010110000
01000
Funct
00000
0000010010110000
100000
Riassumendo
• Ciascuna istruzione viene espressa comeun
numero di 32bit
• Unprogramma consiste dunque inuna
sequenza di numeri
• Talesequenza viene scritta inlocaziomi
consecuitve di RAM
• Inmomenti diversi,nella stessa RAM,
possiamo rappresentare programmi diversi
Codici delle istruzioni viste
fino ad ora
Elenco (quasi completo)
delle istruzioni MIPS
Elenco (quasi completo)
delle istruzioni MIPS
Operazioni Logiche
• Iprimi calcolatori operavano solosu parole
intere
• Molto prestosi manifesto’lanecessita’di
operare su porzioni di paroleo addirittura sul
singolo bit
• IlMIPSfornisce alcune istruzioni che
permettono di farequesto inmaniera
semplificata (rispetto adaltre architetture)ma
efficace
Shift logico
Laprimaoperazione che andiamo avedere e’il cosidetto shiftlogico a
sinistra
L’idea e’di inserire degli zeri nella posizione meno significativa e traslare
tutto asinistra perdendo Ibitpiu’significativi
Esempio consideriamo:
•
•
•
s0 = 0000 0000 0000 0000 0000 0000 0000 1001
•
eseguiamo:
sll $t2, $s0, 4
0000 0000 0000 0000 0000 0000 0000 1001
•
0000
L’effetto e’di memorizzare int2144(da 9inizialmente presente ins0)
Il codice operativo
• Ilcodice operativo dell’istruzione:
sll $t2, $s0, 4
• e’:
op
rs
rt
rd
Ind/Shamt
Funct
0
0
16
10
4
0
Da quisi
comprende
l’utilita’delcampo
“shiftamount”
Effetto “collaterale”
• Uneffetto collaterale di questa istruzione e’moltiplicare il numero
operando per2^I,doveIe’il numero di elementi di cuisi fa loshift
• Questo funziona sempre?
• Esempio:
s0 = 10000000000000000000000000000100
(dec.-2147483644)
• Cosa succede se noi effettuiamo:
sll $t2, $s0, 1
• Otteniamo:
t2 = 00000000000000000000000000001000
(dec. 8)
• Ilproblema e’semplicemente che il numero none’rappresentabile.
Un caso diverso
• Seinvece prendiamo:
s0 = 11111111111111111111111111111110
(dec.-2)
• Seeffettuiamo:
sll $t2, $s0, 1
• Otteniamo:
s0 = 11111111111111111111111111111100
(dec.-4)
• Serimaniamo nel rangedi rappresentabilita’lamoltiplicazione per
potenze di 2tramite shiftfunziona bene.
Shift a destra
• Analogamente allo shiftlogico asinistra si puo’avere uno shift
logico adestra
• Esempio:
s0 = 0000 0000 0000 0000 0000 0000 0000 1001
• Seeffettuiamo:
srl $t2, $s0, 1
0
0000 0000 0000 0000 0000 0000 0000 1001
Effetti collaterali
• Generalizzando il ragionamento che abbiamo fatto prima,ci
verrebbe di direche loshiftadestra di Iunita’corrisponde a
dividere per2^I
• E’corretto?
• Nell’esempio fatto primafacendo loshiftadestra di 1sul numero 9
abbiamo ottenuto 4(che e’il risultato della divisione intera)
• Consideriamo unaltro esempio:
s0 = 11111111111111111111111111111100
(dec.-4)
srl $t2, $s0, 1
• Quello che si ottiene e’unnumero positivo e questo nonostante il
risultato dell’operazione sia perfettamente rappresentabile :=(
Shift aritmetico
• Perrisolvere il problema evidenziato si risolve conloshift
aritmetico adestra.
• Insostanza quello che si inserisce adestra nonsono bituguali a0
mauguali albitdi segno
• Nel nostro esempio
s0 = 11111111111111111111111111111100
sra $t2, $s0, 1
11111111111111111111111111111100
• Risultato (corretto):
11111111111111111111111111111110
Shift aritmetico
• Notare che loshiftaritmetico nonhanessun
senso fatto asinistra
§ Inquel caso o il risultato e’rappresentabile e lo
shiftlogico funziona comeartimetico o nonloe’e
nonc’e’molto che si possa fare.
• Altre architetture offrono entrambi I tipidi
shift
§ MIPSessendo RISCfornisce solol’essenziale :=)
Altre operazioni logiche
• IlMIPSoffre inaggiunta aquelle viste altre
operazioni logiche
• Alcune di queste sono elencate di sotto:
AND bit a bit
• Leoperazioni logiche operano su ciascun bit
• Esempio:
t1 = 0000 0000 0000 0000 0000 1101 0000 0000
t2 = 0000 0000 0000 0000 0011 1100 0000 0000
and $t0, $t1, $t2
• Risultato:
t0 = 0000 0000 0000 0000 0000 1100 0000 0000
• L’operazione andforza alcuni bita0usando come
operando una maschera (I cuibitcorrispondenti a
quelli che si vogliono annullare siano 0)
OR bit a bit
• Analogamente e’possibile settare a1alcuni
bitfacendo orconunoperando che abbia 1
nella posizione corrispondente (maschera)
• Esempio:
§ Supponiamo divolere impostare a1i 4bitpiu’
significativi diuna wordcontenuta ins0.
addi $t0,$zero,0X000F
sll $t0, $t0,28
or $s0, $s0, $t0
Rotazione
• Esempio:
§ Supponiamo di volere girare i quattro bitpiu’
significative di una wordsuisuoi bitmeno
significativi
1101 0000 0000 0000 0000 1100 0000 0000
Esempio
• Primopasso
s0 = 11010000000000000000110000000000
srl $t0, $s0, 28
t0 = 00000000000000000000000000001101
• Secondpasso
s0 = 11010000000000000001100000000000
sll $s0, $s0, 4
s0 = 0000000000000011000000000000000
Esempio
• Terzo passo
s0 = 00000000000000001100000000000000
or $s0, $s0, $to
s0 = 00000000000000001100000000001101
Il nor
• Supponiamo:
t1 = 0000 0000 0000 0000 0000 1101 0000 0000
t2 = 0000 0000 0000 0000 0011 1100 0000 0000
nor$t0, $t1, $t2
• Risultato:
t0 = 1111 1111 1111 1111 1100 0010 1111 1111
Lo strano caso del not
• Ilnot normalmente e’unoperatore unario
• Peri progettisti MIPStutte leoperazioni
artimetiche hanno tre operandidi tipo registro
• Perquesto motivo si e’deciso di nonfornire il
notmail nor
• Ilnotsi ottiene dal normoltofacilmente
nor $s0, $s0, $zero #equivale a not s0
Or esclusivo
• Oltre che AND,OR,NORabbiamo anche unsupporto per
l’OR esclusivo (XOR)
• Ricordiamo che l’OR esclusivo produce1see soloseI due
bitoperandisono uno e zero(e zeronegli altri casi).
t1 = 0000 0000 0000 0000 0000 1101 0000 0000
t2 = 0000 0000 0000 0000 0011 1100 0000 0000
xor$t0, $t1, $t2
• Risultato:
t0 = 0000 0000 0000 0000 0011 0001 0000 0000
Esempio
• Cosa succede sefacciamo?
xor $t0, $t0, $t0
• Ilrisultato e’quello di annullare il valore di t0
• E’una maniera molto veloce ed efficiente per
annullare unregistro
• Ricordare
• A XORB=(AANDNOT(B))OR(NOT(A)ANDB)
Istruzioni per prendere
decisioni
• Una delle caratteristiche fondamentali dei calcolatori
(che li distinguono dalle calcolatrici)e’lapossibilita’di
alterare il flusso di programma alverificarsi di certe
condizioni
§ costrutto ifnelle varie forme
• Illinguaggio macchina delle varie architetture supporta
questa possibilita’fornendo istruzioni di salto
condizionali
• Tipicamente questo avviene sulla basedelvalore di un
registro di flagdi stato
• Nel caso lecondizioni peril salto sono esplicite
nell’istuzione di salto
Salto su condizioni
• Ledueistruzioni di salto condizionale sono:
beq reg1, reg2, L1
bne reg1, reg2, L1
Seil registro reg1e’
uguale alregistro
reg2effettua un
salto all’istruzione
conetichetta L!
Seil registro reg1e’
diverso dal registro
reg2effettua un
salto all’istruzione
conetichetta L!
Costrutto if
• Supponiamo di avere il seguente codice C.Come
viene tradotto?
if (i == j) f = g + h; else f = g – h;
Costrutto if
• Traduzione costrutto ifprecedente:
bne $s3, $s4, ELSE
add $s0, $s1, $s2
j
ESCI
ELSE: sub $s0, $s1, $s2
ESCI: ……
#Salta a ELSE se s3 div. da s4
#f = g + h
# Salto incond. a ESCI
# f = g - h
• Alcune osservazioni
• Lelabelvengono alla finetradotte inindirizzi
• Perfortuna questo lavoro noioso e’operadel
compilatore
Cicli
• Lastruttura che abbiamo presentato puo’essere usata
anche perrealizzare dei cicli
• Consideriamo l’esempio:
while (salva[i] == k)
i += 1;
• Traduzione:
Ciclo: sll
add
lw
bne
addi
j
Esci: ….
$t1, $s2, 2
#Registro temp. t1 = 4*I
$t1, $t1, $s6 #Ind di salva[i] in t1
$t0, 0($t1)
#salva[i] in t0
$t0, $s5, Esci #Esci se raggiunto limite
$s2, $s2, 1
#i = i+1
Ciclo
Commenti
• Lesequenze di istruzioni di salto condizionato
(conditionalbranch)sono cosi’importanti che
viene dato loro unnome:blocchi di base
§ Blocco di base: seq.di istruzioni che noncontiene
istuziomi di salto (conl’eccezione dell’ultima)ne
etichette di destinazione (conl’eccezione dela prima)
• Una delle primefasi della compilazione e’di
individuare I blocchi base
• Tutti I cicli inlinguaggio adaltolivello vengono
implementati coblocchi di base.
Altri confronti
• Oltre alsalto su operandiuguali o diversi,e’utileavere un
salto anche su operandiminori/maggiori o minori uguali
• Ilmodo di faredelMIPSe’tramite istruzioni che settano il
valore di registri flag
• Laprimadi queste e’setta seminore o uguale
slt $t0, $s3, $s4 #t0 = 1 se s3 < s4
• Diquesta istruzione esiste anche una variante immediata:
slti $t0, $s3, 10 #t0 = 1 se s3 < 10
• Icompilatori MIPSottengono I salti su condizioni di tipo
minore o uguale combinando SLTconBEQ,o BNEe usando
lacostante 0perfareI test
Esempio
• Consideriamo il codice
if (i < j) f = g + h; else f = g – h;
• Traduzione
slt $t0, $s3, $s4 #setta t0 se se i < j
beq $t0, $zero, ELSE #Salta a ELSE se s3 div. da s4
add $s0, $s1, $s2 #f = g + h
j
ESCI
# Salto incond. a ESCI
ELSE: sub $s0, $s1, $s2 # f = g - h
ESCI: ……
Signed e unsigned
• L’esito delconfronto e’ovviamente diverso se
si tiene conto delsegno oppure no.
• Perquesto motivo troviamo dueversioni di
SLT(SLTU,SLTUI)che operano su interi senza
segno
Esempio
• Sisupponga che
s0 = 1111 1111 1111 1111 1111 1111 1111 1111
s1 = 0000 0000 0000 0000 0000 0000 0000 0001
• Cosa produce?
slt $t0, $s0, $s1
t0 = 1
• Ecosa
sltu $t0, $s0, $s1
t0 = 0
Un piccolo trucco
• Supponiamo di volere controllare seunindice (s1)e’fuori
dal limite di unarray([0,t2])
• Ce lapossiamo cavare conunsoloconfronto
sltu $t0, $s1, $t2
beq $t0, $zero, FuoriLimite
• Perche’?
• Ses1e’maggiore di t2,ovviamente avremo 0int2
• Ma anche ses1e’negativo,interpretato comeunsigned,
sara’maggiore di t2(che hail bitpiu’significativo a0)
Il costrutto case/switch
• Una possibilita’e’quella di effettuare una
sequenza incascata di if-then-else
• Inrealta’esiste una tecnica diversa
§ Memorizzare i vari indirizzi doveeseguire il codice
inuna tabella (una sequenza di word)
§ Caricare inunregistro l’indirizzo cuisi deve saltare
§ fareunsalto all’indirizzo puntato dal registro (jr)
Il costrutto case/switch
• Esempio:
switch(a) {
case 1: <code 1>;
case 2: <code 2>;
…..
};
Tabella dove
memorizzo gli indirizzi
dei codici
sll $t0, $a0, 2 #moltiplica per
4
lw $t0, TABLE($t0)
jr $t0
Saltoall’indiriizzo nel
registro
Procedure
• L’utilita’di uncomputesarebbe molto limitata
senonsi potessero chiamare procedure(o
funzioni)
• Possiamo pensare auna procedurecomea
una “spia”che fa dellavoro pernoi senza che
noi vogliamo sapere comelofa
• Lacosa importante e’di mettersi d’accordo su
unprotocollo
Protocollo
1.metter i parametri inunposto noto
2.trasferire il controllo alla procedura
1.Acquisire lerisorse necessarie
2.Eseguire il compito
3.mettere i valori di ritorno inposti noti
4.Restituire il controllo alchiamante
3.Prendersi il valore di ritorno e “cancellare”le
traccie
Protocollo
• Ilmodo incuiquesto protocollo viene messo
inpratica dipende dall’architettura e dalle
convenzioni di chiamata delcompilatore
• Ci limitiamo apochi cenni peril MIPS
Protocollo di chiamata
MIPS
• L’idea di basee’di cercare di laddove possibile
iregistri,perche’sono il meccanismo piu’
veloce pereffettuare il passaggio dei
parametri
• Convenzione peril MIPS
§ $a0,..$a3:usati peri parametri iningresso
§ $v0,$v1:valori di ritorno
§ $ra
:indirizzo di ritorno pertornare alpunto
di partenza
Protocollo di chiamata
MIPS
• Oltre ai registri,l’hardware MIPSmette adisposizione
l’istruzione di jumpandlink(JAL)che effettua il salto e
contemporaneamente memorizza inra l’indirizzo di
ritorno
§ L’indirizzo che viene salvato inra e’il PC(programcounter)
incrementato di 4(istruzione sucessiva alla jal)
• Alla finedella procedura sara’sufficiente fareunsalto
jr $ra
…e se i registri non
bastano?
• Incerti casi I registri nonbastano perche’hopiu’
parametri di quanti nepossano contenere I registri
• Intal caso si una lostack,una struttura dati gestita con
disciplina FIFOincuie’possibile mettere apartire da
una posizione notaalla procedura (puntata dal registro
fp)I parametri inpiu’
• Lostacksi puo’usare anche mettere variabili locali
(tramite un’operazione di push)e salvare registri che
occorrera’ripristinare inseguito
• Alla finedella procedura si puo’ripulire lostack
(operazione pop)riportandolo alla situazione
precedente
Esempio
• Consideriamo laprocedura inC:
int esempio_foglia(int g, int h, int i, int j) {
int f;
f = (g+h) – (i+j);
return f;
}
• Cerchiamo di capire comeverrebbe tradotta
Prologo
• Perprimacosa il compilatore sceglie un’etichetta
associata all’indirizzo di entrata della procedura
(esempio_foglia)
§ Infase di collegamento (linking)l’etichetta sara’
collegata aun’indirizzo
• Laprimaoperazione e’quella di salvare in
memoria tutti I registri che laprocedura usa in
modo da poterli ripristinare inseguito
• Talefase e’chiamata prologo e potrebbe
richiedere di allocare nello stackanche spazio per
levariabili locali (sei registri nonbastano).
Uso dei Registri
• Parametri ininput
§ - g =$a0;h=$a1;i=$a2:j=$a3
• Variabile localef:$s0
• Usiamo atitolo diesempio anche Iregistri $t0
e $t1(cosa che nessun compilatore farebbe)
• Supponiamo,sempre atitolo diesempio,di
dover salvere $s0,$t1e $t0
Prologo
•
•
•
Laprocedura usIregistri s0,t0,t1;
Ilregistro SPpunta alla testa dello stack(che si evolveversoil basso)
Ilcodice delprologo e’il seguente:
Decrementiamo spdi
12,perfarposto a3
word
esempio_foglia: addi $sp, $sp, -12;
sw
$t1, 8($sp)
sw
$t0, 4($sp)
sw
$s0, 0($sp)
Salvataggio di t1in
sp+8
Salvataggio di s0in
sp+0
Esecuzione della procedura
• Dopo il prologo,l’esecuzione della procedura:
Int0mettiamo g+h
add $t0, $a0, $a1
add $t1, $a2, $a3
sub $s0, $t0, $t1
Int1mettiamo i+j
Ins0(g+h)-(i+j)
Epilogo
• Dopo avereseguito laprocedura,si ripristinano i
registri usati e si setta il valore di ritorno
Trasferiamo s0inv0
(valore di ritorno)
add
lw
lw
lw
addi
jr
$v0,
$s0,
$t0,
$t1,
$sp,
$ra
Ripristino I registri
prelevando i valori
esattamente da dove
li avevo messi
$s0, $zer0
0($sp)
4($sp)
8($sp)
$sp, 12
Saltoalpunto da
dovesono arrivato
Ripristino lostack
(tutto cio’che e’
sottospnon e’
significativo)
Evoluzione dello stack
Stackprimadella
chiamata
Stackdurante
l’esecuzione della
procedura
Stackdopo la
chiamata
Un bagno di realta’
• Nessun compilatore farebbe mai questo
• Infatti
§ Iregistri temporanei *non*devono essere
salvaguardati
§ L’uso di$s0eranonnecessario (potevamo
lavorare direttamente su $t0e $v0)
Ulteriori complicazioni
• Inrealta’lecose possono complicarsi pervia
di
§ Variabili locali
§ Procedureannidate
• Questo si risolve usando sempre lostacke
allocandovi dentro variabili locali e valori del
registro ra
• Vediamo unesempio
Procedure ricorsiva
• Consideriamo il seguente esempio
int fact(int n) {
if (n < 1)
return 1;
else
return n*fact(n-1);
}
• Qui(masarebbe lostesso conuna qualsiasi funzione
che chiama un’altra funzione)abbiamo dueproblemi:
§ sovrascrittura di$ra che mirenderebbe impossibile il
ritorno una volta finita lachiamata innestata.
§ Sovrascrittura di$a0usato peril registro n
Procedure ricorsiva
• Soluzione:salvaguardare il registro $ra,a0
• Vediamo lasoluzione
• Primostep:creiamo spazio nello stackesalviamo ra
ea0
Fact:
addi $sp, $sp, -8
sw
$ra, 4($sp)
sw
$a0, 0($sp)
#Ci serve spazio per due oggetti
#Salviamo ra
#Salviamo a0
• Secondostep,testiamo sen<1(ritornando 1incaso
affermativo):
slti $t0, $a0, 1
beq $t0, $zero, L1
#t0 settato a 1 se n < 1
#Se n > 1 saltiamo a L1
Procedure ricorsiva
• Sen <1chiudiamo laprocedura
addi $v0, $zero, 1 #metodo del MIP per mettere in v0 1
addi $sp, $sp, 8
#Ripuliamo lo stack
jr
$ra
#Ritorniamo all’indirizzo di ritorno
notache nonripristiniamo ra ea0(comesi farebbe
normalmente,perchè nonliabbiamo cambiati)
• Sen>1decrementiamo nerichiamiamo fact
L1: addi $a0, $a0, -1
jal
fact
#decrementiamo n
#chiamiamo fact(n-1)
Procedure ricorsiva
• Aquesto punto ripristiniamo a0era eripuliamo lo
stack
lw $a0, 0($sp)
lw $ra, 4($sp)
addi $sp, $sp, 8
#Ripristino a0
#Ripristino ra
#ripulisco stack
• Nonciresta che moltiplicare fact(n-1),che è inv0,
perneritornare
mul $v0, $a0, $v0
jr $ra
Storage class
• Levariabili inCsono ingenere associatealocazioni di
memoria
• Sicaratterizzano per
§ Tipo (int,char,float)
§ Storageclass
• IlChaduepossibili storageclass
§ Automatic(variabili locali che hanno unciclo divita
collegata alla funzione)
§ Staticsopravvivono alle chiamate diprocedura.Sono
essenzialmente variabili globali odefinitedentro funzioni
comestatic
• Levariabili statiche sono memorizzate inuna zona di
memoria (nel MIPSaccessibile attraverso il registro
globalpointer,$GP)
Variabili locali
• L’ultimo problema è costituito dalle variabili
locali
• Quando sono poche,si riescono ausare
registri
• Quando sono tante (adesempio struct
complesse oarray)noncisono abbastanza
registri
• Quello che si fa è allocare levariabili locali
nello stack
Record di attivazione
• Ilsegmento distackche contiene registri salvati e
variabili locali relativeauna funzione viene
chimata recorddiattivazione (o stackframe)
• Levariabili locali vengono individuatetramite un
offsetapartire daunpuntatore
• Ilpuntatore $sp è alle voltescomodo comebase
perchè cambiadurante l’esecuzione della
funzione
• Ilregistro $fp (framepointer)viene sempre
mantenuto costante durante lafunzione epuò
essere usato comebase.
Evoluzione dello stack
$fp
$fp
$fp
$sp
$sp
Saved
arguments
registers
Savedreturn
address
$sp
Primadella
chaimata
Saved
registers
Saved
registers
Durantela
chiamata
Dopo la
chiamata
Dati dinamici
• Inaggiunta avariabili globali evariabili locali abbiamo
anche levariabili dinamiche (quelle che vengono allocata
conmalloc/free,new/delete)
• IlMIPSadotta il seguente schemadimemoria
stack
$sp
Dynamicdata
$gp
StaticData
$pc
Text
Resrved
Lostackprocede
perindirizzi
decrescenti
Loheapprocede
perindirizzi
crescenti
Convenzioni sui registi
• Inbasealle convenzioni,l’uso dei registri è nella sequente
tabella
Nome
Numero
Uso
Preservare
$zero
0
Valore costante 0
n.a.
$v0- $v1
2-3
Valori diritorno perchiamate difunzioni e
valuazione diespressioni
No
$a0-$a3
4-7
Argomenti
No
$t0-$t7
8-15
Temporanei
No
$s0- $s7
16-23
Salvati
Si
$t8-$t9
24-25
Ulteriori temporanei
No
$gp
28
Puntatore ai globali
Si
$sp
29
Puntatore allo stack
Si
$fp
30
Framepointer
Si
$ra
31
ReturnAddress
si
Elaborazione
• Perquanto lericorsioni siano eleganti spesso
sono causa divarie inefficienze
Neverhireaprogrammerwhosolvethefactorialwitharecursion
• Consideriamo laseguente funzione
int sum(int n) {
if (n > 0)
return sum(n-1) + n;
else
return n;
}
Elaborazione
• Consideriamo lachiamata sum(2)
2+1
Sum(2)
Ilvalore diritorno viene costruito
n=2
1+0
Sum(1)
n=1
0
Sum(0)
n=0
2+sum(1)
1+sum(0)
Tornando su perlacatenadichiamate.
Ogni framediattivazione deve essere
Preservato perprodurre il risutlato
corretto.
Elaborazione
• Consideriamo ora il codice così modicato
int sum(int n, int acc) {
if (n > 0)
return sum(n-1, acc+n);
else
return acc;
}
• Stavolta lachiamata ricorsiva è l’ultima cosa che la
funzione fa (si limita aritornare).
• Questaricorsione viene detta dicoda…ritorniamo al
nostro esempi sum(2,0).
Codice
• Laprocedura ricorsiva viene compilata comeseguesegue:
sum:
move
blez
$v0, $a1
$a0, $L5
#metti $a1 in $v0
#se $a0 < 0, salta a L5
addiu
sw
addu
addiu
jal
$sp,
$ra,
$a1,
$a0,
sum
#Prologo> crea spazio nello stack
#Prologo, salve ra
#Somma a0 ad a1 (acc=acc+n)
#Decrementa a0 (n=n-1)
#Chiamata ricorsiva (modifica ra)
$sp, -32
(28)$sp
$a1, $a0
$a0, -1
lw
$ra, 28($sp)
addiu $sp, $sp, 32
$L5:
j $ra
#ripristina ra
#rimette a posto lo stack
Elaborazione
• Consideriamo lachiamata sum(2)
3
Sum(2,0)
n=2,acc=0
3
Sum(1)
n=1,acc=2
3
Sum(0)
n=0,acc=3
Sum(1,2)
Sum(0, 3)
Inquesto caso lungo
iramidiritorno nonfaccio
che restituire 3.
Conservare i dati nel framedi
attivazione è inutile.Posso usare
ununico framediattivazione e svolgere
Laricorsione initerazione.
Ottimizzazione
• Alcuni compilatori sanno riconoscere la
ricorsione dicoda:
§ Ilchiamante ritorna subito dopo la“jal”
§ $v0e gli altri registri noncambiano
§ Ilchiamato potrebbe direttamente ritornare al$ra
delchiamante
§ Inaltre paroleil chiamante salva $ra e lorecupera
pernulla
• Torniamo alnostro esempio della somma…
Ottimizzazione
• Quello che potremmo fareguardando alcodice e’molto
semplicemente osservare che possiamo sostituire la“jal”con
unjump“j”,congrandi semplificazioni
sum:
move
blez
$v0, $a1
$a0, $L5
#metti $a1 in $v0
#se $a0 < 0, salta a L5
addiu
sw
addu
addiu
jal
$sp,
$ra,
$a1,
$a0,
sum
#Prologo> crea spazio nello stack
#Prologo, salve ra
#Somma a0 ad a1 (acc=acc+n)
#Decrementa a0 (n=n-1)
#Chiamata ricorsiva (modifica ra)
$sp, -32
(28)$sp
$a1, $a0
$a0, -1
lw
$ra, 28($sp)
addiu $sp, $sp, 32
$L5:
j $ra
#ripristina ra
#rimette a posto lo stack
Ottimizzazione
• Ilcodice risultante e’piu’corto e anche piu’efficiente
• Ilgcc fa questo con–O2
sum:
move
blez
$v0, $a1
$a0, $L5
addu
$a1, $a1, $a0
addiu $a0, $a0, -1
j
sum
$L5:
j $ra
#metti $a1 in $v0
#se $a0 < 0, salta a L5
#Somma a0 ad a1 (acc=acc+n)
#Decrementa a0 (n=n-1)
#Chiamata ricorsiva (modifica ra)