-
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
Migrate some passes to Mini passes #11191
Conversation
engine/runtime-compiler/src/main/java/org/enso/compiler/pass/MiniIRPass.java
Outdated
Show resolved
Hide resolved
engine/runtime-compiler/src/main/java/org/enso/compiler/pass/MiniPassFactory.java
Outdated
Show resolved
Hide resolved
engine/runtime-compiler/src/main/java/org/enso/compiler/pass/MiniPassTraverser.java
Outdated
Show resolved
Hide resolved
...ntime-integration-tests/src/test/java/org/enso/compiler/test/mini/passes/MiniPassTester.java
Show resolved
Hide resolved
engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/expression/Operator.scala
Outdated
Show resolved
Hide resolved
LambdaShorthandToLambda successfuly migrated to mini pass version, implemented by LambdaShorthandToLambdaMini and tested in LambdaShorthandToLambdaTest. This is an example of a pass that needs to use MiniIRPass.prepare method because it handles blank arguments of
The only hack I needed to introduce is a special handling for Please, provide your opinions and thoughts @JaroslavTulach , @hubertp and @4e6. |
...ime-compiler/src/main/scala/org/enso/compiler/pass/desugar/LambdaShorthandToLambdaMini.scala
Outdated
Show resolved
Hide resolved
...ime-compiler/src/main/scala/org/enso/compiler/pass/desugar/LambdaShorthandToLambdaMini.scala
Show resolved
Hide resolved
Jaroslav Tulach reports a new STANDUP for yesterday (2024-10-13): Progress: .
|
Isn't that the whole point of this exercise? Even if we are not gaining (or loosing) much in performance, I would feel more confident with merging this if we could prove that it works on those simple passes. |
(Alas) that's correct. Let's try it. Update: Done. Described at this comment. Also, to set the base benchmark state I did VisualVM profiling for ffd27df and while running
it is apparent we spent 300ms in and yet another 100ms later in tail call mini pass: There are tiny numbers in the whole compiler processing. Let's see what they do when we combine the passes. Anyway they also confirm there are unlikely to be any regressions as the mini passes execute quite quickly even right now when executed one by one. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am a bit hesitant to approve the PR (not only because GH won't let me since I am the original author of the PR). I am not entirely happy about the API in MiniIRPass
, but there is nothing better we can do at the moment. I like that MiniPassTraverser
is no longer recursive, but works with a job queue. I don't understand the implementation, but I trust it does its job.
What I don't like is the fact that TailCall.Mini
does all the work inside the prepare
phase, i.e., it attaches all the metadata in prepare
method, and does nothing in transform
. There are two problems with that. 1) Hard to profile - since you have to remember that for TailCall
, you need to profile prepare
and not transform
. 2) Wrong from the rational perspective. Originally, I even wanted to add an assert to the MiniPassTraverser
that the prepare
methods of minipasses not only change the IR itself, but don't modify any metadata there.
engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/analyse/TailCall.scala
Outdated
Show resolved
Hide resolved
engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/analyse/TailCall.scala
Outdated
Show resolved
Hide resolved
engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/analyse/TailCall.scala
Outdated
Show resolved
Hide resolved
Jaroslav Tulach reports a new STANDUP for yesterday (2024-10-14): Progress: .
|
Done in 2736a76, @hubertp. Described at this comment. |
flushMiniPass(intermediateIR) | ||
} else { | ||
intermediateIR | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The 2736a76 commit changes the PassManager
to combine subsequent mini passes unless the already collected passes prevent such combining by declaring newly collected pass to be invalidated by their changes. Imagine there is m.enso
file:
import Standard.Base.Runtime.Ref.Ref
main =
r = Ref.new "foo"
r.modify (_+"boo")
r.get
then the processing of the m.enso
file logs following info:
runPassesOnModule[m@AFTER_IMPORT_RESOLUTION]
mega running: MethodDefinitions
mini collected: org.enso.compiler.pass.desugar.SectionsToBinOp@784abd3e
mini collected: OperatorToFunction
mini collected: LambdaShorthandToLambda
pass OperatorToFunction forces flush before LambdaShorthandToLambda
flushing pending mini pass: org.enso.compiler.pass.desugar.SectionsToBinOp$Mini:org.enso.compiler.pass.desugar.OperatorToFunctionMini
flushing pending mini pass: org.enso.compiler.pass.desugar.LambdaShorthandToLambdaMini
mega running: ImportSymbolAnalysis
...
e.g. three mini passes are collected in this PassGroup
. Two of them are "flushed" together by a single IR traversal. The 3rd one is "flushed" separately before a subsequent mega pass is executed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The LambdaShorthandToLambda
is defined as being invalidated by OperatorToFunction
pass as it is known that LambdaShorthandToLambda
needs to see result of OperatorToFunction
in its prepare
method - that's only possible if the whole tree produced by OperatorToFunction
is fed into LambdaShorthandToLambda
- e.g. these two mini passes cannot be merged.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Imagine there is m.enso
file:
import Standard.Base.Runtime.Ref.Ref main = r = Ref.new "foo" r.modify (_+"boo") r.get
then the enso --log-level trace --run m.enso
file logs following info (after filtering the relevant parts):
[DEBUG] [2024-10-15T06:17:26.979] [org.enso.compiler.pass.PassManager] runPassesOnModule[m@INITIAL]
mega running: ModuleAnnotations
mega running: DocumentationComments
mega running: Imports
mega running: ComplexType
mega running: FunctionBinding
mega running: GenerateMethodBodies
mega running: BindingAnalysis
mega running: ModuleNameConflicts
[DEBUG] [2024-10-15T06:17:28.103] [org.enso.compiler.pass.PassManager] runPassesOnModule[m@AFTER_IMPORT_RESOLUTION]
mega running: MethodDefinitions
mini collected: org.enso.compiler.pass.desugar.SectionsToBinOp@784abd3e
mini collected: OperatorToFunction
mini collected: LambdaShorthandToLambda
pass OperatorToFunction forces flush before LambdaShorthandToLambda
flushing pending mini pass: org.enso.compiler.pass.desugar.SectionsToBinOp$Mini:org.enso.compiler.pass.desugar.OperatorToFunctionMini
flushing pending mini pass: org.enso.compiler.pass.desugar.LambdaShorthandToLambdaMini
mega running: ImportSymbolAnalysis
mega running: AmbiguousImportsAnalysis
mega running: org.enso.compiler.pass.analyse.PrivateModuleAnalysis@6540cf1d
mega running: org.enso.compiler.pass.analyse.PrivateConstructorAnalysis@ec8f4b9
mega running: ShadowedPatternFields
mega running: UnreachableMatchBranches
mega running: NestedPatternMatch
mega running: IgnoredBindings
mega running: TypeFunctions
mega running: TypeSignatures
[DEBUG] [2024-10-15T06:17:28.141] [org.enso.compiler.pass.PassManager] runPassesOnModule[m@AFTER_GLOBAL_TYPES]
mega running: ExpressionAnnotations
mega running: AliasAnalysis
mega running: FullyQualifiedNames
mega running: GlobalNames
mega running: TypeNames
mega running: org.enso.compiler.pass.resolve.MethodCalls$@bc042d5
mega running: org.enso.compiler.pass.resolve.FullyAppliedFunctionUses$@5484117b
mega running: AliasAnalysis
mega running: LambdaConsolidate
mega running: AliasAnalysis
mega running: SuspendedArguments
mega running: OverloadsResolution
mega running: AliasAnalysis
mega running: DemandAnalysis
mega running: AliasAnalysis
mini collected: TailCall
flushing pending mini pass: org.enso.compiler.pass.analyse.TailCall$Mini
mega running: org.enso.compiler.pass.resolve.Patterns$@36c2b646
mega running: org.enso.compiler.pass.analyse.PrivateSymbolsAnalysis@37df14d1
mega running: AliasAnalysis
mega running: FramePointerAnalysis
mega running: DataflowAnalysis
mega running: CachePreferenceAnalysis
mega running: GenericAnnotations
mega running: UnusedBindings
mega running: org.enso.compiler.pass.lint.NoSelfInStatic$@7efb53af
engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/analyse/TailCall.scala
Outdated
Show resolved
Hide resolved
engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/analyse/TailCall.scala
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have just uploaded minor suggestions, feel free to ignore them and integrate.
...untime-compiler/src/main/java/org/enso/compiler/pass/analyse/PrivateConstructorAnalysis.java
Show resolved
Hide resolved
|
||
/** An identifier for the pass. Useful for keying it in maps. */ | ||
val key: UUID @Identifier = IRPass.genId | ||
trait IRPass extends IRProcessingPass with ProcessingPass { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: What about renaming to MegaIRPass
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I leave that as an exercise for another contender that is using IDE with better refactoring capabilities ;-) Do it as part of
Btw. MiniPassFactory
should be MiniIRPass
and current MiniIRPass
should become something else. For example an MiniIRPass.Transformer
...
On behalf of @Akirathan and me I approve this PR. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am glad I could get my hands dirty with this PR. I feel I better understand motives behind our IR
. On behalf of Pavel and me, let's approve this change.
Jaroslav Tulach reports a new STANDUP for yesterday (2024-10-15): Progress: .
|
Pull Request Description
Gets ready for avoiding IR traversal by introducing mini passes as proposed by #10981:
IRProcessingPass
) to transform anIR
element to anotherIR
elementPassManager
to recognize such mini passes and treat them in a special way - by usingMiniIRPass.compile
MiniIRPass.compile
is usingIR.mapExpressions
to traverse theIR
- alternative approach withNewChildren rejected for now, see future work for detailsIRMiniPass.compile
does not recursively traverse, but with 0964711 it invokes each mini pass at constant stack depth - way better for profilingMiniIRPass.prepare
works on edges since ffd27df - there isIRMiniPass prepare(parent, child)
to collect information while pre-order traversing from a particularIR
parent to a particularIR
childPassManager
rewritten to group subsequent mini passes together byMiniIRPass.combine
and really and traverse theIR
just once - done in 2736a76LambdaShorthandToLambda
,OperatorToFunction
,SectionsToBinOp
andTailCall
IR
produced by old and new implementationsChecklist
Please ensure that the following checklist has been satisfied before submitting the PR:
Scala,
Java,
style guides.
IRPass
esIRPass
es by the mini passestest/*_Tests
continue to work with mini passesFuture Work
Pendings for some subsequent work: