L2Optimizer
An L2Optimizer optimizes its L2ControlFlowGraph. This is a control graph. The vertices are L2BasicBlocks, which are connected via their successor and predecessor lists.
Author
Mark van Gulik
Parameters
An L2Generator used for splicing in short sequences of new code as part of optimization.
Properties
The mutable list of blocks taken from the controlFlowGraph.
An L2Generator used for splicing short sequences of code as part of optimization.
Functions
Any control flow edges that land on jumps should be redirected to the ultimate target of the jump, taking into account chains of jumps.
Assert that each of the specified StateFlags has been set in the controlFlowGraph.
Assert that each of the specified StateFlags has been cleared in the controlFlowGraph.
Clear each of the specified StateFlags from the controlFlowGraph.
For each L2_MOVE instruction, if the register groups associated with the source and destination registers don't have an interference edge between them then merge the groups together. The resulting merged group should have interferences with each group that the either the source register's group or the destination register's group had interferences with.
Assign final coloring to each register based on the interference graph and coalescing map.
Determine which pairs of registers have to be simultaneously live and potentially holding distinct values.
Determine which registers are live-in for each block. We distinguish between always-live-in, where all future paths from the start of a block lead to a use of the register, and sometimes-live-in, where at least one future path from the start of the block leads to a use of the register.
For every phi operation, insert a move at the end of the block that leads to it. Because of our version of edge splitting, that block always contains just a jump. The CFG will no longer be in SSA form, because the phi variables will have multiple defining instructions (the moves).
Optimize the graph of instructions.
Re-order the blocks to minimize the number of pointless jumps. When we start generating JVM code, this should also try to make one of the paths from conditional branches come after the branch, otherwise an extra jump instruction has to be generated.
Remove information from the L2ControlFlowGraph that will no longer be needed. Note that during subsequent inlining of this chunk at a call site, the type information will be reconstructed without too much cost.
Regenerate the edge-split SSA graph, postponing emission of side-effectless instructions until just before they're needed.
Remove all unreachable blocks and all instructions that don't either have a side-effect or produce a value ultimately used by an instruction that has a side-effect.
Eliminate any L2_MOVEs between registers of the same color. The graph must have been colored already, and is not expected to be in SSA form, and is certainly not after this, since removed moves are the SSA definition points for their target registers.
Find the L2BasicBlock that are actually reachable recursively from the blocks marked as L2BasicBlock.isIrremovable.
Replace constant-valued registers with fresh registers that have no definitions. The JVM code generator will recognize that these are constants, and produce code to produce them on the JVM stack by reading the constants pool or via special instructions for int/double constants.
Find any remaining occurrences of L2_VIRTUAL_CREATE_LABEL, or any other L2Instruction using an L2Operation that says it L2Operation.isPlaceholder. This happens in a fresh control flow graph, as part of the injected behavior of an L2Regenerator.
Create a new register for every
Set each of the specified StateFlags in the controlFlowGraph.
For every edge leading from a multiple-out block to a multiple-in block, split it by inserting a new block along it. Note that we do this regardless of whether the target block has any phi functions.