diff --git a/stdlib/public/core/Span/MutableSpan.swift b/stdlib/public/core/Span/MutableSpan.swift index c4c88282621a9..3ffe7b054e68c 100644 --- a/stdlib/public/core/Span/MutableSpan.swift +++ b/stdlib/public/core/Span/MutableSpan.swift @@ -290,12 +290,18 @@ extension MutableSpan where Element: ~Copyable { @_alwaysEmitIntoClient public subscript(_ position: Index) -> Element { unsafeAddress { - _precondition(indices.contains(position), "index out of bounds") + _precondition( + UInt(bitPattern: position) < UInt(bitPattern: _count), + "Index out of bounds" + ) return unsafe UnsafePointer(_unsafeAddressOfElement(unchecked: position)) } @lifetime(self: copy self) unsafeMutableAddress { - _precondition(indices.contains(position), "index out of bounds") + _precondition( + UInt(bitPattern: position) < UInt(bitPattern: _count), + "Index out of bounds" + ) return unsafe _unsafeAddressOfElement(unchecked: position) } } diff --git a/stdlib/public/core/Span/Span.swift b/stdlib/public/core/Span/Span.swift index fafa9b8e92818..92daf0383996e 100644 --- a/stdlib/public/core/Span/Span.swift +++ b/stdlib/public/core/Span/Span.swift @@ -419,7 +419,10 @@ extension Span where Element: ~Copyable { @inline(__always) @_alwaysEmitIntoClient internal func _checkIndex(_ position: Index) { - _precondition(indices.contains(position), "Index out of bounds") + _precondition( + UInt(bitPattern: position) < UInt(bitPattern: _count), + "Index out of bounds" + ) } /// Accesses the element at the specified position in the `Span`. diff --git a/test/stdlib/Span/BoundsCheckOptimization.swift b/test/stdlib/Span/BoundsCheckOptimization.swift new file mode 100644 index 0000000000000..59544891d86ea --- /dev/null +++ b/test/stdlib/Span/BoundsCheckOptimization.swift @@ -0,0 +1,62 @@ +//===--- BoundsCheckOptimization.swift ------------------------*- swift -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2025 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +// RUN: %target-swift-frontend -primary-file %s -O -emit-assembly | %FileCheck %s --check-prefix CHECK --check-prefix CHECK-%target-cpu +// REQUIRES: swift_stdlib_no_asserts + +import Swift + +func read(index: Int, span: Span) -> UInt8 { + span[index] +} +// CHECK: s23BoundsCheckOptimization4read5index4spans5UInt8VSi_s4SpanVyAFGtF: + +// CHECK-arm64-NOT: tbnz +// CHECK-arm64: cmp +// all unsigned comparison spellings? +// CHECK-arm64-NEXT: b.{{hs|hi|ls|lo|cc|cs}} +// CHECK-arm64-NEXT: ldrb +// CHECK-arm64-NEXT: ret + +// CHECK-x86_64-NOT: test +// CHECK-x86_64: cmp +// all unsigned comparison spellings? +// CHECK-x86_64-NEXT: j{{a|ae|b|be|c|na|nae|nb|nbe|nc}} +// CHECK-x86_64-NEXT: movzb +// x86_64 might have a frame pointer operation before ret + +func write(value: UInt8, index: Int, span: inout MutableSpan) { + span[index] = value +} +// CHECK: s23BoundsCheckOptimization5write5value5index4spanys5UInt8V_Sis11MutableSpanVyAGGztF: + +// CHECK-arm64-NOT: tbnz +// CHECK-arm64: cmp +// all unsigned comparison spellings? +// CHECK-arm64-NEXT: b.{{hs|hi|ls|lo|cc|cs}} +// no second compare +// CHECK-arm64-NOT: cmp +// no test after compare +// CHECK-arm64-NOT: tbnz +// CHECK-arm64: strb +// CHECK-arm64-NEXT: ret + +// CHECK-x86_64-NOT: test +// CHECK-x86_64: cmp +// all unsigned comparison spellings? +// CHECK-x86_64-NEXT: j{{a|ae|b|be|c|na|nae|nb|nbe|nc}} +// no second compare +// CHECK-x86_64-NOT: cmp +// no test after compare +// CHECK-x86_64-NOT: test +// CHECK-x86_64: movb +// x86_64 might have a frame pointer operation before ret