Avoids swap problem when eliminating phi functions and therefore gets

back global value numbering optimization
This commit is contained in:
konsoletyper 2014-02-22 23:20:30 +04:00
parent 7831ade3a6
commit 5c03e7547f
4 changed files with 130 additions and 112 deletions

View File

@ -15,9 +15,7 @@
*/ */
package org.teavm.model.util; package org.teavm.model.util;
import java.util.ArrayList;
import java.util.BitSet; import java.util.BitSet;
import java.util.List;
import org.teavm.common.Graph; import org.teavm.common.Graph;
/** /**
@ -25,42 +23,20 @@ import org.teavm.common.Graph;
* @author Alexey Andreev * @author Alexey Andreev
*/ */
class GraphColorer { class GraphColorer {
public void colorize(Graph graph, int[] classes, int[] colors) { public void colorize(Graph graph, int[] colors) {
List<List<Integer>> classMembers = new ArrayList<>();
for (int i = 0; i < classes.length; ++i) {
int cls = classes[i];
while (cls >= classMembers.size()) {
classMembers.add(new ArrayList<Integer>());
}
classMembers.get(cls).add(i);
}
for (int i = 0; i < colors.length; ++i) {
if (colors[i] >= 0) {
int cls = classes[i];
for (int member : classMembers.get(cls)) {
colors[member] = colors[i];
}
}
}
BitSet usedColors = new BitSet(); BitSet usedColors = new BitSet();
for (int v : getOrdering(graph)) { for (int v : getOrdering(graph)) {
if (colors[v] >= 0) { if (colors[v] >= 0) {
continue; continue;
} }
int cls = classes[v];
usedColors.clear(); usedColors.clear();
usedColors.set(0); usedColors.set(0);
for (int member : classMembers.get(cls)) { for (int succ : graph.outgoingEdges(v)) {
for (int succ : graph.outgoingEdges(member)) { if (colors[succ] >= 0) {
if (colors[succ] >= 0) { usedColors.set(colors[succ]);
usedColors.set(colors[succ]);
}
} }
} }
int color = usedColors.nextClearBit(0); colors[v] = usedColors.nextClearBit(0);
for (int member : classMembers.get(cls)) {
colors[member] = color;
}
} }
} }

View File

@ -57,4 +57,9 @@ class MutableGraphEdge {
public MutableGraphEdge getBack() { public MutableGraphEdge getBack() {
return back; return back;
} }
@Override
public String toString() {
return String.valueOf(second.getTag());
}
} }

View File

@ -18,6 +18,7 @@ package org.teavm.model.util;
import java.util.*; import java.util.*;
import org.teavm.common.DisjointSet; import org.teavm.common.DisjointSet;
import org.teavm.common.Graph; import org.teavm.common.Graph;
import org.teavm.common.GraphBuilder;
import org.teavm.model.*; import org.teavm.model.*;
import org.teavm.model.instructions.AssignInstruction; import org.teavm.model.instructions.AssignInstruction;
import org.teavm.model.instructions.EmptyInstruction; import org.teavm.model.instructions.EmptyInstruction;
@ -29,35 +30,28 @@ import org.teavm.model.instructions.JumpInstruction;
*/ */
public class RegisterAllocator { public class RegisterAllocator {
public void allocateRegisters(MethodReader method, Program program) { public void allocateRegisters(MethodReader method, Program program) {
List<PhiArgumentCopy> phiArgsCopies = insertPhiArgumentsCopies(program); insertPhiArgumentsCopies(program);
InterferenceGraphBuilder interferenceBuilder = new InterferenceGraphBuilder(); InterferenceGraphBuilder interferenceBuilder = new InterferenceGraphBuilder();
LivenessAnalyzer liveness = new LivenessAnalyzer(); LivenessAnalyzer liveness = new LivenessAnalyzer();
liveness.analyze(program); liveness.analyze(program);
Graph interferenceGraph = interferenceBuilder.build(program, method.parameterCount(), liveness); Graph interferenceGraph = interferenceBuilder.build(program, method.parameterCount(), liveness);
DisjointSet congruenceClasses = buildPhiCongruenceClasses(program); DisjointSet congruenceClasses = buildPhiCongruenceClasses(program);
List<MutableGraphNode> classInterferenceGraph = makeMutableGraph(interferenceGraph, congruenceClasses); List<MutableGraphNode> classInterferenceGraph = makeMutableGraph(interferenceGraph, congruenceClasses);
removeRedundantCopies(program, phiArgsCopies, classInterferenceGraph, congruenceClasses); removeRedundantCopies(program, classInterferenceGraph, congruenceClasses);
int[] classArray = congruenceClasses.pack(program.variableCount()); int[] classArray = congruenceClasses.pack(program.variableCount());
renameVariables(program, classArray);
int[] colors = new int[program.variableCount()]; int[] colors = new int[program.variableCount()];
Arrays.fill(colors, -1); Arrays.fill(colors, -1);
for (int i = 0; i <= method.parameterCount(); ++i) { for (int i = 0; i <= method.parameterCount(); ++i) {
colors[i] = i; colors[i] = i;
} }
GraphColorer colorer = new GraphColorer(); GraphColorer colorer = new GraphColorer();
colorer.colorize(interferenceGraph, classArray, colors); colorer.colorize(renameInterferenceGraph(interferenceGraph, classArray), colors);
for (int i = 0; i < colors.length; ++i) { for (int i = 0; i < colors.length; ++i) {
program.variableAt(i).setRegister(colors[i]); program.variableAt(i).setRegister(colors[i]);
} }
} }
private static class PhiArgumentCopy {
Incoming incoming;
int original;
int index;
BasicBlock block;
int var;
}
private static List<MutableGraphNode> makeMutableGraph(Graph graph, DisjointSet classes) { private static List<MutableGraphNode> makeMutableGraph(Graph graph, DisjointSet classes) {
List<MutableGraphNode> mutableGraph = new ArrayList<>(); List<MutableGraphNode> mutableGraph = new ArrayList<>();
for (int i = 0; i < graph.size(); ++i) { for (int i = 0; i < graph.size(); ++i) {
@ -77,93 +71,135 @@ public class RegisterAllocator {
return mutableGraph; return mutableGraph;
} }
private List<PhiArgumentCopy> insertPhiArgumentsCopies(Program program) { private void insertPhiArgumentsCopies(Program program) {
List<PhiArgumentCopy> copies = new ArrayList<>();
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
Map<BasicBlock, BasicBlock> blockMap = new HashMap<>(); Map<BasicBlock, BasicBlock> blockMap = new HashMap<>();
for (final Phi phi : program.basicBlockAt(i).getPhis()) { for (Phi phi : program.basicBlockAt(i).getPhis()) {
for (Incoming incoming : phi.getIncomings()) { for (Incoming incoming : phi.getIncomings()) {
PhiArgumentCopy copy = new PhiArgumentCopy(); insertCopy(incoming, blockMap);
copy.incoming = incoming; }
copy.original = incoming.getValue().getIndex(); }
AssignInstruction copyInstruction = new AssignInstruction(); for (Phi phi : program.basicBlockAt(i).getPhis()) {
copyInstruction.setReceiver(program.createVariable()); for (Incoming incoming : phi.getIncomings()) {
copyInstruction.setAssignee(incoming.getValue()); insertCopy(incoming, blockMap);
copy.var = copyInstruction.getReceiver().getIndex();
BasicBlock source = blockMap.get(incoming.getSource());
if (source == null) {
source = incoming.getSource();
} else {
incoming.setSource(source);
}
if (incoming.getSource().getLastInstruction() instanceof JumpInstruction) {
copy.index = incoming.getSource().getInstructions().size() - 1;
copy.block = incoming.getSource();
copy.block.getInstructions().add(copy.index, copyInstruction);
} else {
final BasicBlock copyBlock = program.createBasicBlock();
copyBlock.getInstructions().add(copyInstruction);
JumpInstruction jumpInstruction = new JumpInstruction();
jumpInstruction.setTarget(phi.getBasicBlock());
copyBlock.getInstructions().add(jumpInstruction);
incoming.getSource().getLastInstruction().acceptVisitor(new BasicBlockMapper() {
@Override protected BasicBlock map(BasicBlock block) {
if (block == phi.getBasicBlock()) {
return copyBlock;
} else {
return block;
}
}
});
blockMap.put(source, copyBlock);
incoming.setSource(copyBlock);
copy.index = 0;
copy.block = incoming.getSource();
}
incoming.setValue(copyInstruction.getReceiver());
copies.add(copy);
} }
} }
} }
return copies;
} }
private void removeRedundantCopies(Program program, List<PhiArgumentCopy> copies, private void insertCopy(Incoming incoming, Map<BasicBlock, BasicBlock> blockMap) {
List<MutableGraphNode> interferenceGraph, DisjointSet congruenceClasses) { final Phi phi = incoming.getPhi();
for (PhiArgumentCopy copy : copies) { Program program = phi.getBasicBlock().getProgram();
boolean interfere = false; AssignInstruction copyInstruction = new AssignInstruction();
int varClass = congruenceClasses.find(copy.var); Variable firstCopy = program.createVariable();
int origClass = congruenceClasses.find(copy.original); copyInstruction.setReceiver(firstCopy);
for (MutableGraphEdge edge : interferenceGraph.get(copy.original).getEdges()) { copyInstruction.setAssignee(incoming.getValue());
if (edge.getFirst() == edge.getSecond()) { BasicBlock source = blockMap.get(incoming.getSource());
continue; if (source == null) {
} source = incoming.getSource();
int neighbour = congruenceClasses.find(edge.getSecond().getTag()); } else {
if (neighbour == varClass || neighbour == origClass) { incoming.setSource(source);
interfere = true; }
break; if (!(incoming.getSource().getLastInstruction() instanceof JumpInstruction)) {
} final BasicBlock copyBlock = program.createBasicBlock();
} JumpInstruction jumpInstruction = new JumpInstruction();
if (!interfere) { jumpInstruction.setTarget(phi.getBasicBlock());
int newClass = congruenceClasses.union(varClass, origClass); copyBlock.getInstructions().add(jumpInstruction);
copy.block.getInstructions().set(copy.index, new EmptyInstruction()); incoming.getSource().getLastInstruction().acceptVisitor(new BasicBlockMapper() {
copy.incoming.setValue(program.variableAt(copy.original)); @Override protected BasicBlock map(BasicBlock block) {
for (MutableGraphEdge edge : interferenceGraph.get(varClass).getEdges() if (block == phi.getBasicBlock()) {
.toArray(new MutableGraphEdge[0])) { return copyBlock;
if (edge.getFirst() != null) { } else {
edge.setFirst(interferenceGraph.get(newClass)); return block;
} }
} }
for (MutableGraphEdge edge : interferenceGraph.get(origClass).getEdges() });
.toArray(new MutableGraphEdge[0])) { blockMap.put(source, copyBlock);
if (edge.getFirst() != null) { incoming.setSource(copyBlock);
edge.setFirst(interferenceGraph.get(newClass)); source = copyBlock;
}
source.getInstructions().add(source.getInstructions().size() - 1, copyInstruction);
incoming.setValue(copyInstruction.getReceiver());
}
private void removeRedundantCopies(Program program, List<MutableGraphNode> interferenceGraph,
DisjointSet congruenceClasses) {
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
for (int j = 0; j < block.getInstructions().size(); ++j) {
Instruction insn = block.getInstructions().get(j);
if (!(insn instanceof AssignInstruction)) {
continue;
}
AssignInstruction assignment = (AssignInstruction)insn;
boolean interfere = false;
int copyClass = congruenceClasses.find(assignment.getReceiver().getIndex());
int origClass = congruenceClasses.find(assignment.getAssignee().getIndex());
for (MutableGraphEdge edge : interferenceGraph.get(origClass).getEdges()) {
if (edge.getFirst() == edge.getSecond()) {
continue;
}
int neighbour = congruenceClasses.find(edge.getSecond().getTag());
if (neighbour == copyClass || neighbour == origClass) {
interfere = true;
break;
}
}
if (!interfere) {
int newClass = congruenceClasses.union(copyClass, origClass);
block.getInstructions().set(j, new EmptyInstruction());
MutableGraphNode newNode = interferenceGraph.get(origClass);
if (newClass == interferenceGraph.size()) {
newNode = new MutableGraphNode(interferenceGraph.size());
interferenceGraph.add(newNode);
}
for (MutableGraphEdge edge : interferenceGraph.get(origClass).getEdges()
.toArray(new MutableGraphEdge[0])) {
if (edge.getFirst() != null) {
edge.setFirst(interferenceGraph.get(newClass));
}
}
for (MutableGraphEdge edge : interferenceGraph.get(copyClass).getEdges()
.toArray(new MutableGraphEdge[0])) {
if (edge.getFirst() != null) {
edge.setFirst(interferenceGraph.get(newClass));
}
} }
} }
} }
} }
} }
private void renameVariables(final Program program, final int[] varMap) {
InstructionVariableMapper mapper = new InstructionVariableMapper() {
@Override protected Variable map(Variable var) {
return program.variableAt(varMap[var.getIndex()]);
}
};
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
for (Instruction insn : block.getInstructions()) {
insn.acceptVisitor(mapper);
}
for (Phi phi : block.getPhis()) {
phi.setReceiver(program.variableAt(varMap[phi.getReceiver().getIndex()]));
for (Incoming incoming : phi.getIncomings()) {
incoming.setValue(program.variableAt(varMap[incoming.getValue().getIndex()]));
}
}
}
}
private Graph renameInterferenceGraph(Graph graph, final int[] varMap) {
GraphBuilder renamedGraph = new GraphBuilder();
for (int i = 0; i < graph.size(); ++i) {
for (int j : graph.outgoingEdges(i)) {
renamedGraph.addEdge(varMap[i], varMap[j]);
}
}
return renamedGraph.build();
}
private DisjointSet buildPhiCongruenceClasses(Program program) { private DisjointSet buildPhiCongruenceClasses(Program program) {
DisjointSet classes = new DisjointSet(); DisjointSet classes = new DisjointSet();
for (int i = 0; i < program.variableCount(); ++i) { for (int i = 0; i < program.variableCount(); ++i) {

View File

@ -36,7 +36,8 @@ public class ClassSetOptimizer {
} }
private List<MethodOptimization> getOptimizations() { private List<MethodOptimization> getOptimizations() {
return Arrays.<MethodOptimization>asList(new UnusedVariableElimination()); return Arrays.<MethodOptimization>asList(new CommonSubexpressionElimination(),
new UnusedVariableElimination());
} }
public void optimizeAll(ListableClassHolderSource classSource) { public void optimizeAll(ListableClassHolderSource classSource) {