mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
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:
parent
8abf4797af
commit
3d69167280
6
.idea/scala_compiler.xml
Normal file
6
.idea/scala_compiler.xml
Normal 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>
|
|
@ -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) {
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user