Skip to content

Remove checks in UR[M]BP.Iterator.next() #62965

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
merged 1 commit into from
Jan 12, 2023

Conversation

Lukasa
Copy link
Contributor

@Lukasa Lukasa commented Jan 11, 2023

Swift tends to emit unnecessary checks and traps when iterating unsafe raw buffer pointers. These traps are confirming that the position pointer isn't nil, but this check is redundant with the bounds check that is already present. We can safely remove it.

Resolves #62964.

@Lukasa
Copy link
Contributor Author

Lukasa commented Jan 11, 2023

@swift-ci please smoke test

@Lukasa Lukasa force-pushed the cb-better-urbp-iteration branch from 1d708ae to 85c719d Compare January 11, 2023 12:46
//
// We check these invariants in debug builds to defend against invalidly constructed
// pointers.
_debugPrecondition(_position! <= _end!)
Copy link
Contributor

@stephentyrone stephentyrone Jan 11, 2023

Choose a reason for hiding this comment

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

< rather than <=; we already eliminated == above, and < is what guarantees that we can use &+=.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good note, thanks!

@stephentyrone
Copy link
Contributor

@Lukasa let's clone this for 5.8 once we're happy with it.

@Lukasa Lukasa force-pushed the cb-better-urbp-iteration branch from 85c719d to 6a37833 Compare January 11, 2023 13:59
@Lukasa
Copy link
Contributor Author

Lukasa commented Jan 11, 2023

@swift-ci please smoke test

@Lukasa
Copy link
Contributor Author

Lukasa commented Jan 11, 2023

@stephentyrone Yup, will do.

@Lukasa
Copy link
Contributor Author

Lukasa commented Jan 11, 2023

@swift-ci please smoke test

@Lukasa Lukasa force-pushed the cb-better-urbp-iteration branch from 6a37833 to 6fdb7cd Compare January 11, 2023 15:30
@Lukasa
Copy link
Contributor Author

Lukasa commented Jan 11, 2023

@swift-ci please smoke test

@Lukasa Lukasa force-pushed the cb-better-urbp-iteration branch from 6fdb7cd to ece32d4 Compare January 11, 2023 16:55
@Lukasa
Copy link
Contributor Author

Lukasa commented Jan 11, 2023

@swift-ci please smoke test

Copy link
Contributor

@glessard glessard left a comment

Choose a reason for hiding this comment

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

Thanks for this improvement!

@Lukasa
Copy link
Contributor Author

Lukasa commented Jan 12, 2023

@swift-ci please test

@Lukasa
Copy link
Contributor Author

Lukasa commented Jan 12, 2023

@swift-ci please benchmark

@Lukasa
Copy link
Contributor Author

Lukasa commented Jan 12, 2023

Hmm, any idea why the benchmark runner is failing?

let result = _position!.load(as: UInt8.self)
_position! += 1
// We can do an unchecked unwrap here by borrowing invariants from the pointer.
// For a validly constructed buffer pointer, he only way _position can be nil is
Copy link
Contributor

Choose a reason for hiding this comment

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

typo

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks!

Swift tends to emit unnecessary checks and traps when iterating unsafe
raw buffer pointers. These traps are confirming that the position
pointer isn't nil, but this check is redundant with the bounds check
that is already present. We can safely remove it.
@Lukasa Lukasa force-pushed the cb-better-urbp-iteration branch from ece32d4 to d9d9e0f Compare January 12, 2023 11:15
@Lukasa
Copy link
Contributor Author

Lukasa commented Jan 12, 2023

@swift-ci please test

@Lukasa
Copy link
Contributor Author

Lukasa commented Jan 12, 2023

@swift-ci please benchmark

//
// We check these invariants in debug builds to defend against invalidly constructed
// pointers.
_debugPrecondition(_position! < _end!)
Copy link
Contributor

Choose a reason for hiding this comment

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

Couldn't this be hoisted in to the iterator's initializer, as a check that _position <= _end? That would give us the same assurances, but IMO would be a bit cleaner; we wouldn't need to talk about 'validly constructed buffer pointer's any more, more like 'validly constructed iterators'. Additionally, it may improve performance in debug builds, which is also important.

Copy link
Contributor

Choose a reason for hiding this comment

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

There's value in validating invariants outside of the initializer, to detect bugs that corrupt them sooner rather than later. Looking at the codegen, this doesn't cost us much, so it should probably stick around (but I would prefer they be _unsafelyUnwrappedUnchecked)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@stephentyrone Would you like a != nil _debugPrecondition as well?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think I'm fine with it as you have it.

@@ -148,8 +148,21 @@ extension UnsafeRawBufferPointer.Iterator: IteratorProtocol, Sequence {
public mutating func next() -> UInt8? {
if _position == _end { return nil }
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 compile to a single comparison, but doesn't. I'm opening an LLVM bug to see what we can do about that.

@stephentyrone stephentyrone merged commit 9cb3641 into swiftlang:main Jan 12, 2023
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.

UnsafeRawBufferPointer is missing the fast _custom* Collection customisation points [was: ByteBufferView.contains doesn't produce optimal code]
5 participants