Allocazione dei registri - WinDizio
Transcript
Allocazione dei registri - WinDizio
http://www.windizio.altervista.org/appunti/ File distribuito con licenza Creative Commons BYNCSA 2.5 IT Copyright © 2007 Michele Tartara Parte I Allocazione dei registri Il lavoro dell'allocatore dei registri consiste nel assegnare i molti valori temporanei (temporaries) prodotti durante la generazione delle istruzioni ai (pochi) registri a disposizione nella macchina reale. Dove possibile, si tenta anche di assegnare i registri in modo tale da poter rimuovere le istruzioni MOVE. 1 Gra di interferenza Dato un insieme di temporaries a, b, c, . . . che devono essere allocati ad un gruppo di registri r1 , . . . , rk , si denisce interferenza una condizione che previene l'allocazione di a e b allo stesso registro. L'interferenza più comune è causata dalla sovrapposizione degli intervalli di vita di due temporaries. Un'altra possibile causa è l'uso di istruzioni il cui risultato a non può essere assegnato a un certo registro r1 (in architetture in cui alcuni registri hanno usi limitati): in tal caso, si dice che a e r1 interferiscono. Le informazioni del grafo possono essere espresse tramite una matrice oppure tramite un grafo non orientato in cui ogni nodo rappresenta una variabile e ogni arco un interferenza. Il grafo di interferenza si ricava dall'analisi dei gra di controllo e dataow. Il processo di assegnazione di K registri è paragonabile al problema di colorare una mappa con K colori dierenti: ogni colore non può essere assegnato a temporaries in conitto (cioè che sono vivi in contemporanea). Se non è possibile K-colorare il grafo dei conitti, è necessario trasferire alcuni temporaries in memoria: ciò è noto come spilling. 2 Trattamento delle istruzioni MOVE Una istruzione del tipo t ← s è un'istruzione di copia. Normalmente, essa viene tradotta in un'istruzione MOVE e porterebbe a denire un'interferenza tra s e t sul grafo. Tuttavia, non è detto che si abbia bisogno di un registro separato: servirà solo nel caso in cui, successivamente alla move, c'è una denizione di t mentre s è ancora viva. In breve: • per ogni istruzione non-MOVE che denisce una variabile a in cui le variabili vive in uscita (live-out) sono b1 , . . . , bj aggiungere gli archi di interferenza (a, b1 ), . . . , (a, bj ) • per ogni istruzione MOVE a ← c dove le variabili b1 , . . . , bj sono vive in uscita aggiungere gli archi di interferenza (a, b1 ), . . . , (a, bj ) per ogni bi diverso da c. Se si riescono ad assegnare più temporaries ad un solo registro si ottiene un risparmio di tempo (l'istruzione MOVE viene cancellata) oltre che di spazio. 3 Colorazione dei gra 3.1 Per semplicazione Il processo di allocazione dei registri (cioè di colorazione dei gra) è NP-completo. Tuttavia esiste un algoritmo di approssimazione in tempo lineare che fornisce buoni risultati. Le sue fasi sono le seguenti: 1. Build Costruire il grafo di inferenza utilizzando l'analisi dataow. 2. Simplify Colorare il grafo utilizzando un'euristica semplice. Supponiamo che il grafo G contenga un nodo m con meno di K nodi adiacenti. Rimuoviamo (e impiliamo su uno stack) il nodo m. Tale semplicazione diminuirà il grado degli altri nodi e darà la possibilità per ulteriori passi di Simplify. 1 http://www.windizio.altervista.org/appunti/ File distribuito con licenza Creative Commons BYNCSA 2.5 IT Copyright © 2007 Michele Tartara 3. Spill Se ad un certo punto il grafo è composto solo da nodi di grado signicativo (> K ) l'euristica Simplify non può proseguire e si deve segnare il nodo come spill (riversamento in memoria) potenziale prima di rimuoverlo dal grafo e porlo sulla pila. Con una approssimazione ottimistica, si suppone che questa decisione riduca le interferenze degli altri nodi e permetta di proseguire con l'euristica Simplify. 4. Select Assegna i colori ai nodi del grafo. Viene eseguito quando il grafo è stato ormai svuotato e lo ricostruisce prelevando un nodo alla volta dalla cima della pila. Quando aggiungiamo un nodo deve esserci un colore per esso, siccome le premesse per la sua rimozione nella fase simplify richiedevano che un colore potesse essere assegnato. Se il nodo che si sta esaminando era stato marcato come spill potenziale dall'euristica Spill non è detto che ci sia un colore disponibile. Se non è possibile trovare un colore, si ha un actual spill. In tal caso si continua la fase di select per identicare eventuali altri actual spill 5. Start over Se sono stati individuati actual spill si modica il programma per far sì che le relative variabili vengano salvate in memoria e caricate solo prima dell'eettivo uso. Si deve quindi ricominciare tutto l'algoritmo a partire da Build. Raramente servono più di due iterazioni. 3.2 Con coalescenza Quando nel grafo delle interferenze non sono presenti archi tra l'origine e la destinazione di un'istruzione MOVE, è possibile eliminare l'istruzione e rimpiazzare i due nodi con un nodo unico che ha come archi l'unione degli archi dei due nodi originali. Il nodo introdotto ha (in generale) più interferenze dei singoli nodi originali. Bisogna quindi fare attenzione ed applicare la coalescenza solo in determinati casi, per impedire che un grafo K-colorabile diventi non più K-colorabile. Sono state sviluppate due strategie (conservative: rinunciano a possibili riduzioni per essere certe di evitare lo spilling) sicure per decidere quando applicare la coalescenza: Briggs Si può applicare la coalescenza ai nodi a e b se il nodo risultante ab avrà meno di K vicini di grado signicativo (con più di K archi). Se il grafo originale era K-colorabile, questa strategia non altera la colorabilità. George Si può applicare la coalescenza ai nodi a e b se, per ogni vicino t di a, o t interferisce già con b o t è di grado non signicativo. 3.2.1 Procedura empirica di coloratura con coalescenza Figura 1: Procedura di coloratura con coalescenza Le fasi dell'algoritmo di coloratura si alternano come presentato in Figura 1. Le fasi sono le seguenti: Build Costruisce il grafo di interferenza Simplify Rimuove dal grafo i nodi di grado non signicativo non relativi a una MOVE. Coalesce Applica la coalescenza in modo conservativo (Briggs o George). Dopo l'attuazione di una coalescenza, si torna a Simplify. Simplify e Coalesce si alternano nchè rimangono solo nodi di grado signicativo o relativi a una MOVE (ma sui quali Coalesce non è applicabile). Una MOVE si dice constrained se a seguito di una operazione di Coalesce per un'altra MOVE, non è più possibile applicare Coalesce sulla MOVE stessa. In tal caso, si considerano i nodi coinvolti come non più MOVE-related. Freeze Se né Simplify né Coalesce sono applicabili, si cerca un nodo di basso grado relativo a una MOVE e si rinuncia al tentativo di applicare Coalesce su di esso, che diventa quindi semplicabile. Si riprende quindi ad applicare Simplify e Coalesce sui nodi rimanenti. 2 http://www.windizio.altervista.org/appunti/ File distribuito con licenza Creative Commons BYNCSA 2.5 IT Copyright © 2007 Michele Tartara Spill Se non ci sono nodi di basso grado, marchiamo un nodo di grado signicativo per il potential spilling e lo poniamo sulla pila. Select Rimuovere tutti i nodi dalla pila assegnando i colori. Se un nodo potential spill si rivela essere un actual spill è necessario modicare il programma per gestirne la lettura/scrittura da/verso la memoria e ripetere il procedimento di coloratura da capo (algoritmi più ecienti conservano come valide le Coalesce precedenti al primo potential spill e non le ripetono). Coalescing of spills Le architetture con pochi registri (come i Pentium) provocano molti spill. In certi casi, si trovano istruzioni di MOVE tra celle in memoria, che risultano molto pesanti. È possibile applicare l'algoritmo di coloratura e coalescenza per decidere l'assegnazione delle aree di memoria (che in questo caso sono i colori) della pila ed eventualmente per sfruttare contemporaneamente la stessa area per più valori uguali. Questo procedimento deve essere fatto prima di generare le istruzioni di spill dei registri. 4 Nodi precolorati Se un registro ri appare sul grafo di interferenza, si dice che è un nodo precolorato. A un temporary può essere assegnato lo stesso colore di un nodo precolorato, purchè essi non siano collegati da un arco sul grafo. Ciò permette, ad esempio, di sfruttare all'interno di una funzione un registro dedicato al passaggio di parametri se il valore in esso contenuto non è più utile. Su un nodo precolorato non è possibile applicare Simplify (perchè essendo precolorato non avrebbe senso rimuoverlo dal grafo per assegnargli un colore in seguito) nè Spill (un nodo precolorato è un registro, non un valore: non può, sicamente, essere spostato in memoria). Si può invece applicare Coalesce in modo conservativo. Se in un grafo sono presenti nodi precolorati, l'algoritmo di colorazione non li rimuove mai dal grafo stesso: rimuove attraverso Simplify, Coalesce e Spill tutti gli altri e poi li riaggiunge assegnando loro i colori. 5 Registri caller-saved e callee-saved Per ridurre il numero di registri occupati, si cerca di non mantere i callee-saved in memoria troppo a lungo. Per fare ciò si considera come se il registro (poniamo r7 ) sia denito all'ingresso di una funzione e sia usato alla sua uscita (questo ne provoca la sopravvivenza). Si aggiunge poi come prima istruzione della funzione una move verso un temporary e come ultima istruzione la move inversa. In tal modo, se è necessario, l'allocatore dei registri potrà eseguire uno spill del valore verso la memoria. Per quanto riguarda i registri caller-saved, l'istruzione assembly CALL ha il compito di fare una dene (cioè di creare un'interferenza) per tali registri. In questo modo, le variabili che non sono vive al di là di una funzione tenderanno a essere memorizzate in registri caller-saved Usando semplicemente questi accorgimenti, gli algoritmi di allocazione già visti tratteranno correttamente i registri calleesaved. 6 Allocazione dei registri per alberi Quando si devono allocare i registri per istruzioni organizzate secondo una struttura ad albero non è necessaria un'analisi dataow globale o l'uso di gra di interferenza. Trattandosi di alberi di espressioni, già sappiamo che è necessario assegnare un registro per ogni tile non banale (cioè che non è già presente in un registro, come ad esempio FP), escluse eventualmente istruzioni senza eetti sui registri come MOVE tra celle di memoria. L'Algoritmo 1 attraversa l'albero in postordine assegnando un registro ad alla radice di ogni tile. È molto semplice ma non sempre riesce a fornire una allocazione ottimale. Per ottenere una tale allocazione è necessario utilizzare algoritmi più evoluti basati sulla programmzione dinamica. L'idea è quella di etichettare ogni tile con il numero di registri di cui avrà bisogno durante la sua valutazione. L'algoritmo di etichettatura (labeling) di Sethi-Ullman calcola il numero di registri need[t] necessari per portare a termine la valutazione del sottoalbero stesso. Successivamente, o si emettono le istruzioni in modo tale che i sottoalberi vengano emessi in ordine crescente di need (per complilaturi che utilizzano la coloratura dei gra per l'allocazione dei registri) minimizzando quindi il numero di spill, oppure si utilizza l'algoritmo di Sethi-Ullman per l'allocazione dei registri, che si basa sul seguente ragionamento: si supponga che un tile t abbia due gli ulef t e uright che richiedono rispettivamente n e m registri per essere 3 http://www.windizio.altervista.org/appunti/ File distribuito con licenza Creative Commons BYNCSA 2.5 IT Copyright © 2007 Michele Tartara Algorithm 1 Semplice algoritmo di allocazione dei registri function SimpleAlloc(t) for each nontrivial tile u that is a child of t SimpleAlloc(u) for each nontrivial tile u that is a child of t n←n−1 n←n+1 assign rn to hold the value at the root of t calcolati. Se si calcola prima ulef t e poi uright il numero di registri richiesti è max(n, m + 1). Se invece si valuta prima uright ci vorranno max(n + 1, m) registri. In entrambi i casi, il +1 è il registro necessario a contenere il risultato della prima elaborazione. L'algoritmo di Sethi-Ulmann decide di calcolare prima ulef t se n > m e prima uright se n < m. Questo algoritmo, emette le istruzioni assieme all'allocazione dei registri. 4