Further work on incremental phi updater

This commit is contained in:
Alexey Andreev 2016-05-23 22:35:55 +03:00
parent 5ac195df5a
commit ca521f74f0
6 changed files with 205 additions and 101 deletions

View File

@ -19,10 +19,6 @@ import java.util.*;
import org.teavm.common.MutableGraphNode; import org.teavm.common.MutableGraphNode;
import org.teavm.model.*; import org.teavm.model.*;
/**
*
* @author Alexey Andreev
*/
class InterferenceGraphBuilder { class InterferenceGraphBuilder {
public List<MutableGraphNode> build(Program program, int paramCount, LivenessAnalyzer liveness) { public List<MutableGraphNode> build(Program program, int paramCount, LivenessAnalyzer liveness) {
List<MutableGraphNode> nodes = new ArrayList<>(); List<MutableGraphNode> nodes = new ArrayList<>();
@ -32,7 +28,7 @@ class InterferenceGraphBuilder {
UsageExtractor useExtractor = new UsageExtractor(); UsageExtractor useExtractor = new UsageExtractor();
DefinitionExtractor defExtractor = new DefinitionExtractor(); DefinitionExtractor defExtractor = new DefinitionExtractor();
InstructionTransitionExtractor succExtractor = new InstructionTransitionExtractor(); InstructionTransitionExtractor succExtractor = new InstructionTransitionExtractor();
List<List<Incoming>> outgoings = getOutgoings(program); List<List<Incoming>> outgoings = ProgramUtils.getPhiOutputs(program);
Set<MutableGraphNode> live = new HashSet<>(128); Set<MutableGraphNode> live = new HashSet<>(128);
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i); BasicBlock block = program.basicBlockAt(i);
@ -98,20 +94,4 @@ class InterferenceGraphBuilder {
} }
return nodes; return nodes;
} }
private List<List<Incoming>> getOutgoings(Program program) {
List<List<Incoming>> outgoings = new ArrayList<>(program.basicBlockCount());
for (int i = 0; i < program.basicBlockCount(); ++i) {
outgoings.add(new ArrayList<Incoming>());
}
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
for (Phi phi : block.getPhis()) {
for (Incoming incoming : phi.getIncomings()) {
outgoings.get(incoming.getSource().getIndex()).add(incoming);
}
}
}
return outgoings;
}
} }

View File

