Skip to content

[SIL] Perf: Cache basic block during SILSuccessor iteration #16869

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

davezarzycki
Copy link
Contributor

'operator*' in this patch becomes a hot spot in some scenarios. For example: an enum with an unusually large number of cases.

@davezarzycki davezarzycki requested review from gottesmm and hughbe May 28, 2018 14:50
@davezarzycki
Copy link
Contributor Author

@swift-ci please smoke test


bool operator==(pred_iterator I2) const { return Cur == I2.Cur; }
bool operator!=(pred_iterator I2) const { return Cur != I2.Cur; }

pred_iterator &operator++() {
assert(Cur && "Trying to advance past end");
// No need to assert(Cur). Dereferencing nullptr always crashes.
Copy link
Contributor

Choose a reason for hiding this comment

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

We want a nice error message here. I would suggest actually making Cur a NullablePtr to make it explicit.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I never understood the "crash intentionally (a.k.a. "assert") before an implicit crash" convention. What problem is this solving?

Copy link
Contributor

Choose a reason for hiding this comment

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

If you are looking at why something crashed, it provides a really nice error message without you having to load up the debugger.

pred_iterator operator++(int) {
pred_iterator copy = *this;
++*this;
pred_iterator operator+(size_t distance) const {
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we really need to use a size_t here? I thought we were generally using int in such cases, no?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unless I missed something, the iterator is unidirectional, so an unsigned type would be appropriate here, right?

Copy link
Contributor

Choose a reason for hiding this comment

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

I was just talking about the usage of size_t. We generally use unsigned for these cases.

@@ -87,33 +87,45 @@ class SILSuccessor {
class pred_iterator {
SILSuccessor *Cur;

// Cache the basic block to avoid repeated pointer chasing.
SILBasicBlock *BB;
Copy link
Contributor

Choose a reason for hiding this comment

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

Two things:

  1. Can you use Block instead of BB for this name.
  2. I am worried about having to call cacheBasicBlock everywhere. It is an extra step that someone may forget. At least I think it is important to have some sort of assert when you access the block to show that the block is the correct block, even though I would prefer if there was an algebraic way that the code could guarantee that BB will be changed if Cur is changed. It seems almost silly though to say wrap the SILSuccessor field in another struct that makes sure that BB is always updated.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, I can change the name.

I think if the maintainer of the iterator is comfortable with how C++ iterators work, then the calls to cacheBasicBlock will very limited in scope. That being said, if you don't like this tradeoff, then I'll just abandon the pull request. (I'm not invested in this pull request. It just felt like a "freebie" while I was hacking on some other stuff.)

@@ -8094,6 +8094,11 @@ inline EnumElementDecl **SelectEnumInstBase::getEnumElementDeclStorage() {
llvm_unreachable("Unhandled SelectEnumInstBase subclass");
}

inline void SILSuccessor::pred_iterator::cacheBasicBlock() {
// No need to assert(Cur). Dereferencing nullptr always crashes.
Copy link
Contributor

Choose a reason for hiding this comment

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

While it may crash, providing a nice error message when we hit that condition can be useful when triaging bugs and also provides a nice guide for the reader of the code that a pointer is intended to be non-null. Can you put that back in?

'operator*' in this patch becomes a hot spot in some scenarios. For
example: an enum with an unusually large number of cases.
@davezarzycki davezarzycki force-pushed the cache_bb_during_SILSuccessor_iteration branch from b741473 to 52fd7cb Compare May 29, 2018 13:44
@davezarzycki
Copy link
Contributor Author

Hi @gottesmm – I think I've addressed all of your feedback.

@swift-ci please smoke test

@davezarzycki
Copy link
Contributor Author

Ping

@gottesmm
Copy link
Contributor

SGTM

@davezarzycki davezarzycki merged commit 25249e6 into swiftlang:master Jun 12, 2018
@davezarzycki davezarzycki deleted the cache_bb_during_SILSuccessor_iteration branch June 12, 2018 19:56
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