Skip to content

Commit 94b477f

Browse files
authored
Merge pull request swiftlang#60028 from glessard/rdar96841899-5.7
[5.7] [stdlib] fix unaligned loads of large SIMD vectors on x86_64
2 parents b5dfe26 + 7704fd9 commit 94b477f

File tree

3 files changed

+70
-4
lines changed

3 files changed

+70
-4
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: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// RUN: %target-build-swift %s -parse-stdlib -Xfrontend -disable-access-control -o %t.out
2+
// RUN: %target-codesign %t.out
3+
// RUN: %target-run %t.out
4+
// REQUIRES: executable_test
5+
// UNSUPPORTED: freestanding
6+
7+
import Swift
8+
import StdlibUnittest
9+
10+
var UnsafeRawPointerTestSuite =
11+
TestSuite("UnsafeRawPointerTestSuite")
12+
13+
UnsafeRawPointerTestSuite.test("load.unaligned.SIMD")
14+
.skip(.custom({
15+
if #available(SwiftStdlib 5.7, *) { return false }
16+
return true
17+
}, reason: "Requires Swift 5.7's stdlib"))
18+
.code {
19+
guard #available(SwiftStdlib 5.7, *) else { return }
20+
var bytes: [UInt8] = Array(0..<64)
21+
var offset = 3
22+
let vector16 = bytes.withUnsafeBytes { buffer -> SIMD16<UInt8> in
23+
let aligned = buffer.baseAddress!.alignedUp(for: SIMD16<UInt8>.self)
24+
offset += buffer.baseAddress!.distance(to: aligned)
25+
return buffer.loadUnaligned(fromByteOffset: offset, as: SIMD16<UInt8>.self)
26+
}
27+
expectEqual(Int(vector16[0]), offset)
28+
var lastIndex = vector16.indices.last!
29+
expectEqual(Int(vector16[lastIndex]), offset+lastIndex)
30+
31+
offset = 11
32+
let vector32 = bytes.withUnsafeMutableBytes { buffer -> SIMD32<UInt8> in
33+
let aligned = buffer.baseAddress!.alignedUp(for: SIMD32<UInt8>.self)
34+
offset += buffer.baseAddress!.distance(to: aligned)
35+
return buffer.loadUnaligned(fromByteOffset: offset, as: SIMD32<UInt8>.self)
36+
}
37+
expectEqual(Int(vector32[0]), offset)
38+
lastIndex = vector32.indices.last!
39+
expectEqual(Int(vector32[lastIndex]), offset+lastIndex)
40+
}
41+
42+
runAllTests()

0 commit comments

Comments
 (0)