Skip to content
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
84 changes: 84 additions & 0 deletions lib/IRGen/GenArchetype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "swift/AST/Decl.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/IRGenOptions.h"
#include "swift/AST/KnownProtocols.h"
#include "swift/AST/Types.h"
#include "swift/IRGen/Linking.h"
#include "swift/SIL/SILValue.h"
Expand Down Expand Up @@ -172,6 +173,76 @@ class FixedSizeArchetypeTypeInfo
}
};

class BitwiseCopyableArchetypeTypeInfo
: public WitnessSizedTypeInfo<BitwiseCopyableArchetypeTypeInfo> {
using Self = BitwiseCopyableArchetypeTypeInfo;
using Super = WitnessSizedTypeInfo<Self>;
BitwiseCopyableArchetypeTypeInfo(llvm::Type *type,
IsABIAccessible_t abiAccessible)
: Super(type, Alignment(1), IsTriviallyDestroyable, IsBitwiseTakable,
IsCopyable, abiAccessible) {}

public:
static const BitwiseCopyableArchetypeTypeInfo *
create(llvm::Type *type, IsABIAccessible_t abiAccessible) {
return new Self(type, abiAccessible);
}

void bitwiseCopy(IRGenFunction &IGF, Address destAddr, Address srcAddr,
SILType T, bool isOutlined) const {
IGF.Builder.CreateMemCpy(destAddr, srcAddr, getSize(IGF, T));
}

void initializeWithTake(IRGenFunction &IGF, Address destAddr, Address srcAddr,
SILType T, bool isOutlined) const override {
bitwiseCopy(IGF, destAddr, srcAddr, T, isOutlined);
}

void initializeWithCopy(IRGenFunction &IGF, Address destAddr, Address srcAddr,
SILType T, bool isOutlined) const override {
bitwiseCopy(IGF, destAddr, srcAddr, T, isOutlined);
}

void assignWithCopy(IRGenFunction &IGF, Address destAddr, Address srcAddr,
SILType T, bool isOutlined) const override {
bitwiseCopy(IGF, destAddr, srcAddr, T, isOutlined);
}

void assignWithTake(IRGenFunction &IGF, Address destAddr, Address srcAddr,
SILType T, bool isOutlined) const override {
bitwiseCopy(IGF, destAddr, srcAddr, T, isOutlined);
}

void destroy(IRGenFunction &IGF, Address address, SILType T,
bool isOutlined) const override {
// BitwiseCopyable types are trivial, so destroy is a no-op.
}

llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF,
llvm::Value *numEmptyCases,
Address enumAddr, SILType T,
bool isOutlined) const override {
return emitGetEnumTagSinglePayloadCall(IGF, T, numEmptyCases, enumAddr);
}

void storeEnumTagSinglePayload(IRGenFunction &IGF, llvm::Value *whichCase,
llvm::Value *numEmptyCases, Address enumAddr,
SILType T, bool isOutlined) const override {
emitStoreEnumTagSinglePayloadCall(IGF, T, whichCase, numEmptyCases,
enumAddr);
}

void collectMetadataForOutlining(OutliningMetadataCollector &collector,
SILType T) const override {
// We'll need formal type metadata for this archetype.
collector.collectTypeMetadataForLayout(T);
}

TypeLayoutEntry *buildTypeLayoutEntry(IRGenModule &IGM, SILType T,
bool useStructLayouts) const override {
return IGM.typeLayoutCache.getOrCreateArchetypeEntry(T.getObjectType());
}
};
} // end anonymous namespace

/// Emit a single protocol witness table reference.
Expand Down Expand Up @@ -361,6 +432,19 @@ const TypeInfo *TypeConverter::convertArchetypeType(ArchetypeType *archetype) {
? IsABIAccessible
: 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);
}
}

return OpaqueArchetypeTypeInfo::create(storageType, abiAccessible);
}

Expand Down
7 changes: 7 additions & 0 deletions lib/IRGen/IRBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,13 @@ class IRBuilder : public IRBuilderBase {
size.getValue());
}

llvm::CallInst *CreateMemCpy(Address dest, Address src, llvm::Value *size) {
return CreateMemCpy(dest.getAddress(),
llvm::MaybeAlign(dest.getAlignment().getValue()),
src.getAddress(),
llvm::MaybeAlign(src.getAlignment().getValue()), size);
}

using IRBuilderBase::CreateMemSet;
llvm::CallInst *CreateMemSet(Address dest, llvm::Value *value, Size size) {
return CreateMemSet(dest.getAddress(), value, size.getValue(),
Expand Down
41 changes: 41 additions & 0 deletions test/IRGen/bitwise-copyable-derived-loadRaw.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// RUN: %target-run-simple-swift(-Xfrontend -sil-verify-all -enable-experimental-feature BuiltinModule -enable-experimental-feature BitwiseCopyable) | %FileCheck %s

// REQUIRES: executable_test

// Execute an unaligned load of SIMD16<UInt8> which conforms to a protocol derived from BitwiseCopyable.

public protocol MyBitwiseCopyable : _BitwiseCopyable {}

extension SIMD16 : MyBitwiseCopyable {}

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)
//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 : MyBitwiseCopyable>(
fromByteOffset offset: Int = 0,
as type: T.Type
) -> T {
return Builtin.loadRaw((self + offset)._rawValue)
}
}

doit()

@_silgen_name("blackhole")
@inline(never)
@_semantics("optimize.sil.specialize.generic.never")
func blackhole<T>(_ t: T) {
print(t)
}
39 changes: 39 additions & 0 deletions test/IRGen/bitwise-copyable-loadRaw.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// RUN: %target-run-simple-swift(-Xfrontend -sil-verify-all -enable-experimental-feature BuiltinModule -enable-experimental-feature BitwiseCopyable -Xfrontend -disable-availability-checking) | %FileCheck %s

// REQUIRES: executable_test

// Execute an unaligned load of SIMD16<UInt8> which retroactively conforms directly to BitwiseCopyable.

extension SIMD16 : @retroactive _BitwiseCopyable {}

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)
//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")
@inline(never)
@_semantics("optimize.sil.specialize.generic.never")
func blackhole<T>(_ t: T) {
print(t)
}