Implementing loop inversion

This commit is contained in:
Alexey Andreev 2016-05-09 18:13:00 +03:00
parent a57be365b4
commit 3c93b78902
8 changed files with 229 additions and 151 deletions

View File

@ -240,8 +240,7 @@ public final class GraphUtils {
int[] set = new int[items.length]; int[] set = new int[items.length];
int sz = 0; int sz = 0;
int last = -1; int last = -1;
for (int i = 0; i < items.length; ++i) { for (int item : items) {
int item = items[i];
if (item != last) { if (item != last) {
set[sz++] = item; set[sz++] = item;
last = item; last = item;
@ -252,14 +251,4 @@ public final class GraphUtils {
} }
return set; return set;
} }
public static Graph invert(Graph graph) {
GraphBuilder graphBuilder = new GraphBuilder(graph.size());
for (int node = 0; node < graph.size(); ++node) {
for (int pred : graph.incomingEdges(node)) {
graphBuilder.addEdge(node, pred);
}
}
return graphBuilder.build();
}
} }

View File

@ -22,14 +22,14 @@ import java.util.*;
* @author Alexey Andreev * @author Alexey Andreev
*/ */
public class MutableGraphNode { public class MutableGraphNode {
int tag; private int tag;
Map<MutableGraphNode, MutableGraphEdge> edges = new HashMap<>(); final Map<MutableGraphNode, MutableGraphEdge> edges = new LinkedHashMap<>();
public MutableGraphNode(int tag) { public MutableGraphNode(int tag) {
this.tag = tag; this.tag = tag;
} }
public MutableGraphEdge connect(MutableGraphNode other) { private MutableGraphEdge connect(MutableGraphNode other) {
MutableGraphEdge edge = edges.get(other); MutableGraphEdge edge = edges.get(other);
if (edge == null) { if (edge == null) {
edge = new MutableGraphEdge(); edge = new MutableGraphEdge();

View File

@ -15,16 +15,43 @@
*/ */
package org.teavm.model.util; package org.teavm.model.util;
import java.util.function.Function;
import org.teavm.model.BasicBlock;
import org.teavm.model.Incoming;
import org.teavm.model.Instruction;
import org.teavm.model.InvokeDynamicInstruction; import org.teavm.model.InvokeDynamicInstruction;
import org.teavm.model.Phi;
import org.teavm.model.TryCatchBlock;
import org.teavm.model.Variable; import org.teavm.model.Variable;
import org.teavm.model.instructions.*; import org.teavm.model.instructions.*;
/** public class InstructionVariableMapper implements InstructionVisitor {
* private final Function<Variable, Variable> f;
* @author Alexey Andreev
*/ public InstructionVariableMapper(Function<Variable, Variable> f) {
public abstract class InstructionVariableMapper implements InstructionVisitor { this.f = f;
protected abstract Variable map(Variable var); }
public void apply(BasicBlock block) {
for (Instruction insn : block.getInstructions()) {
insn.acceptVisitor(this);
}
for (Phi phi : block.getPhis()) {
phi.setReceiver(map(phi.getReceiver()));
for (Incoming incoming : phi.getIncomings()) {
incoming.setValue(map(incoming.getValue()));
}
}
for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) {
if (tryCatch.getExceptionVariable() != null) {
tryCatch.setExceptionVariable(map(tryCatch.getExceptionVariable()));
}
}
}
private Variable map(Variable var) {
return f.apply(var);
}
@Override @Override
public void visit(EmptyInstruction insn) { public void visit(EmptyInstruction insn) {
@ -252,8 +279,4 @@ public abstract class InstructionVariableMapper implements InstructionVisitor {
public void visit(MonitorExitInstruction insn) { public void visit(MonitorExitInstruction insn) {
insn.setObjectRef(map(insn.getObjectRef())); insn.setObjectRef(map(insn.getObjectRef()));
} }
} }

View File

@ -218,26 +218,11 @@ public class RegisterAllocator {
} }
private void renameVariables(final Program program, final int[] varMap) { private void renameVariables(final Program program, final int[] varMap) {
InstructionVariableMapper mapper = new InstructionVariableMapper() { InstructionVariableMapper mapper = new InstructionVariableMapper(var ->
@Override protected Variable map(Variable var) { program.variableAt(varMap[var.getIndex()]));
return program.variableAt(varMap[var.getIndex()]);
}
};
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i); BasicBlock block = program.basicBlockAt(i);
for (Instruction insn : block.getInstructions()) { mapper.apply(block);
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()]));
}
}
for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) {
tryCatch.setExceptionVariable(program.variableAt(
varMap[tryCatch.getExceptionVariable().getIndex()]));
}
} }
String[][] originalNames = new String[program.variableCount()][]; String[][] originalNames = new String[program.variableCount()][];
for (int i = 0; i < program.variableCount(); ++i) { for (int i = 0; i < program.variableCount(); ++i) {

View File

@ -29,7 +29,6 @@ import org.teavm.model.util.*;
*/ */
public class LoopInvariantMotion implements MethodOptimization { public class LoopInvariantMotion implements MethodOptimization {
private int[] preheaders; private int[] preheaders;
private Instruction[] constantInstructions;
private LoopGraph graph; private LoopGraph graph;
private DominatorTree dom; private DominatorTree dom;
private Program program; private Program program;
@ -45,7 +44,7 @@ public class LoopInvariantMotion implements MethodOptimization {
IntegerStack stack = new IntegerStack(graph.size()); IntegerStack stack = new IntegerStack(graph.size());
int[] defLocation = new int[program.variableCount()]; int[] defLocation = new int[program.variableCount()];
Arrays.fill(defLocation, -1); Arrays.fill(defLocation, -1);
constantInstructions = new Instruction[program.variableCount()]; Instruction[] constantInstructions = new Instruction[program.variableCount()];
for (int i = 0; i <= method.parameterCount(); ++i) { for (int i = 0; i <= method.parameterCount(); ++i) {
defLocation[i] = 0; defLocation[i] = 0;
} }
@ -126,7 +125,8 @@ public class LoopInvariantMotion implements MethodOptimization {
} }
} }
if (variableMap != null) { if (variableMap != null) {
insn.acceptVisitor(new VariableMapperImpl(variableMap)); Variable[] currentVariableMap = variableMap;
insn.acceptVisitor(new InstructionVariableMapper(var -> currentVariableMap[var.getIndex()]));
} }
newInstructions.add(insn); newInstructions.add(insn);
preheaderInstructions.addAll(preheaderInstructions.size() - 1, newInstructions); preheaderInstructions.addAll(preheaderInstructions.size() - 1, newInstructions);
@ -208,21 +208,8 @@ public class LoopInvariantMotion implements MethodOptimization {
return preheader.getIndex(); return preheader.getIndex();
} }
private static class VariableMapperImpl extends InstructionVariableMapper {
private Variable[] map;
public VariableMapperImpl(Variable[] map) {
this.map = map;
}
@Override
protected Variable map(Variable var) {
return map[var.getIndex()];
}
}
private static class InstructionAnalyzer implements InstructionVisitor { private static class InstructionAnalyzer implements InstructionVisitor {
public boolean canMove; boolean canMove;
public boolean constant; public boolean constant;
@Override @Override

View File

@ -67,14 +67,18 @@ import org.teavm.model.util.ProgramUtils;
* ``` * ```
* *
* where `condition` is a part of loop that has exits and `body` has no exits. * where `condition` is a part of loop that has exits and `body` has no exits.
* More formally, we define *condition end* as a node that postdominates all loop exits. * More formally, we define *body start candidate* as a node which 1) dominates all of the "tails" (i.e. nodes
* Therefore, *condition* is a set of nodes of the loop that are postdominated by condition end and * that have edges to loop header), 2) does not dominate loop exits. *Body start* is a body start candidate
* all remaining nodes are *body*. * that is not dominates by some other body start candidate. If body start does not exits, loop is
* not inversible.
*
* Therefore, *body* is a set of nodes of the loop that are dominated by body start and
* all remaining nodes are *condition*.
*/ */
class LoopInversionImpl { class LoopInversionImpl {
private Program program; private final Program program;
private Graph cfg; private Graph cfg;
private DominatorTree pdom; private DominatorTree dom;
private boolean postponed; private boolean postponed;
LoopInversionImpl(Program program) { LoopInversionImpl(Program program) {
@ -85,7 +89,7 @@ class LoopInversionImpl {
do { do {
cfg = ProgramUtils.buildControlFlowGraph(program); cfg = ProgramUtils.buildControlFlowGraph(program);
LoopGraph loopGraph = new LoopGraph(cfg); LoopGraph loopGraph = new LoopGraph(cfg);
pdom = GraphUtils.buildDominatorTree(GraphUtils.invert(cfg)); dom = GraphUtils.buildDominatorTree(cfg);
List<LoopWithExits> loops = getLoopsWithExits(loopGraph); List<LoopWithExits> loops = getLoopsWithExits(loopGraph);
postponed = false; postponed = false;
@ -147,11 +151,12 @@ class LoopInversionImpl {
final IntSet nodes = new IntOpenHashSet(); final IntSet nodes = new IntOpenHashSet();
final IntSet nodesAndCopies = new IntOpenHashSet(); final IntSet nodesAndCopies = new IntOpenHashSet();
final IntSet exits = new IntOpenHashSet(); final IntSet exits = new IntOpenHashSet();
int conditionEnd; int bodyStart;
int copyStart; int copyStart;
int headCopy; int headCopy;
final IntIntMap copiedVars = new IntIntOpenHashMap(); final IntIntMap copiedVars = new IntIntOpenHashMap();
final IntIntMap copiedNodes = new IntIntOpenHashMap(); final IntIntMap copiedNodes = new IntIntOpenHashMap();
final IntIntMap varDefinitionPoints = new IntIntOpenHashMap();
boolean shouldSkip; boolean shouldSkip;
LoopWithExits(int head, LoopWithExits parent) { LoopWithExits(int head, LoopWithExits parent) {
@ -175,8 +180,7 @@ class LoopInversionImpl {
return false; return false;
} }
findCondition(); if (!findCondition() || bodyStart < 0) {
if (conditionEnd < 0 || !canInvert()) {
return false; return false;
} }
@ -187,37 +191,31 @@ class LoopInversionImpl {
removeInternalPhiInputsFromCondition(); removeInternalPhiInputsFromCondition();
removeExternalPhiInputsFromConditionCopy(); removeExternalPhiInputsFromConditionCopy();
putNewPhis(); putNewPhis();
adjustOutputPhis();
return true; return true;
} }
private void findCondition() { private boolean findCondition() {
IntSet endNodes = new IntOpenHashSet(program.basicBlockCount()); IntSet tailNodes = new IntOpenHashSet(program.basicBlockCount());
for (int exit : exits.toArray()) { for (int tailCandidate : cfg.incomingEdges(head)) {
for (int successor : cfg.outgoingEdges(exit)) { if (nodes.contains(tailCandidate)) {
if (nodes.contains(successor) && successor != head) { tailNodes.add(tailCandidate);
endNodes.add(successor);
} }
} }
}
conditionEnd = pdom.commonDominatorOf(endNodes.toArray());
}
/** bodyStart = dom.commonDominatorOf(tailNodes.toArray());
* We can't invert loop if condition has back edges. Indeed, back edges from `if` statement int candidate = bodyStart;
* must point inside loop, which makes CFG irreducible. while (bodyStart != head) {
*/ int currentCandidate = candidate;
private boolean canInvert() { if (Arrays.stream(exits.toArray()).anyMatch(exit -> dom.dominates(currentCandidate, exit))) {
for (int node : nodes.toArray()) { break;
if (pdom.dominates(conditionEnd, node)) {
for (int successor : cfg.outgoingEdges(node)) {
if (successor == head) {
return false;
} }
bodyStart = candidate;
candidate = dom.immediateDominatorOf(candidate);
} }
}
} return candidate != bodyStart;
return true;
} }
private void collectNodesToCopy() { private void collectNodesToCopy() {
@ -225,7 +223,7 @@ class LoopInversionImpl {
Arrays.sort(nodes); Arrays.sort(nodes);
for (int node : nodes) { for (int node : nodes) {
nodesAndCopies.add(node); nodesAndCopies.add(node);
if (pdom.dominates(conditionEnd, node)) { if (node == head || (node != bodyStart && !dom.dominates(bodyStart, node))) {
int copy = program.createBasicBlock().getIndex(); int copy = program.createBasicBlock().getIndex();
if (head == node) { if (head == node) {
headCopy = copy; headCopy = copy;
@ -245,10 +243,12 @@ class LoopInversionImpl {
insn.acceptVisitor(definitionExtractor); insn.acceptVisitor(definitionExtractor);
for (Variable var : definitionExtractor.getDefinedVariables()) { for (Variable var : definitionExtractor.getDefinedVariables()) {
varsToCopy.add(var.getIndex()); varsToCopy.add(var.getIndex());
varDefinitionPoints.put(var.getIndex(), node);
} }
} }
for (Phi phi : block.getPhis()) { for (Phi phi : block.getPhis()) {
varsToCopy.add(phi.getReceiver().getIndex()); varsToCopy.add(phi.getReceiver().getIndex());
varDefinitionPoints.put(phi.getReceiver().getIndex(), node);
} }
} }
@ -260,12 +260,8 @@ class LoopInversionImpl {
} }
private void copyCondition() { private void copyCondition() {
InstructionVariableMapper variableMapper = new InstructionVariableMapper() { InstructionVariableMapper variableMapper = new InstructionVariableMapper(var ->
@Override program.variableAt(copiedVars.getOrDefault(var.getIndex(), var.getIndex())));
protected Variable map(Variable var) {
return program.variableAt(copiedVars.getOrDefault(var.getIndex(), var.getIndex()));
}
};
BasicBlockMapper blockMapper = new BasicBlockMapper() { BasicBlockMapper blockMapper = new BasicBlockMapper() {
@Override @Override
protected BasicBlock map(BasicBlock block) { protected BasicBlock map(BasicBlock block) {
@ -298,7 +294,7 @@ class LoopInversionImpl {
incomingCopy.setValue(program.variableAt(copiedVars.getOrDefault(value, value))); incomingCopy.setValue(program.variableAt(copiedVars.getOrDefault(value, value)));
phiCopy.getIncomings().add(incomingCopy); phiCopy.getIncomings().add(incomingCopy);
} }
targetBlock.getPhis().add(phi); targetBlock.getPhis().add(phiCopy);
} }
for (TryCatchBlock tryCatch : sourceBlock.getTryCatchBlocks()) { for (TryCatchBlock tryCatch : sourceBlock.getTryCatchBlocks()) {
@ -358,54 +354,136 @@ class LoopInversionImpl {
BasicBlock block = program.basicBlockAt(headCopy); BasicBlock block = program.basicBlockAt(headCopy);
for (Phi phi : block.getPhis()) { for (Phi phi : block.getPhis()) {
List<Incoming> incomings = phi.getIncomings(); List<Incoming> incomings = phi.getIncomings();
for (int i = 0; i < incomings.size(); ++i) { List<Incoming> newIncomings = new ArrayList<>(incomings.size());
Incoming incoming = incomings.get(i); for (Incoming incoming : incomings) {
if (!nodesAndCopies.contains(incoming.getSource().getIndex())) { if (nodesAndCopies.contains(incoming.getSource().getIndex())) {
incomings.remove(i--); newIncomings.add(incoming);
} else {
for (int exit : exits.toArray()) {
Incoming newIncoming = new Incoming();
newIncoming.setValue(incoming.getValue());
newIncoming.setSource(program.basicBlockAt(exit));
newIncomings.add(newIncoming);
} }
} }
} }
incomings.clear();
incomings.addAll(newIncomings);
}
} }
/** /**
* Variables defined in condition should be converted to phis in a new loop head (i.e. condition end). * Variables defined in condition should be converted to phis in a new loop head (i.e. body start).
* Every reference to variable from old condition must be replaced by reference to corresponding phi. * Every reference to variable from old condition must be replaced by reference to corresponding phi.
*/ */
private void putNewPhis() { private void putNewPhis() {
BasicBlock head = program.basicBlockAt(conditionEnd); BasicBlock head = program.basicBlockAt(bodyStart);
IntIntMap phiMap = new IntIntOpenHashMap(); IntIntMap phiMap = new IntIntOpenHashMap();
int[] vars = copiedVars.keys().toArray(); int[] vars = copiedVars.keys().toArray();
Arrays.sort(vars); Arrays.sort(vars);
List<Phi> phisToAdd = new ArrayList<>();
for (int var : vars) { for (int var : vars) {
int varCopy = copiedVars.get(var);
Phi phi = new Phi(); Phi phi = new Phi();
phi.setReceiver(program.createVariable()); phi.setReceiver(program.createVariable());
phiMap.put(var, phi.getReceiver().getIndex()); phiMap.put(var, phi.getReceiver().getIndex());
head.getPhis().add(phi); phisToAdd.add(phi);
for (int source : cfg.incomingEdges(bodyStart)) {
if (!nodes.contains(source)) {
continue;
}
for (int source : cfg.incomingEdges(conditionEnd)) {
int inputVar = copiedNodes.containsKey(source) ? var : copiedVars.get(var);
Incoming incoming = new Incoming(); Incoming incoming = new Incoming();
incoming.setValue(program.variableAt(inputVar)); incoming.setValue(program.variableAt(var));
incoming.setSource(program.basicBlockAt(source)); incoming.setSource(program.basicBlockAt(source));
phi.getIncomings().add(incoming); phi.getIncomings().add(incoming);
incoming = new Incoming();
incoming.setValue(program.variableAt(varCopy));
incoming.setSource(program.basicBlockAt(copiedNodes.get(source)));
phi.getIncomings().add(incoming);
} }
} }
InstructionVariableMapper mapper = new InstructionVariableMapper() { InstructionVariableMapper mapper = new InstructionVariableMapper(var -> {
@Override
protected Variable map(Variable var) {
int index = var.getIndex(); int index = var.getIndex();
return program.variableAt(phiMap.getOrDefault(index, index)); return program.variableAt(phiMap.getOrDefault(index, index));
} });
};
for (int node : nodes.toArray()) { for (int node : nodes.toArray()) {
if (copiedNodes.containsKey(node)) { if (!copiedNodes.containsKey(node)) {
BasicBlock block = program.basicBlockAt(node); BasicBlock block = program.basicBlockAt(node);
for (Instruction instruction : block.getInstructions()) { mapper.apply(block);
instruction.acceptVisitor(mapper); }
} }
}
head.getPhis().addAll(phisToAdd);
}
private void adjustOutputPhis() {
IntIntMap phiMap = new IntIntOpenHashMap();
class PhiToAdd {
private final Phi phi;
private final BasicBlock target;
private PhiToAdd(Phi phi, BasicBlock target) {
this.phi = phi;
this.target = target;
}
}
List<PhiToAdd> phis = new ArrayList<>();
int[] vars = copiedVars.keys().toArray();
Arrays.sort(vars);
int[] exits = this.exits.toArray();
Arrays.sort(exits);
for (int exit : exits) {
for (int var : vars) {
int definedAt = varDefinitionPoints.get(var);
if (!dom.dominates(definedAt, exit)) {
continue;
}
int varCopy = copiedVars.get(var);
int copiedAt = copiedNodes.get(definedAt);
for (int successor : cfg.outgoingEdges(exit)) {
if (nodes.contains(successor)) {
continue;
}
Phi phi = new Phi();
phi.setReceiver(program.createVariable());
Incoming originalInput = new Incoming();
originalInput.setSource(program.basicBlockAt(definedAt));
originalInput.setValue(program.variableAt(var));
phi.getIncomings().add(originalInput);
Incoming copyInput = new Incoming();
copyInput.setSource(program.basicBlockAt(copiedAt));
copyInput.setValue(program.variableAt(varCopy));
phi.getIncomings().add(copyInput);
phis.add(new PhiToAdd(phi, program.basicBlockAt(successor)));
phiMap.put(var, phi.getReceiver().getIndex());
}
}
}
InstructionVariableMapper mapper = new InstructionVariableMapper(var -> {
int index = var.getIndex();
return program.variableAt(phiMap.getOrDefault(index, index));
});
for (int i = 0; i < cfg.size(); ++i) {
if (!nodes.contains(i)) {
mapper.apply(program.basicBlockAt(i));
}
}
for (PhiToAdd phiToAdd : phis) {
phiToAdd.target.getPhis().add(phiToAdd.phi);
} }
} }
} }

View File

@ -54,16 +54,13 @@ import org.teavm.model.ClassReader;
import org.teavm.model.ClassReaderSource; import org.teavm.model.ClassReaderSource;
import org.teavm.model.ElementModifier; import org.teavm.model.ElementModifier;
import org.teavm.model.FieldHolder; import org.teavm.model.FieldHolder;
import org.teavm.model.Incoming;
import org.teavm.model.Instruction; import org.teavm.model.Instruction;
import org.teavm.model.InstructionLocation; import org.teavm.model.InstructionLocation;
import org.teavm.model.MethodDescriptor; import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodHolder; import org.teavm.model.MethodHolder;
import org.teavm.model.MethodReader; import org.teavm.model.MethodReader;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.model.Phi;
import org.teavm.model.Program; import org.teavm.model.Program;
import org.teavm.model.TryCatchBlock;
import org.teavm.model.ValueType; import org.teavm.model.ValueType;
import org.teavm.model.Variable; import org.teavm.model.Variable;
import org.teavm.model.instructions.AssignInstruction; import org.teavm.model.instructions.AssignInstruction;
@ -82,15 +79,15 @@ import org.teavm.model.util.ProgramUtils;
* @author Alexey Andreev * @author Alexey Andreev
*/ */
class JSClassProcessor { class JSClassProcessor {
private ClassReaderSource classSource; private final ClassReaderSource classSource;
private JSBodyRepository repository; private final JSBodyRepository repository;
private JavaInvocationProcessor javaInvocationProcessor; private final JavaInvocationProcessor javaInvocationProcessor;
private Program program; private Program program;
private List<Instruction> replacement = new ArrayList<>(); private final List<Instruction> replacement = new ArrayList<>();
private JSTypeHelper typeHelper; private final JSTypeHelper typeHelper;
private Diagnostics diagnostics; private final Diagnostics diagnostics;
private int methodIndexGenerator; private int methodIndexGenerator;
private Map<MethodReference, MethodReader> overridenMethodCache = new HashMap<>(); private final Map<MethodReference, MethodReader> overridenMethodCache = new HashMap<>();
public JSClassProcessor(ClassReaderSource classSource, JSBodyRepository repository, Diagnostics diagnostics) { public JSClassProcessor(ClassReaderSource classSource, JSBodyRepository repository, Diagnostics diagnostics) {
this.classSource = classSource; this.classSource = classSource;
@ -170,32 +167,15 @@ class JSClassProcessor {
callerMethod.getModifiers().add(ElementModifier.STATIC); callerMethod.getModifiers().add(ElementModifier.STATIC);
final Program program = ProgramUtils.copy(method.getProgram()); final Program program = ProgramUtils.copy(method.getProgram());
program.createVariable(); program.createVariable();
InstructionVariableMapper variableMapper = new InstructionVariableMapper() { InstructionVariableMapper variableMapper = new InstructionVariableMapper(var ->
@Override protected Variable map(Variable var) { program.variableAt(var.getIndex() + 1));
return program.variableAt(var.getIndex() + 1);
}
};
for (int i = program.variableCount() - 1; i > 0; --i) { for (int i = program.variableCount() - 1; i > 0; --i) {
program.variableAt(i).getDebugNames().addAll(program.variableAt(i - 1).getDebugNames()); program.variableAt(i).getDebugNames().addAll(program.variableAt(i - 1).getDebugNames());
program.variableAt(i - 1).getDebugNames().clear(); program.variableAt(i - 1).getDebugNames().clear();
} }
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i); BasicBlock block = program.basicBlockAt(i);
for (Instruction insn : block.getInstructions()) { variableMapper.apply(block);
insn.acceptVisitor(variableMapper);
}
for (Phi phi : block.getPhis()) {
phi.setReceiver(program.variableAt(phi.getReceiver().getIndex() + 1));
for (Incoming incoming : phi.getIncomings()) {
incoming.setValue(program.variableAt(incoming.getValue().getIndex() + 1));
}
}
for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) {
if (tryCatch.getExceptionVariable() != null) {
tryCatch.setExceptionVariable(program.variableAt(
tryCatch.getExceptionVariable().getIndex() + 1));
}
}
} }
callerMethod.setProgram(program); callerMethod.setProgram(program);
ModelUtils.copyAnnotations(method.getAnnotations(), callerMethod.getAnnotations()); ModelUtils.copyAnnotations(method.getAnnotations(), callerMethod.getAnnotations());
@ -277,7 +257,7 @@ class JSClassProcessor {
} }
} }
static ValueType[] getStaticSignature(MethodReference method) { private static ValueType[] getStaticSignature(MethodReference method) {
ValueType[] signature = method.getSignature(); ValueType[] signature = method.getSignature();
ValueType[] staticSignature = new ValueType[signature.length + 1]; ValueType[] staticSignature = new ValueType[signature.length + 1];
for (int i = 0; i < signature.length; ++i) { for (int i = 0; i < signature.length; ++i) {
@ -287,7 +267,7 @@ class JSClassProcessor {
return staticSignature; return staticSignature;
} }
public void processProgram(MethodHolder methodToProcess) { void processProgram(MethodHolder methodToProcess) {
program = methodToProcess.getProgram(); program = methodToProcess.getProgram();
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i); BasicBlock block = program.basicBlockAt(i);

View File

@ -0,0 +1,36 @@
/*
* Copyright 2016 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.optimizations;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.teavm.junit.TeaVMTestRunner;
@RunWith(TeaVMTestRunner.class)
public class LoopInversionTest {
@Test
public void respectsLoopOutput() {
int a = 0;
int b = 1;
for (int i = 0; i < 10; ++i) {
int c = a + b;
a = b;
b = c;
}
assertEquals(55, a);
}
}