Skip to content

[stdlib] BitwiseCopyable loadUnaligned overloads. #70248

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 8 additions & 10 deletions lib/IRGen/GenArchetype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -433,16 +433,14 @@ const TypeInfo *TypeConverter::convertArchetypeType(ArchetypeType *archetype) {
: IsNotABIAccessible;
}

auto &ASTContext = IGM.getSwiftModule()->getASTContext();
if (ASTContext.LangOpts.hasFeature(Feature::BitwiseCopyable)) {
// TODO: Should this conformance imply isAddressOnlyTrivial is true?
auto *proto = ASTContext.getProtocol(KnownProtocolKind::BitwiseCopyable);
// It's possible for the protocol not to exist if the stdlib is built
// no_asserts.
if (proto && IGM.getSwiftModule()->lookupConformance(archetype, proto)) {
return BitwiseCopyableArchetypeTypeInfo::create(storageType,
abiAccessible);
}
// TODO: Should this conformance imply isAddressOnlyTrivial is true?
auto *bitwiseCopyableProtocol =
IGM.getSwiftModule()->getASTContext().getProtocol(
KnownProtocolKind::BitwiseCopyable);
// The protocol won't be present in swiftinterfaces from older SDKs.
if (bitwiseCopyableProtocol && IGM.getSwiftModule()->lookupConformance(
archetype, bitwiseCopyableProtocol)) {
return BitwiseCopyableArchetypeTypeInfo::create(storageType, abiAccessible);
}

return OpaqueArchetypeTypeInfo::create(storageType, abiAccessible);
Expand Down
22 changes: 22 additions & 0 deletions stdlib/public/core/UnsafeBufferPointerSlice.swift
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,17 @@ extension Slice where Base == UnsafeMutableRawBufferPointer {
/// with `type`.
/// - Returns: A new instance of type `T`, copied from the buffer pointer's
/// memory.
#if $BitwiseCopyable
@inlinable
@_alwaysEmitIntoClient
public func loadUnaligned<T : _BitwiseCopyable>(
fromByteOffset offset: Int = 0,
as type: T.Type
) -> T {
let buffer = Base(rebasing: self)
return buffer.loadUnaligned(fromByteOffset: offset, as: T.self)
}
#endif
@inlinable
@_alwaysEmitIntoClient
public func loadUnaligned<T>(
Expand Down Expand Up @@ -606,6 +617,17 @@ extension Slice where Base == UnsafeRawBufferPointer {
/// with `type`.
/// - Returns: A new instance of type `T`, copied from the buffer pointer's
/// memory.
#if $BitwiseCopyable
@inlinable
@_alwaysEmitIntoClient
public func loadUnaligned<T : _BitwiseCopyable>(
fromByteOffset offset: Int = 0,
as type: T.Type
) -> T {
let buffer = Base(rebasing: self)
return buffer.loadUnaligned(fromByteOffset: offset, as: T.self)
}
#endif
@inlinable
@_alwaysEmitIntoClient
public func loadUnaligned<T>(
Expand Down
12 changes: 12 additions & 0 deletions stdlib/public/core/UnsafeRawBufferPointer.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,18 @@ extension Unsafe${Mutable}RawBufferPointer {
/// with `type`.
/// - Returns: A new instance of type `T`, copied from the buffer pointer's
/// memory.
#if $BitwiseCopyable
@_alwaysEmitIntoClient
public func loadUnaligned<T : _BitwiseCopyable>(
fromByteOffset offset: Int = 0,
as type: T.Type
) -> T {
_debugPrecondition(offset >= 0, "${Self}.load with negative offset")
_debugPrecondition(offset + MemoryLayout<T>.size <= self.count,
"${Self}.load out of bounds")
return baseAddress!.loadUnaligned(fromByteOffset: offset, as: T.self)
}
#endif
@_alwaysEmitIntoClient
public func loadUnaligned<T>(
fromByteOffset offset: Int = 0,
Expand Down
24 changes: 20 additions & 4 deletions stdlib/public/core/UnsafeRawPointer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,16 @@ public struct UnsafeRawPointer: _Pointer {
/// - Returns: A new instance of type `T`, read from the raw bytes at
/// `offset`. The returned instance isn't associated
/// with the value in the range of memory referenced by this pointer.
#if $BitwiseCopyable
@inlinable
@_alwaysEmitIntoClient
public func loadUnaligned<T : _BitwiseCopyable>(
fromByteOffset offset: Int = 0,
as type: T.Type
) -> T {
return Builtin.loadRaw((self + offset)._rawValue)
}
#endif
@inlinable
@_alwaysEmitIntoClient
public func loadUnaligned<T>(
Expand All @@ -473,8 +483,6 @@ public struct UnsafeRawPointer: _Pointer {
)
return temporary.pointee
}
//FIXME: reimplement with `loadRaw` when supported in SIL (rdar://96956089)
// e.g. Builtin.loadRaw((self + offset)._rawValue)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can Builtin.loadRaw be used for the version that doesn't have the generic constraint?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately no--we need to generate a direct call to memcpy rather than to a value witness; the compiler needs to know the type is BitwiseCopyable in order to know doing so is correct.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. Nice to know!

}

Expand Down Expand Up @@ -1238,6 +1246,16 @@ public struct UnsafeMutableRawPointer: _Pointer {
/// - Returns: A new instance of type `T`, read from the raw bytes at
/// `offset`. The returned instance isn't associated
/// with the value in the range of memory referenced by this pointer.
#if $BitwiseCopyable
@inlinable
@_alwaysEmitIntoClient
public func loadUnaligned<T : _BitwiseCopyable>(
fromByteOffset offset: Int = 0,
as type: T.Type
) -> T {
return Builtin.loadRaw((self + offset)._rawValue)
}
#endif
@inlinable
@_alwaysEmitIntoClient
public func loadUnaligned<T>(
Expand All @@ -1255,8 +1273,6 @@ public struct UnsafeMutableRawPointer: _Pointer {
)
return temporary.pointee
}
//FIXME: reimplement with `loadRaw` when supported in SIL (rdar://96956089)
// e.g. Builtin.loadRaw((self + offset)._rawValue)
}

/// Stores the given value's bytes into raw memory at the specified offset.
Expand Down
13 changes: 1 addition & 12 deletions test/IRGen/bitwise-copyable-loadRaw.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,14 @@ func doit() {
let bytes: [UInt8] = Array(repeating: 0, count: 64)
bytes.withUnsafeBufferPointer { bytes in
let rawBytes = UnsafeRawPointer(bytes.baseAddress!) + 1
let vector = rawBytes.myLoadUnaligned(as: SIMD16<UInt8>.self)
let vector = rawBytes.loadUnaligned(as: SIMD16<UInt8>.self)
//CHECK: SIMD16<UInt8>(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
blackhole(vector)
}
}

import Builtin

extension UnsafeRawPointer {
@inlinable
@_alwaysEmitIntoClient
public func myLoadUnaligned<T : _BitwiseCopyable>(
fromByteOffset offset: Int = 0,
as type: T.Type
) -> T {
return Builtin.loadRaw((self + offset)._rawValue)
}
}

doit()

@_silgen_name("blackhole")
Expand Down