This shows you the differences between two versions of the page.
Next revision | Previous revision | ||
dev:crosscompiler:backend_ppc:register_allocation [2014/07/03 15:25] – external edit 127.0.0.1 | dev:crosscompiler:backend_ppc:register_allocation [2018/12/20 17:14] (current) – [Register Usage] ursgraf | ||
---|---|---|---|
Line 1: | Line 1: | ||
====== Register Allocation ====== | ====== Register Allocation ====== | ||
- | Starting with the SSA form for each result of an SSA instruction a register has to be assigned. However, it must be decided how the registers of a processor will be used generally. | + | The PowerPC architecture offers 32 GPR's and 32 FPR's. |
===== Register Usage ===== | ===== Register Usage ===== | ||
- | Registers can be classified as // | + | |
| Register | State | Use | | | Register | State | Use | | ||
- | | R0 | volatile | method prologue, | + | | R0 | volatile | method prologue, |
| R1 | dedicated | stack pointer | | | R1 | dedicated | stack pointer | | ||
| R2 | volatile | 1. parameter, return value | | | R2 | volatile | 1. parameter, return value | | ||
Line 25: | Line 25: | ||
==== Parameter Passing ==== | ==== Parameter Passing ==== | ||
- | Parameters are passes | + | Parameters are passed |
- | In the interface // | + | In the interface // |
- | + | ||
- | ===== Resolving of Phi-Functions ===== | + | |
- | The operands of a phi-function must all get the same register as the result of the phi-function. For this purpose all these operands have a field //join//. \\ | + | |
- | Before the phi-functions can be resolved, loops need special treatment. Let's consider the folowing case: | + | |
- | [{{ .: | + | |
- | + | ||
- | The SSAValue of //a// is used in the loop. The live range of //a// extends to the instruction for //b = 2 * a//. However, this would be wrong, because the register for //a// would be released at this point and might be used otherwise. It must stay reserved until the end of the loop. At the beginning of node 2 a phi-function is created for //a//. This function will be deleted because //a// is set in node 1 and only read in node 2. For all phi-functions in loops (whether deleted or not) the field //last// is set to the last instruction of this loop.\\ | + | |
- | Subsequently, | + | |
- | All used phi-functions are marked (field //used//). //used// indicates if a deleted phi-Funktion is used further downstream. If not, the register can be released immediately. The reason for doing this is the fact, that phi-functions were inserted for every local variable if loops are present. Most of this phi-functions are deleted and should not occupy a register unnecessarily. \\ | + | |
- | Phi-functions will be resolved as follows: A new state array //join// is created. The field //join// of the result of the phi-function and of its operands refer to the value in this state array with the same index as the phi-function. Several phi-functions might refer to the same //join// value. \\ | + | |
- | There are cases where two different phi-functions with the same index refer to two different variables, as in: | + | |
- | <code java> | + | |
- | if() { | + | |
- | int a = ...; | + | |
- | while() a = ...; | + | |
- | } else { | + | |
- | float f = ...; | + | |
- | while() f = ...; | + | |
- | } | + | |
- | </ | + | |
- | //a// and //f// occupy the same slot (or index). Nevertheless, | + | |
- | [{{ .: | + | |
- | + | ||
- | + | ||
- | ===== Determination of Live Range ===== | + | |
- | We determine for the results of all SSA instructions up to which instruction they are used (field //end//). | + | |
- | Results of phi-functions must be handled separately. Such results might be used as operands of instructions which are placed further upstream. For this reason the live range of a phi-function does not start with its instruction but with its first use of an operand or the phi-function itself. Hence, phi-function need a field //start//. | + | |
- | ===== Determine the Register Type ===== | ||
- | Before beeing able to assign registers we have to decide whether to use a volatile or nonvolatile register. As soon there is a call to a method within the live range of a value (holds also for phi-functions) then this value must be assigned a nonvolatile Register. Other values are assigned a volatile register. The same is true for exceptions. If the live range of a variable extends into (or over) a catch block we must assign a nonvolatile register, as the handling of the exception destroys volatiles.\\ | ||
- | A special case is the SSA instruction // | ||
- | ===== Determine Used Parameters ===== | ||
- | Zu Beginn einer Methode werden alle Parameter in den volatile Registern übergeben. Zum Teil müssen sie in nonvolatile Register umkopiert werden. Es gibt auch den Fall, dass Parameter in der Methode gar nicht verwendet werden. Dies ist aus dem exit set des letzten Knotens ersichtlich. Wenn dort ein Wert null ist, wurde der Parameter mit diesem Index nie geladen und sein Register muss nicht reserviert werden. Das folgende Beispiel verdeutlicht das Vorgehen. | ||
- | <code java> | ||
- | float m2(long a, float b, double c, byte[] d, short e, int f, int g) { | ||
- | a = 0x7545 & a; | ||
- | e += 100; | ||
- | T08Calls.classMethod(d[2]); | ||
- | e = (short)(20 + e); | ||
- | g |= 0x223344; | ||
- | c = 3.2; | ||
- | int h = g - e; | ||
- | T08Calls.classMethod(h); | ||
- | short i = (short)h; | ||
- | return b; | ||
- | } | ||
- | </ | ||
- | |**Variable**|this|a|b|c|d|e|f|g| | ||
- | |**Typ**|ref|Long|Float|Double|ByteArray|Short|Integer|Integer| | ||
- | |**Register Typ**| |vol|nonVol|vol|vol|vol| |nonVol| | ||
- | |**nicht verwendet**|x| | | | | |x| | | ||
- | |**Register**| |R3, | ||
- | ===== Zuweisung der Register ===== | ||
- | Zuletzt erhält jedes Resultat einer SSA Instruktion ein Register zugewiesen. | ||
- | ==== Laden der Parameter ==== | ||
- | Alle sCloadLocal Instruktionen benutzen das gleiche Register, wie bereits der Parameter erhalten hat. Falls //join != null// erhält auch die referenzierte phi-Funktion das gleiche Register. | ||
- | ==== Reservation von Hilfsregistern ==== | ||
- | Einige Instruktionen benötigen 1 oder 2 zusätzliche Hilfsregister. Diese werden reserviert und in den Feldern //regAux1// und //regAux2// abgelegt. Anschliessend können sie gleich wieder freigegeben werden. Somit kann das Resultat der SSA Instruktion das gleiche sein, wie eines dieser Hilfsregister. | ||
- | ==== Freigabe der Operandenregister ==== | ||
- | Die Register aller Operanden, die das Ende ihrer live range erreicht haben, können freigegeben werden. Falls diese vom Typ Long sind, darf dieser Schritt erst am Schluss erfolgen. | ||
- | ==== Reservation eines Registers für das Resultat ==== | ||
- | Jetzt kann im Registerpool ein Register reserviert werden. Der Typ des Resultates bestimmt dabei, ob 1 oder 2 GPR's oder 1 FPR. Dabei müssen die 2 folgenden Fälle unterschieden werden. | ||
- | === 1. join != null === | ||
- | Hier muss das gleiche Register wie dem Resultat der phi-Funktion zugewiesen werden. Falls noch nicht behandelt, muss die phi-Funktion zuerst behandelt werden. | ||
- | Es kann der Fall auftreten, dass mehrere phi-Funktionen den gleichen Index im Statearray belegen, siehe folgendes Beispiel: | ||
- | <code java> | ||
- | switch(i) { | ||
- | case 0: return 0; | ||
- | case 1: i++; break; | ||
- | case 2: return 2; | ||
- | case 3: i += 3; | ||
- | case 4: i += 4; break; | ||
- | default: return -1; | ||
- | .. | ||
- | return i + 3; | ||
- | </ | ||
- | Alle phi-Funktionen mit dem gleichen Index erhalten das gleiche Register zugewiesen. | ||
- | === 2. Laden einer Konstanten === | ||
- | Falls die Konstante 16 Bit nicht überschreitet und die Instruktion, | ||
- | ==== Freigabe des Resultatregisters ==== | ||
- | Das Resultatregister darf gleich wieder freigegeben werden, wenn das Ende der live range bereits erreicht wurde (der erzeugte Wert wird gar nie verwendet). | ||
- | Jetzt |