Skip to content

Commit bee4eae

Browse files
authored
Merge pull request #60025 from glessard/rdar96841899
[stdlib] fix unaligned loads of large SIMD vectors on x86_64
2 parents 7ea4e43 + 9d1ca61 commit bee4eae

File tree

3 files changed

+61
-8
lines changed

3 files changed

+61
-8
lines changed

stdlib/public/core/StringUTF16View.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -597,11 +597,11 @@ extension String.UTF16View {
597597

598598
while readPtr + MemoryLayout<U>.stride < endPtr {
599599
//Find the number of continuations (0b10xxxxxx)
600-
let sValue = Builtin.loadRaw(readPtr._rawValue) as S
600+
let sValue = readPtr.loadUnaligned(as: S.self)
601601
let continuations = S.zero.replacing(with: S.one, where: sValue .< -65 + 1)
602602

603603
//Find the number of 4 byte code points (0b11110xxx)
604-
let uValue = Builtin.loadRaw(readPtr._rawValue) as U
604+
let uValue = readPtr.loadUnaligned(as: U.self)
605605
let fourBytes = S.zero.replacing(
606606
with: S.one,
607607
where: unsafeBitCast(

stdlib/public/core/UnsafeRawPointer.swift

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ public struct UnsafeRawPointer: _Pointer {
244244
/// - Parameter other: The typed pointer to convert.
245245
@_transparent
246246
public init<T>(@_nonEphemeral _ other: UnsafeMutablePointer<T>) {
247-
_rawValue = other._rawValue
247+
_rawValue = other._rawValue
248248
}
249249

250250
/// Creates a new raw pointer from the given typed pointer.
@@ -257,8 +257,8 @@ public struct UnsafeRawPointer: _Pointer {
257257
/// result is `nil`.
258258
@_transparent
259259
public init?<T>(@_nonEphemeral _ other: UnsafeMutablePointer<T>?) {
260-
guard let unwrapped = other else { return nil }
261-
_rawValue = unwrapped._rawValue
260+
guard let unwrapped = other else { return nil }
261+
_rawValue = unwrapped._rawValue
262262
}
263263

264264
/// Deallocates the previously allocated memory block referenced by this pointer.
@@ -429,7 +429,7 @@ public struct UnsafeRawPointer: _Pointer {
429429
MemoryLayout<T>.alignment._builtinWordValue)
430430
return Builtin.loadRaw(alignedPointer)
431431
#else
432-
return Builtin.loadRaw(rawPointer)
432+
return Builtin.loadRaw(rawPointer)
433433
#endif
434434
}
435435

@@ -455,13 +455,25 @@ public struct UnsafeRawPointer: _Pointer {
455455
/// - Returns: A new instance of type `T`, read from the raw bytes at
456456
/// `offset`. The returned instance isn't associated
457457
/// with the value in the range of memory referenced by this pointer.
458+
@inlinable
458459
@_alwaysEmitIntoClient
459460
public func loadUnaligned<T>(
460461
fromByteOffset offset: Int = 0,
461462
as type: T.Type
462463
) -> T {
463464
_debugPrecondition(_isPOD(T.self))
464-
return Builtin.loadRaw((self + offset)._rawValue)
465+
return withUnsafeTemporaryAllocation(of: T.self, capacity: 1) {
466+
let temporary = $0.baseAddress._unsafelyUnwrappedUnchecked
467+
Builtin.int_memcpy_RawPointer_RawPointer_Int64(
468+
temporary._rawValue,
469+
(self + offset)._rawValue,
470+
UInt64(MemoryLayout<T>.size)._value,
471+
/*volatile:*/ false._value
472+
)
473+
return temporary.pointee
474+
}
475+
//FIXME: reimplement with `loadRaw` when supported in SIL (rdar://96956089)
476+
// e.g. Builtin.loadRaw((self + offset)._rawValue)
465477
}
466478
}
467479

@@ -1180,13 +1192,25 @@ public struct UnsafeMutableRawPointer: _Pointer {
11801192
/// - Returns: A new instance of type `T`, read from the raw bytes at
11811193
/// `offset`. The returned instance isn't associated
11821194
/// with the value in the range of memory referenced by this pointer.
1195+
@inlinable
11831196
@_alwaysEmitIntoClient
11841197
public func loadUnaligned<T>(
11851198
fromByteOffset offset: Int = 0,
11861199
as type: T.Type
11871200
) -> T {
11881201
_debugPrecondition(_isPOD(T.self))
1189-
return Builtin.loadRaw((self + offset)._rawValue)
1202+
return withUnsafeTemporaryAllocation(of: T.self, capacity: 1) {
1203+
let temporary = $0.baseAddress._unsafelyUnwrappedUnchecked
1204+
Builtin.int_memcpy_RawPointer_RawPointer_Int64(
1205+
temporary._rawValue,
1206+
(self + offset)._rawValue,
1207+
UInt64(MemoryLayout<T>.size)._value,
1208+
/*volatile:*/ false._value
1209+
)
1210+
return temporary.pointee
1211+
}
1212+
//FIXME: reimplement with `loadRaw` when supported in SIL (rdar://96956089)
1213+
// e.g. Builtin.loadRaw((self + offset)._rawValue)
11901214
}
11911215

11921216
/// Stores the given value's bytes into raw memory at the specified offset.

test/stdlib/UnsafeRawPointer.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,35 @@ UnsafeMutableRawPointerExtraTestSuite.test("load.unaligned")
114114
expectEqual(result, 0xffff_0000)
115115
}
116116

117+
UnsafeMutableRawPointerExtraTestSuite.test("load.unaligned.SIMD")
118+
.skip(.custom({
119+
if #available(SwiftStdlib 5.7, *) { return false }
120+
return true
121+
}, reason: "Requires Swift 5.7's stdlib"))
122+
.code {
123+
guard #available(SwiftStdlib 5.7, *) else { return }
124+
var bytes: [UInt8] = Array(0..<64)
125+
var offset = 3
126+
let vector16 = bytes.withUnsafeBytes { buffer -> SIMD16<UInt8> in
127+
let aligned = buffer.baseAddress!.alignedUp(for: SIMD16<UInt8>.self)
128+
offset += buffer.baseAddress!.distance(to: aligned)
129+
return buffer.loadUnaligned(fromByteOffset: offset, as: SIMD16<UInt8>.self)
130+
}
131+
expectEqual(Int(vector16[0]), offset)
132+
var lastIndex = vector16.indices.last!
133+
expectEqual(Int(vector16[lastIndex]), offset+lastIndex)
134+
135+
offset = 11
136+
let vector32 = bytes.withUnsafeMutableBytes { buffer -> SIMD32<UInt8> in
137+
let aligned = buffer.baseAddress!.alignedUp(for: SIMD32<UInt8>.self)
138+
offset += buffer.baseAddress!.distance(to: aligned)
139+
return buffer.loadUnaligned(fromByteOffset: offset, as: SIMD32<UInt8>.self)
140+
}
141+
expectEqual(Int(vector32[0]), offset)
142+
lastIndex = vector32.indices.last!
143+
expectEqual(Int(vector32[lastIndex]), offset+lastIndex)
144+
}
145+
117146
UnsafeMutableRawPointerExtraTestSuite.test("load.invalid")
118147
.skip(.custom({ !_isDebugAssertConfiguration() },
119148
reason: "This tests a debug precondition.."))

0 commit comments

Comments
 (0)