public final class LoopVersioning extends CompilerPhase
AnnotatedLSTNodes. The optimisations performs the following
operations:
Example:
for (int t1=0; t1 < 100; t1++) {
g1 = null_check l0
g2 = bounds_check l0, t1
g3 = guard_combine g1,g2
t2 = aload l0, t1, g3
g4 = null_check l1
g5 = bounds_check l1, t1
g6 = guard_combine g4,g5
astore t2, l1, t1, g6
}
becomes:
goto explicit_test_block
successor_to_loops:
g1 = phi g1_1, g1_2
g2 = phi g2_1, g2_2
g3 = phi g3_1, g3_2
t2 = phi t2_1, t2_2
g4 = phi g4_1, g4_2
g5 = phi g5_1, g5_2
g6 = phi g6_1, g6_2
goto after_loop
explicit_test_block:
if l0 == null (unlikely) goto sub_optimal_loop
if 100 >= l0.length (unlikely) goto sub_optimal_loop
if l1 == null (unlikely) goto sub_optimal_loop
if 100 >= l1.length (unlikely) goto sub_optimal_loop
goto optimal_loop
sub_optimal_loop:
for (int t1_1=0; t1_1 < 100; t1_1++) {
g1_1 = null_check l0
g2_1 = bounds_check l0, t1_1
g3_1 = guard_combine g1_1,g2_1
t2_1 = aload l0, t1_1, g3_1
g4_1 = null_check l1
g5_1 = bounds_check l1, t1_1
g6_1 = guard_combine g4_1,g5_1
astore t2_1, l1, t1_1, g6_1
}
goto successor_to_loops
optimal_loop:
for (int t1_2=0; t1_2 < 100; t1_2++) {
g1_2 = true_guard
g2_2 = true_guard
g3_2 = guard_combine g1_2,g2_2
t2_2 = aload l0, t1_2, g3_2
g4_2 = null_check l1
g5_2 = bounds_check l1, t1_2
g6_2 = guard_combine g4_2,g5_2
astore t2_2, l1, t1_2, g6_2
}
goto successor_to_loops
after_loop:
The optimisation works on the Heap SSA form. A more accurate
example of the transformation would be:
heap1 = ...; // previous heap state
t1_1 = 0;
if t1_1 ≥ 100 goto label2
label1:
t1_2 = phi t1_1, t1_3
heap2 = phi heap1, heap3
g1 = null_check l0
g2 = bounds_check l0, t1_2
g3 = guard_combine g1,g2
t2 = aload l0, t1_2, g3
g4 = null_check l1
g5 = bounds_check l1, t1_2
g6 = guard_combine g4,g5
heap3 = astore t2, l1, t1_2, g6
t1_3 = t1_2 + 1
if t1_3 < 100 label1 * label2:
becomes:
heap1 = ...; // previous heap state
t1_1 = 0;
if t1_1 ≥ 100 goto label2
goto explicit_test_block
successor_to_loops:
t1_2 = phi t1_2_1, t1_2_2
heap2 = phi heap2_1, heap2_2
g1 = phi g1_1, g1_2
g2 = phi g2_1, g2_2
g3 = phi g3_1, g3_2
t2 = phi t2_1, t2_2
g4 = phi g4_1, g4_2
g5 = phi g5_1, g5_2
g6 = phi g6_1, g6_2
heap3 = phi heap3_1, heap3_2
t1_3 = phi t1_3_1, t1_3_2
goto after_loop
explicit_test_block:
g1_2 = if l0 == null (unlikely) goto sub_optimal_loop
g2_2 = if 100 >= l0.length (unlikely) goto sub_optimal_loop
g4_2 = if l1 == null (unlikely) goto sub_optimal_loop
g5_2 = if 100 >= l1.length (unlikely) goto sub_optimal_loop
goto optimal_loop
sub_optimal_loop:
label1_1:
t1_2_1 = phi t1_1, t1_3_1
heap2_1 = phi heap1, heap3_1
g1_1 = null_check l0
g2_1 = bounds_check l0, t1_2_1
g3_1 = guard_combine g1_1,g2_1
t2_1 = aload l0, t1_2_1, g3_1
g4_1 = null_check l1
g5_1 = bounds_check l1, t1_2_1
g6_1 = guard_combine g4_1,g5_1
heap3_1 = astore t2_1, l1, t1_2_1, g6_1
t1_3_1 = t1_2_1 + 1
if t1_3_1 < 100 label1_1
goto successor_to_loops
optimal_loop:
label1_2:
t1_2_2 = phi t1_1, t1_3_2
heap2_2 = phi heap1, heap3_2
g3_2 = guard_combine g1_2,g2_2
t2_2 = aload l0, t1_2_2, g3_2
g6_2 = guard_combine g4_2,g5_2
heap3_2 = astore t2_2, l1, t1_2_2, g6_2
t1_3_2 = t1_2_2 + 1
if t1_3_2 < 100 label1_2
goto successor_to_loops
after_loop:
label2:
| Modifier and Type | Field and Description |
|---|---|
private static Constructor<CompilerPhase> |
constructor
Constructor for this compiler phase
|
private static boolean |
DEBUG
Flag to optionally print verbose debugging messages
|
private SSAOptions |
desiredSSAOptions
SSA options
|
private CompilerPhase |
domPhase |
private CompilerPhase |
enterSSA
Compiler phases called from this one
|
private static boolean |
inSSAphase
Run inside SSA sub-phase
|
private IR |
ir
IR for optimisation
|
private CompilerPhase |
leaveSSA
Compiler phases called from this one
|
private HashSet<Register> |
loopRegisterSet
Set used to store the loop related register
|
private static int |
OPTIMIZED_LOOP_OPERAND
The phi instruction operand holding the optimized loop variable
|
private static int |
UNOPTIMIZED_LOOP_OPERAND
The phi instruction operand holding the unoptimized loop variable
|
private static boolean |
VERIFY
Flag to verify computed IR
|
container| Constructor and Description |
|---|
LoopVersioning()
Constructor
|
| Modifier and Type | Method and Description |
|---|---|
private boolean |
createBranchBlocks(AnnotatedLSTNode loop,
BasicBlock block,
ArrayList<Instruction> checksToEliminate,
BasicBlock unoptimizedLoopEntry,
BasicBlock optimizedLoopEntry,
HashMap<Register,Register> optimalRegMap) |
private HashMap<BasicBlock,BasicBlock> |
createCloneLoop(AnnotatedLSTNode loop,
HashMap<Register,Register> regMap,
HashMap<Register,BasicBlock> regToBlockMap)
Create a clone of the loop replacing definitions in the cloned
loop with those found in the register map
|
private HashMap<BasicBlock,BasicBlock> |
createOptimizedLoop(AnnotatedLSTNode loop,
HashMap<Register,Register> regMap,
ArrayList<Instruction> instrToEliminate,
HashMap<Register,BasicBlock> regToBlockMap)
Create a clone of the loop replacing definitions in the cloned
loop with those found in the register map and eliminate
unnecessary bound checks
|
private boolean |
findLoopToOptimise(AnnotatedLSTNode loop)
Find an outermost loop to optimise and optimise it.
|
private void |
fixUpPhiPredecessors(ArrayList<Instruction> phiInstructions,
BasicBlock unoptimizedLoopExit,
BasicBlock optimizedLoopExit)
When phi nodes were generated the basic blocks weren't known for
the predecessors, fix this up now.
|
private BasicBlock |
generateExplicitBoundCheck(Instruction boundCheckInstr,
Operand minIndexValue,
Operand maxIndexValue,
HashMap<Register,Register> optimalRegMap,
BasicBlock block,
BasicBlock unoptimizedLoopEntry)
Generate bound check branch blocks
|
private BasicBlock |
generateNullCheckBranchBlocks(AnnotatedLSTNode loop,
ArrayList<Instruction> checksToEliminate,
HashMap<Register,Register> optimalRegMap,
BasicBlock block,
BasicBlock unoptimizedLoopEntry)
Generate null check branch blocks
|
private void |
generatePhiNodes(AnnotatedLSTNode loop,
ArrayList<Register> registers,
ArrayList<TypeReference> types,
ArrayList<Instruction> phiInstructions,
HashMap<Register,Register> subOptimalRegMap,
HashMap<Register,Register> optimalRegMap)
Generate into a new block phi nodes that define the original
register defined by the loop and use two newly created
registers.
|
Constructor<CompilerPhase> |
getClassConstructor()
Get a constructor object for this compiler phase
|
private int |
getConstantAdjustedArrayLengthDistance(Operand op)
Get the distance from an array length by addding up instructions
that adjust the array length result by a constant amount
|
private Operand |
getConstantAdjustedArrayLengthRef(Operand op)
Gets the array length reference ignoring instructions that adjust
its result by a fixed amount.
|
private void |
getListOfChecksToEliminate(AnnotatedLSTNode loop,
ArrayList<Instruction> instrToEliminate)
Create a list of instructions to be eliminated
|
String |
getName()
Return a string name for this phase.
|
private void |
getRegistersDefinedInLoop(AnnotatedLSTNode loop,
ArrayList<Register> registers,
ArrayList<TypeReference> types,
ArrayList<Instruction> definingInstructions)
Get registers defined in the given loop.
|
private boolean |
isOptimizedLoop(Register reg)
Check whether the loop that contain such iterator register had
been optimized
|
private void |
modifyOriginalLoop(AnnotatedLSTNode loop,
ArrayList<Instruction> phiInstructions,
ArrayList<Instruction> definingInstrInOriginalLoop,
HashMap<Register,Register> subOptimalRegMap,
HashMap<Register,Register> optimalRegMap) |
private RegisterOperand |
nullCheckPerformedInLoopPredecessors(BasicBlock header,
Instruction instr)
Can we eliminate a null check as it has lready been performed?
|
void |
perform(IR _ir)
This is the method that actually does the work of the phase.
|
private void |
removeUnoptimizedLoop(AnnotatedLSTNode loop,
HashMap<BasicBlock,BasicBlock> unoptimizedLoopMap) |
private void |
renameOptimizedLoops(HashMap<Register,Register> subOptimalRegMap,
HashMap<Register,Register> optimalRegMap) |
private static void |
report(String s)
Human readable report of what goes on
|
private void |
setOptimizedLoop(Register reg)
Put the optimized loop's iterator register into the hash set
|
boolean |
shouldPerform(OptOptions options)
Should loop versioning be performed?
|
dumpIR, dumpIR, getCompilerPhaseConstructor, getCompilerPhaseConstructor, newExecution, performPhase, printingEnabled, reportAdditionalStats, setContainer, verifyprivate static final boolean DEBUG
private static final boolean VERIFY
private static final int OPTIMIZED_LOOP_OPERAND
private static final int UNOPTIMIZED_LOOP_OPERAND
private HashSet<Register> loopRegisterSet
private final SSAOptions desiredSSAOptions
private CompilerPhase enterSSA
private CompilerPhase leaveSSA
private final CompilerPhase domPhase
private static final boolean inSSAphase
private static final Constructor<CompilerPhase> constructor
public LoopVersioning()
private static void report(String s)
s - String to printpublic String getName()
getName in class CompilerPhasepublic Constructor<CompilerPhase> getClassConstructor()
getClassConstructor in class CompilerPhasepublic boolean shouldPerform(OptOptions options)
shouldPerform in class CompilerPhaseoptions - the compiler options for the compilationpublic void perform(IR _ir)
CompilerPhaseperform in class CompilerPhase_ir - the IR to processprivate boolean findLoopToOptimise(AnnotatedLSTNode loop)
loop - Loop to searchprivate void getListOfChecksToEliminate(AnnotatedLSTNode loop, ArrayList<Instruction> instrToEliminate)
loop - the loop to examineinstrToEliminate - the instructions to removeprivate void getRegistersDefinedInLoop(AnnotatedLSTNode loop, ArrayList<Register> registers, ArrayList<TypeReference> types, ArrayList<Instruction> definingInstructions)
loop - - the loop to examineregisters - - vector to which defined registers are addedtypes - list to which the register's types are addeddefiningInstructions - list to which the defining instructions for
the registers are addedprivate void generatePhiNodes(AnnotatedLSTNode loop, ArrayList<Register> registers, ArrayList<TypeReference> types, ArrayList<Instruction> phiInstructions, HashMap<Register,Register> subOptimalRegMap, HashMap<Register,Register> optimalRegMap)
loop - the loop to processregisters - - vector to which defined registers need to be
created registers.x used in creating phi nodestypes - - vector of corresponding types of registers.phiInstructions - - created phi instructionssubOptimalRegMap - - mapping of orignal destination to the
newly created destination for the unoptimized loopoptimalRegMap - - mapping of orignal destination to the
newly created destination for the optimized loopprivate HashMap<BasicBlock,BasicBlock> createCloneLoop(AnnotatedLSTNode loop, HashMap<Register,Register> regMap, HashMap<Register,BasicBlock> regToBlockMap)
loop - - loop to cloneregMap - - mapping of original definition to new
definitionregToBlockMap - mapping of registers to new, unoptimized blocks. This starts
empty and will be filled during execution of the method.private HashMap<BasicBlock,BasicBlock> createOptimizedLoop(AnnotatedLSTNode loop, HashMap<Register,Register> regMap, ArrayList<Instruction> instrToEliminate, HashMap<Register,BasicBlock> regToBlockMap)
loop - - loop to cloneregMap - - mapping of original definition to new
definitioninstrToEliminate - - instructions to eliminateregToBlockMap - - mapping of a register to its defining BBprivate void fixUpPhiPredecessors(ArrayList<Instruction> phiInstructions, BasicBlock unoptimizedLoopExit, BasicBlock optimizedLoopExit)
phiInstructions - a list of phi nodesunoptimizedLoopExit - the exit block of the unoptimized loop.
This may be null if the unoptimized loop is no longer reachable.optimizedLoopExit - the exit block of the optimized loopprivate boolean createBranchBlocks(AnnotatedLSTNode loop, BasicBlock block, ArrayList<Instruction> checksToEliminate, BasicBlock unoptimizedLoopEntry, BasicBlock optimizedLoopEntry, HashMap<Register,Register> optimalRegMap)
private BasicBlock generateNullCheckBranchBlocks(AnnotatedLSTNode loop, ArrayList<Instruction> checksToEliminate, HashMap<Register,Register> optimalRegMap, BasicBlock block, BasicBlock unoptimizedLoopEntry)
loop - the current loop where checks are being eliminatedchecksToEliminate - all of the checks that are being eliminated in the passoptimalRegMap - a map from original register to the register used in the optimal loopblock - the block to generate code intounoptimizedLoopEntry - entry to the unoptimized loop for if the check failsprivate BasicBlock generateExplicitBoundCheck(Instruction boundCheckInstr, Operand minIndexValue, Operand maxIndexValue, HashMap<Register,Register> optimalRegMap, BasicBlock block, BasicBlock unoptimizedLoopEntry)
boundCheckInstr - the bound check instruction in questionminIndexValue - the min value for an iterator a loop will generatemaxIndexValue - the max value for an iterator a loop will generateoptimalRegMap - a map from original register to the register used in the optimal loopblock - the block to generate code intounoptimizedLoopEntry - entry to the unoptimized loop for if the check failsprivate RegisterOperand nullCheckPerformedInLoopPredecessors(BasicBlock header, Instruction instr)
header - loop header basic blockinstr - null check instructionnull if the check hasn't been performed yetprivate Operand getConstantAdjustedArrayLengthRef(Operand op)
op - operand to chase arraylength opcode to
constant value from an array lengthprivate int getConstantAdjustedArrayLengthDistance(Operand op)
op - operand to chase arraylength opcode toprivate void modifyOriginalLoop(AnnotatedLSTNode loop, ArrayList<Instruction> phiInstructions, ArrayList<Instruction> definingInstrInOriginalLoop, HashMap<Register,Register> subOptimalRegMap, HashMap<Register,Register> optimalRegMap)
private void removeUnoptimizedLoop(AnnotatedLSTNode loop, HashMap<BasicBlock,BasicBlock> unoptimizedLoopMap)
private void setOptimizedLoop(Register reg)
reg - registerprivate boolean isOptimizedLoop(Register reg)
reg - register