@ -15,12 +15,57 @@
*/ */
package org.teavm.model.util; package org.teavm.model.util;
import java.util.*; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.teavm.common.DominatorTree; import org.teavm.common.DominatorTree;
import org.teavm.common.Graph; import org.teavm.common.Graph;
import org.teavm.common.GraphUtils; import org.teavm.common.GraphUtils;
import org.teavm.model.*; import org.teavm.model.BasicBlock;
import org.teavm.model.instructions.*; import org.teavm.model.Incoming;
import org.teavm.model.Instruction;
import org.teavm.model.InvokeDynamicInstruction;
import org.teavm.model.Phi;
import org.teavm.model.Program;
import org.teavm.model.TryCatchBlock;
import org.teavm.model.Variable;
import org.teavm.model.instructions.ArrayLengthInstruction;
import org.teavm.model.instructions.AssignInstruction;
import org.teavm.model.instructions.BinaryBranchingInstruction;
import org.teavm.model.instructions.BinaryInstruction;
import org.teavm.model.instructions.BranchingInstruction;
import org.teavm.model.instructions.CastInstruction;
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.InstructionVisitor;
import org.teavm.model.instructions.IntegerConstantInstruction;
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.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.UnwrapArrayInstruction;
public class PhiUpdater { public class PhiUpdater {
private Program program; private Program program;
@ -30,13 +75,15 @@ public class PhiUpdater {
private BasicBlock currentBlock; private BasicBlock currentBlock;
private Phi[][] phiMap; private Phi[][] phiMap;
private int[][] phiIndexMap; private int[][] phiIndexMap;
private List<List<Phi>> synthesizedPhis = new ArrayList<>();
private boolean[] usedDefinitions;
public void updatePhis(Program program, Variable[] arguments) { public void updatePhis(Program program, Variable[] arguments) {
if (program.basicBlockCount() == 0) { if (program.basicBlockCount() == 0) {
return; return;
} }
this.program = program; this.program = program;
cfg = ProgramUtils.buildControlFlowGraphWithTryCatch(program); cfg = ProgramUtils.buildControlFlowGraph(program);
DominatorTree domTree = GraphUtils.buildDominatorTree(cfg); DominatorTree domTree = GraphUtils.buildDominatorTree(cfg);
domFrontiers = new int[cfg.size()][]; domFrontiers = new int[cfg.size()][];
variableMap = new Variable[program.variableCount()]; variableMap = new Variable[program.variableCount()];
@ -50,6 +97,12 @@ public class PhiUpdater {
phiIndexMap[i] = new int[program.variableCount()]; phiIndexMap[i] = new int[program.variableCount()];
} }
domFrontiers = GraphUtils.findDominanceFrontiers(cfg, domTree); domFrontiers = GraphUtils.findDominanceFrontiers(cfg, domTree);
synthesizedPhis.clear();
for (int i = 0; i < program.basicBlockCount(); ++i) {
synthesizedPhis.add(new ArrayList<>());
}
usedDefinitions = new boolean[program.variableCount()];
estimatePhis(); estimatePhis();
renameVariables(); renameVariables();
} }
@ -89,61 +142,54 @@ public class PhiUpdater {
} }
} }
List<List<TryCatchBlock>> caughtBlocks = new ArrayList<>(); List<List<Incoming>> phiOutputs = ProgramUtils.getPhiOutputs(program);
List<List<Phi>> specialPhis = new ArrayList<>();
for (int i = 0; i < program.basicBlockCount(); ++i) {
caughtBlocks.add(new ArrayList<>());
specialPhis.add(new ArrayList<>());
}
for (int i = 0; i < program.basicBlockCount(); ++i) {
for (TryCatchBlock tryCatch : program.basicBlockAt(i).getTryCatchBlocks()) {
caughtBlocks.get(tryCatch.getHandler().getIndex()).add(tryCatch);
}
}
boolean[] processed = new boolean[program.basicBlockCount()]; boolean[] processed = new boolean[program.basicBlockCount()];
while (head > 0) { while (head > 0) {
Task task = stack[--head]; Task task = stack[--head];
currentBlock = task.block; currentBlock = task.block;
if (processed[currentBlock.getIndex()]) { int index = currentBlock.getIndex();
if (processed[index]) {
continue; continue;
} }
processed[currentBlock.getIndex()] = true; processed[index] = true;
variableMap = Arrays.copyOf(task.variables, task.variables.length); variableMap = Arrays.copyOf(task.variables, task.variables.length);
for (Phi phi : currentBlock.getPhis()) {
for (Phi phi : synthesizedPhis.get(index)) {
Variable var = program.createVariable(); Variable var = program.createVariable();
var.getDebugNames().addAll(phi.getReceiver().getDebugNames()); var.getDebugNames().addAll(phi.getReceiver().getDebugNames());
variableMap[phi.getReceiver().getIndex()] = var; variableMap[phi.getReceiver().getIndex()] = var;
phi.setReceiver(var); phi.setReceiver(var);
} }
if (!caughtBlocks.get(currentBlock.getIndex()).isEmpty()) {
Phi phi = new Phi(); for (Phi phi : currentBlock.getPhis()) {
phi.setReceiver(program.createVariable()); phi.setReceiver(define(phi.getReceiver()));
for (TryCatchBlock tryCatch : caughtBlocks.get(currentBlock.getIndex())) {
variableMap[tryCatch.getExceptionVariable().getIndex()] = phi.getReceiver();
Set<String> debugNames = tryCatch.getExceptionVariable().getDebugNames();
tryCatch.setExceptionVariable(program.createVariable());
tryCatch.getExceptionVariable().getDebugNames().addAll(debugNames);
Incoming incoming = new Incoming();
incoming.setSource(tryCatch.getProtectedBlock());
incoming.setValue(tryCatch.getExceptionVariable());
phi.getIncomings().add(incoming);
}
specialPhis.get(currentBlock.getIndex()).add(phi);
} }
for (Instruction insn : currentBlock.getInstructions()) { for (Instruction insn : currentBlock.getInstructions()) {
insn.acceptVisitor(consumer); insn.acceptVisitor(consumer);
} }
int[] successors = domGraph.outgoingEdges(currentBlock.getIndex()); for (TryCatchBlock tryCatch : currentBlock.getTryCatchBlocks()) {
Variable var = tryCatch.getExceptionVariable();
if (var != null) {
tryCatch.setExceptionVariable(define(var));
}
}
for (Incoming output : phiOutputs.get(index)) {
output.setValue(use(output.getValue()));
}
int[] successors = domGraph.outgoingEdges(index);
for (int successor : successors) { for (int successor : successors) {
Task next = new Task(); Task next = new Task();
next.variables = Arrays.copyOf(variableMap, variableMap.length); next.variables = Arrays.copyOf(variableMap, variableMap.length);
next.block = program.basicBlockAt(successor); next.block = program.basicBlockAt(successor);
stack[head++] = next; stack[head++] = next;
} }
successors = cfg.outgoingEdges(currentBlock.getIndex()); successors = cfg.outgoingEdges(index);
for (int successor : successors) { for (int successor : successors) {
int[] phiIndexes = phiIndexMap[successor]; int[] phiIndexes = phiIndexMap[successor];
List<Phi> phis = program.basicBlockAt(successor).getPhis(); List<Phi> phis = synthesizedPhis.get(successor);
for (int j = 0; j < phis.size(); ++j) { for (int j = 0; j < phis.size(); ++j) {
Phi phi = phis.get(j); Phi phi = phis.get(j);
Variable var = variableMap[phiIndexes[j]]; Variable var = variableMap[phiIndexes[j]];
@ -156,9 +202,8 @@ public class PhiUpdater {
} }
} }
} }
}
for (int i = 0; i < specialPhis.size(); ++i) { program.basicBlockAt(index).getPhis().addAll(synthesizedPhis.get(index));
program.basicBlockAt(i).getPhis().addAll(specialPhis.get(i));
} }
} }
@ -174,13 +219,12 @@ public class PhiUpdater {
} }
for (int frontier : frontiers) { for (int frontier : frontiers) {
BasicBlock frontierBlock = program.basicBlockAt(frontier); BasicBlock frontierBlock = program.basicBlockAt(frontier);
frontierBlock.getPhis();
Phi phi = phiMap[frontier][var.getIndex()]; Phi phi = phiMap[frontier][var.getIndex()];
if (phi == null) { if (phi == null) {
phi = new Phi(); phi = new Phi();
phi.setReceiver(var); phi.setReceiver(var);
phiIndexMap[frontier][frontierBlock.getPhis().size()] = var.getIndex(); phiIndexMap[frontier][synthesizedPhis.get(frontier).size()] = var.getIndex();
frontierBlock.getPhis().add(phi); synthesizedPhis.get(frontier).add(phi);
phiMap[frontier][var.getIndex()] = phi; phiMap[frontier][var.getIndex()] = phi;
worklist[head++] = frontierBlock; worklist[head++] = frontierBlock;
} }
@ -189,7 +233,14 @@ public class PhiUpdater {
} }
private Variable define(Variable var) { private Variable define(Variable var) {
Variable result = program.createVariable(); Variable result;
if (!usedDefinitions[var.getIndex()]) {
usedDefinitions[var.getIndex()] = true;
result = var;
} else {
result = program.createVariable();
}
variableMap[var.getIndex()] = result; variableMap[var.getIndex()] = result;
return result; return result;
} }

View File

@ -59,30 +59,6 @@ public final class ProgramUtils {
return graphBuilder.build(); return graphBuilder.build();
} }
public static Graph buildControlFlowGraphWithTryCatch(Program program) {
GraphBuilder graphBuilder = new GraphBuilder(program.basicBlockCount());
InstructionTransitionExtractor transitionExtractor = new InstructionTransitionExtractor();
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
Instruction insn = block.getLastInstruction();
if (insn != null) {
insn.acceptVisitor(transitionExtractor);
if (transitionExtractor.getTargets() != null) {
for (BasicBlock successor : transitionExtractor.getTargets()) {
graphBuilder.addEdge(i, successor.getIndex());
for (TryCatchBlock succTryCatch : successor.getTryCatchBlocks()) {
graphBuilder.addEdge(i, succTryCatch.getHandler().getIndex());
}
}
}
}
for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) {
graphBuilder.addEdge(i, tryCatch.getHandler().getIndex());
}
}
return graphBuilder.build();
}
public static Map<InstructionLocation, InstructionLocation[]> getLocationCFG(Program program) { public static Map<InstructionLocation, InstructionLocation[]> getLocationCFG(Program program) {
return new LocationGraphBuilder().build(program); return new LocationGraphBuilder().build(program);
} }
@ -149,4 +125,22 @@ public final class ProgramUtils {
} }
return result; return result;
} }
public static List<List<Incoming>> getPhiOutputs(Program program) {
List<List<Incoming>> outputs = new ArrayList<>(program.basicBlockCount());
for (int i = 0; i < program.basicBlockCount(); ++i) {
outputs.add(new ArrayList<>());
}
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
for (Phi phi : block.getPhis()) {
for (Incoming incoming : phi.getIncomings()) {
outputs.get(incoming.getSource().getIndex()).add(incoming);
}
}
}
return outputs;
}
} }

