From b96c5038ce830acf9e4e2d92af2379c3cc4634d8 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Thu, 27 Mar 2014 20:09:05 +0400 Subject: [PATCH] Adds loop invariant code motion optimization --- .../java/org/teavm/javascript/Decompiler.java | 3 - .../teavm/optimization/ClassSetOptimizer.java | 3 +- .../optimization/LoopInvariantMotion.java | 319 ++++++++++++++++++ 3 files changed, 321 insertions(+), 4 deletions(-) create mode 100644 teavm-core/src/main/java/org/teavm/optimization/LoopInvariantMotion.java 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 a23806533..6630b8362 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java @@ -213,9 +213,6 @@ public class Decompiler { if (node >= 0) { generator.currentBlock = program.basicBlockAt(node); int tmp = indexer.nodeAt(next); - if (tmp < 0) { - throw new IllegalArgumentException(); - } generator.nextBlock = next < indexer.size() ? program.basicBlockAt(tmp) : null; generator.statements.clear(); for (Instruction insn : generator.currentBlock.getInstructions()) { diff --git a/teavm-core/src/main/java/org/teavm/optimization/ClassSetOptimizer.java b/teavm-core/src/main/java/org/teavm/optimization/ClassSetOptimizer.java index 1faca0b76..5ff73991c 100644 --- a/teavm-core/src/main/java/org/teavm/optimization/ClassSetOptimizer.java +++ b/teavm-core/src/main/java/org/teavm/optimization/ClassSetOptimizer.java @@ -36,7 +36,8 @@ public class ClassSetOptimizer { } private List getOptimizations() { - return Arrays.asList(new GlobalValueNumbering(), new UnusedVariableElimination()); + return Arrays.asList(new LoopInvariantMotion(), new GlobalValueNumbering(), + new UnusedVariableElimination()); } public void optimizeAll(ListableClassHolderSource classSource) { diff --git a/teavm-core/src/main/java/org/teavm/optimization/LoopInvariantMotion.java b/teavm-core/src/main/java/org/teavm/optimization/LoopInvariantMotion.java new file mode 100644 index 000000000..535ef6ada --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/optimization/LoopInvariantMotion.java @@ -0,0 +1,319 @@ +/* + * Copyright 2014 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.teavm.optimization; + +import java.util.Arrays; +import java.util.List; +import org.teavm.common.*; +import org.teavm.model.*; +import org.teavm.model.instructions.*; +import org.teavm.model.util.DefinitionExtractor; +import org.teavm.model.util.ProgramUtils; +import org.teavm.model.util.UsageExtractor; + +/** + * + * @author Alexey Andreev + */ +public class LoopInvariantMotion implements MethodOptimization { + private int[] preheaders; + private LoopGraph graph; + private DominatorTree dom; + private Program program; + + @Override + public void optimize(MethodReader method, Program program) { + this.program = program; + graph = new LoopGraph(ProgramUtils.buildControlFlowGraph(program)); + dom = GraphUtils.buildDominatorTree(graph); + Graph domGraph = GraphUtils.buildDominatorGraph(dom, graph.size()); + preheaders = new int[graph.size()]; + Arrays.fill(preheaders, -1); + IntegerStack stack = new IntegerStack(graph.size()); + int[] defLocation = new int[program.variableCount()]; + Arrays.fill(defLocation, -1); + for (int i = 0; i < domGraph.size(); ++i) { + if (dom.immediateDominatorOf(i) < 0) { + stack.push(i); + } + } + + DefinitionExtractor defExtractor = new DefinitionExtractor(); + UsageExtractor useExtractor = new UsageExtractor(); + InstructionAnalyzer analyzer = new InstructionAnalyzer(); + while (!stack.isEmpty()) { + int v = stack.pop(); + BasicBlock block = program.basicBlockAt(v); + insnLoop: for (int i = 0; i < block.getInstructions().size(); ++i) { + Instruction insn = block.getInstructions().get(i); + insn.acceptVisitor(defExtractor); + Variable[] defs = defExtractor.getDefinedVariables(); + for (Variable def : defs) { + defLocation[def.getIndex()] = v; + } + analyzer.canMove = false; + insn.acceptVisitor(analyzer); + if (!analyzer.canMove) { + continue; + } + Loop defLoop = graph.loopAt(v); + if (defLoop == null) { + continue; + } + insn.acceptVisitor(useExtractor); + Loop commonUseLoop = null; + for (Variable use : useExtractor.getUsedVariables()) { + int useLoc = defLocation[use.getIndex()]; + if (useLoc == -1) { + continue insnLoop; + } + Loop useLoop = graph.loopAt(useLoc); + if (useLoop == defLoop) { + continue insnLoop; + } + if (useLoop != null && useLoop.isChildOf(commonUseLoop)) { + commonUseLoop = useLoop; + } + } + block.getInstructions().set(i, new EmptyInstruction()); + while (defLoop.getParent() != commonUseLoop) { + defLoop = defLoop.getParent(); + } + int preheader = getPreheader(defLoop.getHead()); + List preheaderInstructions = program.basicBlockAt(preheader).getInstructions(); + preheaderInstructions.add(preheaderInstructions.size() - 1, insn); + defLocation[defs[0].getIndex()] = commonUseLoop != null ? commonUseLoop.getHead() : 0; + } + for (int succ : domGraph.outgoingEdges(v)) { + stack.push(succ); + } + } + } + + private int getPreheader(int header) { + int preheader = preheaders[header]; + if (preheader < 0) { + int[] entries = getLoopEntries(header); + if (entries.length == 1) { + preheader = graph.incomingEdges(header)[0]; + } else { + preheader = insertPreheader(header); + } + preheaders[header] = preheader; + } + return preheader; + } + + private int[] getLoopEntries(int header) { + int[] predecessors = graph.incomingEdges(header); + int j = 0; + for (int i = 0; i < predecessors.length; ++i) { + int pred = predecessors[i]; + if (!dom.dominates(header, pred)) { + predecessors[j++] = pred; + } + } + return Arrays.copyOf(predecessors, j); + } + + private int insertPreheader(int headerIndex) { + BasicBlock preheader = program.createBasicBlock(); + JumpInstruction escapeInsn = new JumpInstruction(); + BasicBlock header = program.basicBlockAt(headerIndex); + escapeInsn.setTarget(header); + preheader.getInstructions().add(escapeInsn); + for (int i = 0; i < header.getPhis().size(); ++i) { + Phi phi = header.getPhis().get(i); + Phi preheaderPhi = null; + for (int j = 0; j < phi.getIncomings().size(); ++j) { + Incoming incoming = phi.getIncomings().get(j); + if (!dom.dominates(headerIndex, incoming.getSource().getIndex())) { + phi.getIncomings().remove(j--); + if (preheaderPhi == null) { + preheaderPhi = new Phi(); + preheaderPhi.setReceiver(program.createVariable()); + preheader.getPhis().add(preheaderPhi); + } + preheaderPhi.getIncomings().add(incoming); + } + } + if (preheaderPhi != null) { + Incoming incoming = new Incoming(); + incoming.setSource(preheader); + incoming.setValue(phi.getReceiver()); + phi.getIncomings().add(incoming); + } + } + return preheader.getIndex(); + } + + private static class InstructionAnalyzer implements InstructionVisitor { + public boolean canMove; + + @Override + public void visit(EmptyInstruction insn) { + } + + @Override + public void visit(ClassConstantInstruction insn) { + canMove = true; + } + + @Override + public void visit(NullConstantInstruction insn) { + canMove = true; + } + + @Override + public void visit(IntegerConstantInstruction insn) { + canMove = true; + } + + @Override + public void visit(LongConstantInstruction insn) { + canMove = true; + } + + @Override + public void visit(FloatConstantInstruction insn) { + canMove = true; + } + + @Override + public void visit(DoubleConstantInstruction insn) { + canMove = true; + } + + @Override + public void visit(StringConstantInstruction insn) { + canMove = true; + } + + @Override + public void visit(BinaryInstruction insn) { + canMove = true; + } + + @Override + public void visit(NegateInstruction insn) { + canMove = true; + } + + @Override + public void visit(AssignInstruction insn) { + canMove = true; + } + + @Override + public void visit(CastInstruction insn) { + canMove = true; + } + + @Override + public void visit(CastNumberInstruction insn) { + canMove = true; + } + + @Override + public void visit(CastIntegerInstruction insn) { + canMove = true; + } + + @Override + public void visit(BranchingInstruction insn) { + } + + @Override + public void visit(BinaryBranchingInstruction insn) { + } + + @Override + public void visit(JumpInstruction insn) { + } + + @Override + public void visit(SwitchInstruction insn) { + } + + @Override + public void visit(ExitInstruction insn) { + } + + @Override + public void visit(RaiseInstruction insn) { + } + + @Override + public void visit(ConstructArrayInstruction insn) { + } + + @Override + public void visit(ConstructInstruction insn) { + } + + @Override + public void visit(ConstructMultiArrayInstruction insn) { + } + + @Override + public void visit(GetFieldInstruction insn) { + } + + @Override + public void visit(PutFieldInstruction insn) { + } + + @Override + public void visit(ArrayLengthInstruction insn) { + canMove = true; + } + + @Override + public void visit(CloneArrayInstruction insn) { + } + + @Override + public void visit(UnwrapArrayInstruction insn) { + canMove = true; + } + + @Override + public void visit(GetElementInstruction insn) { + } + + @Override + public void visit(PutElementInstruction insn) { + } + + @Override + public void visit(InvokeInstruction insn) { + } + + @Override + public void visit(IsInstanceInstruction insn) { + canMove = true; + } + + @Override + public void visit(InitClassInstruction insn) { + } + + @Override + public void visit(NullCheckInstruction insn) { + canMove = true; + } + } +}