Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
Beide Seiten der vorigen RevisionVorhergehende ÜberarbeitungNächste Überarbeitung | Vorhergehende Überarbeitung | ||
software:deep:dev:crosscompiler:ssa [2014-02-27 18:11] – graf | software:deep:dev:crosscompiler:ssa [Unbekanntes Datum] (aktuell) – gelöscht - Externe Bearbeitung (Unbekanntes Datum) 127.0.0.1 | ||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
- | ====== Static Single Assignment Form ====== | ||
- | The Static Single Assignment Form (SSA) is an intermediate form which allows various optimizations and facilitates register allocation. The main point of the SSA is that each variable is assigned a value only once. Each new assignment leads to a new instance of this variable (indicated by i< | ||
- | When optimizing, subsequent instuctions can simply use the definition and the value of these variables (e.g. for constant folding). The register allocation can be made more efficient as the living ranges of the instances are generally very short. More information about the creation and usage of the SSA can be found in [[literatur: | ||
- | The SSA is stored into nodes similar to the CFG nodes. For this purpose we define SSANode as an extension of CFGNode. | ||
- | [{{ .: | ||
- | When generating the CFG we already create instances of type SSANode. | ||
- | |||
- | ===== SSA Instructions ===== | ||
- | All Bytecode instructions of all nodes are translated into SSA instructions. The SSA instructions can be categorized as follows: | ||
- | [{{ ssainstructions.png? | ||
- | As the figure shows, the following types are available | ||
- | * NoOpnd: no operands, pushes the result to the stack | ||
- | * NoOpndRef: no operands, get reference from constant pool, pushes the result to the stack | ||
- | * Monadic: fetches one operand from the stack, pushes the result to the stack | ||
- | * MonadicRef: fetches one operand from the stack, get reference from constant pool, pushes the result to the stack | ||
- | * Dyadic: fetches two operands from the stack, pushes the result to the stack | ||
- | * DyadicRef: fetches two operands from the stack, get reference from constant pool, pushes the result to the stack | ||
- | * Triadic: fetches three operands from the stack, pushes the result to the stack | ||
- | * Branch | ||
- | * Call | ||
- | * PhiFunction | ||
- | |||
- | Each instruction has an opcode (// | ||
- | * sCloadConst: | ||
- | * sCloadLocal: | ||
- | * sCloadFromField, | ||
- | * sCloadFromArray, | ||
- | * sCadd, sCsub, sCmul, sCdiv, sCrem, sCneg: arithmetic operations | ||
- | * sCshl, sCshr, sCushr: shift operations | ||
- | * sCand, sCor, sCxor: logical operations | ||
- | * sCconvInt, sCconvLong, sCconvFloat, | ||
- | * sCcmpl, sCcmpg: comparing long, float and double | ||
- | * sCinstanceof, | ||
- | * sCalength: array length | ||
- | * sCbranch, sCswitch, sCcall, sCnew, sCreturn: branching and method calls | ||
- | * sCregMove, sCPhiFunc: phi functions | ||
- | |||
- | IMPORTANT Storing to fields (// | ||
- | Some SSA instructions don't produce a result, such as // | ||
- | |||
- | ===== SSA Value ===== | ||
- | All operands and results of the SSA instructions are of type SSAValue. | ||
- | [{{ .: | ||
- | |||
- | ===== State Array ===== | ||
- | For each SSANode a state array is carried along with information about local variables and the operand stack. The state of this array at the beginning of a node is the // | ||
- | [{{ .: | ||
- | The state array shows the state of the operand stack and indicates which instruction created a certain local variable. | ||
- | When generating SSA instructions the following rules apply: | ||
- | * Loading of a constant: Create new SSA instruction, | ||
- | * Loading of a local variable with index i: Creates no SSA instruction, | ||
- | * Loading of a local variable which is not yet initialized: | ||
- | * Arithmetic operation (as example of general instruction): | ||
- | * Storing of a local variable: Creates no SSA instruction, | ||
- | |||
- | ===== Phi-Functions ===== | ||
- | We use phi-functions whenever a node has more than one predecessors. A phi-function combines a local variable from the exit sets of these predecessors. The resulting value (result of the phi-function) goes into the entry set of the actual node. | ||
- | |||
- | ===Special case: loop header=== | ||
- | During the first traverse all necessary phi-functions will be generated. At this stage, not all parameters are known. Such parameters are added during the second traverse. | ||
- | |||
- | ===Elimination of redundant phi-functions=== | ||
- | Two cases have to be considered: | ||
- | Case 1: | ||
- | x = [y, | ||
- | here, all operands except one are the same as the assigned value. Such phi-function can occur in loop headers, if the value of a variable does not change in the loop. The value can be replaced by y. | ||
- | |||
- | Case 2: | ||
- | x = [x,x,...,x] | ||
- | here, all operands are the same as the assigned value. such phi-functions can occur when other phi-functions are eliminated. Simply replace with the value x. | ||
- | |||
- | Die Phi-Funktion selbst kann aber nur als gelöscht markiert werden. Da sie bei der Registerreservierung dennoch gebraucht werden. | ||
- | |||
- | ===== Paramter laden ===== | ||
- | Jede lokale Variable muss zugewiesen sein, bevor sie verwendet werden kann. Ein Parameter wird jedoch beim Aufruf der Methode übergeben, somit existiert in der SSA keine Zuweisung. Daher muss direkt vor dem ersten Gebrauch des Parameters eine SSAInstruction " | ||
- | |||
- | Spezialfall Phi-Funktion: | ||
- | Benutzt diese einen Parameter welcher noch nicht geladen ist, so wird die SSAInstruction " | ||
- | |||
- | ===== Traversieren eines Knotens ===== | ||
- | - Bestimmen des EntrySet | ||
- | * Knoten hat kein Vorgänger -> neues EntrySet erzeugen | ||
- | * Knoten hat einen Vorgänger -> ExitSet des Vorgängers kopieren | ||
- | * Einzige Ausnahme ist, wenn der Knoten selbst ein Loopheader ist. Dann muss obwohl es nichts zum zusammenführen gibt für jeden Local eine PhiFunktion erzeugt werden. Diese werden dann für die Registerreservierung benötigt. | ||
- | * Knoten hat mehrere Vorgänger -> ExitSets mittels Phi Funktionen zusammenführen. | ||
- | * Wenn Loopheader und erster Besuch -> für alle Locals jeweils eine PhiFunktion erzeugen. | ||
- | * Wenn Loopheader und zweiter Besuch -> alle ExitsSets der Predecessoren werden zusammengeführt, | ||
- | * Wenn kein Loopheader -> Werden nur PhiFunktionen erzeugt, wenn ein Local in mehreren Predecessoren gesetzt wurden und diese auch vom selben Typ sind. | ||
- | * Wobei für Parameter immer eine PhiFunktion erzeugt wird. Unter Berücksichtigung ob eine LoadParamter Instruktion erzeugt werden muss. | ||
- | * Ist der Local bereits eine PhiFunktion so muss bestimmt werden, ob diese in diesem Knoten erzeugt wurde. Ist dies nicht der Fall so wird eine neue PhiFunktion erzeugt und die bestehende wird als Parameter übergeben. | ||
- | - Redundante PhiFunktionen löschen. | ||
- | - Bytecode traversieren und jeweilige SSAInstruction erzeugen. Gleichzeitig auch locals nachführen. | ||
- | - Locals dem ExitSet zuweisen. | ||
- | |||
- | ===== Bilden der SSA ===== | ||
- | Beim Bilden der SSA ist die Reihenfolge, | ||
- | * Ein Knoten darf nur traversiert werden, wenn alle seine direkten Vorgänger bereits traversiert worden sind. (Ausnahme Loopheaders) | ||
- | * Loopheaders müssen 2-mal traversiert werden, da beim ersten mal noch nicht alle direkten Vorgänger traversiert worden sind. | ||
- | |||
- | ===== Einfügen von Register Moves ===== | ||
- | Die Phi-Funktionen müssen aufgelöst werden. Das heisst, alle ihre Operanden und ihr Resultat erhalten das gleiche Register zugewiesen. Dazu wird der Index in den locals verwendet. \\ | ||
- | Üblicherweise haben die Operanden und das Resultat auch den gleichen Index. Es gibt aber zwei Fälle, wo das nicht zutrifft. Für diese Fälle muss in allen Vorgängerknotens des Knotens mit der phi-Funktion ein Registermoves eingefügt werden. Ebenso müssen die Exit-Sets dieser Vorgängerknoten angepasst werden. | ||
- | ==== Conditional Operator ==== | ||
- | < | ||
- | boolean a = i > 10? b : c; | ||
- | </ | ||
- | Hier belegen alle drei Variablen vom Typ Boolean (a,b,c) je einen anderen Index im Exit-Set. | ||
- | ==== Zuweisung nach Verzweigung ==== | ||
- | <code java> | ||
- | if (condition) | ||
- | a = 1; | ||
- | else | ||
- | a = 2; | ||
- | b = a; | ||
- | </ | ||
- | Hier hat a z.B. den Index 0 und b den Index 1. Die SSA-Form von a = 1 lädt die Konstante 1. b = a taucht in der SSA-Form nicht auf, resp. b ist das Resultat der phi-Funktion mit den Konstanten 1 und 2 als Operanden. | ||
- | |||
- | ===== Erstellen der Line Number Table ===== | ||
- | Für das Source-Lookup des Debuggers muss nachher bekannt sein, welche Instruktion zu welcher Sourcezeile gehört. Diese Information findet sich im Bytecode in der // |