-
Notifications
You must be signed in to change notification settings - Fork 571
Add inlining for runEffFnN/mkEffFnN #3026
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
Conversation
| isNFn prefix n (Var _ name) = name == (prefix <> T.pack (show n)) | ||
| isNFn prefix n (Indexer _ (StringLiteral _ name) (Var _ dataFunctionUncurried)) | dataFunctionUncurried == C.dataFunctionUncurried = | ||
| isNFn :: Text -> Text -> Int -> AST -> Bool | ||
| isNFn _ prefix n (Var _ name) = name == (prefix <> T.pack (show n)) |
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 think this line (preserved from the existing code) means that all runFnX defined in some arbitrary local module are inlined by this same scheme (verified this with an example) - shouldn't it only apply to the target module as per the next clause?
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.
It certainly seems like it. Is it possible to break the current code?
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.
Yes, I defined in my Main module
runFn3 f a b c = f a b cand application of this was inlined, leading to runtime failure. I think this line can just be removed, the optimisation still seems to apply otherwise - I just don't understand what case this was meant to address.
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.
Ok great, could you please add a test for that then, to make sure it doesn't break any more? Thanks.
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.
Removing the line sounds fine to me if it works.
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.
Hmm, I didn't realise the compiled test output actually gets run, for some reason I thought there were just compiles/warns/errors tests.
|
Hah! I worked this up last night, and my version was exactly the same, modulo function names. One thing that I think really needs to be solved though, is that the compiler will insert something like this in magic do blocks (if you use case/if): main = function __do () {
foo = bar();
(function () {
var $1 = ...;
if ($1 ...) {
return someEff;
}
return otherEff;
})()();
return unit;
}This is a problem because with EffFn inlining, you lose a significant optimization opportunity: (function () {
if (...) {
return function () {
return someEffFn(1, 2, 3);
}
}
return function () {
return someEffFn(4, 5, 6);
}
})()()If we floated that call into the leaves (I think |
|
FWIW, I'm working converting halogen-vdom to EffFn, so we can compare output and performance. |
|
Oops. So I verified that the simple binding in magic-do just becomes a straight call: function __do() {
...
$foreign.log2("Hello", "World");
...
}But yeah this is just the case for the straightforward discard or binding cases of the magic-do optimisation. |
|
I added this case to undo (App _ (App s1 (Function s2 Nothing [] (Block ss body)) []) []) =
App s1 (Function s2 Nothing [] (Block ss (applyReturns `fmap` body))) [] |
From natefaubion purescript#3026 (comment)
|
Yup, I can see that working in my example. Feel free to PR any other changes to this branch if that would be easiest? |
|
Another change I made was to do |
|
Just using |
| -- Remove __do function applications which remain after desugaring | ||
| undo :: AST -> AST | ||
| undo (Return _ (App _ (Function _ (Just ident) [] body) [])) | ident == fnName = body | ||
| undo (App _ (App s1 (Function s2 Nothing [] (Block ss body)) []) []) = |
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'm not sure why this case is needed, but it makes the code harder to read in my opinion. applyReturns is only used in convert right now, and undo runs after the full traversal.
Can you give an example of why this is necessary? Is it possible to accomplish the same thing by modifying the convert function?
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.
Defer to @natefaubion here. But the example code is in #3026 (comment) - with this change an extra thunk is removed.
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 made a PR to this branch that rearranges the optimizations, and removes undo in favor of running convert to a fixed point. The problem was that some cases that covert inlines only arise after undo is run.
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.
Oh I didn't get a notification, sorry
Apply magicDo until fixed point
|
Given the new Also, since this code is quite fragile, we should try to build the package set, and actually run some package test suites to make sure nothing gets broken. |
|
Maybe the fixed point isn't necessary? It should stabilize after another run, So maybe you'd just need to split up convert into two functions, and inline the repetition. |
|
Removed the case that was firing on local definitions rather than the particular module name, now there is a test failure for |
|
If you merge master, the failure should go away. |
|
We can try this out extensively once the release candidate is done, just to make sure there isn't a significant performance regression. Thanks! |
paf31
left a comment
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.
👍 Thanks!
Reusing the same inlining code from runFnN/mkFnN