mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
Avoids swap problem when eliminating phi functions and therefore gets
back global value numbering optimization
This commit is contained in:
parent
7831ade3a6
commit
5c03e7547f
|
@ -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]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
colors[v] = usedColors.nextClearBit(0);
|
||||||
int color = usedColors.nextClearBit(0);
|
|
||||||
for (int member : classMembers.get(cls)) {
|
|
||||||
colors[member] = color;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,32 +71,37 @@ 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();
|
}
|
||||||
|
for (Phi phi : program.basicBlockAt(i).getPhis()) {
|
||||||
|
for (Incoming incoming : phi.getIncomings()) {
|
||||||
|
insertCopy(incoming, blockMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void insertCopy(Incoming incoming, Map<BasicBlock, BasicBlock> blockMap) {
|
||||||
|
final Phi phi = incoming.getPhi();
|
||||||
|
Program program = phi.getBasicBlock().getProgram();
|
||||||
AssignInstruction copyInstruction = new AssignInstruction();
|
AssignInstruction copyInstruction = new AssignInstruction();
|
||||||
copyInstruction.setReceiver(program.createVariable());
|
Variable firstCopy = program.createVariable();
|
||||||
|
copyInstruction.setReceiver(firstCopy);
|
||||||
copyInstruction.setAssignee(incoming.getValue());
|
copyInstruction.setAssignee(incoming.getValue());
|
||||||
copy.var = copyInstruction.getReceiver().getIndex();
|
|
||||||
BasicBlock source = blockMap.get(incoming.getSource());
|
BasicBlock source = blockMap.get(incoming.getSource());
|
||||||
if (source == null) {
|
if (source == null) {
|
||||||
source = incoming.getSource();
|
source = incoming.getSource();
|
||||||
} else {
|
} else {
|
||||||
incoming.setSource(source);
|
incoming.setSource(source);
|
||||||
}
|
}
|
||||||
if (incoming.getSource().getLastInstruction() instanceof JumpInstruction) {
|
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();
|
final BasicBlock copyBlock = program.createBasicBlock();
|
||||||
copyBlock.getInstructions().add(copyInstruction);
|
|
||||||
JumpInstruction jumpInstruction = new JumpInstruction();
|
JumpInstruction jumpInstruction = new JumpInstruction();
|
||||||
jumpInstruction.setTarget(phi.getBasicBlock());
|
jumpInstruction.setTarget(phi.getBasicBlock());
|
||||||
copyBlock.getInstructions().add(jumpInstruction);
|
copyBlock.getInstructions().add(jumpInstruction);
|
||||||
|
@ -117,42 +116,42 @@ public class RegisterAllocator {
|
||||||
});
|
});
|
||||||
blockMap.put(source, copyBlock);
|
blockMap.put(source, copyBlock);
|
||||||
incoming.setSource(copyBlock);
|
incoming.setSource(copyBlock);
|
||||||
copy.index = 0;
|
source = copyBlock;
|
||||||
copy.block = incoming.getSource();
|
|
||||||
}
|
}
|
||||||
|
source.getInstructions().add(source.getInstructions().size() - 1, copyInstruction);
|
||||||
incoming.setValue(copyInstruction.getReceiver());
|
incoming.setValue(copyInstruction.getReceiver());
|
||||||
copies.add(copy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return copies;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeRedundantCopies(Program program, List<PhiArgumentCopy> copies,
|
private void removeRedundantCopies(Program program, List<MutableGraphNode> interferenceGraph,
|
||||||
List<MutableGraphNode> interferenceGraph, DisjointSet congruenceClasses) {
|
DisjointSet congruenceClasses) {
|
||||||
for (PhiArgumentCopy copy : copies) {
|
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;
|
boolean interfere = false;
|
||||||
int varClass = congruenceClasses.find(copy.var);
|
int copyClass = congruenceClasses.find(assignment.getReceiver().getIndex());
|
||||||
int origClass = congruenceClasses.find(copy.original);
|
int origClass = congruenceClasses.find(assignment.getAssignee().getIndex());
|
||||||
for (MutableGraphEdge edge : interferenceGraph.get(copy.original).getEdges()) {
|
for (MutableGraphEdge edge : interferenceGraph.get(origClass).getEdges()) {
|
||||||
if (edge.getFirst() == edge.getSecond()) {
|
if (edge.getFirst() == edge.getSecond()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
int neighbour = congruenceClasses.find(edge.getSecond().getTag());
|
int neighbour = congruenceClasses.find(edge.getSecond().getTag());
|
||||||
if (neighbour == varClass || neighbour == origClass) {
|
if (neighbour == copyClass || neighbour == origClass) {
|
||||||
interfere = true;
|
interfere = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!interfere) {
|
if (!interfere) {
|
||||||
int newClass = congruenceClasses.union(varClass, origClass);
|
int newClass = congruenceClasses.union(copyClass, origClass);
|
||||||
copy.block.getInstructions().set(copy.index, new EmptyInstruction());
|
block.getInstructions().set(j, new EmptyInstruction());
|
||||||
copy.incoming.setValue(program.variableAt(copy.original));
|
MutableGraphNode newNode = interferenceGraph.get(origClass);
|
||||||
for (MutableGraphEdge edge : interferenceGraph.get(varClass).getEdges()
|
if (newClass == interferenceGraph.size()) {
|
||||||
.toArray(new MutableGraphEdge[0])) {
|
newNode = new MutableGraphNode(interferenceGraph.size());
|
||||||
if (edge.getFirst() != null) {
|
interferenceGraph.add(newNode);
|
||||||
edge.setFirst(interferenceGraph.get(newClass));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for (MutableGraphEdge edge : interferenceGraph.get(origClass).getEdges()
|
for (MutableGraphEdge edge : interferenceGraph.get(origClass).getEdges()
|
||||||
.toArray(new MutableGraphEdge[0])) {
|
.toArray(new MutableGraphEdge[0])) {
|
||||||
|
@ -160,9 +159,46 @@ public class RegisterAllocator {
|
||||||
edge.setFirst(interferenceGraph.get(newClass));
|
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();
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user