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

View File

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

View File

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

View File

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

View File

@ -5,15 +5,15 @@ $start
catch java.lang.RuntimeException goto $catch
@a_2 := ephi @a, @a_1
$second
@a_3 := invokeStatic `Foo.boo()I`
@a_5 := invokeStatic `Foo.boo()I`
goto $end
catch java.lang.RuntimeException goto $catch
@a_4 := ephi @a_1, @a_3
@a_6 := ephi @a_1, @a_5
$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
@a_6 := @a_5 + @b as int
@a_4 := @a_3 + @b as int
goto $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

View File

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