swift
300f4da1 - [stdlib] Simplify buffer pointer initialization.

Commit
4 years ago
[stdlib] Simplify buffer pointer initialization. UnsafeRawBufferPointer was not made self-slicing, but is instead sliced by Slice<UnsafeRawBufferPointer>. When working with UnsafeRawBufferPointer objects it is quite common to want to transform back into the underlying collection, which is why the UnsafeRawBufferPointer provides a constructor from its subsequence: UnsafeRawBufferPointer.init(rebasing:). Unfortunately for an initializer on this extremely low-level type, this initializer is surprisingly expensive. When disassembled on Linux it emits 7 separate traps and 11 branches. This relative heft means this method often gets outlined, which is a shame, as several of the branches could often be eliminated due to checks elsewhere in functions where this initializer is used. Almost all of these branches and almost all of the traps are unnecessary. We can remove them by noting that it is impossible to construct a Slice whose endIndex is earlier than its startIndex. All Slice inits are constructed with bounds expressed as Range, and Range enforces ordering on its endpoints. For this reason, we can do unchecked arithmetic on the start and end index of the slice, and remove 5 traps in one fell swoop. This greatly cheapens the cost of the initializer, improving its odds of being inlined and having even more of its branches optimised away. For what it's worth, I also considered trying to remove the last two preconditions. Unfortunately I concluded I couldn't confidently do that. I wanted to remove them based on the premise that a valid Slice must have indices that were in-bounds for its parent Collection, and so we could safely assume that if the parent base address was nil the count would have to be zero, and that adding start index to the base address would definitely not overflow. However, the existence of the Slice.init(base:bounds:) constructor led me to be a bit suspicions of removing those checks. Given that UnsafeRawBufferPointer.init(start:count:) enforces those invariants, I decided it was safest for us to continue to do that.
Author
Committer
Parents
  • stdlib/public/core
    • UnsafeBufferPointer.swift.gyb
    • UnsafeRawBufferPointer.swift.gyb