View File

@ -15,12 +15,13 @@
*/ */
package org.teavm.optimization; package org.teavm.optimization;
import org.teavm.model.ElementModifier;
import org.teavm.model.MethodReader; import org.teavm.model.MethodReader;
import org.teavm.model.Program; import org.teavm.model.Program;
public class LoopInversion implements MethodOptimization { public class LoopInversion implements MethodOptimization {
@Override @Override
public void optimize(MethodReader method, Program program) { public void optimize(MethodReader method, Program program) {
new LoopInversionImpl(program).apply(); new LoopInversionImpl(program, method.parameterCount() + 1).apply();
} }
} }

View File

@ -38,8 +38,10 @@ import org.teavm.model.Instruction;
import org.teavm.model.Phi; import org.teavm.model.Phi;
import org.teavm.model.Program; import org.teavm.model.Program;
import org.teavm.model.TryCatchBlock; import org.teavm.model.TryCatchBlock;
import org.teavm.model.Variable;
import org.teavm.model.util.BasicBlockMapper; import org.teavm.model.util.BasicBlockMapper;
import org.teavm.model.util.InstructionCopyReader; import org.teavm.model.util.InstructionCopyReader;
import org.teavm.model.util.PhiUpdater;
import org.teavm.model.util.ProgramUtils; import org.teavm.model.util.ProgramUtils;
/** /**
@ -74,12 +76,15 @@ import org.teavm.model.util.ProgramUtils;
*/ */
class LoopInversionImpl { class LoopInversionImpl {
private final Program program; private final Program program;
private final int parameterCount;
private Graph cfg; private Graph cfg;
private DominatorTree dom; private DominatorTree dom;
private boolean postponed; private boolean postponed;
private boolean changed;
LoopInversionImpl(Program program) { LoopInversionImpl(Program program, int parameterCount) {
this.program = program; this.program = program;
this.parameterCount = parameterCount;
} }
void apply() { void apply() {
@ -90,9 +95,18 @@ class LoopInversionImpl {
List<LoopWithExits> loops = getLoopsWithExits(loopGraph); List<LoopWithExits> loops = getLoopsWithExits(loopGraph);
postponed = false; postponed = false;
if (!loops.isEmpty()) {
for (LoopWithExits loop : loops) { for (LoopWithExits loop : loops) {
loop.invert(); loop.invert();
} }
if (changed) {
Variable[] inputs = new Variable[parameterCount];
for (int i = 0; i < inputs.length; ++i) {
inputs[i] = program.variableAt(i);
}
new PhiUpdater().updatePhis(program, inputs);
}
}
} while (postponed); } while (postponed);
} }
@ -185,6 +199,7 @@ class LoopInversionImpl {
removeInternalPhiInputsFromCondition(); removeInternalPhiInputsFromCondition();
removeExternalPhiInputsFromConditionCopy(); removeExternalPhiInputsFromConditionCopy();
changed = true;
return true; return true;
} }

