Refactor phi updater

This commit is contained in:
Alexey Andreev 2017-01-04 23:46:34 +03:00
parent a5eb9ac800
commit 9532f9a32b
6 changed files with 152 additions and 80 deletions

View File

@ -228,6 +228,7 @@ public class BasicBlock implements BasicBlockReader, Iterable<Instruction> {
@Override @Override
public InstructionIterator iterateInstructions() { public InstructionIterator iterateInstructions() {
return new InstructionIterator() { return new InstructionIterator() {
TextLocation location;
Instruction instruction = firstInstruction; Instruction instruction = firstInstruction;
Instruction readInstruction; Instruction readInstruction;
InstructionReadVisitor visitor = new InstructionReadVisitor(null); InstructionReadVisitor visitor = new InstructionReadVisitor(null);
@ -257,6 +258,10 @@ public class BasicBlock implements BasicBlockReader, Iterable<Instruction> {
@Override @Override
public void read(InstructionReader reader) { public void read(InstructionReader reader) {
visitor.reader = reader; visitor.reader = reader;
if (!Objects.equals(readInstruction.getLocation(), location)) {
location = readInstruction.getLocation();
reader.location(location);
}
readInstruction.acceptVisitor(visitor); readInstruction.acceptVisitor(visitor);
visitor.reader = null; visitor.reader = null;
} }

View File

@ -136,6 +136,7 @@ public class Inlining {
ExitInstruction exit = (ExitInstruction) lastInsn; ExitInstruction exit = (ExitInstruction) lastInsn;
JumpInstruction exitReplacement = new JumpInstruction(); JumpInstruction exitReplacement = new JumpInstruction();
exitReplacement.setTarget(splitBlock); exitReplacement.setTarget(splitBlock);
exitReplacement.setLocation(exit.getLocation());
exit.replace(exitReplacement); exit.replace(exitReplacement);
if (exit.getValueToReturn() != null) { if (exit.getValueToReturn() != null) {
Incoming resultIncoming = new Incoming(); Incoming resultIncoming = new Incoming();

View File

@ -21,9 +21,12 @@ import com.carrotsearch.hppc.IntObjectMap;
import com.carrotsearch.hppc.IntObjectOpenHashMap; import com.carrotsearch.hppc.IntObjectOpenHashMap;
import com.carrotsearch.hppc.IntOpenHashSet; import com.carrotsearch.hppc.IntOpenHashSet;
import com.carrotsearch.hppc.IntSet; import com.carrotsearch.hppc.IntSet;
import java.util.ArrayDeque;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.BitSet; import java.util.BitSet;
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -84,9 +87,13 @@ import org.teavm.model.instructions.UnwrapArrayInstruction;
public class PhiUpdater { public class PhiUpdater {
private Program program; private Program program;
private Graph cfg; private Graph cfg;
private DominatorTree domTree;
private Graph domGraph;
private int[][] domFrontiers; private int[][] domFrontiers;
private Variable[] variableMap; private Variable[] variableMap;
private boolean[] variableDefined;
private BasicBlock currentBlock; private BasicBlock currentBlock;
private TryCatchBlock currentTryCatch;
private Phi[][] phiMap; private Phi[][] phiMap;
private int[][] phiIndexMap; private int[][] phiIndexMap;
private Map<TryCatchBlock, Map<Variable, TryCatchJoint>> jointMap = new HashMap<>(); private Map<TryCatchBlock, Map<Variable, TryCatchJoint>> jointMap = new HashMap<>();
@ -124,8 +131,10 @@ public class PhiUpdater {
phisByReceiver.clear(); phisByReceiver.clear();
jointsByReceiver.clear(); jointsByReceiver.clear();
cfg = ProgramUtils.buildControlFlowGraph(program); cfg = ProgramUtils.buildControlFlowGraph(program);
DominatorTree domTree = GraphUtils.buildDominatorTree(cfg); domTree = GraphUtils.buildDominatorTree(cfg);
domFrontiers = new int[cfg.size()][]; domFrontiers = new int[cfg.size()][];
domGraph = GraphUtils.buildDominatorGraph(domTree, program.basicBlockCount());
variableMap = new Variable[program.variableCount()]; variableMap = new Variable[program.variableCount()];
usedDefinitions = new boolean[program.variableCount()]; usedDefinitions = new boolean[program.variableCount()];
for (int i = 0; i < arguments.length; ++i) { for (int i = 0; i < arguments.length; ++i) {
@ -167,13 +176,23 @@ public class PhiUpdater {
private void estimatePhis() { private void estimatePhis() {
DefinitionExtractor definitionExtractor = new DefinitionExtractor(); DefinitionExtractor definitionExtractor = new DefinitionExtractor();
for (int i = 0; i < program.basicBlockCount(); ++i) { List<List<TryCatchJoint>> inputJoints = getInputJoints(program);
variableDefined = new boolean[program.variableCount()];
IntDeque stack = new IntArrayDeque();
stack.addLast(0);
while (!stack.isEmpty()) {
int i = stack.removeLast();
currentBlock = program.basicBlockAt(i); currentBlock = program.basicBlockAt(i);
if (currentBlock.getExceptionVariable() != null) { if (currentBlock.getExceptionVariable() != null) {
markAssignment(currentBlock.getExceptionVariable()); markAssignment(currentBlock.getExceptionVariable());
} }
for (TryCatchJoint joint : inputJoints.get(currentBlock.getIndex())) {
markAssignment(joint.getReceiver());
}
for (Phi phi : currentBlock.getPhis()) { for (Phi phi : currentBlock.getPhis()) {
markAssignment(phi.getReceiver()); markAssignment(phi.getReceiver());
} }
@ -197,85 +216,71 @@ public class PhiUpdater {
} }
} }
} }
for (int successor : domGraph.outgoingEdges(i)) {
stack.addLast(successor);
}
} }
} }
private static class Task { private static class Task {
Variable[] variables; Variable[] variables;
BasicBlock block; BasicBlock block;
TryCatchBlock tryCatch;
int tryCatchIndex;
} }
private void renameVariables() { private void renameVariables() {
DominatorTree domTree = GraphUtils.buildDominatorTree(ProgramUtils.buildControlFlowGraph(program)); Deque<Task> stack = new ArrayDeque<>();
Graph domGraph = GraphUtils.buildDominatorGraph(domTree, program.basicBlockCount());
Task[] stack = new Task[cfg.size() * 2];
int head = 0;
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
if (domGraph.incomingEdgesCount(i) == 0) { if (domGraph.incomingEdgesCount(i) == 0) {
Task task = new Task(); Task task = new Task();
task.block = program.basicBlockAt(i); task.block = program.basicBlockAt(i);
task.variables = variableMap.clone(); task.variables = variableMap.clone();
stack[head++] = task; stack.push(task);
} }
} }
List<List<Incoming>> phiOutputs = ProgramUtils.getPhiOutputs(program); List<List<Incoming>> phiOutputs = ProgramUtils.getPhiOutputs(program);
while (head > 0) { while (!stack.isEmpty()) {
Task task = stack[--head]; Task task = stack.pop();
currentBlock = task.block; currentBlock = task.block;
currentTryCatch = task.tryCatch;
int index = currentBlock.getIndex(); int index = currentBlock.getIndex();
variableMap = task.variables.clone(); variableMap = task.variables.clone();
if (currentBlock.getExceptionVariable() != null) { if (currentTryCatch == null) {
currentBlock.setExceptionVariable(define(currentBlock.getExceptionVariable())); if (currentBlock.getExceptionVariable() != null) {
} currentBlock.setExceptionVariable(define(currentBlock.getExceptionVariable()));
}
for (Phi phi : synthesizedPhisByBlock.get(index)) { for (Phi phi : synthesizedPhisByBlock.get(index)) {
Variable var = program.createVariable(); Variable var = program.createVariable();
var.setDebugName(phi.getReceiver().getDebugName()); var.setDebugName(phi.getReceiver().getDebugName());
var.setLabel(phi.getReceiver().getLabel()); var.setLabel(phi.getReceiver().getLabel());
mapVariable(phi.getReceiver().getIndex(), var); mapVariable(phi.getReceiver().getIndex(), var);
phisByReceiver.put(var.getIndex(), phi); phisByReceiver.put(var.getIndex(), phi);
phi.setReceiver(var); phi.setReceiver(var);
} }
for (Phi phi : currentBlock.getPhis()) { for (Phi phi : currentBlock.getPhis()) {
phi.setReceiver(define(phi.getReceiver())); phi.setReceiver(define(phi.getReceiver()));
} }
for (Instruction insn : currentBlock) { for (Instruction insn : currentBlock) {
insn.acceptVisitor(consumer); insn.acceptVisitor(consumer);
} }
} else {
for (TryCatchBlock tryCatch : currentBlock.getTryCatchBlocks()) { for (TryCatchJoint joint : currentTryCatch.getJoints()) {
for (TryCatchJoint joint : tryCatch.getJoints()) { joint.setReceiver(define(joint.getReceiver()));
for (int i = 0; i < joint.getSourceVariables().size(); ++i) {
joint.getSourceVariables().set(i, use(joint.getSourceVariables().get(i)));
}
} }
} }
IntSet catchSuccessors = new IntOpenHashSet(); boolean tryCatchIsSuccessor = currentTryCatch != null
for (TryCatchBlock tryCatch : currentBlock.getTryCatchBlocks()) { && domTree.immediateDominatorOf(currentTryCatch.getHandler().getIndex()) == index;
catchSuccessors.add(tryCatch.getHandler().getIndex()); if (currentTryCatch != null) {
} for (TryCatchJoint joint : synthesizedJointsByBlock.get(index).get(task.tryCatchIndex)) {
for (Incoming output : phiOutputs.get(index)) {
if (!catchSuccessors.contains(output.getPhi().getBasicBlock().getIndex())) {
Variable var = output.getValue();
output.setValue(use(var));
}
}
Variable[] regularVariableMap = variableMap;
Variable[] catchVariableMap = variableMap.clone();
variableMap = catchVariableMap;
for (int i = 0; i < currentBlock.getTryCatchBlocks().size(); ++i) {
TryCatchBlock tryCatch = currentBlock.getTryCatchBlocks().get(i);
catchSuccessors.add(tryCatch.getHandler().getIndex());
for (TryCatchJoint joint : synthesizedJointsByBlock.get(index).get(i)) {
Variable var = program.createVariable(); Variable var = program.createVariable();
var.setDebugName(joint.getReceiver().getDebugName()); var.setDebugName(joint.getReceiver().getDebugName());
var.setLabel(joint.getReceiver().getLabel()); var.setLabel(joint.getReceiver().getLabel());
@ -284,21 +289,65 @@ public class PhiUpdater {
jointsByReceiver.put(var.getIndex(), joint); jointsByReceiver.put(var.getIndex(), joint);
} }
} }
variableMap = regularVariableMap;
int[] successors = domGraph.outgoingEdges(index); int[] successors;
List<TryCatchBlock> tryCatchBlockSuccessors = new ArrayList<>();
IntSet tryCatchSuccessors = new IntOpenHashSet();
if (currentTryCatch != null) {
successors = tryCatchIsSuccessor ? new int[] { currentTryCatch.getHandler().getIndex() } : new int[0];
} else {
List<TryCatchBlock> tryCatchBlocks = currentBlock.getTryCatchBlocks();
for (int i = 0; i < tryCatchBlocks.size(); i++) {
TryCatchBlock tryCatch = tryCatchBlocks.get(i);
tryCatchSuccessors.add(tryCatch.getHandler().getIndex());
tryCatchBlockSuccessors.add(tryCatch);
}
successors = Arrays.stream(domGraph.outgoingEdges(index))
.filter(successor -> !tryCatchSuccessors.contains(successor))
.toArray();
}
IntSet successorSet = IntOpenHashSet.from(successors);
for (Incoming output : phiOutputs.get(index)) {
if (successorSet.contains(output.getPhi().getBasicBlock().getIndex())) {
Variable var = output.getValue();
output.setValue(use(var));
}
}
if (tryCatchIsSuccessor) {
for (TryCatchJoint joint : currentTryCatch.getJoints()) {
for (int i = 0; i < joint.getSourceVariables().size(); ++i) {
joint.getSourceVariables().set(i, use(joint.getSourceVariables().get(i)));
}
}
}
for (int j = successors.length - 1; j >= 0; --j) { for (int j = successors.length - 1; j >= 0; --j) {
int successor = successors[j]; int successor = successors[j];
Task next = new Task(); Task next = new Task();
next.variables = (catchSuccessors.contains(successor) ? catchVariableMap : variableMap).clone(); next.variables = variableMap.clone();
next.block = program.basicBlockAt(successor); next.block = program.basicBlockAt(successor);
stack[head++] = next; stack.push(next);
} }
successors = cfg.outgoingEdges(index); for (int j = tryCatchBlockSuccessors.size() - 1; j >= 0; --j) {
for (int successor : successors) { TryCatchBlock tryCatch = tryCatchBlockSuccessors.get(j);
variableMap = catchSuccessors.contains(successor) ? catchVariableMap : regularVariableMap; Task next = new Task();
renameOutgoingPhis(successor); next.variables = variableMap.clone();
next.block = currentBlock;
next.tryCatch = tryCatch;
next.tryCatchIndex = j;
stack.push(next);
}
if (currentTryCatch == null) {
for (int successor : cfg.outgoingEdges(index)) {
if (!tryCatchSuccessors.contains(successor)) {
renameOutgoingPhis(successor);
}
}
} else {
renameOutgoingPhis(currentTryCatch.getHandler().getIndex());
} }
} }
} }
@ -395,18 +444,22 @@ public class PhiUpdater {
int head = 0; int head = 0;
worklist[head++] = currentBlock; worklist[head++] = currentBlock;
BasicBlock startBlock = currentBlock; if (variableDefined[var.getIndex()]) {
List<TryCatchBlock> tryCatchBlocks = startBlock.getTryCatchBlocks(); BasicBlock startBlock = currentBlock;
for (int i = 0; i < tryCatchBlocks.size(); i++) { List<TryCatchBlock> tryCatchBlocks = startBlock.getTryCatchBlocks();
TryCatchBlock tryCatch = tryCatchBlocks.get(i); for (int i = 0; i < tryCatchBlocks.size(); i++) {
TryCatchJoint joint = jointMap.computeIfAbsent(tryCatch, k -> new HashMap<>()).get(var); TryCatchBlock tryCatch = tryCatchBlocks.get(i);
if (joint == null) { TryCatchJoint joint = jointMap.computeIfAbsent(tryCatch, k -> new HashMap<>()).get(var);
joint = new TryCatchJoint(); if (joint == null) {
joint.setReceiver(var); joint = new TryCatchJoint();
synthesizedJointsByBlock.get(startBlock.getIndex()).get(i).add(joint); joint.setReceiver(var);
jointMap.get(tryCatch).put(var, joint); synthesizedJointsByBlock.get(startBlock.getIndex()).get(i).add(joint);
worklist[head++] = tryCatch.getHandler(); jointMap.get(tryCatch).put(var, joint);
worklist[head++] = tryCatch.getHandler();
}
} }
} else {
variableDefined[var.getIndex()] = true;
} }
while (head > 0) { while (head > 0) {
@ -504,6 +557,19 @@ public class PhiUpdater {
return mappedVar; return mappedVar;
} }
private static List<List<TryCatchJoint>> getInputJoints(Program program) {
List<List<TryCatchJoint>> inputJoints = new ArrayList<>(Collections.nCopies(program.basicBlockCount(), null));
for (int i = 0; i < program.basicBlockCount(); ++i) {
inputJoints.set(i, new ArrayList<>());
}
for (BasicBlock block : program.getBasicBlocks()) {
for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) {
inputJoints.get(tryCatch.getHandler().getIndex()).addAll(tryCatch.getJoints());
}
}
return inputJoints;
}
private InstructionVisitor consumer = new InstructionVisitor() { private InstructionVisitor consumer = new InstructionVisitor() {
@Override @Override
public void visit(EmptyInstruction insn) { public void visit(EmptyInstruction insn) {

View File

@ -6,8 +6,8 @@ $start
@a_2 := ephi @a, @a_1 @a_2 := ephi @a, @a_1
$catch $catch
@b := 1 @b := 1
@a_4 := @a_2 + @b as int @a_3 := @a_2 + @b as int
goto $end goto $end
$end $end
@a_3 := phi @a_1 from $start, @a_4 from $catch @a_4 := phi @a_1 from $start, @a_3 from $catch
return @a_3 return @a_4

View File

@ -5,15 +5,15 @@ $start
catch java.lang.RuntimeException goto $catch catch java.lang.RuntimeException goto $catch
@a_2 := ephi @a, @a_1 @a_2 := ephi @a, @a_1
$second $second
@a_3 := invokeStatic `Foo.boo()I` @a_5 := invokeStatic `Foo.boo()I`
goto $end goto $end
catch java.lang.RuntimeException goto $catch catch java.lang.RuntimeException goto $catch
@a_4 := ephi @a_1, @a_3 @a_6 := ephi @a_1, @a_5
$catch $catch
@a_5 := phi @a_2 from $start, @a_4 from $second @a_3 := phi @a_2 from $start, @a_6 from $second
@b := 1 @b := 1
@a_6 := @a_5 + @b as int @a_4 := @a_3 + @b as int
goto $end goto $end
$end $end
@a_7 := phi @a_3 from $second, @a_6 from $catch @a_7 := phi @a_4 from $catch, @a_5 from $second
return @a_7 return @a_7

View File

@ -34,7 +34,7 @@ interface TeaVMTestConfiguration {
@Override @Override
public void apply(TeaVM vm) { public void apply(TeaVM vm) {
vm.setOptimizationLevel(TeaVMOptimizationLevel.FULL); vm.setOptimizationLevel(TeaVMOptimizationLevel.SIMPLE);
} }
@Override @Override