http://www.windizio.altervista.org/appunti/
File distribuito con licenza Creative Commons BY­NC­SA 2.5 IT
Copyright © 2007 ­ Michele Tartara
Parte I
Linguaggio IR
1 Espressioni (exp - expressions) del linguaggio
CONST un valore costante
NAME indica un'etichetta di destinazione per i salti condizionati (come la LABEL assembly)
TEMP un temporary (simile ad un registro delle macchine reali). Ne possono esistere inniti.
BINOP operazione binaria, applicata su due espressioni (sottoalberi)
MEM il contenuto di una cella di memoria. Se usata come sottoalbero sinistro di una MOVE indica una operazione store, in
tutti gli altri casi una fetch
CALL una chiamata di funzione applicata a una lista di argomenti
ESEQ riceve due parametri, s (un'istruzione) e e (un'espressione). s è valutato per la produzione di side-eect, poi e è valutato
per restituire un risultato
2 Istruzioni (stm - statements) del linguaggio
MOVE(TEMP t,e) valuta l'espressione e e pone il risultato in t
MOVE(MEM(e1 ),e2 ) pone il risultato dell'espressione e1 nella cella di memoria all'indirizzo indicato da e1
EXP(e) valuta l'espressione e e scarta il risultato
JUMP(l) salta all'etichetta indicata da l (e denita, altrove, da LABEL)
CJUMP(o,e1 ,e2 ,t,f ) valuta e1 ed e2 , ne compara i risultati tramite l'operatore o (EQ, NE, LT, GT, LE, GE) e salta all'etichetta
indicata da t se il risultato è vero, da f se il risultato è falso
SEQ(s1 ,s2 ) l'istruzione s1 è seguita dall'istruzione s2
LABEL(n) denisce l'etichetta n assegnandogli l'indirizzo di codice macchina attuale. Si può usare NAME per riferirsi ad
un'etichetta denita da LABEL.
3 Traduzione di espressioni in alberi
3.1 Variabile
Una variabile v che sappiamo essere posta a distanza k dal frame pointer f p può essere rappresentata in un albero come:
MEM(BINOP(PLUS, TEMP f p, CONST k ))
oppure, in forma abbreviata:
MEM(+(TEMP f p, CONST k ))
3.2 Array
In un linguaggio come il C, il nome a di un array rappresenta l'indirizzo e del suo primo elemento. Perciò, considerando una
dimensione delle celle di memoria pari a W , l'accesso all'elemento i-esimo a[i] diventa l'indirizzo del primo elemento sommato a
i volte W :
MEM(+(MEM(e), BINOP(MUL, i, CONST W )))
Nota: Nei compilatori moderni è importante controllare il rispetto dei limiti di un array!
1
http://www.windizio.altervista.org/appunti/
File distribuito con licenza Creative Commons BY­NC­SA 2.5 IT
Copyright © 2007 ­ Michele Tartara
3.2.1 Creazione
Per generare le istruzioni di creazione (dinamica) di un nuovo array, il complilatore deve eseguire i seguenti passi:
1. Determinare quanto spazio è necessario per l'array, tramite questa formula: ((lunghezza dell'array)+1)×(dimensione di un element
Il +1 è necessario per poter memorizzare anche la dimensione dell'array stesso, ai ni del controllo dei limiti.
2. Chiamare una funzione esterna per ottenere lo spazio sullo heap. La chiamata restituirà un puntatore all'inizio dell'array.
3. Generare il codice per salvare la lunghezza dell'array all'oset 0
4. Generare il codice per inizializzare tutte le celle dell'array (opzionale, dipende dal linguaggio che il compilatore tratterà).
3.3 If
Un'istruzione condizionale viene tradotta con una CJUMP.
Tuttavia, se sono presenti più condizioni (ad esempio connesse da &&) è necessario fare attenzione, perchè CJUMP permette
un unica condizione: bisogna tradurre l'istruzione in due CJUMP successive. La prima CJUMP riporta la prima condizione e,
in caso questa sia valutata a true, manda alla seconda CJUMP (che avrà una sua etichetta, creata dal compilatore) la quale
valuterà la seconda condizione e, sul risultato true provocherà il salto all'etichetta del codice da eseguire in caso di condizione
vera dell'istruzione if.
Entrambe le CJUMP, in caso di risultato false, mandano all'etichetta che indica il codice da eseguire in caso di condizione
falsa dell'if.
Ad esempio (supponendo, per semplicità, che a e b siano temporaries e non variabili, e omettendo per essi l'uso di TEMP),
if (a<3 && b>5) then goto t, else goto f
si traduce come
SEQ(CJUMP(LT,a,3,second,f ), SEQ(LABEL(second), CJUMP(GT,b,5,t,f )))
4 Cicli
Possono essere tradotti tramite CJUMP e LABEL tramite opportune equivalenze a codici contenenti solo if e goto.
La presenza di un'istruzione break è modellizzata come un salto incondizionato a done.
4.1 while
while(condizione) {
//body
}
è equivalente a
test :
if not(condition) goto done
//body
goto test
done :
4.2 for
for (i=lo; i<=hi; i++) {
//body
}
è equivalente a
i=lo;
limit=hi;
while(i<=limit) {
//body
i++;
}
2
http://www.windizio.altervista.org/appunti/
File distribuito con licenza Creative Commons BY­NC­SA 2.5 IT
Copyright © 2007 ­ Michele Tartara
L'approccio più frequente e semplice prevede la riscrittura di un for in un while e la successiva traduzione di quest'ultimo in IR,
facendo però attenzione a far sì che i non superi il valore massimo per gli interi nell'architettura considerata. In tal caso il ciclo
deve essere modicato in modo tale che il test venga eseguito in modo tale da impedire che i vada in overow.
5 Funzione
5.1 Chiamata
Semplice uso dell'istruzione CALL.
Nei linguaggi a oggetti, durante la traduzione bisogna anche inserire esplicitamente this (il riferimento all'oggetto stesso) tra
le variabili passate alla chiamata di un metodo.
5.2 Denizione
Una funzione viene tradotta in tre parti di codice assembly:
1. Prologo
(a) Pseudo-istruzioni (come richiesto dal particolare assembly) per annunciare l'inizio di una funzione
(b) Denizione di una label per il nome della funzione
(c) Istruzione per la modica dello stack pointer (per allocare un nuovo frame)
(d) Istruzioni per salvere nel frame gli argomenti che sfuggono (escape ) e per inserire gli altri dentro opportuni temporaries
(e) Istruzioni per salvare i registri callee-save
2. Corpo
Tutte le istruzioni della funzione, come denite dal programmatore
3. Epilogo
(a) Istruzione per inserire il valore di ritorno della funzione nel registro apposito
(b) Istruzioni per ripristinare i registri callee-save
(c) Istruzioni per ripristinare lo stack pointer (per deallocare il frame)
(d) Istruzione di ritorno (JUMP all'indirizzo di ritorno)
(e) Pseudo-istruzioni (come richiesto dal particolare assembly) per annunciare la ne di una funzione
6 Static link
Nei linguaggi a blocchi (che presentano uno static link per determinare la visibilità delle variabili) è necessario che il compilatore
sappia tradurre l'accesso a variabili non locali tramite un'opportuna catena di operazioni di fetch dalla memoria dell'indirizzo
del precedente stack frame lungo gli static link.
Ad esempio, per il programma
int a=0;
function f() {
int b = a;
}
l'esecuzione dell'istruzione di assegnamento è tradotta dal seguente albero:
MOVE(MEM(+(TEMP(fp), CONST(b))), MEM(+(MEM(+(TEMP(fp), CONST(k))), CONST(a))))
3
Scarica

Linguaggio IR - WinDizio