Skip to content

Commit 8533b42

Browse files
authored
Merge pull request #37424 from Lukasa/cb-fewer-checks-in-ubp
Remove as much checked math as possible from buffer pointers.
2 parents bea6c50 + 0a82ef8 commit 8533b42

File tree

3 files changed

+45
-13
lines changed

3 files changed

+45
-13
lines changed

stdlib/public/core/UnsafeBufferPointer.swift.gyb

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,14 @@ extension Unsafe${Mutable}BufferPointer: ${Mutable}Collection, RandomAccessColle
205205
// optimizer is not capable of creating partial specializations yet.
206206
// NOTE: Range checks are not performed here, because it is done later by
207207
// the subscript function.
208-
return i + 1
208+
// NOTE: Wrapping math because we allow unsafe buffer pointers not to verify
209+
// index preconditions in release builds. Our (optimistic) assumption is
210+
// that the caller is already ensuring that indices are valid, so we can
211+
// elide the usual checks to help the optimizer generate better code.
212+
// However, we still check for overflow in debug mode.
213+
let result = i.addingReportingOverflow(1)
214+
_debugPrecondition(!result.overflow)
215+
return result.partialValue
209216
}
210217

211218
@inlinable // unsafe-performance
@@ -215,7 +222,10 @@ extension Unsafe${Mutable}BufferPointer: ${Mutable}Collection, RandomAccessColle
215222
// optimizer is not capable of creating partial specializations yet.
216223
// NOTE: Range checks are not performed here, because it is done later by
217224
// the subscript function.
218-
i += 1
225+
// See note on wrapping arithmetic in `index(after:)` above.
226+
let result = i.addingReportingOverflow(1)
227+
_debugPrecondition(!result.overflow)
228+
i = result.partialValue
219229
}
220230

221231
@inlinable // unsafe-performance
@@ -225,7 +235,10 @@ extension Unsafe${Mutable}BufferPointer: ${Mutable}Collection, RandomAccessColle
225235
// optimizer is not capable of creating partial specializations yet.
226236
// NOTE: Range checks are not performed here, because it is done later by
227237
// the subscript function.
228-
return i - 1
238+
// See note on wrapping arithmetic in `index(after:)` above.
239+
let result = i.subtractingReportingOverflow(1)
240+
_debugPrecondition(!result.overflow)
241+
return result.partialValue
229242
}
230243

231244
@inlinable // unsafe-performance
@@ -235,7 +248,10 @@ extension Unsafe${Mutable}BufferPointer: ${Mutable}Collection, RandomAccessColle
235248
// optimizer is not capable of creating partial specializations yet.
236249
// NOTE: Range checks are not performed here, because it is done later by
237250
// the subscript function.
238-
i -= 1
251+
// See note on wrapping arithmetic in `index(after:)` above.
252+
let result = i.subtractingReportingOverflow(1)
253+
_debugPrecondition(!result.overflow)
254+
i = result.partialValue
239255
}
240256

241257
@inlinable // unsafe-performance
@@ -245,7 +261,10 @@ extension Unsafe${Mutable}BufferPointer: ${Mutable}Collection, RandomAccessColle
245261
// optimizer is not capable of creating partial specializations yet.
246262
// NOTE: Range checks are not performed here, because it is done later by
247263
// the subscript function.
248-
return i + n
264+
// See note on wrapping arithmetic in `index(after:)` above.
265+
let result = i.addingReportingOverflow(n)
266+
_debugPrecondition(!result.overflow)
267+
return result.partialValue
249268
}
250269

