Refactor block mappers. Remove phi placement from loop inversion, since it's easier to make SSATransformer incremental and call it after each application of loop inversion

This commit is contained in:
Alexey Andreev 2016-05-14 23:36:19 +03:00
parent 8abf4797af
commit 3d69167280
9 changed files with 47 additions and 219 deletions

6
.idea/scala_compiler.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ScalaCompilerConfiguration">
<profile name="Maven 1" modules="teavm-samples-scala" />
</component>
</project>

View File

@ -15,6 +15,7 @@
*/
package org.teavm.model.util;
import java.util.function.IntUnaryOperator;
import org.teavm.model.*;
import org.teavm.model.instructions.*;
@ -22,8 +23,17 @@ import org.teavm.model.instructions.*;
*
* @author Alexey Andreev
*/
public abstract class BasicBlockMapper implements InstructionVisitor {
protected abstract BasicBlock map(BasicBlock block);
public class BasicBlockMapper implements InstructionVisitor {
private IntUnaryOperator mapFunction;
public BasicBlockMapper(IntUnaryOperator mapFunction) {
this.mapFunction = mapFunction;
}
private BasicBlock map(BasicBlock block) {
Program program = block.getProgram();
return program.basicBlockAt(mapFunction.applyAsInt(block.getIndex()));
}
public void transform(Program program) {
for (int i = 0; i < program.basicBlockCount(); ++i) {

View File

@ -33,15 +33,27 @@ public class InstructionVariableMapper implements InstructionVisitor {
}
public void apply(BasicBlock block) {
applyToInstructions(block);
applyToPhis(block);
applyToTryCatchBlocks(block);
}
public void applyToInstructions(BasicBlock block) {
for (Instruction insn : block.getInstructions()) {
insn.acceptVisitor(this);
}
}
public void applyToPhis(BasicBlock block) {
for (Phi phi : block.getPhis()) {
phi.setReceiver(map(phi.getReceiver()));
for (Incoming incoming : phi.getIncomings()) {
incoming.setValue(map(incoming.getValue()));
}
}
}
public void applyToTryCatchBlocks(BasicBlock block) {
for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) {
if (tryCatch.getExceptionVariable() != null) {
tryCatch.setExceptionVariable(map(tryCatch.getExceptionVariable()));

View File

@ -45,7 +45,10 @@ public class ProgramNodeSplittingBackend implements GraphSplittingBackend {
copies[i] = blockCopy.getIndex();
map.put(nodes[i], copies[i] + 1);
}
CopyBlockMapper copyBlockMapper = new CopyBlockMapper(map);
BasicBlockMapper copyBlockMapper = new BasicBlockMapper(block -> {
int mappedIndex = map.get(block);
return mappedIndex == 0 ? block : mappedIndex - 1;
});
for (int i = 0; i < copies.length; ++i) {
copyBlockMapper.transform(program.basicBlockAt(copies[i]));
}
@ -54,21 +57,4 @@ public class ProgramNodeSplittingBackend implements GraphSplittingBackend {
}
return copies;
}
private static class CopyBlockMapper extends BasicBlockMapper {
private IntIntMap map;
public CopyBlockMapper(IntIntMap map) {
this.map = map;
}
@Override
protected BasicBlock map(BasicBlock block) {
int mappedIndex = map.get(block.getIndex());
if (mappedIndex == 0) {
return block;
}
return block.getProgram().basicBlockAt(mappedIndex - 1);
}
}
}

View File

@ -136,15 +136,8 @@ public class RegisterAllocator {
JumpInstruction jumpInstruction = new JumpInstruction();
jumpInstruction.setTarget(phi.getBasicBlock());
copyBlock.getInstructions().add(jumpInstruction);
incoming.getSource().getLastInstruction().acceptVisitor(new BasicBlockMapper() {
@Override protected BasicBlock map(BasicBlock block) {
if (block == phi.getBasicBlock()) {
return copyBlock;
} else {
return block;
}
}
});
incoming.getSource().getLastInstruction().acceptVisitor(new BasicBlockMapper(block ->
block == phi.getBasicBlock().getIndex() ? copyBlock.getIndex() : block));
blockMap.put(source, copyBlock);
incoming.setSource(copyBlock);
source = copyBlock;

View File

@ -44,11 +44,7 @@ public class EmptyBlockElimination implements MethodOptimization {
}
lastNonEmpty = blockMapping[i];
}
new BasicBlockMapper() {
@Override protected BasicBlock map(BasicBlock block) {
return program.basicBlockAt(blockMapping[block.getIndex()]);
}
}.transform(program);
new BasicBlockMapper(block -> blockMapping[block]).transform(program);
for (int i = 0; i < program.basicBlockCount(); ++i) {
if (blockMapping[i] != i) {
program.deleteBasicBlock(i);

View File

@ -195,14 +195,8 @@ public class LoopInvariantMotion implements MethodOptimization {
for (int predIndex : graph.incomingEdges(headerIndex)) {
if (!dom.dominates(headerIndex, predIndex)) {
BasicBlock pred = program.basicBlockAt(predIndex);
pred.getLastInstruction().acceptVisitor(new BasicBlockMapper() {
@Override protected BasicBlock map(BasicBlock block) {
if (block == header) {
block = preheader;
}
return block;
}
});
pred.getLastInstruction().acceptVisitor(new BasicBlockMapper(
block -> block == header.getIndex() ? preheader.getIndex() : block));
}
}
return preheader.getIndex();

View File

@ -38,11 +38,8 @@ 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;
/**
@ -69,8 +66,8 @@ import org.teavm.model.util.ProgramUtils;
* where `condition` is a part of loop that has exits and `body` has no exits.
* More formally, we define *body start candidate* as a node which 1) dominates all of the "tails" (i.e. nodes
* that have edges to loop header), 2) does not dominate loop exits. *Body start* is a body start candidate
* that is not dominates by some other body start candidate. If body start does not exits, loop is
* not inversible.
* that is not dominated by some other body start candidate. If body start does not exits, loop is
* not invertible.
*
* Therefore, *body* is a set of nodes of the loop that are dominated by body start and
* all remaining nodes are *condition*.
@ -154,10 +151,7 @@ class LoopInversionImpl {
int bodyStart;
int copyStart;
int headCopy;
final IntIntMap copiedVars = new IntIntOpenHashMap();
final IntIntMap copiedNodes = new IntIntOpenHashMap();
final IntIntMap varDefinitionPoints = new IntIntOpenHashMap();
final IntIntMap newHeadPhiMap = new IntIntOpenHashMap();
boolean shouldSkip;
LoopWithExits(int head, LoopWithExits parent) {
@ -186,13 +180,10 @@ class LoopInversionImpl {
}
collectNodesToCopy();
collectVariablesToCopy();
copyCondition();
moveBackEdges();
putNewPhis();
removeInternalPhiInputsFromCondition();
removeExternalPhiInputsFromConditionCopy();
adjustOutputPhis();
return true;
}
@ -235,40 +226,8 @@ class LoopInversionImpl {
}
}
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());
varDefinitionPoints.put(var.getIndex(), node);
}
}
for (Phi phi : block.getPhis()) {
varsToCopy.add(phi.getReceiver().getIndex());
varDefinitionPoints.put(phi.getReceiver().getIndex(), node);
}
}
int[] orderedVarsToCopy = varsToCopy.toArray();
Arrays.sort(orderedVarsToCopy);
for (int var : orderedVarsToCopy) {
copiedVars.put(var, program.createVariable().getIndex());
}
}
private void copyCondition() {
InstructionVariableMapper variableMapper = new InstructionVariableMapper(var ->
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()));
}
};
BasicBlockMapper blockMapper = new BasicBlockMapper(block -> copiedNodes.getOrDefault(block, block));
InstructionCopyReader copier = new InstructionCopyReader(program);
for (int node : copiedNodes.keys().toArray()) {
@ -278,21 +237,18 @@ class LoopInversionImpl {
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)));
phiCopy.setReceiver(phi.getReceiver());
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)));
incomingCopy.setValue(incoming.getValue());
phiCopy.getIncomings().add(incomingCopy);
}
targetBlock.getPhis().add(phiCopy);
@ -300,10 +256,9 @@ class LoopInversionImpl {
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.setExceptionVariable(tryCatch.getExceptionVariable());
tryCatchCopy.setHandler(program.basicBlockAt(copiedNodes.getOrDefault(handler, handler)));
targetBlock.getTryCatchBlocks().add(tryCatchCopy);
}
@ -314,12 +269,7 @@ class LoopInversionImpl {
* 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;
}
};
BasicBlockMapper mapper = new BasicBlockMapper(block -> block == head ? headCopy : block);
for (int node : nodes.toArray()) {
BasicBlock block = program.basicBlockAt(node);
@ -359,128 +309,9 @@ class LoopInversionImpl {
Incoming incoming = incomings.get(i);
if (!nodesAndCopies.contains(incoming.getSource().getIndex())) {
incomings.remove(i--);
} else {
int var = incoming.getValue().getIndex();
incoming.setValue(program.variableAt(newHeadPhiMap.getOrDefault(var, var)));
}
}
}
}
/**
* Variables defined in condition should be converted to phis in a new loop head (i.e. body start).
* Every reference to variable from old condition must be replaced by reference to corresponding phi.
*/
private void putNewPhis() {
BasicBlock head = program.basicBlockAt(bodyStart);
IntIntMap phiMap = new IntIntOpenHashMap();
int[] vars = copiedVars.keys().toArray();
Arrays.sort(vars);
List<Phi> phisToAdd = new ArrayList<>();
for (int var : vars) {
int varCopy = copiedVars.get(var);
Phi phi = new Phi();
phi.setReceiver(program.createVariable());
phiMap.put(var, phi.getReceiver().getIndex());
newHeadPhiMap.put(varCopy, phi.getReceiver().getIndex());
phisToAdd.add(phi);
for (int source : cfg.incomingEdges(bodyStart)) {
if (!nodes.contains(source)) {
continue;
}
Incoming incoming = new Incoming();
incoming.setValue(program.variableAt(var));
incoming.setSource(program.basicBlockAt(source));
phi.getIncomings().add(incoming);
incoming = new Incoming();
incoming.setValue(program.variableAt(varCopy));
incoming.setSource(program.basicBlockAt(copiedNodes.get(source)));
phi.getIncomings().add(incoming);
}
}
InstructionVariableMapper mapper = new InstructionVariableMapper(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);
mapper.apply(block);
}
}
head.getPhis().addAll(phisToAdd);
}
private void adjustOutputPhis() {
IntIntMap phiMap = new IntIntOpenHashMap();
class PhiToAdd {
private final Phi phi;
private final BasicBlock target;
private PhiToAdd(Phi phi, BasicBlock target) {
this.phi = phi;
this.target = target;
}
}
List<PhiToAdd> phis = new ArrayList<>();
int[] vars = copiedVars.keys().toArray();
Arrays.sort(vars);
int[] exits = this.exits.toArray();
Arrays.sort(exits);
for (int exit : exits) {
for (int var : vars) {
int definedAt = varDefinitionPoints.get(var);
if (!dom.dominates(definedAt, exit)) {
continue;
}
int varCopy = copiedVars.get(var);
int copiedAt = copiedNodes.get(definedAt);
for (int successor : cfg.outgoingEdges(exit)) {
if (nodes.contains(successor)) {
continue;
}
Phi phi = new Phi();
phi.setReceiver(program.createVariable());
Incoming originalInput = new Incoming();
originalInput.setSource(program.basicBlockAt(definedAt));
originalInput.setValue(program.variableAt(var));
phi.getIncomings().add(originalInput);
Incoming copyInput = new Incoming();
copyInput.setSource(program.basicBlockAt(copiedAt));
copyInput.setValue(program.variableAt(varCopy));
phi.getIncomings().add(copyInput);
phis.add(new PhiToAdd(phi, program.basicBlockAt(successor)));
phiMap.put(var, phi.getReceiver().getIndex());
}
}
}
InstructionVariableMapper mapper = new InstructionVariableMapper(var -> {
int index = var.getIndex();
return program.variableAt(phiMap.getOrDefault(index, index));
});
for (int i = 0; i < cfg.size(); ++i) {
if (!nodes.contains(i)) {
mapper.apply(program.basicBlockAt(i));
}
}
for (PhiToAdd phiToAdd : phis) {
phiToAdd.target.getPhis().add(phiToAdd.phi);
}
}
}
}

View File

@ -649,7 +649,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
}
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());
}