mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -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 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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)) {
|
||||
BreakStatement breakStmt = new BreakStatement();
|
||||
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;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.teavm.common.Graph;
|
||||
import org.teavm.common.GraphBuilder;
|
||||
import org.teavm.model.*;
|
||||
import org.teavm.model.instructions.*;
|
||||
import org.teavm.model.BasicBlock;
|
||||
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 {
|
||||
private ProgramUtils() {
|
||||
}
|
||||
|
@ -81,8 +89,6 @@ public final class ProgramUtils {
|
|||
|
||||
public static Program copy(ProgramReader program) {
|
||||
Program copy = new Program();
|
||||
InstructionCopyReader insnCopier = new InstructionCopyReader();
|
||||
insnCopier.programCopy = copy;
|
||||
for (int i = 0; i < program.variableCount(); ++i) {
|
||||
Variable var = copy.createVariable();
|
||||
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) {
|
||||
List<Instruction> result = new ArrayList<>();
|
||||
InstructionCopyReader copyReader = new InstructionCopyReader();
|
||||
copyReader.programCopy = target;
|
||||
InstructionCopyReader copyReader = new InstructionCopyReader(target);
|
||||
for (int i = from; i < to; ++i) {
|
||||
block.readInstruction(i, copyReader);
|
||||
copyReader.copy.setLocation(copyReader.location);
|
||||
result.add(copyReader.copy);
|
||||
result.add(copyReader.getCopy());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -145,394 +149,4 @@ public final class ProgramUtils {
|
|||
}
|
||||
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() {
|
||||
return Arrays.asList(new ArrayUnwrapMotion(), new LoopInvariantMotion(),
|
||||
return Arrays.asList(new ArrayUnwrapMotion(), new LoopInversion(), new LoopInvariantMotion(),
|
||||
new GlobalValueNumbering(), new UnusedVariableElimination());
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user