Skip to content

Commit 8ccaad1

Browse files
committed
[IRGen] Emit swift_singlePayloadEnumGeneric_destructiveInjectEnumTag
Assign swift_singlePayloadEnumGeneric_destructiveInjectEnumTag as witness function on generic single payload enums when using layout strings
1 parent 89d37da commit 8ccaad1

File tree

3 files changed

+82
-3
lines changed

3 files changed

+82
-3
lines changed

lib/IRGen/GenValueWitness.cpp

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,38 @@ static llvm::Constant *getEnumTagFunction(IRGenModule &IGM,
931931
}
932932
}
933933

934+
static llvm::Constant *
935+
getDestructiveInjectEnumTagFunction(IRGenModule &IGM,
936+
const EnumTypeLayoutEntry *typeLayoutEntry,
937+
GenericSignature genericSig) {
938+
if ((!typeLayoutEntry->layoutString(IGM, genericSig) &&
939+
!isRuntimeInstatiatedLayoutString(IGM, typeLayoutEntry)) ||
940+
typeLayoutEntry->isSingleton()) {
941+
return nullptr;
942+
} else if (!typeLayoutEntry->isFixedSize(IGM)) {
943+
if (typeLayoutEntry->isMultiPayloadEnum()) {
944+
return nullptr;
945+
} else {
946+
return IGM.getSinglePayloadEnumGenericDestructiveInjectEnumTagFn();
947+
}
948+
} else if (typeLayoutEntry->isMultiPayloadEnum()) {
949+
return nullptr;
950+
} else {
951+
auto &payloadTI = **(typeLayoutEntry->cases[0]->getFixedTypeInfo());
952+
auto mask = payloadTI.getFixedExtraInhabitantMask(IGM);
953+
auto tzCount = mask.countTrailingZeros();
954+
auto shiftedMask = mask.lshr(tzCount);
955+
auto toCount = shiftedMask.countTrailingOnes();
956+
if (payloadTI.mayHaveExtraInhabitants(IGM) &&
957+
(mask.countPopulation() > 64 || toCount != mask.countPopulation() ||
958+
(tzCount % toCount != 0))) {
959+
return nullptr;
960+
} else {
961+
return nullptr;
962+
}
963+
}
964+
}
965+
934966
static bool
935967
valueWitnessRequiresCopyability(ValueWitness index) {
936968
switch (index) {
@@ -1189,8 +1221,31 @@ addValueWitness(IRGenModule &IGM, ConstantStructBuilder &B, ValueWitness index,
11891221
}
11901222
goto standard;
11911223
}
1224+
case ValueWitness::DestructiveInjectEnumTag: {
1225+
assert(concreteType.getEnumOrBoundGenericEnum());
1226+
if (IGM.Context.LangOpts.hasFeature(Feature::LayoutStringValueWitnesses) &&
1227+
IGM.getOptions().EnableLayoutStringValueWitnesses) {
1228+
auto ty = boundGenericCharacteristics
1229+
? boundGenericCharacteristics->concreteType
1230+
: concreteType;
1231+
auto &typeInfo = boundGenericCharacteristics
1232+
? *boundGenericCharacteristics->TI
1233+
: concreteTI;
1234+
if (auto *typeLayoutEntry = typeInfo.buildTypeLayoutEntry(
1235+
IGM, ty, /*useStructLayouts*/ true)) {
1236+
if (auto *enumLayoutEntry = typeLayoutEntry->getAsEnum()) {
1237+
auto genericSig = concreteType.getNominalOrBoundGenericNominal()
1238+
->getGenericSignature();
1239+
if (auto *fn = getDestructiveInjectEnumTagFunction(
1240+
IGM, enumLayoutEntry, genericSig)) {
1241+
return addFunction(fn);
1242+
}
1243+
}
1244+
}
1245+
}
1246+
goto standard;
1247+
}
11921248
case ValueWitness::DestructiveProjectEnumData:
1193-
case ValueWitness::DestructiveInjectEnumTag:
11941249
assert(concreteType.getEnumOrBoundGenericEnum());
11951250
goto standard;
11961251
}

test/Interpreter/Inputs/layout_string_witnesses_types_resilient.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public struct GenericResilient<C, T> {
2222
public enum ResilientSinglePayloadEnumGeneric<T> {
2323
case empty0
2424
case empty1
25-
case nonEmpty0(T)
25+
case nonEmpty(T)
2626
}
2727

2828
public enum ResilientMultiPayloadEnumGeneric<T> {

test/Interpreter/layout_string_witnesses_dynamic.swift

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,7 @@ testResilientMultiPayloadEnumTag()
569569

570570
func testResilientSinglePayloadEnumGenericTag() {
571571
let x = switch getResilientSinglePayloadEnumGenericEmpty0(AnyObject.self) {
572-
case .nonEmpty0: 0
572+
case .nonEmpty: 0
573573
case .empty0: 1
574574
case .empty1: 2
575575
}
@@ -594,6 +594,30 @@ func testResilientMultiPayloadEnumGenericTag() {
594594

595595
testResilientMultiPayloadEnumGenericTag()
596596

597+
@inline(never)
598+
func matchResilientSinglePayloadEnumGenericTag(_ x: ResilientSinglePayloadEnumGeneric<AnyObject>) -> Int {
599+
return switch x {
600+
case .nonEmpty: 0
601+
case .empty0: 1
602+
case .empty1: 2
603+
}
604+
}
605+
606+
func testResilientSinglePayloadEnumGenericInjectTag() {
607+
let x = ResilientSinglePayloadEnumGeneric<AnyObject>.nonEmpty(SimpleClass(x: 23))
608+
let y = ResilientSinglePayloadEnumGeneric<AnyObject>.empty0
609+
let z = ResilientSinglePayloadEnumGeneric<AnyObject>.empty1
610+
611+
// CHECK: Enum case: 0
612+
print("Enum case: \(matchResilientSinglePayloadEnumGenericTag(x))")
613+
// CHECK: Enum case: 1
614+
print("Enum case: \(matchResilientSinglePayloadEnumGenericTag(y))")
615+
// CHECK: Enum case: 2
616+
print("Enum case: \(matchResilientSinglePayloadEnumGenericTag(z))")
617+
}
618+
619+
testResilientSinglePayloadEnumGenericInjectTag()
620+
597621
#if os(macOS)
598622

599623
import Foundation

0 commit comments

Comments
 (0)