Skip to content

[sil-inst-opt] Change InstModCallbacks to specify a setUseValue callback instead of RAUW callbacks. #35256

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

Merged

Conversation

gottesmm
Copy link
Contributor

@gottesmm gottesmm commented Jan 5, 2021

NOTE: This PR contains two changes. The first commit (4600aa7) is the meat and I included the commit message below. The other commit is just follow up changes to #35253 the predecessor PR of this PR.


[sil-inst-opt] Change InstModCallbacks to specify a setUseValue callback instead of RAUW callbacks.

This allows for me to do a couple of things improving quality/correctness/ease of use:

  1. I reimplemented InstMod's RAUW and RAUW/erase helpers on top of
    setUseValue/deleteInst. Beyond allowing the caller to specify less things, we
    gain an orthogonality preventing bugs like overriding erase/RAUW but not
    overriding erase or having the erase used in erase/RAUW act differently than
    the erase for deleteInst.

  2. There were a bunch of places using InstModCallback that also were setting
    uses without having the ability for InstModCallbacks perform it (since it
    only supported RAUW). This is an anti-pattern and could cause subtle bugs to
    be introduced by appropriate state in the caller not being updated.

…ack instead of RAUW callbacks.

This allows for me to do a couple of things improving quality/correctness/ease of use:

1. I reimplemented InstMod's RAUW and RAUW/erase helpers on top of
   setUseValue/deleteInst. Beyond allowing the caller to specify less things, we
   gain an orthogonality preventing bugs like overriding erase/RAUW but not
   overriding erase or having the erase used in erase/RAUW act differently than
   the erase for deleteInst.

2. There were a bunch of places using InstModCallback that also were setting
   uses without having the ability for InstModCallbacks perform it (since it
   only supported RAUW). This is an anti-pattern and could cause subtle bugs to
   be introduced by appropriate state in the caller not being updated.
… to wereAnyCallbacksInvoked.

This makes it clear that we are not talking about a madeChange in a general
sense and are instead just tracking if /any/ of our callbacks were invoked. This
is still useful enough for our users and will prevent confusion.
@gottesmm gottesmm requested review from atrick and meg-gupta January 5, 2021 00:49
@gottesmm
Copy link
Contributor Author

gottesmm commented Jan 5, 2021

@swift-ci smoke test

[this](SingleValueInstruction *i, SILValue value) {
eraseAndRAUWSingleValueInstruction(i, value);
[this](Operand *use, SILValue newValue) {
use->set(newValue);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This hunk may be slightly confusing. What is happening is that rather than passing an empty argument for createdNewInst, I am just using an overload of InstModCallback's constructor that omits it (and thus assumes we want the default... which we do).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A single RAUW could replace thousands of operands. We design IR's very carefully so operand setting can be as efficient as possible. We definitely don't want to do a hash lookup each time. There only needs to be a single worklist insertion per RAUW operation.

@@ -434,7 +434,7 @@ void OwnershipRAUWUtility::eliminateReborrowsOfRecursiveBorrows(

// Then set our borrowing operand to take our innerBorrow instead of value
// (whose lifetime we just ended).
borrowingOperand->set(innerBorrow);
callbacks.setUseValue(*borrowingOperand, innerBorrow);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is one of the files where I already knew there were issues with us not having full coverage of IR changes via InstModCallbacks. I went through and fixed it in all of the appropriate places.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, but who needs to know that borrowingOperand changed as opposed to innerBorrow?

@@ -752,7 +752,7 @@ swift::replaceAllUsesAndErase(SingleValueInstruction *svi, SILValue newValue,
callbacks.deleteInst(user);
continue;
}
use->set(newValue);
callbacks.setUseValue(use, newValue);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is one of the files where I already knew there were issues with us not having full coverage of IR changes via InstModCallbacks. I went through and fixed it in all of the appropriate places to use callbacks.setUseValue();

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The obvious fix here would just have been to call the rauw callback, which we'll still need to do anyway.

@gottesmm
Copy link
Contributor Author

gottesmm commented Jan 5, 2021

@swift-ci smoke test linux platform

@gottesmm gottesmm merged commit 409ad6e into swiftlang:main Jan 5, 2021
@gottesmm gottesmm deleted the pr-9c2c0f1fec0527092a68ca8fd955d6a5dc77799d branch January 5, 2021 05:14
Copy link
Contributor

@atrick atrick left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This goes against our efforts at IR design where we've gone to great lengths to make operand setting (and iteration) as fast as possible. There are two reasons I've never added a setUse hook in any IR I've worked on

  1. The nature of SSA means that any optimization is at least quadratic
    and usually cubic in the number of operand updates.

  2. All SSA algorithms I'm aware of only need to know when an SSA value
    has new uses, not when each individual operand changes.

It's not clear why you need the setUseValue hook. AFAICT we only need a notifyHasNewUsers.

It's awesome that these hooks aren't indirect calls when they're not used. But that doesn't change the fact that this new hook should never be used and isn't needed. People will reach for it without realizing how disastrous it is rather than designing their code to use notifyHasNewUsers instead.

[this](SingleValueInstruction *i, SILValue value) {
eraseAndRAUWSingleValueInstruction(i, value);
[this](Operand *use, SILValue newValue) {
use->set(newValue);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A single RAUW could replace thousands of operands. We design IR's very carefully so operand setting can be as efficient as possible. We definitely don't want to do a hash lookup each time. There only needs to be a single worklist insertion per RAUW operation.

@@ -752,7 +752,7 @@ swift::replaceAllUsesAndErase(SingleValueInstruction *svi, SILValue newValue,
callbacks.deleteInst(user);
continue;
}
use->set(newValue);
callbacks.setUseValue(use, newValue);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The obvious fix here would just have been to call the rauw callback, which we'll still need to do anyway.

worklist.replaceValueUsesWith(oldValue, newValue);
[this](Operand *use, SILValue newValue) {
use->set(newValue);
worklist.add(use->getUser());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should not be doing a hash lookup on every operand update!

@@ -434,7 +434,7 @@ void OwnershipRAUWUtility::eliminateReborrowsOfRecursiveBorrows(

// Then set our borrowing operand to take our innerBorrow instead of value
// (whose lifetime we just ended).
borrowingOperand->set(innerBorrow);
callbacks.setUseValue(*borrowingOperand, innerBorrow);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, but who needs to know that borrowingOperand changed as opposed to innerBorrow?

@atrick
Copy link
Contributor

atrick commented Jan 8, 2021

@gottesmm post-commit review

@atrick
Copy link
Contributor

atrick commented Jan 8, 2021

To be a little more helpful, you could have a setUseValue API in limited cases, but it should simply call a notifyNewNewUsers callback and should never be used in a RAUW context.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants