GENERAZIONE CODICE MACCHINA Daniela Briola Lorena Bellino
Funzione getreg Restituisce la locazione L destinata a ospitare il valore di x nelle istruzioni del tipo x := y op z Locazioni restituite dalla funzione: L è il registro che contiene y L è un registro vuoto L è un registro occupato L è la locazione di x
Esempio 1/2 d := (a - b) + (a - c) +(a - c) t := a – b u := a – c v := t + u d := v + u
Esempio 2/2 Statement Code generated Register descriptor Address t := a - b MOV a, R0 SUB b, R0 R0 contiene t t in R0 u := a - c MOV a, R1 SUB c, R1 R1 contiene u u in R1 v := t + u ADD R1, R0 R0 contiene v v in R0 d := v + u R0 contiene d d in R0 MOV R0, d d in R0 e in memoria
Indici statement i in register Ri i in memoria Mi i nello stack codice costo a := b[i] MOV b(Ri), R 2 MOV Mi, R MOV b(R), R 4 MOV Si(A), R a[i] := b MOV b, a(Ri) 3 MOV b, a(R) 5
Istruzioni condizionali Branch condition Condition code: che indicano se l’ultima quantità calcolata è positiva, negativa o zero Esempio: If x < y goto z -----> CMP x, y CJ< z x := y + z MOV y, R0 if x < 0 goto z ------> ADD z, R0 if x > 0 goto w MOV R0, x CJ> w
Allocazione e assegnazione registri Locale Assegnazione di specifici valori a determinati registri Più semplice da implementare ma meno efficiente Globale Registri mantengono i valori per la durata del blocco Registri riservati alle variabili più utilizzate Più efficiente ma più complesso da implementare
Allocazione e assegnazione registri Risparmi Utilizzo di x in loop L non preceduto da assegnazione -1 per ogni blocco di L in cui x è vivo all’uscita e gli viene assegnato un valore nel blocco -2 Allocazione di un registro ad una variabile x in un loop L: ∑B Î L use(x, B) + 2 * live(x, B) (*) Dove: Use(x, B): n° volte in cui x è usato in B prima di ogni definizione di x Live(x, B): 1 se x è viva all’uscita di B e gli viene assegnato un valore in B, 0 altrimenti
Esempio 1/2 ∑B Î L use(x, B) + 2 * live(x, B) R0, R1, R2
Esempio 2/2 Valutazione di (*) per x = a: ∑B Î L 2*live(a, B) = 2 ∑B Î L use(a, B) = 0 + 1 + 1 + 0 = 2 ∑B Î L use(a, B) + 2 * live(a, B) = 4 Per b, c, d, e, f i valori sono rispettivamente 6, 3, 6, 4, 4 È ragionevole pensare che R0, R1ed R2 mantengano i valori di a, b, d
Rappresentazione di BB tramite dags I dag sono utili strutture per rappresentare i BB Etichette sui nodi: Foglie etichettate da identificatori unici: nomi di variabili o costanti Nodi interni etichettati da operatori I nodi possono avere opzionalmente una sequenza di identificatori che rappresentano i corrispondenti valori calcolati
Esempio t1 := 4 * i t2 := a[t1] t3 := 4 * i t4 := b[t3] t5 := t2 * t4 t6 := prod + t5 prod := t6 t7 := i + 1 i := t7 if i <= 20 goto 1.
Costruzione dag – Algoritmo 1/3 Input: basic block (BB) Output: dag rappresentante il BB che contiene le seguenti informazioni: Un’etichetta per ogni nodo Ad ogni nodo si associa una lista di identificatori Metodo: Struttura dati per rappresentare dag Lista contenente tutti gli identificatori cui è associato un nodo Node(y): restituisce nodo con identificatore y Statement della forma x := y op z x := op z x := z
Costruzione dag – algoritmo 3/3 Se node(y) non è definito, creare una foglia etichettata y, e sia node(y) tale nodo Nel caso (i) determinare se esiste nodo etichettato op con figlio sinistro = node(y) e figlio destro = node(z). Se non esiste creare così un nuovo nodo. Nel caso (ii) determinare se esiste un nodo etichettato op il quale ha come figlio node(y), se non esiste creare così un nuovo nodo. In entrambi i casi, il nodo trovato o creato lo indichiamo con n. Nel caso (iii) n = node(y). Eliminare x dalla lista degli identificatori associati a node(x); appendere x alla lista degli identificatori associati al nodo n e settare node(x) a n.
Applicazioni dell’uso di DAG Individuazione di sottoespressioni comuni Stabilire quali identificatori hanno valori usati nel blocco Determinare gli statement che calcolano valori che possono essere usati al di fuori del blocco
Ristrutturazione dell’ordine di esecuzione (a + b) – (e – (c + d)) BB t1 := a + b t2 := c + d t3 := e – t2 t4 := t1 – t3 MOV a, R0 ADD b, R0 MOV c, R1 ADD d, R1 MOV R0, t1 MOV e, R0 SUB R1, R0 MOV t1, R1 SUB R0, R1 MOV R1, t4
Ristrutturazione dell’ordine di esecuzione Modificando l’ordine delle istruzioni nel BB t2 := c + d t3 := e – t2 t1 := a + b t4 := t1 – t3 vengono risparmiate due istruzioni MOV c, R0 ADD d, R0 MOV e, R1 SUB R0, R1 MOV a, R0 ADD b, R0 SUB R1, R0 MOV R0, t4
Generazione codice ottimale Algoritmo consiste di 2 parti Etichetta ogni nodo con un intero che denota il più piccolo numero di registri richiesti per valutare l’albero Visita dell’albero il cui ordine è dato dal valore delle etichette calcolato nel passo 1. Il codice di output viene generato durante la visita dell’albero.
Algoritmo di etichettatura Foglia sinistra = è un nodo foglia il quale è il discendente più a sinistra del proprio padre. Le altre foglie sono dette foglie destre L’etichettatura viene effettuata in una visita bottom-up
Algoritmo di etichettatura If n is leaf then if n is the leftmost child of its parent then label(n) := 1 else label(n) := 0 Else begin let l1, l2 be the children of n (6) label(n) = max(l1, l2) se l1 != l2 l1 + 1 l1 == l2 end Nel caso generico, (6) viene sostituita con: let n1, … nk be the children on n ordered by “label”, so label(n1) >= … >= label(nk) label(n) := max 1<=i<=k (label(ni) + i - 1)
Algoritmo di etichettatura Ordine: a, b, t1, e, c, d, t2, t3, t4
Generazione codice da albero etichettato Procedura gencode(n): produce codice macchina valutando i sottoalberi di T con radice n. rstack: stack utilizzato per allocare i registri tstack: stack utilizzato per allocare locazioni di memoria temporanea swap: procedura che scambia i primi 2 registri sul top di rstack
Generazione codice da albero etichettato Procedure gencode(n); Begin /* case 0 */ If n is a left leaf representing operand “name” and n is the leftmost child of its parent then print ‘MOV’ || name || top(rstack) else if n is an interior node with operator “op”, left child n1 and right child n2 then /* case 1*/ if label(n2) = 0 then begin let name be the operand represented by n2; gencode(n1); print op || name || ‘,’ || top(rstack) end /*case 2*/ else if 1<=label(n1) < label(n2) and label(n1) < r then swap(rstack); gencode(n2); R := pop(rstack); /* n2 was evaluated into register R */ print op || R || ‘,’ || top(rstack); push(rstack, R); swap(rstack);
Generazione codice da albero etichettato /* case 3*/ else if 1 <= label(n2) <= label(n1) and label(n2) < r then begin gencode(n1); R := pop(rstack); /*n1 was evaluated into register R*/ gencode(n2); print op || top(rstack) || ‘,’ || R; push(rstack, R); end /* case 4 both labels >= r the total number of register */ else T := pop(tstack); print ‘MOV’ || top(rstack) || ‘,’ || T; push(tstack, T); print op || T || ‘,’ || top(rstack);