mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-23 00:24:11 -08:00
Implementing loop inversion
This commit is contained in:
parent
eb3558cb1a
commit
a57be365b4
|
@ -29,4 +29,16 @@ public interface DominatorTree {
|
||||||
int immediateDominatorOf(int a);
|
int immediateDominatorOf(int a);
|
||||||
|
|
||||||
int levelOf(int a);
|
int levelOf(int a);
|
||||||
|
|
||||||
|
default int commonDominatorOf(int[] nodes) {
|
||||||
|
if (nodes.length == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = nodes[0];
|
||||||
|
for (int i = 1; i < nodes.length; ++i) {
|
||||||
|
result = commonDominatorOf(result, nodes[i]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -252,4 +252,14 @@ 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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -608,6 +608,9 @@ class StatementGenerator implements InstructionVisitor {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Decompiler.Block block = blockMap[target.getIndex()];
|
Decompiler.Block block = blockMap[target.getIndex()];
|
||||||
|
if (block == null) {
|
||||||
|
throw new IllegalStateException("Could not find block for basic block $" + target.getIndex());
|
||||||
|
}
|
||||||
if (target.getIndex() == indexer.nodeAt(block.end)) {
|
if (target.getIndex() == indexer.nodeAt(block.end)) {
|
||||||
BreakStatement breakStmt = new BreakStatement();
|
BreakStatement breakStmt = new BreakStatement();
|
||||||
breakStmt.setLocation(currentLocation);
|
breakStmt.setLocation(currentLocation);
|
||||||
|
|
|
@ -0,0 +1,482 @@
|
||||||
|
/*
|
||||||
|
* 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.model.util;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import org.teavm.model.BasicBlock;
|
||||||
|
import org.teavm.model.BasicBlockReader;
|
||||||
|
import org.teavm.model.FieldReference;
|
||||||
|
import org.teavm.model.Instruction;
|
||||||
|
import org.teavm.model.InstructionLocation;
|
||||||
|
import org.teavm.model.InvokeDynamicInstruction;
|
||||||
|
import org.teavm.model.MethodDescriptor;
|
||||||
|
import org.teavm.model.MethodHandle;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.model.Program;
|
||||||
|
import org.teavm.model.RuntimeConstant;
|
||||||
|
import org.teavm.model.ValueType;
|
||||||
|
import org.teavm.model.Variable;
|
||||||
|
import org.teavm.model.VariableReader;
|
||||||
|
import org.teavm.model.instructions.ArrayElementType;
|
||||||
|
import org.teavm.model.instructions.ArrayLengthInstruction;
|
||||||
|
import org.teavm.model.instructions.AssignInstruction;
|
||||||
|
import org.teavm.model.instructions.BinaryBranchingCondition;
|
||||||
|
import org.teavm.model.instructions.BinaryBranchingInstruction;
|
||||||
|
import org.teavm.model.instructions.BinaryInstruction;
|
||||||
|
import org.teavm.model.instructions.BinaryOperation;
|
||||||
|
import org.teavm.model.instructions.BranchingCondition;
|
||||||
|
import org.teavm.model.instructions.BranchingInstruction;
|
||||||
|
import org.teavm.model.instructions.CastInstruction;
|
||||||
|
import org.teavm.model.instructions.CastIntegerDirection;
|
||||||
|
import org.teavm.model.instructions.CastIntegerInstruction;
|
||||||
|
import org.teavm.model.instructions.CastNumberInstruction;
|
||||||
|
import org.teavm.model.instructions.ClassConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.CloneArrayInstruction;
|
||||||
|
import org.teavm.model.instructions.ConstructArrayInstruction;
|
||||||
|
import org.teavm.model.instructions.ConstructInstruction;
|
||||||
|
import org.teavm.model.instructions.ConstructMultiArrayInstruction;
|
||||||
|
import org.teavm.model.instructions.DoubleConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.EmptyInstruction;
|
||||||
|
import org.teavm.model.instructions.ExitInstruction;
|
||||||
|
import org.teavm.model.instructions.FloatConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.GetElementInstruction;
|
||||||
|
import org.teavm.model.instructions.GetFieldInstruction;
|
||||||
|
import org.teavm.model.instructions.InitClassInstruction;
|
||||||
|
import org.teavm.model.instructions.InstructionReader;
|
||||||
|
import org.teavm.model.instructions.IntegerConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.IntegerSubtype;
|
||||||
|
import org.teavm.model.instructions.InvocationType;
|
||||||
|
import org.teavm.model.instructions.InvokeInstruction;
|
||||||
|
import org.teavm.model.instructions.IsInstanceInstruction;
|
||||||
|
import org.teavm.model.instructions.JumpInstruction;
|
||||||
|
import org.teavm.model.instructions.LongConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.MonitorEnterInstruction;
|
||||||
|
import org.teavm.model.instructions.MonitorExitInstruction;
|
||||||
|
import org.teavm.model.instructions.NegateInstruction;
|
||||||
|
import org.teavm.model.instructions.NullCheckInstruction;
|
||||||
|
import org.teavm.model.instructions.NullConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.NumericOperandType;
|
||||||
|
import org.teavm.model.instructions.PutElementInstruction;
|
||||||
|
import org.teavm.model.instructions.PutFieldInstruction;
|
||||||
|
import org.teavm.model.instructions.RaiseInstruction;
|
||||||
|
import org.teavm.model.instructions.StringConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.SwitchInstruction;
|
||||||
|
import org.teavm.model.instructions.SwitchTableEntry;
|
||||||
|
import org.teavm.model.instructions.SwitchTableEntryReader;
|
||||||
|
import org.teavm.model.instructions.UnwrapArrayInstruction;
|
||||||
|
|
||||||
|
public class InstructionCopyReader implements InstructionReader {
|
||||||
|
private Instruction copy;
|
||||||
|
private Program programCopy;
|
||||||
|
private InstructionLocation location;
|
||||||
|
|
||||||
|
public InstructionCopyReader(Program programCopy) {
|
||||||
|
this.programCopy = programCopy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Instruction getCopy() {
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetLocation() {
|
||||||
|
location = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void location(InstructionLocation location) {
|
||||||
|
this.location = location;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Variable copyVar(VariableReader var) {
|
||||||
|
if (var == null) {
|
||||||
|
throw new NullPointerException();
|
||||||
|
}
|
||||||
|
return programCopy.variableAt(var.getIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
private BasicBlock copyBlock(BasicBlockReader block) {
|
||||||
|
return programCopy.basicBlockAt(block.getIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void nop() {
|
||||||
|
copy = new EmptyInstruction();
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void classConstant(VariableReader receiver, ValueType cst) {
|
||||||
|
ClassConstantInstruction insnCopy = new ClassConstantInstruction();
|
||||||
|
insnCopy.setConstant(cst);
|
||||||
|
insnCopy.setReceiver(copyVar(receiver));
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void nullConstant(VariableReader receiver) {
|
||||||
|
NullConstantInstruction insnCopy = new NullConstantInstruction();
|
||||||
|
insnCopy.setReceiver(copyVar(receiver));
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void integerConstant(VariableReader receiver, int cst) {
|
||||||
|
IntegerConstantInstruction insnCopy = new IntegerConstantInstruction();
|
||||||
|
insnCopy.setConstant(cst);
|
||||||
|
insnCopy.setReceiver(copyVar(receiver));
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void longConstant(VariableReader receiver, long cst) {
|
||||||
|
LongConstantInstruction insnCopy = new LongConstantInstruction();
|
||||||
|
insnCopy.setConstant(cst);
|
||||||
|
insnCopy.setReceiver(copyVar(receiver));
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void floatConstant(VariableReader receiver, float cst) {
|
||||||
|
FloatConstantInstruction insnCopy = new FloatConstantInstruction();
|
||||||
|
insnCopy.setConstant(cst);
|
||||||
|
insnCopy.setReceiver(copyVar(receiver));
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doubleConstant(VariableReader receiver, double cst) {
|
||||||
|
DoubleConstantInstruction insnCopy = new DoubleConstantInstruction();
|
||||||
|
insnCopy.setConstant(cst);
|
||||||
|
insnCopy.setReceiver(copyVar(receiver));
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stringConstant(VariableReader receiver, String cst) {
|
||||||
|
StringConstantInstruction insnCopy = new StringConstantInstruction();
|
||||||
|
insnCopy.setConstant(cst);
|
||||||
|
insnCopy.setReceiver(copyVar(receiver));
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void binary(BinaryOperation op, VariableReader receiver, VariableReader first, VariableReader second,
|
||||||
|
NumericOperandType type) {
|
||||||
|
BinaryInstruction insnCopy = new BinaryInstruction(op, type);
|
||||||
|
insnCopy.setFirstOperand(copyVar(first));
|
||||||
|
insnCopy.setSecondOperand(copyVar(second));
|
||||||
|
insnCopy.setReceiver(copyVar(receiver));
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void negate(VariableReader receiver, VariableReader operand, NumericOperandType type) {
|
||||||
|
NegateInstruction insnCopy = new NegateInstruction(type);
|
||||||
|
insnCopy.setOperand(copyVar(operand));
|
||||||
|
insnCopy.setReceiver(copyVar(receiver));
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void assign(VariableReader receiver, VariableReader assignee) {
|
||||||
|
AssignInstruction insnCopy = new AssignInstruction();
|
||||||
|
insnCopy.setAssignee(copyVar(assignee));
|
||||||
|
insnCopy.setReceiver(copyVar(receiver));
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) {
|
||||||
|
CastInstruction insnCopy = new CastInstruction();
|
||||||
|
insnCopy.setValue(copyVar(value));
|
||||||
|
insnCopy.setReceiver(copyVar(receiver));
|
||||||
|
insnCopy.setTargetType(targetType);
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cast(VariableReader receiver, VariableReader value, NumericOperandType sourceType,
|
||||||
|
NumericOperandType targetType) {
|
||||||
|
CastNumberInstruction insnCopy = new CastNumberInstruction(sourceType, targetType);
|
||||||
|
insnCopy.setValue(copyVar(value));
|
||||||
|
insnCopy.setReceiver(copyVar(receiver));
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cast(VariableReader receiver, VariableReader value, IntegerSubtype type,
|
||||||
|
CastIntegerDirection dir) {
|
||||||
|
CastIntegerInstruction insnCopy = new CastIntegerInstruction(type, dir);
|
||||||
|
insnCopy.setValue(copyVar(value));
|
||||||
|
insnCopy.setReceiver(copyVar(receiver));
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void jumpIf(BranchingCondition cond, VariableReader operand, BasicBlockReader consequent,
|
||||||
|
BasicBlockReader alternative) {
|
||||||
|
BranchingInstruction insnCopy = new BranchingInstruction(cond);
|
||||||
|
insnCopy.setOperand(copyVar(operand));
|
||||||
|
insnCopy.setConsequent(copyBlock(consequent));
|
||||||
|
insnCopy.setAlternative(copyBlock(alternative));
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void jumpIf(BinaryBranchingCondition cond, VariableReader first, VariableReader second,
|
||||||
|
BasicBlockReader consequent, BasicBlockReader alternative) {
|
||||||
|
BinaryBranchingInstruction insnCopy = new BinaryBranchingInstruction(cond);
|
||||||
|
insnCopy.setFirstOperand(copyVar(first));
|
||||||
|
insnCopy.setSecondOperand(copyVar(second));
|
||||||
|
insnCopy.setConsequent(copyBlock(consequent));
|
||||||
|
insnCopy.setAlternative(copyBlock(alternative));
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void jump(BasicBlockReader target) {
|
||||||
|
JumpInstruction insnCopy = new JumpInstruction();
|
||||||
|
insnCopy.setTarget(copyBlock(target));
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void choose(VariableReader condition, List<? extends SwitchTableEntryReader> table,
|
||||||
|
BasicBlockReader defaultTarget) {
|
||||||
|
SwitchInstruction insnCopy = new SwitchInstruction();
|
||||||
|
insnCopy.setCondition(copyVar(condition));
|
||||||
|
insnCopy.setDefaultTarget(copyBlock(defaultTarget));
|
||||||
|
for (SwitchTableEntryReader entry : table) {
|
||||||
|
SwitchTableEntry entryCopy = new SwitchTableEntry();
|
||||||
|
entryCopy.setCondition(entry.getCondition());
|
||||||
|
entryCopy.setTarget(copyBlock(entry.getTarget()));
|
||||||
|
insnCopy.getEntries().add(entryCopy);
|
||||||
|
}
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exit(VariableReader valueToReturn) {
|
||||||
|
ExitInstruction insnCopy = new ExitInstruction();
|
||||||
|
insnCopy.setValueToReturn(valueToReturn != null ? copyVar(valueToReturn) : null);
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void raise(VariableReader exception) {
|
||||||
|
RaiseInstruction insnCopy = new RaiseInstruction();
|
||||||
|
insnCopy.setException(copyVar(exception));
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createArray(VariableReader receiver, ValueType itemType, VariableReader size) {
|
||||||
|
ConstructArrayInstruction insnCopy = new ConstructArrayInstruction();
|
||||||
|
insnCopy.setItemType(itemType);
|
||||||
|
insnCopy.setSize(copyVar(size));
|
||||||
|
insnCopy.setReceiver(copyVar(receiver));
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createArray(VariableReader receiver, ValueType itemType,
|
||||||
|
List<? extends VariableReader> dimensions) {
|
||||||
|
ConstructMultiArrayInstruction insnCopy = new ConstructMultiArrayInstruction();
|
||||||
|
insnCopy.setItemType(itemType);
|
||||||
|
insnCopy.setReceiver(copyVar(receiver));
|
||||||
|
for (VariableReader dim : dimensions) {
|
||||||
|
insnCopy.getDimensions().add(copyVar(dim));
|
||||||
|
}
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void create(VariableReader receiver, String type) {
|
||||||
|
ConstructInstruction insnCopy = new ConstructInstruction();
|
||||||
|
insnCopy.setType(type);
|
||||||
|
insnCopy.setReceiver(copyVar(receiver));
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getField(VariableReader receiver, VariableReader instance, FieldReference field,
|
||||||
|
ValueType fieldType) {
|
||||||
|
GetFieldInstruction insnCopy = new GetFieldInstruction();
|
||||||
|
insnCopy.setField(field);
|
||||||
|
insnCopy.setFieldType(fieldType);
|
||||||
|
insnCopy.setInstance(instance != null ? copyVar(instance) : null);
|
||||||
|
insnCopy.setReceiver(copyVar(receiver));
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putField(VariableReader instance, FieldReference field, VariableReader value,
|
||||||
|
ValueType fieldType) {
|
||||||
|
PutFieldInstruction insnCopy = new PutFieldInstruction();
|
||||||
|
insnCopy.setField(field);
|
||||||
|
insnCopy.setInstance(instance != null ? copyVar(instance) : null);
|
||||||
|
insnCopy.setValue(copyVar(value));
|
||||||
|
insnCopy.setFieldType(fieldType);
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void arrayLength(VariableReader receiver, VariableReader array) {
|
||||||
|
ArrayLengthInstruction insnCopy = new ArrayLengthInstruction();
|
||||||
|
insnCopy.setArray(copyVar(array));
|
||||||
|
insnCopy.setReceiver(copyVar(receiver));
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cloneArray(VariableReader receiver, VariableReader array) {
|
||||||
|
CloneArrayInstruction insnCopy = new CloneArrayInstruction();
|
||||||
|
insnCopy.setArray(copyVar(array));
|
||||||
|
insnCopy.setReceiver(copyVar(receiver));
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unwrapArray(VariableReader receiver, VariableReader array, ArrayElementType elementType) {
|
||||||
|
UnwrapArrayInstruction insnCopy = new UnwrapArrayInstruction(elementType);
|
||||||
|
insnCopy.setArray(copyVar(array));
|
||||||
|
insnCopy.setReceiver(copyVar(receiver));
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getElement(VariableReader receiver, VariableReader array, VariableReader index) {
|
||||||
|
GetElementInstruction insnCopy = new GetElementInstruction();
|
||||||
|
insnCopy.setArray(copyVar(array));
|
||||||
|
insnCopy.setReceiver(copyVar(receiver));
|
||||||
|
insnCopy.setIndex(copyVar(index));
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putElement(VariableReader array, VariableReader index, VariableReader value) {
|
||||||
|
PutElementInstruction insnCopy = new PutElementInstruction();
|
||||||
|
insnCopy.setArray(copyVar(array));
|
||||||
|
insnCopy.setValue(copyVar(value));
|
||||||
|
insnCopy.setIndex(copyVar(index));
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invoke(VariableReader receiver, VariableReader instance, MethodReference method,
|
||||||
|
List<? extends VariableReader> arguments, InvocationType type) {
|
||||||
|
InvokeInstruction insnCopy = new InvokeInstruction();
|
||||||
|
insnCopy.setMethod(method);
|
||||||
|
insnCopy.setType(type);
|
||||||
|
insnCopy.setInstance(instance != null ? copyVar(instance) : null);
|
||||||
|
insnCopy.setReceiver(receiver != null ? copyVar(receiver) : null);
|
||||||
|
for (VariableReader arg : arguments) {
|
||||||
|
insnCopy.getArguments().add(copyVar(arg));
|
||||||
|
}
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invokeDynamic(VariableReader receiver, VariableReader instance, MethodDescriptor method,
|
||||||
|
List<? extends VariableReader> arguments, MethodHandle bootstrapMethod,
|
||||||
|
List<RuntimeConstant> bootstrapArguments) {
|
||||||
|
InvokeDynamicInstruction insnCopy = new InvokeDynamicInstruction();
|
||||||
|
insnCopy.setMethod(method);
|
||||||
|
insnCopy.setBootstrapMethod(bootstrapMethod);
|
||||||
|
insnCopy.getBootstrapArguments().addAll(bootstrapArguments);
|
||||||
|
if (instance != null) {
|
||||||
|
insnCopy.setInstance(copyVar(instance));
|
||||||
|
}
|
||||||
|
insnCopy.getArguments().addAll(arguments.stream().map(this::copyVar).collect(Collectors.toList()));
|
||||||
|
insnCopy.setReceiver(receiver != null ? copyVar(receiver) : null);
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void isInstance(VariableReader receiver, VariableReader value, ValueType type) {
|
||||||
|
IsInstanceInstruction insnCopy = new IsInstanceInstruction();
|
||||||
|
insnCopy.setValue(copyVar(value));
|
||||||
|
insnCopy.setReceiver(copyVar(receiver));
|
||||||
|
insnCopy.setType(type);
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initClass(String className) {
|
||||||
|
InitClassInstruction insnCopy = new InitClassInstruction();
|
||||||
|
insnCopy.setClassName(className);
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void nullCheck(VariableReader receiver, VariableReader value) {
|
||||||
|
NullCheckInstruction insnCopy = new NullCheckInstruction();
|
||||||
|
insnCopy.setReceiver(copyVar(receiver));
|
||||||
|
insnCopy.setValue(copyVar(value));
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void monitorEnter(VariableReader objectRef) {
|
||||||
|
MonitorEnterInstruction insnCopy = new MonitorEnterInstruction();
|
||||||
|
insnCopy.setObjectRef(copyVar(objectRef));
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void monitorExit(VariableReader objectRef) {
|
||||||
|
MonitorExitInstruction insnCopy = new MonitorExitInstruction();
|
||||||
|
insnCopy.setObjectRef(copyVar(objectRef));
|
||||||
|
copy = insnCopy;
|
||||||
|
copy.setLocation(location);
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,17 +15,25 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.model.util;
|
package org.teavm.model.util;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
import java.util.stream.Collectors;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import org.teavm.common.Graph;
|
import org.teavm.common.Graph;
|
||||||
import org.teavm.common.GraphBuilder;
|
import org.teavm.common.GraphBuilder;
|
||||||
import org.teavm.model.*;
|
import org.teavm.model.BasicBlock;
|
||||||
import org.teavm.model.instructions.*;
|
import org.teavm.model.BasicBlockReader;
|
||||||
|
import org.teavm.model.Incoming;
|
||||||
|
import org.teavm.model.IncomingReader;
|
||||||
|
import org.teavm.model.Instruction;
|
||||||
|
import org.teavm.model.InstructionLocation;
|
||||||
|
import org.teavm.model.Phi;
|
||||||
|
import org.teavm.model.PhiReader;
|
||||||
|
import org.teavm.model.Program;
|
||||||
|
import org.teavm.model.ProgramReader;
|
||||||
|
import org.teavm.model.TryCatchBlock;
|
||||||
|
import org.teavm.model.TryCatchBlockReader;
|
||||||
|
import org.teavm.model.Variable;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Alexey Andreev
|
|
||||||
*/
|
|
||||||
public final class ProgramUtils {
|
public final class ProgramUtils {
|
||||||
private ProgramUtils() {
|
private ProgramUtils() {
|
||||||
}
|
}
|
||||||
|
@ -81,8 +89,6 @@ public final class ProgramUtils {
|
||||||
|
|
||||||
public static Program copy(ProgramReader program) {
|
public static Program copy(ProgramReader program) {
|
||||||
Program copy = new Program();
|
Program copy = new Program();
|
||||||
InstructionCopyReader insnCopier = new InstructionCopyReader();
|
|
||||||
insnCopier.programCopy = copy;
|
|
||||||
for (int i = 0; i < program.variableCount(); ++i) {
|
for (int i = 0; i < program.variableCount(); ++i) {
|
||||||
Variable var = copy.createVariable();
|
Variable var = copy.createVariable();
|
||||||
var.getDebugNames().addAll(program.variableAt(i).readDebugNames());
|
var.getDebugNames().addAll(program.variableAt(i).readDebugNames());
|
||||||
|
@ -108,12 +114,10 @@ public final class ProgramUtils {
|
||||||
|
|
||||||
public static List<Instruction> copyInstructions(BasicBlockReader block, int from, int to, Program target) {
|
public static List<Instruction> copyInstructions(BasicBlockReader block, int from, int to, Program target) {
|
||||||
List<Instruction> result = new ArrayList<>();
|
List<Instruction> result = new ArrayList<>();
|
||||||
InstructionCopyReader copyReader = new InstructionCopyReader();
|
InstructionCopyReader copyReader = new InstructionCopyReader(target);
|
||||||
copyReader.programCopy = target;
|
|
||||||
for (int i = from; i < to; ++i) {
|
for (int i = from; i < to; ++i) {
|
||||||
block.readInstruction(i, copyReader);
|
block.readInstruction(i, copyReader);
|
||||||
copyReader.copy.setLocation(copyReader.location);
|
result.add(copyReader.getCopy());
|
||||||
result.add(copyReader.copy);
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -145,394 +149,4 @@ public final class ProgramUtils {
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class InstructionCopyReader implements InstructionReader {
|
|
||||||
Instruction copy;
|
|
||||||
Program programCopy;
|
|
||||||
InstructionLocation location;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void location(InstructionLocation location) {
|
|
||||||
this.location = location;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Variable copyVar(VariableReader var) {
|
|
||||||
if (var == null) {
|
|
||||||
throw new NullPointerException();
|
|
||||||
}
|
|
||||||
return programCopy.variableAt(var.getIndex());
|
|
||||||
}
|
|
||||||
|
|
||||||
private BasicBlock copyBlock(BasicBlockReader block) {
|
|
||||||
return programCopy.basicBlockAt(block.getIndex());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void nop() {
|
|
||||||
copy = new EmptyInstruction();
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void classConstant(VariableReader receiver, ValueType cst) {
|
|
||||||
ClassConstantInstruction insnCopy = new ClassConstantInstruction();
|
|
||||||
insnCopy.setConstant(cst);
|
|
||||||
insnCopy.setReceiver(copyVar(receiver));
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void nullConstant(VariableReader receiver) {
|
|
||||||
NullConstantInstruction insnCopy = new NullConstantInstruction();
|
|
||||||
insnCopy.setReceiver(copyVar(receiver));
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void integerConstant(VariableReader receiver, int cst) {
|
|
||||||
IntegerConstantInstruction insnCopy = new IntegerConstantInstruction();
|
|
||||||
insnCopy.setConstant(cst);
|
|
||||||
insnCopy.setReceiver(copyVar(receiver));
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void longConstant(VariableReader receiver, long cst) {
|
|
||||||
LongConstantInstruction insnCopy = new LongConstantInstruction();
|
|
||||||
insnCopy.setConstant(cst);
|
|
||||||
insnCopy.setReceiver(copyVar(receiver));
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void floatConstant(VariableReader receiver, float cst) {
|
|
||||||
FloatConstantInstruction insnCopy = new FloatConstantInstruction();
|
|
||||||
insnCopy.setConstant(cst);
|
|
||||||
insnCopy.setReceiver(copyVar(receiver));
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void doubleConstant(VariableReader receiver, double cst) {
|
|
||||||
DoubleConstantInstruction insnCopy = new DoubleConstantInstruction();
|
|
||||||
insnCopy.setConstant(cst);
|
|
||||||
insnCopy.setReceiver(copyVar(receiver));
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void stringConstant(VariableReader receiver, String cst) {
|
|
||||||
StringConstantInstruction insnCopy = new StringConstantInstruction();
|
|
||||||
insnCopy.setConstant(cst);
|
|
||||||
insnCopy.setReceiver(copyVar(receiver));
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void binary(BinaryOperation op, VariableReader receiver, VariableReader first, VariableReader second,
|
|
||||||
NumericOperandType type) {
|
|
||||||
BinaryInstruction insnCopy = new BinaryInstruction(op, type);
|
|
||||||
insnCopy.setFirstOperand(copyVar(first));
|
|
||||||
insnCopy.setSecondOperand(copyVar(second));
|
|
||||||
insnCopy.setReceiver(copyVar(receiver));
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void negate(VariableReader receiver, VariableReader operand, NumericOperandType type) {
|
|
||||||
NegateInstruction insnCopy = new NegateInstruction(type);
|
|
||||||
insnCopy.setOperand(copyVar(operand));
|
|
||||||
insnCopy.setReceiver(copyVar(receiver));
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void assign(VariableReader receiver, VariableReader assignee) {
|
|
||||||
AssignInstruction insnCopy = new AssignInstruction();
|
|
||||||
insnCopy.setAssignee(copyVar(assignee));
|
|
||||||
insnCopy.setReceiver(copyVar(receiver));
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) {
|
|
||||||
CastInstruction insnCopy = new CastInstruction();
|
|
||||||
insnCopy.setValue(copyVar(value));
|
|
||||||
insnCopy.setReceiver(copyVar(receiver));
|
|
||||||
insnCopy.setTargetType(targetType);
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void cast(VariableReader receiver, VariableReader value, NumericOperandType sourceType,
|
|
||||||
NumericOperandType targetType) {
|
|
||||||
CastNumberInstruction insnCopy = new CastNumberInstruction(sourceType, targetType);
|
|
||||||
insnCopy.setValue(copyVar(value));
|
|
||||||
insnCopy.setReceiver(copyVar(receiver));
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void cast(VariableReader receiver, VariableReader value, IntegerSubtype type,
|
|
||||||
CastIntegerDirection dir) {
|
|
||||||
CastIntegerInstruction insnCopy = new CastIntegerInstruction(type, dir);
|
|
||||||
insnCopy.setValue(copyVar(value));
|
|
||||||
insnCopy.setReceiver(copyVar(receiver));
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void jumpIf(BranchingCondition cond, VariableReader operand, BasicBlockReader consequent,
|
|
||||||
BasicBlockReader alternative) {
|
|
||||||
BranchingInstruction insnCopy = new BranchingInstruction(cond);
|
|
||||||
insnCopy.setOperand(copyVar(operand));
|
|
||||||
insnCopy.setConsequent(copyBlock(consequent));
|
|
||||||
insnCopy.setAlternative(copyBlock(alternative));
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void jumpIf(BinaryBranchingCondition cond, VariableReader first, VariableReader second,
|
|
||||||
BasicBlockReader consequent, BasicBlockReader alternative) {
|
|
||||||
BinaryBranchingInstruction insnCopy = new BinaryBranchingInstruction(cond);
|
|
||||||
insnCopy.setFirstOperand(copyVar(first));
|
|
||||||
insnCopy.setSecondOperand(copyVar(second));
|
|
||||||
insnCopy.setConsequent(copyBlock(consequent));
|
|
||||||
insnCopy.setAlternative(copyBlock(alternative));
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void jump(BasicBlockReader target) {
|
|
||||||
JumpInstruction insnCopy = new JumpInstruction();
|
|
||||||
insnCopy.setTarget(copyBlock(target));
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void choose(VariableReader condition, List<? extends SwitchTableEntryReader> table,
|
|
||||||
BasicBlockReader defaultTarget) {
|
|
||||||
SwitchInstruction insnCopy = new SwitchInstruction();
|
|
||||||
insnCopy.setCondition(copyVar(condition));
|
|
||||||
insnCopy.setDefaultTarget(copyBlock(defaultTarget));
|
|
||||||
for (SwitchTableEntryReader entry : table) {
|
|
||||||
SwitchTableEntry entryCopy = new SwitchTableEntry();
|
|
||||||
entryCopy.setCondition(entry.getCondition());
|
|
||||||
entryCopy.setTarget(copyBlock(entry.getTarget()));
|
|
||||||
insnCopy.getEntries().add(entryCopy);
|
|
||||||
}
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void exit(VariableReader valueToReturn) {
|
|
||||||
ExitInstruction insnCopy = new ExitInstruction();
|
|
||||||
insnCopy.setValueToReturn(valueToReturn != null ? copyVar(valueToReturn) : null);
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void raise(VariableReader exception) {
|
|
||||||
RaiseInstruction insnCopy = new RaiseInstruction();
|
|
||||||
insnCopy.setException(copyVar(exception));
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void createArray(VariableReader receiver, ValueType itemType, VariableReader size) {
|
|
||||||
ConstructArrayInstruction insnCopy = new ConstructArrayInstruction();
|
|
||||||
insnCopy.setItemType(itemType);
|
|
||||||
insnCopy.setSize(copyVar(size));
|
|
||||||
insnCopy.setReceiver(copyVar(receiver));
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void createArray(VariableReader receiver, ValueType itemType,
|
|
||||||
List<? extends VariableReader> dimensions) {
|
|
||||||
ConstructMultiArrayInstruction insnCopy = new ConstructMultiArrayInstruction();
|
|
||||||
insnCopy.setItemType(itemType);
|
|
||||||
insnCopy.setReceiver(copyVar(receiver));
|
|
||||||
for (VariableReader dim : dimensions) {
|
|
||||||
insnCopy.getDimensions().add(copyVar(dim));
|
|
||||||
}
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void create(VariableReader receiver, String type) {
|
|
||||||
ConstructInstruction insnCopy = new ConstructInstruction();
|
|
||||||
insnCopy.setType(type);
|
|
||||||
insnCopy.setReceiver(copyVar(receiver));
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void getField(VariableReader receiver, VariableReader instance, FieldReference field,
|
|
||||||
ValueType fieldType) {
|
|
||||||
GetFieldInstruction insnCopy = new GetFieldInstruction();
|
|
||||||
insnCopy.setField(field);
|
|
||||||
insnCopy.setFieldType(fieldType);
|
|
||||||
insnCopy.setInstance(instance != null ? copyVar(instance) : null);
|
|
||||||
insnCopy.setReceiver(copyVar(receiver));
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void putField(VariableReader instance, FieldReference field, VariableReader value,
|
|
||||||
ValueType fieldType) {
|
|
||||||
PutFieldInstruction insnCopy = new PutFieldInstruction();
|
|
||||||
insnCopy.setField(field);
|
|
||||||
insnCopy.setInstance(instance != null ? copyVar(instance) : null);
|
|
||||||
insnCopy.setValue(copyVar(value));
|
|
||||||
insnCopy.setFieldType(fieldType);
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void arrayLength(VariableReader receiver, VariableReader array) {
|
|
||||||
ArrayLengthInstruction insnCopy = new ArrayLengthInstruction();
|
|
||||||
insnCopy.setArray(copyVar(array));
|
|
||||||
insnCopy.setReceiver(copyVar(receiver));
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void cloneArray(VariableReader receiver, VariableReader array) {
|
|
||||||
CloneArrayInstruction insnCopy = new CloneArrayInstruction();
|
|
||||||
insnCopy.setArray(copyVar(array));
|
|
||||||
insnCopy.setReceiver(copyVar(receiver));
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void unwrapArray(VariableReader receiver, VariableReader array, ArrayElementType elementType) {
|
|
||||||
UnwrapArrayInstruction insnCopy = new UnwrapArrayInstruction(elementType);
|
|
||||||
insnCopy.setArray(copyVar(array));
|
|
||||||
insnCopy.setReceiver(copyVar(receiver));
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void getElement(VariableReader receiver, VariableReader array, VariableReader index) {
|
|
||||||
GetElementInstruction insnCopy = new GetElementInstruction();
|
|
||||||
insnCopy.setArray(copyVar(array));
|
|
||||||
insnCopy.setReceiver(copyVar(receiver));
|
|
||||||
insnCopy.setIndex(copyVar(index));
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void putElement(VariableReader array, VariableReader index, VariableReader value) {
|
|
||||||
PutElementInstruction insnCopy = new PutElementInstruction();
|
|
||||||
insnCopy.setArray(copyVar(array));
|
|
||||||
insnCopy.setValue(copyVar(value));
|
|
||||||
insnCopy.setIndex(copyVar(index));
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void invoke(VariableReader receiver, VariableReader instance, MethodReference method,
|
|
||||||
List<? extends VariableReader> arguments, InvocationType type) {
|
|
||||||
InvokeInstruction insnCopy = new InvokeInstruction();
|
|
||||||
insnCopy.setMethod(method);
|
|
||||||
insnCopy.setType(type);
|
|
||||||
insnCopy.setInstance(instance != null ? copyVar(instance) : null);
|
|
||||||
insnCopy.setReceiver(receiver != null ? copyVar(receiver) : null);
|
|
||||||
for (VariableReader arg : arguments) {
|
|
||||||
insnCopy.getArguments().add(copyVar(arg));
|
|
||||||
}
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void invokeDynamic(VariableReader receiver, VariableReader instance, MethodDescriptor method,
|
|
||||||
List<? extends VariableReader> arguments, MethodHandle bootstrapMethod,
|
|
||||||
List<RuntimeConstant> bootstrapArguments) {
|
|
||||||
InvokeDynamicInstruction insnCopy = new InvokeDynamicInstruction();
|
|
||||||
insnCopy.setMethod(method);
|
|
||||||
insnCopy.setBootstrapMethod(bootstrapMethod);
|
|
||||||
insnCopy.getBootstrapArguments().addAll(bootstrapArguments);
|
|
||||||
if (instance != null) {
|
|
||||||
insnCopy.setInstance(copyVar(instance));
|
|
||||||
}
|
|
||||||
insnCopy.getArguments().addAll(arguments.stream().map(this::copyVar).collect(Collectors.toList()));
|
|
||||||
insnCopy.setReceiver(receiver != null ? copyVar(receiver) : null);
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void isInstance(VariableReader receiver, VariableReader value, ValueType type) {
|
|
||||||
IsInstanceInstruction insnCopy = new IsInstanceInstruction();
|
|
||||||
insnCopy.setValue(copyVar(value));
|
|
||||||
insnCopy.setReceiver(copyVar(receiver));
|
|
||||||
insnCopy.setType(type);
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initClass(String className) {
|
|
||||||
InitClassInstruction insnCopy = new InitClassInstruction();
|
|
||||||
insnCopy.setClassName(className);
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void nullCheck(VariableReader receiver, VariableReader value) {
|
|
||||||
NullCheckInstruction insnCopy = new NullCheckInstruction();
|
|
||||||
insnCopy.setReceiver(copyVar(receiver));
|
|
||||||
insnCopy.setValue(copyVar(value));
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void monitorEnter(VariableReader objectRef) {
|
|
||||||
MonitorEnterInstruction insnCopy = new MonitorEnterInstruction();
|
|
||||||
insnCopy.setObjectRef(copyVar(objectRef));
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void monitorExit(VariableReader objectRef) {
|
|
||||||
MonitorExitInstruction insnCopy = new MonitorExitInstruction();
|
|
||||||
insnCopy.setObjectRef(copyVar(objectRef));
|
|
||||||
copy = insnCopy;
|
|
||||||
copy.setLocation(location);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2013 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.model.ClassHolder;
|
|
||||||
import org.teavm.model.ListableClassHolderSource;
|
|
||||||
import org.teavm.model.MethodHolder;
|
|
||||||
import org.teavm.model.Program;
|
|
||||||
import org.teavm.model.util.ProgramUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Alexey Andreev
|
|
||||||
*/
|
|
||||||
public class ClassSetOptimizer {
|
|
||||||
private List<MethodOptimization> getOptimizations() {
|
|
||||||
return Arrays.asList(new ArrayUnwrapMotion(), new LoopInvariantMotion(),
|
|
||||||
new GlobalValueNumbering(), new UnusedVariableElimination());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void optimizeAll(ListableClassHolderSource classSource) {
|
|
||||||
for (String className : classSource.getClassNames()) {
|
|
||||||
ClassHolder cls = classSource.get(className);
|
|
||||||
for (MethodHolder method : cls.getMethods()) {
|
|
||||||
if (method.getProgram() != null && method.getProgram().basicBlockCount() > 0) {
|
|
||||||
Program program = ProgramUtils.copy(method.getProgram());
|
|
||||||
for (MethodOptimization optimization : getOptimizations()) {
|
|
||||||
optimization.optimize(method, program);
|
|
||||||
}
|
|
||||||
method.setProgram(program);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
26
core/src/main/java/org/teavm/optimization/LoopInversion.java
Normal file
26
core/src/main/java/org/teavm/optimization/LoopInversion.java
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* 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.optimization;
|
||||||
|
|
||||||
|
import org.teavm.model.MethodReader;
|
||||||
|
import org.teavm.model.Program;
|
||||||
|
|
||||||
|
public class LoopInversion implements MethodOptimization {
|
||||||
|
@Override
|
||||||
|
public void optimize(MethodReader method, Program program) {
|
||||||
|
new LoopInversionImpl(program).apply();
|
||||||
|
}
|
||||||
|
}
|
412
core/src/main/java/org/teavm/optimization/LoopInversionImpl.java
Normal file
412
core/src/main/java/org/teavm/optimization/LoopInversionImpl.java
Normal file
|
@ -0,0 +1,412 @@
|
||||||
|
/*
|
||||||
|
* 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.optimization;
|
||||||
|
|
||||||
|
import com.carrotsearch.hppc.IntIntMap;
|
||||||
|
import com.carrotsearch.hppc.IntIntOpenHashMap;
|
||||||
|
import com.carrotsearch.hppc.IntOpenHashSet;
|
||||||
|
import com.carrotsearch.hppc.IntSet;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import org.teavm.common.DominatorTree;
|
||||||
|
import org.teavm.common.Graph;
|
||||||
|
import org.teavm.common.GraphUtils;
|
||||||
|
import org.teavm.common.Loop;
|
||||||
|
import org.teavm.common.LoopGraph;
|
||||||
|
import org.teavm.model.BasicBlock;
|
||||||
|
import org.teavm.model.Incoming;
|
||||||
|
import org.teavm.model.Instruction;
|
||||||
|
import org.teavm.model.Phi;
|
||||||
|
import org.teavm.model.Program;
|
||||||
|
import org.teavm.model.TryCatchBlock;
|
||||||
|
import org.teavm.model.Variable;
|
||||||
|
import org.teavm.model.util.BasicBlockMapper;
|
||||||
|
import org.teavm.model.util.DefinitionExtractor;
|
||||||
|
import org.teavm.model.util.InstructionCopyReader;
|
||||||
|
import org.teavm.model.util.InstructionVariableMapper;
|
||||||
|
import org.teavm.model.util.ProgramUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms loop in form:
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* while (true) {
|
||||||
|
* condition;
|
||||||
|
* body;
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* to form:
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* if (condition) {
|
||||||
|
* while (true) {
|
||||||
|
* body;
|
||||||
|
* condition; // copy
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
* Therefore, *condition* is a set of nodes of the loop that are postdominated by condition end and
|
||||||
|
* all remaining nodes are *body*.
|
||||||
|
*/
|
||||||
|
class LoopInversionImpl {
|
||||||
|
private Program program;
|
||||||
|
private Graph cfg;
|
||||||
|
private DominatorTree pdom;
|
||||||
|
private boolean postponed;
|
||||||
|
|
||||||
|
LoopInversionImpl(Program program) {
|
||||||
|
this.program = program;
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply() {
|
||||||
|
do {
|
||||||
|
cfg = ProgramUtils.buildControlFlowGraph(program);
|
||||||
|
LoopGraph loopGraph = new LoopGraph(cfg);
|
||||||
|
pdom = GraphUtils.buildDominatorTree(GraphUtils.invert(cfg));
|
||||||
|
List<LoopWithExits> loops = getLoopsWithExits(loopGraph);
|
||||||
|
|
||||||
|
postponed = false;
|
||||||
|
for (LoopWithExits loop : loops) {
|
||||||
|
loop.invert();
|
||||||
|
}
|
||||||
|
} while (postponed);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<LoopWithExits> getLoopsWithExits(LoopGraph cfg) {
|
||||||
|
Map<Loop, LoopWithExits> loops = new HashMap<>();
|
||||||
|
|
||||||
|
for (int node = 0; node < cfg.size(); ++node) {
|
||||||
|
Loop loop = cfg.loopAt(node);
|
||||||
|
while (loop != null) {
|
||||||
|
LoopWithExits loopWithExits = getLoopWithExits(loops, loop);
|
||||||
|
loopWithExits.nodes.add(node);
|
||||||
|
for (int successor : cfg.outgoingEdges(node)) {
|
||||||
|
Loop successorLoop = cfg.loopAt(successor);
|
||||||
|
if (successorLoop == null || !successorLoop.isChildOf(loop)) {
|
||||||
|
loopWithExits.exits.add(node);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loop = loop.getParent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<LoopWithExits> resultList = new ArrayList<>();
|
||||||
|
Set<LoopWithExits> visited = new HashSet<>();
|
||||||
|
for (LoopWithExits loop : loops.values()) {
|
||||||
|
sortLoops(loop, visited, resultList);
|
||||||
|
}
|
||||||
|
Collections.reverse(resultList);
|
||||||
|
|
||||||
|
return resultList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoopWithExits getLoopWithExits(Map<Loop, LoopWithExits> cache, Loop loop) {
|
||||||
|
return cache.computeIfAbsent(loop, key ->
|
||||||
|
new LoopWithExits(key.getHead(), key.getParent() != null
|
||||||
|
? getLoopWithExits(cache, key.getParent())
|
||||||
|
: null));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sortLoops(LoopWithExits loop, Set<LoopWithExits> visited, List<LoopWithExits> target) {
|
||||||
|
if (!visited.add(loop)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (loop.parent != null) {
|
||||||
|
sortLoops(loop.parent, visited, target);
|
||||||
|
}
|
||||||
|
target.add(loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class LoopWithExits {
|
||||||
|
final int head;
|
||||||
|
final LoopWithExits parent;
|
||||||
|
final IntSet nodes = new IntOpenHashSet();
|
||||||
|
final IntSet nodesAndCopies = new IntOpenHashSet();
|
||||||
|
final IntSet exits = new IntOpenHashSet();
|
||||||
|
int conditionEnd;
|
||||||
|
int copyStart;
|
||||||
|
int headCopy;
|
||||||
|
final IntIntMap copiedVars = new IntIntOpenHashMap();
|
||||||
|
final IntIntMap copiedNodes = new IntIntOpenHashMap();
|
||||||
|
boolean shouldSkip;
|
||||||
|
|
||||||
|
LoopWithExits(int head, LoopWithExits parent) {
|
||||||
|
this.head = head;
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void invert() {
|
||||||
|
if (tryInvert()) {
|
||||||
|
LoopWithExits ancestor = parent;
|
||||||
|
while (ancestor != null) {
|
||||||
|
ancestor.shouldSkip = true;
|
||||||
|
ancestor = ancestor.parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean tryInvert() {
|
||||||
|
if (shouldSkip) {
|
||||||
|
postponed = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
findCondition();
|
||||||
|
if (conditionEnd < 0 || !canInvert()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
collectNodesToCopy();
|
||||||
|
collectVariablesToCopy();
|
||||||
|
copyCondition();
|
||||||
|
moveBackEdges();
|
||||||
|
removeInternalPhiInputsFromCondition();
|
||||||
|
removeExternalPhiInputsFromConditionCopy();
|
||||||
|
putNewPhis();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void findCondition() {
|
||||||
|
IntSet endNodes = new IntOpenHashSet(program.basicBlockCount());
|
||||||
|
for (int exit : exits.toArray()) {
|
||||||
|
for (int successor : cfg.outgoingEdges(exit)) {
|
||||||
|
if (nodes.contains(successor) && successor != head) {
|
||||||
|
endNodes.add(successor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
conditionEnd = pdom.commonDominatorOf(endNodes.toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We can't invert loop if condition has back edges. Indeed, back edges from `if` statement
|
||||||
|
* must point inside loop, which makes CFG irreducible.
|
||||||
|
*/
|
||||||
|
private boolean canInvert() {
|
||||||
|
for (int node : nodes.toArray()) {
|
||||||
|
if (pdom.dominates(conditionEnd, node)) {
|
||||||
|
for (int successor : cfg.outgoingEdges(node)) {
|
||||||
|
if (successor == head) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collectNodesToCopy() {
|
||||||
|
int[] nodes = this.nodes.toArray();
|
||||||
|
Arrays.sort(nodes);
|
||||||
|
for (int node : nodes) {
|
||||||
|
nodesAndCopies.add(node);
|
||||||
|
if (pdom.dominates(conditionEnd, node)) {
|
||||||
|
int copy = program.createBasicBlock().getIndex();
|
||||||
|
if (head == node) {
|
||||||
|
headCopy = copy;
|
||||||
|
}
|
||||||
|
copiedNodes.put(node, copy);
|
||||||
|
nodesAndCopies.add(copy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collectVariablesToCopy() {
|
||||||
|
DefinitionExtractor definitionExtractor = new DefinitionExtractor();
|
||||||
|
IntSet varsToCopy = new IntOpenHashSet();
|
||||||
|
for (int node : copiedNodes.keys().toArray()) {
|
||||||
|
BasicBlock block = program.basicBlockAt(node);
|
||||||
|
for (Instruction insn : block.getInstructions()) {
|
||||||
|
insn.acceptVisitor(definitionExtractor);
|
||||||
|
for (Variable var : definitionExtractor.getDefinedVariables()) {
|
||||||
|
varsToCopy.add(var.getIndex());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (Phi phi : block.getPhis()) {
|
||||||
|
varsToCopy.add(phi.getReceiver().getIndex());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] orderedVarsToCopy = varsToCopy.toArray();
|
||||||
|
Arrays.sort(orderedVarsToCopy);
|
||||||
|
for (int var : orderedVarsToCopy) {
|
||||||
|
copiedVars.put(var, program.createVariable().getIndex());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copyCondition() {
|
||||||
|
InstructionVariableMapper variableMapper = new InstructionVariableMapper() {
|
||||||
|
@Override
|
||||||
|
protected Variable map(Variable var) {
|
||||||
|
return program.variableAt(copiedVars.getOrDefault(var.getIndex(), var.getIndex()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
BasicBlockMapper blockMapper = new BasicBlockMapper() {
|
||||||
|
@Override
|
||||||
|
protected BasicBlock map(BasicBlock block) {
|
||||||
|
return program.basicBlockAt(copiedNodes.getOrDefault(block.getIndex(), block.getIndex()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
InstructionCopyReader copier = new InstructionCopyReader(program);
|
||||||
|
for (int node : copiedNodes.keys().toArray()) {
|
||||||
|
BasicBlock sourceBlock = program.basicBlockAt(node);
|
||||||
|
BasicBlock targetBlock = program.basicBlockAt(copiedNodes.get(node));
|
||||||
|
copier.resetLocation();
|
||||||
|
for (int i = 0; i < sourceBlock.instructionCount(); ++i) {
|
||||||
|
sourceBlock.readInstruction(i, copier);
|
||||||
|
Instruction insn = copier.getCopy();
|
||||||
|
insn.acceptVisitor(variableMapper);
|
||||||
|
insn.acceptVisitor(blockMapper);
|
||||||
|
targetBlock.getInstructions().add(insn);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Phi phi : sourceBlock.getPhis()) {
|
||||||
|
Phi phiCopy = new Phi();
|
||||||
|
int receiver = phi.getReceiver().getIndex();
|
||||||
|
phiCopy.setReceiver(program.variableAt(copiedVars.getOrDefault(receiver, receiver)));
|
||||||
|
for (Incoming incoming : phi.getIncomings()) {
|
||||||
|
Incoming incomingCopy = new Incoming();
|
||||||
|
int source = incoming.getSource().getIndex();
|
||||||
|
int value = incoming.getValue().getIndex();
|
||||||
|
incomingCopy.setSource(program.basicBlockAt(copiedNodes.getOrDefault(source, source)));
|
||||||
|
incomingCopy.setValue(program.variableAt(copiedVars.getOrDefault(value, value)));
|
||||||
|
phiCopy.getIncomings().add(incomingCopy);
|
||||||
|
}
|
||||||
|
targetBlock.getPhis().add(phi);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (TryCatchBlock tryCatch : sourceBlock.getTryCatchBlocks()) {
|
||||||
|
TryCatchBlock tryCatchCopy = new TryCatchBlock();
|
||||||
|
int var = tryCatch.getExceptionVariable().getIndex();
|
||||||
|
int handler = tryCatch.getHandler().getIndex();
|
||||||
|
tryCatchCopy.setExceptionType(tryCatch.getExceptionType());
|
||||||
|
tryCatchCopy.setExceptionVariable(program.variableAt(copiedVars.getOrDefault(var, var)));
|
||||||
|
tryCatchCopy.setHandler(program.basicBlockAt(copiedNodes.getOrDefault(handler, handler)));
|
||||||
|
targetBlock.getTryCatchBlocks().add(tryCatchCopy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Back edges from body are not back edges anymore, instead they point to a copied condition.
|
||||||
|
*/
|
||||||
|
private void moveBackEdges() {
|
||||||
|
BasicBlockMapper mapper = new BasicBlockMapper() {
|
||||||
|
@Override
|
||||||
|
protected BasicBlock map(BasicBlock block) {
|
||||||
|
return block.getIndex() == head ? program.basicBlockAt(headCopy) : block;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int node : nodes.toArray()) {
|
||||||
|
BasicBlock block = program.basicBlockAt(node);
|
||||||
|
Instruction last = block.getLastInstruction();
|
||||||
|
if (last != null) {
|
||||||
|
last.acceptVisitor(mapper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Original head becomes start of `if (condition)`, it's not loop head anymore.
|
||||||
|
* Hence we don't need phi inputs that come from back edges.
|
||||||
|
*/
|
||||||
|
private void removeInternalPhiInputsFromCondition() {
|
||||||
|
BasicBlock block = program.basicBlockAt(head);
|
||||||
|
for (Phi phi : block.getPhis()) {
|
||||||
|
List<Incoming> incomings = phi.getIncomings();
|
||||||
|
for (int i = 0; i < incomings.size(); ++i) {
|
||||||
|
Incoming incoming = incomings.get(i);
|
||||||
|
if (nodes.contains(incoming.getSource().getIndex())) {
|
||||||
|
incomings.remove(i--);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Head copy is not a loop head anymore and there aren't transition from outside of former loop,
|
||||||
|
* therefore delete all external phi inputs.
|
||||||
|
*/
|
||||||
|
private void removeExternalPhiInputsFromConditionCopy() {
|
||||||
|
BasicBlock block = program.basicBlockAt(headCopy);
|
||||||
|
for (Phi phi : block.getPhis()) {
|
||||||
|
List<Incoming> incomings = phi.getIncomings();
|
||||||
|
for (int i = 0; i < incomings.size(); ++i) {
|
||||||
|
Incoming incoming = incomings.get(i);
|
||||||
|
if (!nodesAndCopies.contains(incoming.getSource().getIndex())) {
|
||||||
|
incomings.remove(i--);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variables defined in condition should be converted to phis in a new loop head (i.e. condition end).
|
||||||
|
* Every reference to variable from old condition must be replaced by reference to corresponding phi.
|
||||||
|
*/
|
||||||
|
private void putNewPhis() {
|
||||||
|
BasicBlock head = program.basicBlockAt(conditionEnd);
|
||||||
|
IntIntMap phiMap = new IntIntOpenHashMap();
|
||||||
|
|
||||||
|
int[] vars = copiedVars.keys().toArray();
|
||||||
|
Arrays.sort(vars);
|
||||||
|
for (int var : vars) {
|
||||||
|
Phi phi = new Phi();
|
||||||
|
phi.setReceiver(program.createVariable());
|
||||||
|
phiMap.put(var, phi.getReceiver().getIndex());
|
||||||
|
head.getPhis().add(phi);
|
||||||
|
|
||||||
|
for (int source : cfg.incomingEdges(conditionEnd)) {
|
||||||
|
int inputVar = copiedNodes.containsKey(source) ? var : copiedVars.get(var);
|
||||||
|
Incoming incoming = new Incoming();
|
||||||
|
incoming.setValue(program.variableAt(inputVar));
|
||||||
|
incoming.setSource(program.basicBlockAt(source));
|
||||||
|
phi.getIncomings().add(incoming);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InstructionVariableMapper mapper = new InstructionVariableMapper() {
|
||||||
|
@Override
|
||||||
|
protected Variable map(Variable var) {
|
||||||
|
int index = var.getIndex();
|
||||||
|
return program.variableAt(phiMap.getOrDefault(index, index));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for (int node : nodes.toArray()) {
|
||||||
|
if (copiedNodes.containsKey(node)) {
|
||||||
|
BasicBlock block = program.basicBlockAt(node);
|
||||||
|
for (Instruction instruction : block.getInstructions()) {
|
||||||
|
instruction.acceptVisitor(mapper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -649,7 +649,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<MethodOptimization> getOptimizations() {
|
private List<MethodOptimization> getOptimizations() {
|
||||||
return Arrays.asList(new ArrayUnwrapMotion(), new LoopInvariantMotion(),
|
return Arrays.asList(new ArrayUnwrapMotion(), new LoopInversion(), new LoopInvariantMotion(),
|
||||||
new GlobalValueNumbering(), new UnusedVariableElimination());
|
new GlobalValueNumbering(), new UnusedVariableElimination());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user