251270
@inlinable // unsafe-performance
@@ -255,11 +274,18 @@ extension Unsafe${Mutable}BufferPointer: ${Mutable}Collection, RandomAccessColle
255274
// optimizer is not capable of creating partial specializations yet.
256275
// NOTE: Range checks are not performed here, because it is done later by
257276
// the subscript function.
258-
let l = limit - i
277+
// See note on wrapping arithmetic in `index(after:)` above.
278+
let maxOffset = limit.subtractingReportingOverflow(i)
279+
_debugPrecondition(!maxOffset.overflow)
280+
let l = maxOffset.partialValue
281+
259282
if n > 0 ? l >= 0 && l < n : l <= 0 && n < l {
260283
return nil
261284
}
262-
return i + n
285+
286+
let result = i.addingReportingOverflow(n)
287+
_debugPrecondition(!result.overflow)
288+
return result.partialValue
263289
}
264290

265291
@inlinable // unsafe-performance
@@ -295,7 +321,8 @@ extension Unsafe${Mutable}BufferPointer: ${Mutable}Collection, RandomAccessColle
295321

296322
@inlinable // unsafe-performance
297323
public var indices: Indices {
298-
return startIndex..<endIndex
324+
// Not checked because init forbids negative count.
325+
return Indices(uncheckedBounds: (startIndex, endIndex))
299326
}
300327

301328
/// Accesses the element at the specified position.

stdlib/public/core/UnsafeRawBufferPointer.swift.gyb

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,8 @@ extension Unsafe${Mutable}RawBufferPointer: ${Mutable}Collection {
212212

213213
@inlinable
214214
public var indices: Indices {
215-
return startIndex..<endIndex
215+
// Not checked because init forbids negative count.
216+
return Indices(uncheckedBounds: (startIndex, endIndex))
216217
}
217218

218219
/// Accesses the byte at the given offset in the memory region as a `UInt8`
@@ -293,7 +294,10 @@ extension Unsafe${Mutable}RawBufferPointer: ${Mutable}Collection {
293294
@inlinable
294295
public var count: Int {
295296
if let pos = _position {
296-
return _assumeNonNegative(_end! - pos)
297+
// Unsafely unwrapped because init forbids end being nil if _position
298+
// isn't.
299+
_internalInvariant(_end != nil)
300+
return _assumeNonNegative(_end._unsafelyUnwrappedUnchecked - pos)
297301
}
298302
return 0
299303
}
@@ -631,7 +635,7 @@ extension Unsafe${Mutable}RawBufferPointer {
631635
return UnsafeMutableBufferPointer<T>(start: nil, count: 0)
632636
}
633637

634-
let count = (_end! - base) / MemoryLayout<T>.stride
638+
let count = (_end._unsafelyUnwrappedUnchecked - base) / MemoryLayout<T>.stride
635639
let typed = base.initializeMemory(
636640
as: type, repeating: repeatedValue, count: count)
637641
return UnsafeMutableBufferPointer<T>(start: typed, count: count)
@@ -680,9 +684,10 @@ extension Unsafe${Mutable}RawBufferPointer {
680684
return (it, UnsafeMutableBufferPointer(start: nil, count: 0))
681685
}
682686

687+
_internalInvariant(_end != nil)
683688
for p in stride(from: base,
684689
// only advance to as far as the last element that will fit
685-
to: base + count - elementStride + 1,
690+
to: _end._unsafelyUnwrappedUnchecked - elementStride + 1,
686691
by: elementStride
687692
) {
688693
// underflow is permitted -- e.g. a sequence into

test/SILOptimizer/unsafebufferpointer.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public func testSubscript(_ ubp: UnsafeBufferPointer<Float>) -> Float {
8080
// CHECK: [[CMP:%[0-9]+]] = icmp eq
8181
// CHECK: br i1 [[CMP]], label %[[RET:.*]], label %[[LOOP]]
8282
//
83-
// CHECK: [[RET]]: ; preds = %[[LOOP]], %entry
83+
// CHECK: [[RET]]: ; preds = %[[LOOP]], %{{.*}}
8484
// CHECK: ret i64
8585
public func testSubscript(_ ubp: UnsafeRawBufferPointer) -> Int64 {
8686
var sum: Int64 = 0

0 commit comments

Comments
 (0)