View File

@ -15,26 +15,89 @@
*/ */
package org.teavm.vm; package org.teavm.vm;
import java.io.*; import java.io.File;
import java.util.*; import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.ServiceLoader;
import java.util.Set;
import org.teavm.cache.NoCache; import org.teavm.cache.NoCache;
import org.teavm.codegen.*; import org.teavm.codegen.AliasProvider;
import org.teavm.codegen.DefaultAliasProvider;
import org.teavm.codegen.DefaultNamingStrategy;
import org.teavm.codegen.MinifyingAliasProvider;
import org.teavm.codegen.SourceWriter;
import org.teavm.codegen.SourceWriterBuilder;
import org.teavm.common.ServiceRepository; import org.teavm.common.ServiceRepository;
import org.teavm.debugging.information.DebugInformationEmitter; import org.teavm.debugging.information.DebugInformationEmitter;
import org.teavm.debugging.information.SourceLocation; import org.teavm.debugging.information.SourceLocation;
import org.teavm.dependency.*; import org.teavm.dependency.BootstrapMethodSubstitutor;
import org.teavm.dependency.DependencyChecker;
import org.teavm.dependency.DependencyInfo;
import org.teavm.dependency.DependencyListener;
import org.teavm.dependency.Linker;
import org.teavm.dependency.MethodDependency;
import org.teavm.diagnostics.AccumulationDiagnostics; import org.teavm.diagnostics.AccumulationDiagnostics;
import org.teavm.diagnostics.ProblemProvider; import org.teavm.diagnostics.ProblemProvider;
import org.teavm.javascript.*; import org.teavm.javascript.Decompiler;
import org.teavm.javascript.EmptyRegularMethodNodeCache;
import org.teavm.javascript.MethodNodeCache;
import org.teavm.javascript.Renderer;
import org.teavm.javascript.RenderingException;
import org.teavm.javascript.ast.ClassNode; import org.teavm.javascript.ast.ClassNode;
import org.teavm.javascript.spi.GeneratedBy; import org.teavm.javascript.spi.GeneratedBy;
import org.teavm.javascript.spi.Generator; import org.teavm.javascript.spi.Generator;
import org.teavm.javascript.spi.InjectedBy; import org.teavm.javascript.spi.InjectedBy;
import org.teavm.javascript.spi.Injector; import org.teavm.javascript.spi.Injector;
import org.teavm.model.*; import org.teavm.model.BasicBlock;
import org.teavm.model.instructions.*; import org.teavm.model.CallLocation;
import org.teavm.model.util.*; import org.teavm.model.ClassHolder;
import org.teavm.optimization.*; import org.teavm.model.ClassHolderSource;
import org.teavm.model.ClassHolderTransformer;
import org.teavm.model.ClassReader;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.ElementHolder;
import org.teavm.model.ElementModifier;
import org.teavm.model.InstructionLocation;
import org.teavm.model.ListableClassHolderSource;
import org.teavm.model.ListableClassReaderSource;
import org.teavm.model.MethodHolder;
import org.teavm.model.MethodReference;
import org.teavm.model.MutableClassHolderSource;
import org.teavm.model.Program;
import org.teavm.model.ProgramCache;
import org.teavm.model.ValueType;
import org.teavm.model.Variable;
import org.teavm.model.instructions.ConstructInstruction;
import org.teavm.model.instructions.InvocationType;
import org.teavm.model.instructions.InvokeInstruction;
import org.teavm.model.instructions.RaiseInstruction;
import org.teavm.model.instructions.StringConstantInstruction;
import org.teavm.model.util.AsyncMethodFinder;
import org.teavm.model.util.ListingBuilder;
import org.teavm.model.util.MissingItemsProcessor;
import org.teavm.model.util.ModelUtils;
import org.teavm.model.util.ProgramUtils;
import org.teavm.model.util.RegisterAllocator;
import org.teavm.optimization.ArrayUnwrapMotion;
import org.teavm.optimization.Devirtualization;
import org.teavm.optimization.GlobalValueNumbering;
import org.teavm.optimization.LoopInvariantMotion;
import org.teavm.optimization.LoopInversion;
import org.teavm.optimization.MethodOptimization;
import org.teavm.optimization.UnusedVariableElimination;
import org.teavm.vm.spi.RendererListener; import org.teavm.vm.spi.RendererListener;
import org.teavm.vm.spi.TeaVMHost; import org.teavm.vm.spi.TeaVMHost;
import org.teavm.vm.spi.TeaVMPlugin; import org.teavm.vm.spi.TeaVMPlugin;
@ -649,7 +712,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
} }
private List<MethodOptimization> getOptimizations() { private List<MethodOptimization> getOptimizations() {
return Arrays.asList(new ArrayUnwrapMotion(), /*new LoopInversion(),*/ new LoopInvariantMotion(), return Arrays.asList(new ArrayUnwrapMotion(), new LoopInversion(), new LoopInvariantMotion(),
new GlobalValueNumbering(), new UnusedVariableElimination()); new GlobalValueNumbering(), new UnusedVariableElimination());
} }