-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[semantic-arc] Change StorageGuaranteesLoadVisitor::visitClassAccess to find borrow scope introducers using utilities from OwnershipUtils.h. #30069
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
@atrick the biggest change in the patterns we support is not we can promote load [copy] -> load_borrow if our guaranteed base is switched or casted upon via switch_enums, checked_cast_br. I.e. we can transform this:
Into this:
|
@swift-ci test |
@swift-ci test source compatibility |
@swift-ci benchmark |
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 changes to semantic ARC look correct to me. The new utility just doesn't make sense... because it's reason for existing is based entirely on some nonsense in the original implementation...
lib/SIL/OwnershipUtils.cpp
Outdated
|
||
BorrowScopeIntroducingValueGenerator::Result | ||
BorrowScopeIntroducingValueGenerator::next() { | ||
while (!worklist.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.
I don't like the idea of a worklist here because it contradicts the basic design of a single borrow introducer for each scope.
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.
What if I have a struct literal that has multiple guaranteed parameters lets say from different sil function arguments.
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.
In such a case, I think we would need to return both borrow introducers.
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, if we allow a borrowed tuple or struct to be composed from borrowed elements, then this utility makes sense. The only thing I don't like is the general code that places all operands on the worklist. I feel like forwarding instructions (casts) should have an API that returns the single forwarded operand. And tuple/struct should be handled explicitly as the only thing that can "merge" borrow scopes.
There should be no reason to allow cond_br to handle borrowed values. No passes require critical edges in the mandatory pipeline. If it's done temporarily until we get around to enforcing that, then it should be a FIXME.
lib/SIL/OwnershipUtils.cpp
Outdated
// instruction | ||
if (isGuaranteedForwardingValue(v)) { | ||
if (auto *i = v->getDefiningInstruction()) { | ||
llvm::transform(i->getAllOperands(), std::back_inserter(worklist), |
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.
Any forwarding instruction should identify the single operand that it forwards. We shouldn't just arbitrarily dump all the operands on a worklist.
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 is nonsense to forward multiple guaranteed values into a single scope.
lib/SIL/OwnershipUtils.cpp
Outdated
auto *arg = cast<SILPhiArgument>(v); | ||
auto *termInst = arg->getSingleTerminator(); | ||
assert(termInst && termInst->isTransformationTerminator()); | ||
llvm::transform(termInst->getAllOperands(), std::back_inserter(worklist), |
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 here, a forwarding terminator should identify the single operand that it forwards
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 fine with doing that.
lib/SIL/OwnershipUtils.cpp
Outdated
namespace { | ||
|
||
/// A generator of borrow scope introducing values. | ||
struct BorrowScopeIntroducingValueGenerator { |
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 we want this abstraction at all.... see comments below.
Performance: -OCode size: -OPerformance: -Osize
Code size: -OsizePerformance: -Onone
Code size: -swiftlibsHow to read the dataThe tables contain differences in performance which are larger than 8% and differences in code size which are larger than 1%.If you see any unexpected regressions, you should consider fixing the Noise: Sometimes the performance results (not code size!) contain false Hardware Overview
|
I am going to swing back around and clean this up a little bit/add some more comments/etc before this lands. |
…to find borrow scope introducers using utilities from OwnershipUtils.h. I added a new API into OwnershipUtils called getSingleBorrowIntroducingValue. This API returns a single BorrowScopeIntroducingValue for a passed in guaranteed value. If we can not find such a BorrowScopeIntroducingValue or we find multiple such, we return None. Using that, I refactored StorageGuaranteesLoadVisitor::visitClassAccess(...) to use this new API which should make it significantly more robust since the routine uses the definitions of "guaranteed forwarding" that the ownership verifier uses when it verifies meaning that we can rely on the routine to be exhaustive and correct. This means that we now promote load [copy] -> load_borrow even if our borrow scope introducer feeds through a switch_enum or checked_cast_br result (the main reason I looked into this change). To create getSingleBorrowIntroducingValue, I refactored getUnderlyingBorrowIntroucingValues to use a generator to find all of its underlying values. Then in getSingleBorrowIntroducingValue, I just made it so that we call the generator 1-2 times (as appropriate) to implement this query.
46efc9a
to
962b4ed
Compare
@swift-ci smoke test |
@swift-ci benchmark |
1 similar comment
@swift-ci benchmark |
Performance: -O
Code size: -OPerformance: -Osize
Code size: -OsizePerformance: -Onone
Code size: -swiftlibsHow to read the dataThe tables contain differences in performance which are larger than 8% and differences in code size which are larger than 1%.If you see any unexpected regressions, you should consider fixing the Noise: Sometimes the performance results (not code size!) contain false Hardware Overview
|
I added a new API into OwnershipUtils called
getSingleBorrowIntroducingValue. This API returns a single
BorrowScopeIntroducingValue for a passed in guaranteed value. If we can not find
such a BorrowScopeIntroducingValue or we find multiple such, we return None.
Using that, I refactored StorageGuaranteesLoadVisitor::visitClassAccess(...) to
use this new API which should make it significantly more robust since the
routine uses the definitions of "guaranteed forwarding" that the ownership
verifier uses when it verifies meaning that we can rely on the routine to be
exhaustive and correct. This means that we now promote load [copy] ->
load_borrow even if our borrow scope introducer feeds through a switch_enum or
checked_cast_br result (the main reason I looked into this change).
To create getSingleBorrowIntroducingValue, I refactored
getUnderlyingBorrowIntroucingValues to use a generator to find all of its
underlying values. Then in getSingleBorrowIntroducingValue, I just made it so
that we call the generator 1-2 times (as appropriate) to implement this query.