[Runtime] Add specialized CVW entry points for multi payload enums

rdar://143852239

Adding these specialized entry points reduces the overhead of the witness functions by removing the first indirection.
This commit is contained in:
Dario Rexin
2025-01-29 15:59:38 -08:00
parent 109e2081b6
commit 923cccf1ea
8 changed files with 318 additions and 35 deletions

View File

@@ -2747,6 +2747,68 @@ FUNCTION(GenericInitializeBufferWithCopyOfBuffer,
EFFECT(RefCounting),
UNKNOWN_MEMEFFECTS)
// void swift_cvw_destroyMultiPayloadEnumFN(opaque*, const Metadata* type);
FUNCTION(GenericDestroyMultiPayloadEnumFN,
Swift, swift_cvw_destroyMultiPayloadEnumFN,
C_CC, AlwaysAvailable,
RETURNS(VoidTy),
ARGS(Int8PtrTy, TypeMetadataPtrTy),
ATTRS(NoUnwind),
EFFECT(Deallocating),
UNKNOWN_MEMEFFECTS)
// void *swift_cvw_assignWithCopyMultiPayloadEnumFN(opaque* dest, opaque* src, const Metadata* type);
FUNCTION(GenericAssignWithCopyMultiPayloadEnumFN,
Swift, swift_cvw_assignWithCopyMultiPayloadEnumFN,
C_CC, AlwaysAvailable,
RETURNS(Int8PtrTy),
ARGS(Int8PtrTy, Int8PtrTy, TypeMetadataPtrTy),
ATTRS(NoUnwind),
EFFECT(RefCounting, Deallocating),
UNKNOWN_MEMEFFECTS)
// void *swift_cvw_assignWithTakeMultiPayloadEnumFN(opaque* dest, opaque* src, const Metadata* type);
FUNCTION(GenericAssignWithTakeMultiPayloadEnumFN,
Swift, swift_cvw_assignWithTakeMultiPayloadEnumFN,
C_CC, AlwaysAvailable,
RETURNS(Int8PtrTy),
ARGS(Int8PtrTy, Int8PtrTy, TypeMetadataPtrTy),
ATTRS(NoUnwind),
EFFECT(RefCounting, Deallocating),
UNKNOWN_MEMEFFECTS)
// void *swift_cvw_initWithCopyMultiPayloadEnumFN(opaque* dest, opaque* src, const Metadata* type);
FUNCTION(GenericInitWithCopyMultiPayloadEnumFN,
Swift, swift_cvw_initWithCopyMultiPayloadEnumFN,
C_CC, AlwaysAvailable,
RETURNS(Int8PtrTy),
ARGS(Int8PtrTy, Int8PtrTy, TypeMetadataPtrTy),
ATTRS(NoUnwind),
EFFECT(RefCounting),
UNKNOWN_MEMEFFECTS)
// void *swift_cvw_initWithTakeMultiPayloadEnumFN(opaque* dest, opaque* src, const Metadata* type);
FUNCTION(GenericInitWithTakeMultiPayloadEnumFN,
Swift, swift_cvw_initWithTakeMultiPayloadEnumFN,
C_CC, AlwaysAvailable,
RETURNS(Int8PtrTy),
ARGS(Int8PtrTy, Int8PtrTy, TypeMetadataPtrTy),
ATTRS(NoUnwind),
EFFECT(RefCounting),
UNKNOWN_MEMEFFECTS)
// void *swift_cvw_initializeBufferWithCopyOfBufferMultiPayloadEnumFN(ValueBuffer* dest, ValueBuffer* src, const Metadata* type);
FUNCTION(GenericInitializeBufferWithCopyOfBufferMultiPayloadEnumFN,
Swift, swift_cvw_initializeBufferWithCopyOfBufferMultiPayloadEnumFN,
C_CC, AlwaysAvailable,
RETURNS(Int8PtrTy),
ARGS(getFixedBufferTy()->getPointerTo(),
getFixedBufferTy()->getPointerTo(),
TypeMetadataPtrTy),
ATTRS(NoUnwind),
EFFECT(RefCounting),
UNKNOWN_MEMEFFECTS)
// unsigned swift_cvw_singletonEnum_getEnumTag(swift::OpaqueValue *address,
// const Metadata *metadata);
FUNCTION(SingletonEnumGetEnumTag,

View File

@@ -933,6 +933,21 @@ static bool isRuntimeInstatiatedLayoutString(IRGenModule &IGM,
return false;
}
static bool
useMultiPayloadEnumFNSpecialization(IRGenModule &IGM,
const TypeLayoutEntry *typeLayoutEntry,
GenericSignature genericSig) {
// if (!typeLayoutEntry->layoutString(IGM, genericSig)) {
// return false;
// }
// auto *enumTLE = typeLayoutEntry->getAsEnum();
// return enumTLE && enumTLE->isFixedSize(IGM) &&
// enumTLE->isMultiPayloadEnum();
// Disabled for now
return false;
}
static llvm::Constant *getEnumTagFunction(IRGenModule &IGM,
const EnumTypeLayoutEntry *typeLayoutEntry,
GenericSignature genericSig) {
@@ -953,19 +968,7 @@ static llvm::Constant *getEnumTagFunction(IRGenModule &IGM,
} else if (typeLayoutEntry->isMultiPayloadEnum()) {
return IGM.getEnumFnGetEnumTagFn();
} else {
auto &payloadTI = **(typeLayoutEntry->cases[0]->getFixedTypeInfo());
auto mask = payloadTI.getFixedExtraInhabitantMask(IGM);
auto tzCount = mask.countTrailingZeros();
auto shiftedMask = mask.lshr(tzCount);
// auto toCount = shiftedMask.countTrailingOnes();
// if (payloadTI.mayHaveExtraInhabitants(IGM) &&
// (mask.popcount() > 64 ||
// toCount != mask.popcount() ||
// (tzCount % toCount != 0))) {
return IGM.getEnumFnGetEnumTagFn();
// } else {
// return IGM.getEnumSimpleGetEnumTagFn();
// }
}
}
@@ -990,18 +993,7 @@ getDestructiveInjectEnumTagFunction(IRGenModule &IGM,
} else if (typeLayoutEntry->isMultiPayloadEnum()) {
return nullptr;
} else {
auto &payloadTI = **(typeLayoutEntry->cases[0]->getFixedTypeInfo());
auto mask = payloadTI.getFixedExtraInhabitantMask(IGM);
auto tzCount = mask.countTrailingZeros();
auto shiftedMask = mask.lshr(tzCount);
// auto toCount = shiftedMask.countTrailingOnes();
// if (payloadTI.mayHaveExtraInhabitants(IGM) &&
// (mask.popcount() > 64 || toCount != mask.popcount() ||
// (tzCount % toCount != 0))) {
return nullptr;
// } else {
// return IGM.getEnumSimpleDestructiveInjectEnumTagFn();
// }
}
}
@@ -1072,10 +1064,15 @@ static void addValueWitness(IRGenModule &IGM, ConstantStructBuilder &B,
->getGenericSignature();
if (typeLayoutEntry->layoutString(IGM, genericSig) ||
isRuntimeInstatiatedLayoutString(IGM, typeLayoutEntry)) {
if (useMultiPayloadEnumFNSpecialization(IGM, typeLayoutEntry,
genericSig)) {
return addFunction(IGM.getGenericDestroyMultiPayloadEnumFNFn());
} else {
return addFunction(IGM.getGenericDestroyFn());
}
}
}
}
goto standard;
case ValueWitness::InitializeBufferWithCopyOfBuffer:
@@ -1101,11 +1098,17 @@ static void addValueWitness(IRGenModule &IGM, ConstantStructBuilder &B,
->getGenericSignature();
if (typeLayoutEntry->layoutString(IGM, genericSig) ||
isRuntimeInstatiatedLayoutString(IGM, typeLayoutEntry)) {
if (useMultiPayloadEnumFNSpecialization(IGM, typeLayoutEntry,
genericSig)) {
return addFunction(
IGM.getGenericInitializeBufferWithCopyOfBufferMultiPayloadEnumFNFn());
} else {
return addFunction(
IGM.getGenericInitializeBufferWithCopyOfBufferFn());
}
}
}
}
goto standard;
case ValueWitness::InitializeWithTake:
@@ -1121,10 +1124,16 @@ static void addValueWitness(IRGenModule &IGM, ConstantStructBuilder &B,
->getGenericSignature();
if (typeLayoutEntry->layoutString(IGM, genericSig) ||
isRuntimeInstatiatedLayoutString(IGM, typeLayoutEntry)) {
if (useMultiPayloadEnumFNSpecialization(IGM, typeLayoutEntry,
genericSig)) {
return addFunction(
IGM.getGenericInitWithTakeMultiPayloadEnumFNFn());
} else {
return addFunction(IGM.getGenericInitWithTakeFn());
}
}
}
}
goto standard;
case ValueWitness::AssignWithCopy:
@@ -1142,10 +1151,16 @@ static void addValueWitness(IRGenModule &IGM, ConstantStructBuilder &B,
->getGenericSignature();
if (typeLayoutEntry->layoutString(IGM, genericSig) ||
isRuntimeInstatiatedLayoutString(IGM, typeLayoutEntry)) {
if (useMultiPayloadEnumFNSpecialization(IGM, typeLayoutEntry,
genericSig)) {
return addFunction(
IGM.getGenericAssignWithCopyMultiPayloadEnumFNFn());
} else {
return addFunction(IGM.getGenericAssignWithCopyFn());
}
}
}
}
goto standard;
case ValueWitness::AssignWithTake:
@@ -1163,10 +1178,16 @@ static void addValueWitness(IRGenModule &IGM, ConstantStructBuilder &B,
->getGenericSignature();
if (typeLayoutEntry->layoutString(IGM, genericSig) ||
isRuntimeInstatiatedLayoutString(IGM, typeLayoutEntry)) {
if (useMultiPayloadEnumFNSpecialization(IGM, typeLayoutEntry,
genericSig)) {
return addFunction(
IGM.getGenericAssignWithTakeMultiPayloadEnumFNFn());
} else {
return addFunction(IGM.getGenericAssignWithTakeFn());
}
}
}
}
goto standard;
case ValueWitness::InitializeWithCopy:
@@ -1184,10 +1205,16 @@ static void addValueWitness(IRGenModule &IGM, ConstantStructBuilder &B,
->getGenericSignature();
if (typeLayoutEntry->layoutString(IGM, genericSig) ||
isRuntimeInstatiatedLayoutString(IGM, typeLayoutEntry)) {
if (useMultiPayloadEnumFNSpecialization(IGM, typeLayoutEntry,
genericSig)) {
return addFunction(
IGM.getGenericInitWithCopyMultiPayloadEnumFNFn());
} else {
return addFunction(IGM.getGenericInitWithCopyFn());
}
}
}
}
goto standard;
case ValueWitness::Size: {

View File

@@ -310,6 +310,42 @@ OVERRIDE_CVW(cvw_initializeBufferWithCopyOfBuffer, swift::OpaqueValue *,
const Metadata *metadata),
(dest, src, metadata))
OVERRIDE_CVW(cvw_destroyMultiPayloadEnumFN, void, SWIFT_RUNTIME_EXPORT,
, swift::, (swift::OpaqueValue *address,
const Metadata *metadata),
(address, metadata))
OVERRIDE_CVW(cvw_assignWithCopyMultiPayloadEnumFN, swift::OpaqueValue *, SWIFT_RUNTIME_EXPORT,
, swift::, (swift::OpaqueValue *dest,
swift::OpaqueValue *src,
const Metadata *metadata),
(dest, src, metadata))
OVERRIDE_CVW(cvw_assignWithTakeMultiPayloadEnumFN, swift::OpaqueValue *, SWIFT_RUNTIME_EXPORT,
, swift::, (swift::OpaqueValue *dest,
swift::OpaqueValue *src,
const Metadata *metadata),
(dest, src, metadata))
OVERRIDE_CVW(cvw_initWithCopyMultiPayloadEnumFN, swift::OpaqueValue *, SWIFT_RUNTIME_EXPORT,
, swift::, (swift::OpaqueValue *dest,
swift::OpaqueValue *src,
const Metadata *metadata),
(dest, src, metadata))
OVERRIDE_CVW(cvw_initWithTakeMultiPayloadEnumFN, swift::OpaqueValue *, SWIFT_RUNTIME_EXPORT,
, swift::, (swift::OpaqueValue *dest,
swift::OpaqueValue *src,
const Metadata *metadata),
(dest, src, metadata))
OVERRIDE_CVW(cvw_initializeBufferWithCopyOfBufferMultiPayloadEnumFN, swift::OpaqueValue *,
SWIFT_RUNTIME_EXPORT,
, swift::, (swift::ValueBuffer *dest,
swift::ValueBuffer *src,
const Metadata *metadata),
(dest, src, metadata))
OVERRIDE_CVW(cvw_enumSimple_getEnumTag, unsigned, SWIFT_RUNTIME_EXPORT,
, swift::, (swift::OpaqueValue *address,
const Metadata *metadata),

View File

@@ -1147,7 +1147,7 @@ static void handleRefCountsInitWithCopy(const Metadata *metadata,
uintptr_t _addrOffset = addrOffset;
auto tag = reader.readBytes<uint64_t>();
auto offset = (tag & ~(0xFFULL << 56));
if (SWIFT_UNLIKELY(offset)) {
if (offset) {
memcpy(dest + _addrOffset, src + _addrOffset, offset);
}
addrOffset = _addrOffset + offset;
@@ -1305,7 +1305,7 @@ static void handleRefCountsInitWithTake(const Metadata *metadata,
uintptr_t _addrOffset = addrOffset;
auto tag = reader.readBytes<uint64_t>();
auto offset = (tag & ~(0xFFULL << 56));
if (SWIFT_UNLIKELY(offset)) {
if (offset) {
memcpy(dest + _addrOffset, src + _addrOffset, offset);
}
addrOffset += offset;
@@ -2589,6 +2589,121 @@ void swift::swift_cvw_resolve_resilientAccessors(uint8_t *layoutStr,
}
}
static void swift_cvw_destroyMultiPayloadEnumFNImpl(swift::OpaqueValue *address,
const Metadata *metadata) {
const uint8_t *layoutStr = metadata->getLayoutString();
LayoutStringReader1 reader{layoutStr + layoutStringHeaderSize};
uintptr_t addrOffset = 0;
uint8_t *addr = (uint8_t *)address;
#ifndef NDEBUG
assert(reader.readBytes<uint64_t>() ==
((uint64_t)RefCountingKind::MultiPayloadEnumFN) << 56 &&
"Invalid tag, expected MultiPayloadEnumFN");
#else
reader.skip(sizeof(uint64_t));
#endif
multiPayloadEnumFN<handleRefCountsDestroy>(metadata, reader, addrOffset,
addr);
}
static swift::OpaqueValue *
swift_cvw_assignWithCopyMultiPayloadEnumFNImpl(swift::OpaqueValue *_dest,
swift::OpaqueValue *_src,
const Metadata *metadata) {
const uint8_t *layoutStr = metadata->getLayoutString();
LayoutStringReader1 reader{layoutStr + layoutStringHeaderSize};
uintptr_t addrOffset = 0;
uint8_t *dest = (uint8_t *)_dest;
uint8_t *src = (uint8_t *)_src;
#ifndef NDEBUG
assert(reader.readBytes<uint64_t>() ==
((uint64_t)RefCountingKind::MultiPayloadEnumFN) << 56 &&
"Invalid tag, expected MultiPayloadEnumFN");
#else
reader.skip(sizeof(uint64_t));
#endif
multiPayloadEnumFNAssignWithCopy(metadata, reader, addrOffset, dest, src);
return _dest;
}
static swift::OpaqueValue *
swift_cvw_assignWithTakeMultiPayloadEnumFNImpl(swift::OpaqueValue *dest,
swift::OpaqueValue *src,
const Metadata *metadata) {
swift_cvw_destroyMultiPayloadEnumFN(dest, metadata);
return swift_cvw_initWithTake(dest, src, metadata);
}
static swift::OpaqueValue *
swift_cvw_initWithCopyMultiPayloadEnumFNImpl(swift::OpaqueValue *_dest,
swift::OpaqueValue *_src,
const Metadata *metadata) {
const uint8_t *layoutStr = metadata->getLayoutString();
LayoutStringReader1 reader{layoutStr + layoutStringHeaderSize};
uintptr_t addrOffset = 0;
uint8_t *dest = (uint8_t *)_dest;
uint8_t *src = (uint8_t *)_src;
#ifndef NDEBUG
assert(reader.readBytes<uint64_t>() ==
((uint64_t)RefCountingKind::MultiPayloadEnumFN) << 56 &&
"Invalid tag, expected MultiPayloadEnumFN");
#else
reader.skip(sizeof(uint64_t));
#endif
multiPayloadEnumFN<handleRefCountsInitWithCopy>(metadata, reader, addrOffset,
dest, src);
return _dest;
}
static swift::OpaqueValue *
swift_cvw_initWithTakeMultiPayloadEnumFNImpl(swift::OpaqueValue *_dest,
swift::OpaqueValue *_src,
const Metadata *metadata) {
if (SWIFT_LIKELY(metadata->getValueWitnesses()->isBitwiseTakable())) {
size_t size = metadata->vw_size();
memcpy(_dest, _src, size);
return _dest;
}
const uint8_t *layoutStr = metadata->getLayoutString();
LayoutStringReader1 reader{layoutStr + layoutStringHeaderSize};
uintptr_t addrOffset = 0;
uint8_t *dest = (uint8_t *)_dest;
uint8_t *src = (uint8_t *)_src;
#ifndef NDEBUG
assert(reader.readBytes<uint64_t>() ==
((uint64_t)RefCountingKind::MultiPayloadEnumFN) << 56 &&
"Invalid tag, expected MultiPayloadEnumFN");
#else
reader.skip(sizeof(uint64_t));
#endif
multiPayloadEnumFN<handleRefCountsInitWithTake>(metadata, reader, addrOffset,
dest, src);
return _dest;
}
static swift::OpaqueValue *
swift_cvw_initializeBufferWithCopyOfBufferMultiPayloadEnumFNImpl(
swift::ValueBuffer *dest, swift::ValueBuffer *src,
const Metadata *metadata) {
if (metadata->getValueWitnesses()->isValueInline()) {
return swift_cvw_initWithCopyMultiPayloadEnumFN(
(swift::OpaqueValue *)dest, (swift::OpaqueValue *)src, metadata);
} else {
memcpy(dest, src, sizeof(swift::HeapObject *));
swift_retain(*(swift::HeapObject **)src);
return (swift::OpaqueValue *)&(*(swift::HeapObject **)dest)[1];
}
}
extern "C" void swift_cvw_instantiateLayoutString(const uint8_t *layoutStr,
Metadata *type) {
type->setLayoutString(layoutStr);

View File

@@ -195,6 +195,36 @@ swift::OpaqueValue *
swift_cvw_initializeBufferWithCopyOfBuffer(swift::ValueBuffer *dest,
swift::ValueBuffer *src,
const Metadata *metadata);
SWIFT_RUNTIME_EXPORT
void swift_cvw_destroyMultiPayloadEnumFN(swift::OpaqueValue *address,
const Metadata *metadata);
SWIFT_RUNTIME_EXPORT
swift::OpaqueValue *
swift_cvw_assignWithCopyMultiPayloadEnumFN(swift::OpaqueValue *dest,
swift::OpaqueValue *src,
const Metadata *metadata);
SWIFT_RUNTIME_EXPORT
swift::OpaqueValue *
swift_cvw_assignWithTakeMultiPayloadEnumFN(swift::OpaqueValue *dest,
swift::OpaqueValue *src,
const Metadata *metadata);
SWIFT_RUNTIME_EXPORT
swift::OpaqueValue *
swift_cvw_initWithCopyMultiPayloadEnumFN(swift::OpaqueValue *dest,
swift::OpaqueValue *src,
const Metadata *metadata);
SWIFT_RUNTIME_EXPORT
swift::OpaqueValue *
swift_cvw_initWithTakeMultiPayloadEnumFN(swift::OpaqueValue *dest,
swift::OpaqueValue *src,
const Metadata *metadata);
SWIFT_RUNTIME_EXPORT
swift::OpaqueValue *
swift_cvw_initializeBufferWithCopyOfBufferMultiPayloadEnumFN(
swift::ValueBuffer *dest, swift::ValueBuffer *src,
const Metadata *metadata);
SWIFT_RUNTIME_EXPORT
unsigned swift_cvw_singletonEnum_getEnumTag(swift::OpaqueValue *address,
const Metadata *metadata);
@@ -271,6 +301,7 @@ swift::OpaqueValue *
swift_generic_initializeBufferWithCopyOfBuffer(swift::ValueBuffer *dest,
swift::ValueBuffer *src,
const Metadata *metadata);
SWIFT_RUNTIME_EXPORT
unsigned swift_singletonEnum_getEnumTag(swift::OpaqueValue *address,
const Metadata *metadata);

View File

@@ -717,7 +717,7 @@ public func testInitTake<T>(_ ptr: UnsafeMutablePointer<T>, to x: consuming T) {
@inline(never)
public func testDestroy<T>(_ ptr: UnsafeMutablePointer<T>) {
ptr.deinitialize(count: 1)
_ = ptr.move()
}
@inline(never)

View File

@@ -870,3 +870,9 @@ Added: _swift_cvw_singlePayloadEnumGeneric_destructiveInjectEnumTag
Added: _swift_cvw_singlePayloadEnumGeneric_getEnumTag
Added: _swift_cvw_singletonEnum_destructiveInjectEnumTag
Added: _swift_cvw_singletonEnum_getEnumTag
Added: _swift_cvw_assignWithCopyMultiPayloadEnumFN
Added: _swift_cvw_assignWithTakeMultiPayloadEnumFN
Added: _swift_cvw_destroyMultiPayloadEnumFN
Added: _swift_cvw_initWithCopyMultiPayloadEnumFN
Added: _swift_cvw_initWithTakeMultiPayloadEnumFN
Added: _swift_cvw_initializeBufferWithCopyOfBufferMultiPayloadEnumFN

View File

@@ -871,3 +871,9 @@ Added: _swift_cvw_singlePayloadEnumGeneric_destructiveInjectEnumTag
Added: _swift_cvw_singlePayloadEnumGeneric_getEnumTag
Added: _swift_cvw_singletonEnum_destructiveInjectEnumTag
Added: _swift_cvw_singletonEnum_getEnumTag
Added: _swift_cvw_assignWithCopyMultiPayloadEnumFN
Added: _swift_cvw_assignWithTakeMultiPayloadEnumFN
Added: _swift_cvw_destroyMultiPayloadEnumFN
Added: _swift_cvw_initWithCopyMultiPayloadEnumFN
Added: _swift_cvw_initWithTakeMultiPayloadEnumFN
Added: _swift_cvw_initializeBufferWithCopyOfBufferMultiPayloadEnumFN