Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
Beide Seiten der vorigen RevisionVorhergehende ÜberarbeitungNächste Überarbeitung | Vorhergehende Überarbeitung | ||
software:deep:dev:crosscompiler:ssa [2014-04-10 12:58] – 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. Such phi-functions serve the following purpose: all the combined locals (operands of a phi-function) should be assigned the same register. | ||
- | |||
- | ===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. | ||
- | Phi-functions are never really deleted. They are marked as deletet, because even deleted phi-functions are used for register allocation. | ||
- | |||
- | ===== Loading of Parameters ===== | ||
- | Every local variable must be assigned before it can be used. However, a parameter has no assignment instruction in the SSA. Therefore, before the first use of a parameter a SSA-instruction // | ||
- | |||
- | ===Special case: phi-function=== | ||
- | If a phi-function uses a parameter which is not yet loaded, the SSA-instruction // | ||
- | |||
- | ===== 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. | ||
- | |||
- | ===== Building the SSA ===== | ||
- | When building the SSABeim 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. | ||
- | |||
- | ===== Insertion of Register Moves ===== | ||
- | The phi-functions will be resolved when register allocation takes places. That means its operands and its result are assigned the same register. For this, the index into //locals// is used. \\ | ||
- | Generally the operands and the result have the same index. However, there are two cases, where this is not true. | ||
- | ===Conditional Operator=== | ||
- | <code java> | ||
- | boolean a = i > 10? b : c; | ||
- | </ | ||
- | In that case all three variables of type boolean occupy another index in the exit-set. | ||
- | === Assignment after Branch === | ||
- | <code java> | ||
- | if (condition) | ||
- | a = 1; | ||
- | else | ||
- | a = 2; | ||
- | b = a; | ||
- | </ | ||
- | Let's assume that //a// has index 0 and //b// has index 1. The ssa instruction for //a = 1// loads the constant 1. //b = a// does not create any ssa instruction, | ||
- | |||
- | For these two cases a new ssa instruction //regMove// has to be inserted into all predecessors of the node with the phi-function. It simply copies the ssa value into a new value. The exit-sets of the predecessors have to be updated as well. | ||
- | |||
- | ===== Handling Exceptions ===== | ||
- | Catch clauses of exceptions need special treatment. | ||
- | |||
- | ===== Creating the Line Number Table ===== | ||
- | For the source lookup the debugger needs information about which SSA instruction belongs to which line number in the source. The information about line numbers and Bytecode instruction can be found in the // |