From b7917f25113e918170e487f8981745a4c7001f5e Mon Sep 17 00:00:00 2001 From: konsoletyper Date: Fri, 24 Jan 2014 17:26:03 +0400 Subject: [PATCH] Register allocator almost complete --- .../java/org/teavm/javascript/Decompiler.java | 6 +- .../teavm/javascript/JavascriptBuilder.java | 6 +- .../org/teavm/model/util/GraphColorer.java | 27 +++++- .../teavm/model/util/RegisterAllocator.java | 95 ++++++++++++++----- 4 files changed, 105 insertions(+), 29 deletions(-) diff --git a/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java b/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java index b443f1579..a3688c1cc 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java @@ -182,7 +182,11 @@ public class Decompiler { } if (node >= 0) { generator.currentBlock = program.basicBlockAt(node); - generator.nextBlock = next < indexer.size() ? program.basicBlockAt(indexer.nodeAt(next)) : null; + int tmp = indexer.nodeAt(next); + if (tmp == -1) { + System.out.println(); + } + generator.nextBlock = next < indexer.size() ? program.basicBlockAt(tmp) : null; generator.statements.clear(); for (Instruction insn : generator.currentBlock.getInstructions()) { insn.acceptVisitor(generator); diff --git a/teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilder.java b/teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilder.java index bddfd4caf..cda48cd99 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilder.java +++ b/teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilder.java @@ -163,12 +163,10 @@ public class JavascriptBuilder { writer.println(")"); if (method.getProgram() != null && method.getProgram().basicBlockCount() > 0) { ListingBuilder builder = new ListingBuilder(); + RegisterAllocator allocator = new RegisterAllocator(); + int[] colors = allocator.allocateRegisters(method); writer.print(builder.buildListing(method.getProgram(), " ")); writer.print(" Register allocation:"); - LivenessAnalyzer analyzer = new LivenessAnalyzer(); - analyzer.analyze(method.getProgram()); - RegisterAllocator allocator = new RegisterAllocator(); - int[] colors = allocator.allocateRegisters(method, analyzer); for (int i = 0; i < colors.length; ++i) { writer.print(i + ":" + colors[i] + " "); } diff --git a/teavm-core/src/main/java/org/teavm/model/util/GraphColorer.java b/teavm-core/src/main/java/org/teavm/model/util/GraphColorer.java index 2277129e9..bfe7c0351 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/GraphColorer.java +++ b/teavm-core/src/main/java/org/teavm/model/util/GraphColorer.java @@ -15,7 +15,9 @@ */ package org.teavm.model.util; +import java.util.ArrayList; import java.util.BitSet; +import java.util.List; import org.teavm.common.Graph; /** @@ -23,7 +25,25 @@ import org.teavm.common.Graph; * @author Alexey Andreev */ class GraphColorer { - public void colorize(Graph graph, int[] colors) { + public void colorize(Graph graph, int[] classes, int[] colors) { + List> classMembers = new ArrayList<>(); + for (int i = 0; i < classes.length; ++i) { + int cls = classes[i]; + while (cls >= classMembers.size()) { + classMembers.add(new ArrayList()); + } + classMembers.get(cls).add(i); + } + for (int i = 0; i < colors.length; ++i) { + int color = colors[i]; + if (color != -1) { + int cls = classes[i]; + for (int member : classMembers.get(cls)) { + colors[member] = color; + } + classMembers.get(cls).clear(); + } + } BitSet usedColors = new BitSet(); for (int v : getOrdering(graph)) { if (colors[v] >= 0) { @@ -36,7 +56,10 @@ class GraphColorer { usedColors.set(colors[succ]); } } - colors[v] = usedColors.nextClearBit(0); + int color = usedColors.nextClearBit(0); + for (int member : classMembers.get(classes[v])) { + colors[member] = color; + } } } diff --git a/teavm-core/src/main/java/org/teavm/model/util/RegisterAllocator.java b/teavm-core/src/main/java/org/teavm/model/util/RegisterAllocator.java index 1e4ce4cf5..aff46bcf1 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/RegisterAllocator.java +++ b/teavm-core/src/main/java/org/teavm/model/util/RegisterAllocator.java @@ -20,58 +20,109 @@ import java.util.Arrays; import java.util.List; import org.teavm.common.DisjointSet; import org.teavm.common.Graph; -import org.teavm.common.GraphBuilder; import org.teavm.model.*; +import org.teavm.model.instructions.AssignInstruction; +import org.teavm.model.instructions.EmptyInstruction; +import org.teavm.model.instructions.JumpInstruction; /** * * @author Alexey Andreev */ public class RegisterAllocator { - public int[] allocateRegisters(MethodHolder method, LivenessAnalyzer liveness) { + public int[] allocateRegisters(MethodHolder method) { + Program program = method.getProgram(); + List phiArgsCopies = insertPhiArgumentsCopies(program); InterferenceGraphBuilder interferenceBuilder = new InterferenceGraphBuilder(); - Graph interferenceGraph = interferenceBuilder.build(method.getProgram(), liveness); - int[] congruenceClasses = buildPhiCongruenceClasses(method.getProgram()); - int[] colors = new int[method.getProgram().variableCount() * 2]; + LivenessAnalyzer liveness = new LivenessAnalyzer(); + liveness.analyze(program); + Graph interferenceGraph = interferenceBuilder.build(program, liveness); + DisjointSet congruenceClasses = buildPhiCongruenceClasses(program); + removeRedundantCopies(program, phiArgsCopies, interferenceGraph, congruenceClasses); + int[] classArray = congruenceClasses.pack(program.variableCount()); + int[] colors = new int[program.variableCount()]; Arrays.fill(colors, -1); for (int i = 0; i < method.parameterCount(); ++i) { colors[i] = i; } - GraphBuilder graphBuilder = new GraphBuilder(); - Program program = method.getProgram(); - for (int v = 0; v < interferenceGraph.size(); ++v) { - for (int w : interferenceGraph.outgoingEdges(v)) { - if (w <= v) { - continue; - } - if (congruenceClasses[v] == congruenceClasses[w]) { - - } - } - } GraphColorer colorer = new GraphColorer(); - colorer.colorize(interferenceGraph, colors); + colorer.colorize(interferenceGraph, classArray, colors); return colors; } private static class PhiArgumentCopy { Incoming incoming; int original; + int index; + BasicBlock block; + int var; } private List insertPhiArgumentsCopies(Program program) { List copies = new ArrayList<>(); for (int i = 0; i < program.basicBlockCount(); ++i) { - for (Phi phi : program.basicBlockAt(i).getPhis()) { + for (final Phi phi : program.basicBlockAt(i).getPhis()) { for (Incoming incoming : phi.getIncomings()) { - + PhiArgumentCopy copy = new PhiArgumentCopy(); + copy.incoming = incoming; + copy.original = incoming.getValue().getIndex(); + AssignInstruction copyInstruction = new AssignInstruction(); + copyInstruction.setReceiver(program.createVariable()); + copyInstruction.setAssignee(incoming.getValue()); + copy.var = copyInstruction.getReceiver().getIndex(); + 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; + } + } + }); + incoming.setSource(copyBlock); + copy.index = 0; + copy.block = incoming.getSource(); + } + copies.add(copy); } } } return copies; } - private int[] buildPhiCongruenceClasses(Program program) { + private void removeRedundantCopies(Program program, List copies, Graph inteferenceGraph, + DisjointSet congruenceClasses) { + for (PhiArgumentCopy copy : copies) { + boolean interfere = false; + for (int neighbour : inteferenceGraph.outgoingEdges(copy.original)) { + if (neighbour == copy.var || neighbour == copy.original) { + continue; + } + if (congruenceClasses.find(neighbour) == congruenceClasses.find(copy.var) || + congruenceClasses.find(neighbour) == congruenceClasses.find(copy.original)) { + interfere = true; + break; + } + } + if (!interfere) { + congruenceClasses.union(copy.var, copy.original); + copy.block.getInstructions().set(copy.index, new EmptyInstruction()); + copy.incoming.setValue(program.variableAt(copy.original)); + } + } + } + + private DisjointSet buildPhiCongruenceClasses(Program program) { DisjointSet classes = new DisjointSet(); for (int i = 0; i < program.variableCount(); ++i) { classes.create(); @@ -84,6 +135,6 @@ public class RegisterAllocator { } } } - return classes.pack(program.variableCount()); + return classes; } }