Rewriting MiniIRPass processing to queue - much easier for profiling each mini pass

This commit is contained in:
Jaroslav Tulach 2024-10-14 11:09:48 +02:00
parent c84e8815f1
commit 0964711ba9

View File

@ -1,54 +1,89 @@
package org.enso.compiler.pass;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import org.enso.compiler.core.IR;
import org.enso.compiler.core.ir.Expression;
import org.enso.compiler.core.ir.Module;
/** Implementation of {@link MiniIRPass#compile}. */
final class MiniPassTraverser {
private MiniPassTraverser() {}
private final MiniIRPass miniPass;
private List<IR> in;
private final List<IR> out;
private int outIndex;
static IR compileRecursively(IR ir, MiniIRPass miniPass) {
var preparedMiniPass =
switch (ir) {
case Module m -> miniPass.prepareForModule(m);
case Expression e -> miniPass.prepare(e);
default -> throw new IllegalArgumentException("" + ir);
};
IR newIr;
var childExpressions = new ArrayList<Expression>();
private MiniPassTraverser(MiniIRPass miniPass, List<IR> out, int outIndex) {
this.miniPass = miniPass;
this.out = out;
this.outIndex = outIndex;
}
private boolean enqueue(Collection<MiniPassTraverser> queue) {
if (in == null) {
var ir = out.get(outIndex);
in = enqueueSubExpressions(queue, ir, miniPass);
return !in.isEmpty();
} else {
return false;
}
}
private void convertExpression() {
if (outIndex != -1) {
var oldIr = out.get(outIndex);
var index = new int[1];
var newIr = oldIr.mapExpressions((old) -> (Expression) in.get(index[0]++));
var transformedIr =
switch (newIr) {
case Module m -> miniPass.transformModule(m);
case Expression e -> miniPass.transformExpression(e);
default -> throw new IllegalArgumentException("" + oldIr);
};
if (oldIr != transformedIr) {
out.set(outIndex, transformedIr);
}
outIndex = -1;
}
}
static IR compileDeep(IR root, MiniIRPass miniPass) {
var result = new IR[] {root};
var rootTask = new MiniPassTraverser(miniPass, Arrays.asList(result), 0);
var stackOfPendingIrs = new LinkedList<MiniPassTraverser>();
stackOfPendingIrs.add(rootTask);
while (!stackOfPendingIrs.isEmpty()) {
if (stackOfPendingIrs.peekLast().enqueue(stackOfPendingIrs)) {
// continue descent
continue;
}
var deepestIr = stackOfPendingIrs.removeLast();
deepestIr.convertExpression();
}
assert result[0] != null;
return result[0];
}
/**
* @param queue queue to put objects in
* @param ir IR to process
* @param miniPass process with this mini pass
* @return {@code true} if the has been modified with new tries to process first
*/
private static List<IR> enqueueSubExpressions(
Collection<MiniPassTraverser> queue, IR ir, MiniIRPass miniPass) {
var childExpressions = new ArrayList<IR>();
var i = new int[1];
ir.mapExpressions(
(ch) -> {
var preparedMiniPass = miniPass.prepare(ir, ch);
childExpressions.add(ch);
queue.add(new MiniPassTraverser(preparedMiniPass, childExpressions, i[0]++));
return ch;
});
if (childExpressions.isEmpty()) {
newIr = ir;
} else {
var changed = false;
for (var i = 0; i < childExpressions.size(); i++) {
var child = childExpressions.get(i);
var newChild = (Expression) compileRecursively(child, preparedMiniPass);
if (child == newChild) {
continue;
}
changed = true;
childExpressions.set(i, newChild);
}
if (changed) {
var index = new int[1];
newIr = ir.mapExpressions((old) -> childExpressions.get(index[0]++));
} else {
newIr = ir;
}
}
var transformedIr =
switch (newIr) {
case Module m -> miniPass.transformModule(m);
case Expression e -> miniPass.transformExpression(e);
default -> throw new IllegalArgumentException("" + newIr);
};
return transformedIr;
return childExpressions;
}
}