diff --git a/stdlib/public/core/UnsafeBufferPointer.swift.gyb b/stdlib/public/core/UnsafeBufferPointer.swift.gyb index 59372435150a9..7b4d56f4917cc 100644 --- a/stdlib/public/core/UnsafeBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeBufferPointer.swift.gyb @@ -143,7 +143,14 @@ extension Unsafe${Mutable}BufferPointer: ${Mutable}Collection, RandomAccessColle // optimizer is not capable of creating partial specializations yet. // NOTE: Range checks are not performed here, because it is done later by // the subscript function. - return i + 1 + // NOTE: Wrapping math because we allow unsafe buffer pointers not to verify + // index preconditions in release builds. Our (optimistic) assumption is + // that the caller is already ensuring that indices are valid, so we can + // elide the usual checks to help the optimizer generate better code. + // However, we still check for overflow in debug mode. + let result = i.addingReportingOverflow(1) + _debugPrecondition(!result.overflow) + return result.partialValue } @inlinable // unsafe-performance @@ -153,7 +160,10 @@ extension Unsafe${Mutable}BufferPointer: ${Mutable}Collection, RandomAccessColle // optimizer is not capable of creating partial specializations yet. // NOTE: Range checks are not performed here, because it is done later by // the subscript function. - i += 1 + // See note on wrapping arithmetic in `index(after:)` above. + let result = i.addingReportingOverflow(1) + _debugPrecondition(!result.overflow) + i = result.partialValue } @inlinable // unsafe-performance @@ -163,7 +173,10 @@ extension Unsafe${Mutable}BufferPointer: ${Mutable}Collection, RandomAccessColle // optimizer is not capable of creating partial specializations yet. // NOTE: Range checks are not performed here, because it is done later by // the subscript function. - return i - 1 + // See note on wrapping arithmetic in `index(after:)` above. + let result = i.subtractingReportingOverflow(1) + _debugPrecondition(!result.overflow) + return result.partialValue } @inlinable // unsafe-performance @@ -173,7 +186,10 @@ extension Unsafe${Mutable}BufferPointer: ${Mutable}Collection, RandomAccessColle // optimizer is not capable of creating partial specializations yet. // NOTE: Range checks are not performed here, because it is done later by // the subscript function. - i -= 1 + // See note on wrapping arithmetic in `index(after:)` above. + let result = i.subtractingReportingOverflow(1) + _debugPrecondition(!result.overflow) + i = result.partialValue } @inlinable // unsafe-performance @@ -183,7 +199,10 @@ extension Unsafe${Mutable}BufferPointer: ${Mutable}Collection, RandomAccessColle // optimizer is not capable of creating partial specializations yet. // NOTE: Range checks are not performed here, because it is done later by // the subscript function. - return i + n + // See note on wrapping arithmetic in `index(after:)` above. + let result = i.addingReportingOverflow(n) + _debugPrecondition(!result.overflow) + return result.partialValue } @inlinable // unsafe-performance @@ -193,11 +212,18 @@ extension Unsafe${Mutable}BufferPointer: ${Mutable}Collection, RandomAccessColle // optimizer is not capable of creating partial specializations yet. // NOTE: Range checks are not performed here, because it is done later by // the subscript function. - let l = limit - i + // See note on wrapping arithmetic in `index(after:)` above. + let maxOffset = limit.subtractingReportingOverflow(i) + _debugPrecondition(!maxOffset.overflow) + let l = maxOffset.partialValue + if n > 0 ? l >= 0 && l < n : l <= 0 && n < l { return nil } - return i + n + + let result = i.addingReportingOverflow(n) + _debugPrecondition(!result.overflow) + return result.partialValue } @inlinable // unsafe-performance @@ -233,7 +259,8 @@ extension Unsafe${Mutable}BufferPointer: ${Mutable}Collection, RandomAccessColle @inlinable // unsafe-performance public var indices: Indices { - return startIndex..(start: nil, count: 0) } - let count = (_end! - base) / MemoryLayout.stride + let count = (_end._unsafelyUnwrappedUnchecked - base) / MemoryLayout.stride let typed = base.initializeMemory( as: type, repeating: repeatedValue, count: count) return UnsafeMutableBufferPointer(start: typed, count: count) @@ -644,9 +648,10 @@ extension Unsafe${Mutable}RawBufferPointer { return (it, UnsafeMutableBufferPointer(start: nil, count: 0)) } + _internalInvariant(_end != nil) for p in stride(from: base, // only advance to as far as the last element that will fit - to: base + count - elementStride + 1, + to: _end._unsafelyUnwrappedUnchecked - elementStride + 1, by: elementStride ) { // underflow is permitted -- e.g. a sequence into diff --git a/test/SILOptimizer/unsafebufferpointer.swift b/test/SILOptimizer/unsafebufferpointer.swift index adf1c27328e81..a58db2a63fca1 100644 --- a/test/SILOptimizer/unsafebufferpointer.swift +++ b/test/SILOptimizer/unsafebufferpointer.swift @@ -80,7 +80,7 @@ public func testSubscript(_ ubp: UnsafeBufferPointer) -> Float { // CHECK: [[CMP:%[0-9]+]] = icmp eq // CHECK: br i1 [[CMP]], label %[[RET:.*]], label %[[LOOP]] // -// CHECK: [[RET]]: ; preds = %[[LOOP]], %entry +// CHECK: [[RET]]: ; preds = %[[LOOP]], %{{.*}} // CHECK: ret i64 public func testSubscript(_ ubp: UnsafeRawBufferPointer) -> Int64 { var sum: Int64 = 0