-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[Optimize] Move dead partial apply elimination to mandatory combine #28536
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
[Optimize] Move dead partial apply elimination to mandatory combine #28536
Conversation
@gottesmm friendly ping. Does the general idea of this patch look good to you? |
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.
Are there any tests that exercise the old code? If not, do you mind adding one?
// Remove the stack dealloc, then the partial apply, then the function ref. | ||
instModCallbacks.deleteInst(user->getUser()); | ||
instModCallbacks.deleteInst(i); | ||
instModCallbacks.deleteInst(cast<FunctionRefInst>(i->getCallee())); |
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's unlikely but possible that the function_ref has other uses, so I'm not sure it's quite safe to remove it.
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.
Good point. I'll fix this.
@swift-ci Please smoke test |
@slavapestov this should mostly be a NFC. So, no tests should need to change. Do you mean I should add a test that only runs mandatory inlining (to make sure the closure isn't optimized)? |
instModCallbacks.deleteInst(i); | ||
// If the only use of the function_ref is us, then remove it. | ||
if (i->getCallee()->getSingleUse()->getUser() == i) | ||
instModCallbacks.deleteInst(cast<FunctionRefInst>(i->getCallee())); |
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 don't think you can guarantee that the callee is always going to be a function_ref. Can you add an isa check to make sure?
It's up to you if you want to add a SIL test that only runs mandatory combining or not (do please fix the unconditional cast though) |
@swift-ci Please smoke test |
return %5 : $Builtin.Int8 | ||
} | ||
|
||
sil shared [transparent] @identity_closure : $@convention(thin) (Builtin.Int8) -> Builtin.Int8 { |
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 ignoring the fact that this function no longer gets removed because it seems inline with the update in #28484
@@ -1088,7 +1012,7 @@ bb0(%0 : $C): | |||
// CHECK: [[F:%.*]] = function_ref @use_c | |||
// CHECK: apply [[F]]([[ARG]]) | |||
// CHECK: strong_release [[ARG]] | |||
// CHECK: strong_release [[ARG]] | |||
// TODO: why is this broken? |
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 need to figure out why there are too few strong_release
s here. Any ideas?
// CHECK-NEXT: br [[MERGE_BB]] | ||
// | ||
// CHECK: [[MERGE_BB]]: | ||
// TODO: strong_release [[ARG]] |
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 was able to fix the other strong_release
todos but I'm still looking into the cause of this one.
@slavapestov I've added I had to update this patch quite a bit to cover all the closure cleanup done in mandatory inlining, now it should cover all the cases that it used to.
|
…o that cleanupLoadedCalleeValue can work properly (and other small fixes)
@@ -1449,7 +1449,8 @@ static bool keepArgsOfPartialApplyAlive(PartialApplyInst *pai, | |||
|
|||
ValueLifetimeAnalysis::Frontier partialApplyFrontier; | |||
if (!vla.computeFrontier(partialApplyFrontier, | |||
ValueLifetimeAnalysis::DontModifyCFG)) { | |||
ValueLifetimeAnalysis::DontModifyCFG) || | |||
partialApplyFrontier.empty()) { |
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.
If partialApplyFrontier
is empty (and we don't return), we will create an alloc_stack
and copy_addr
but no dealloc_stack
.
@slavapestov and @gottesmm friendly ping. I've made sure that all the tests will pass after this patch is applied. Some of the tests appear to have been deleted but that either reflects an increase in deleted I realize this is a large patch so it may take a while to review. Let me know if you have any questions. |
@swift-ci please test. |
@swift-ci please test. |
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.
Some quick comments. I am going to want to relook at this after you make improvements/what we talked about over chat.
@@ -1943,3 +1944,102 @@ AbstractFunctionDecl *swift::getBaseMethod(AbstractFunctionDecl *FD) { | |||
} | |||
return FD; | |||
} | |||
|
|||
SILValue swift::stripCopiesAndBorrows(SILValue v) { | |||
while (isa<CopyValueInst>(v) || isa<BeginBorrowInst>(v)) { |
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 we already have a routine like this. I would look around.
@@ -201,11 +203,6 @@ bool MandatoryCombiner::doOneIteration(SILFunction &function, | |||
); | |||
} | |||
|
|||
for (SILInstruction *instruction : instructionsPendingDeletion) { |
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.
Why is this removed?
} | ||
} | ||
|
||
if (auto *convFunc = dyn_cast<ConvertFunctionInst>(val)) { |
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.
This is not needed. Should happen automatically when we go back around.
} | ||
} | ||
} else if (auto *tttf = dyn_cast<ThinToThickFunctionInst>(src)) { | ||
if (tryDeleteDeadClosure(tttf, instModCallbacks)) { |
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.
Most of the optimizations here should not be on LoadInst. You aren't removing load inst anywhere! Instead, all of these should be on the actual instructions you are removing (i.e. ThinToThick, Partial, Etc).
* remove mand inlining changes * update combiner to be more like a "combiner" * delete trivially dead instructions * promote loads * don't delete instructions in the callback
I'll make all these changes as their own (smaller, more focused) PRs. |
This patch moves the removal of dead partial applies to mandatory combine (from mandatory inlining). SourceKit doesn't run mandatory combine but, it does run mandatory inlining, so the more we can move out of mandatory inlining, the better.
refs #28484 #28394 #28396
cc @gottesmm