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)