-
Notifications
You must be signed in to change notification settings - Fork 323
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Avoid IR traversal by converting (some of) our Pass
es to mini passes
#10981
Comments
Pass
es to _mini passes_Pass
es to mini passes
When at it please design the traversing architecture to be ready for parallelization by fork join pool. |
Pavel Marek reports a new STANDUP for today (2024-09-26): Progress: - Skeleton of mini pass framework implementation in #11191
|
Pavel Marek reports a new STANDUP for today (2024-09-27): Progress: - Migrating
|
Pavel Marek reports a new STANDUP for today (2024-09-30): Progress: - Fix for unable to boot enso on MacOS - https://github.com/enso-org/enso/actions/runs/11104391535/job/30848357375?pr=11212
|
Pavel Marek reports a new STANDUP for today (2024-10-01): Progress: - Migrating
|
Pavel Marek reports a new STANDUP for today (2024-10-02): Progress: - Remove parentIr from the
|
Hello Pavel, I have a problem understanding following part of your standup:
As far as I see, there is no recursion in enso.master$ git diff
diff --git engine/runtime-parser/src/test/java/org/enso/compiler/core/EnsoParserTest.java engine/runtime-parser/src/test/java/org/enso/compiler/core/EnsoParserTest.java
index 256d415952..2596841789 100644
--- engine/runtime-parser/src/test/java/org/enso/compiler/core/EnsoParserTest.java
+++ engine/runtime-parser/src/test/java/org/enso/compiler/core/EnsoParserTest.java
@@ -37,6 +37,27 @@ public class EnsoParserTest {
""", true, true, true);
}
+ @Test
+ public void testApplicationShallowTraversal() {
+ var ir = compile("""
+ fn x y z = x ((y 2) (z 1))
+ """);
+ java.util.function.BiConsumer<String, IR> log =
+ (prefix, fst) -> {
+ System.out.println(prefix + fst.getClass().getSimpleName() + ":" + fst.showCode());
+ };
+ ir.mapExpressions(
+ (fst) -> {
+ log.accept("first level: ", fst);
+ fst.mapExpressions(
+ (snd) -> {
+ log.accept(" second level: ", snd);
+ return snd;
+ });
+ return fst;
+ });
+ }
+
@Test
public void testLocationsApplicationsAndMethodCalls() {
parseTest(""" it runs and prints:
e.g. only first and second level is iterated. Not the whole tree composed of
Is this claim based on the previous (not proved) one? Or is there some other reason why it doesn't seem possible? |
@JaroslavTulach Sorry for not being precise. Let's look closely at your example. Put "Deep traversal" should {
"XX work" in {
implicit val ctx: ModuleContext = mkModuleContext
def log(prefix: String, fst: IR) = {
println(prefix + fst.getClass.getSimpleName + ":" + fst.showCode())
}
val ir =
"""
|fn x y z = x ((y 2) (z 1))
|""".stripMargin.preprocessModule.analyse
// prefix is `x ((y 2) (z 1))` expression
val prefix = ir.bindings(0)
.asInstanceOf[Method.Explicit]
.body
.asInstanceOf[Function.Lambda]
.body
.asInstanceOf[Application.Prefix]
prefix.function.asInstanceOf[Name.Literal].name shouldEqual "x"
prefix.arguments should have size 1
val arg = prefix.arguments(0).asInstanceOf[CallArgument.Specified]
arg.value.isInstanceOf[Application.Prefix] shouldBe true
prefix.mapExpressions { fst =>
log("first level: ", fst)
fst.mapExpressions { snd =>
log(" second level: ", snd)
snd
}
}
}
} At the end of As you can see, the prefix direct children is
The relevant code is TL;DR; We cannot rely on |
OK, that's indeed a different problem than being recursive:
Yes, obviously |
Pavel Marek reports a new STANDUP for the provided date (2024-10-04): Progress: - More discussion about the design of the new API. Playing with some ideas.
|
Pavel Marek reports a new STANDUP for today (2024-10-09): Progress: - Moved the old mega passes to tests
|
Pavel Marek reports a new STANDUP for today (2024-10-10): Progress: - Working with traversal with only
|
Pavel Marek reports a new STANDUP for today (2024-10-11): Progress: - Further discussing about the mini pass IR traversal - letting Jaroslav implement tail call based on
|
Gets ready for avoiding IR traversal by introducing _mini passes_ as proposed by #10981: - creates [MiniPassFactory](762045a) (that extends common `IRProcessingPass`) to transform an `IR` element to another `IR` element - modifies `PassManager` to recognize such _mini passes_ and treat them in a special way - by using `MiniIRPass.compile` - `MiniIRPass.compile` is using `IR.mapExpressions` to traverse the `IR` - alternative approach [withNewChildren](1abc70d) rejected for now, see _future work_ for details - unlike _mega passes_ `IRMiniPass.compile` **does not recursively** traverse, but with 0964711 it invokes each _mini pass_ at constant stack depth - way better for profiling - `MiniIRPass.prepare` _works on edges_ since ffd27df - there is `IRMiniPass prepare(parent, child)` to collect information while pre-order traversing from a particular `IR` parent to a particular `IR` child - `PassManager` rewritten to group _subsequent mini passes_ together by `MiniIRPass.combine` and really and traverse the `IR` just once - done in 2736a76 - converted to _mini pass_: `LambdaShorthandToLambda`, `OperatorToFunction`, `SectionsToBinOp` and `TailCall` - tested for 1:1 compatibility by [converting original code to test code](f54ba6d) and _comparing `IR` produced by old and new_ implementations
After discussing this idea @hubertp pointed out there is a prior work - read at Miniphases: compilation using modular and efficient tree transformations.
Current State
Enso static compiler currently works on
IR
tree. The work is performed by many IR passes. EachPass
getsIR
tree as an input and is supposed to return copy of theIR
tree as output. This is very inefficient:IR
tree - yet they have to traverse it themselvesIR
tree escapes (from a point of escape analysis) - e.g. it has to be allocated on the heap - as it is too large/heterogenous to optimize by any compilerIR
on the heap we create unnecessary pressure on the GCGoal
Rather than passing the whole
IR
as data and letting eachPass
to implement the traversal itself, let's:PartialFunction<IR, IR>
PartialFunction<IR, IR>
IR
elementBy doing this we:
Impact
A lot of
Pass
es may be eligible for the mini passes approach. Usually they just invoketransformExpression
with a single partial function - all of them are eligible for rewrite:DemandAnalysis
GatherDiagnostics
ImportSymbolAnalysis
TailCall
OperatorToFunction
Pre-requisite
We need generic traversal function. Right now there is
ir.Expression.transformExpression
, but we need such atransform
function for everyIR
element. See:Update: At the end #11191 uses
IR.mapExpressions
to traverse the tree and things seem to work fine.The text was updated successfully, but these errors were encountered: