Skip to content

Commit 87432bd

Browse files
authored
[IRGen] Generate proper TypeLayout for singleton enums (#61966)
* [IRGen] Generate proper TypeLayout for singleton enums rdar://101587387 Instead of creating a proper TypeLayout, we returned the layout for the singleton case, which caused the tags for the nested cases cases to be returned, instead of the expected `0` for singleton enums. * Forward destroy, copy calls * Add some missing forwarding cases
1 parent 9c5645f commit 87432bd

File tree

4 files changed

+103
-18
lines changed

4 files changed

+103
-18
lines changed

lib/IRGen/GenEnum.cpp

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -382,16 +382,21 @@ namespace {
382382

383383
TypeLayoutEntry *buildTypeLayoutEntry(IRGenModule &IGM,
384384
SILType T) const override {
385-
if (ElementsWithPayload.empty())
386-
return IGM.typeLayoutCache.getEmptyEntry();
387-
if (!ElementsAreABIAccessible)
388-
return IGM.typeLayoutCache.getOrCreateResilientEntry(T);
389-
if (TIK >= Loadable) {
390-
return IGM.typeLayoutCache.getOrCreateScalarEntry(getTypeInfo(), T);
391-
}
392-
393-
return getSingleton()->buildTypeLayoutEntry(IGM,
394-
getSingletonType(IGM, T));
385+
if (ElementsWithPayload.empty())
386+
return IGM.typeLayoutCache.getEmptyEntry();
387+
if (!ElementsAreABIAccessible)
388+
return IGM.typeLayoutCache.getOrCreateResilientEntry(T);
389+
if (TIK >= Loadable) {
390+
return IGM.typeLayoutCache.getOrCreateScalarEntry(getTypeInfo(), T);
391+
}
392+
393+
unsigned emptyCases = 0;
394+
std::vector<TypeLayoutEntry *> nonEmptyCases;
395+
nonEmptyCases.push_back(
396+
getSingleton()->buildTypeLayoutEntry(IGM,
397+
getSingletonType(IGM, T)));
398+
return IGM.typeLayoutCache.getOrCreateEnumEntry(emptyCases,
399+
nonEmptyCases);
395400
}
396401

397402
llvm::Value *

lib/IRGen/TypeLayout.cpp

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1457,6 +1457,8 @@ EnumTypeLayoutEntry::CopyDestroyStrategy
14571457
EnumTypeLayoutEntry::copyDestroyKind(IRGenFunction &IGF) const {
14581458
if (isPOD()) {
14591459
return POD;
1460+
} else if (isSingleton()) {
1461+
return ForwardToPayload;
14601462
} else if (cases.size() == 1 && numEmptyCases <= 1 &&
14611463
cases[0]->isSingleRetainablePointer()) {
14621464
return NullableRefcounted;
@@ -1476,7 +1478,9 @@ llvm::Value *EnumTypeLayoutEntry::size(IRGenFunction &IGF) const {
14761478
auto &ctx = IGM.getLLVMContext();
14771479

14781480
auto emptyCaseCount = IGM.getInt32(numEmptyCases);
1479-
if (cases.size() == 1) {
1481+
if (cases.size() == 1 && numEmptyCases == 0) {
1482+
return cases[0]->size(IGF);
1483+
} else if (cases.size() == 1) {
14801484
// Single payload enum.
14811485
// // If there are enough extra inhabitants for all of the cases, then the
14821486
// // size of the enum is the same as its payload.
@@ -1570,7 +1574,10 @@ llvm::Optional<Size> EnumTypeLayoutEntry::fixedSize(IRGenModule &IGM) const {
15701574
if (_fixedSize)
15711575
return *_fixedSize;
15721576
assert(!cases.empty());
1573-
if (cases.size() == 1) {
1577+
1578+
if (cases.size() == 1 && numEmptyCases == 0) {
1579+
return cases[0]->fixedSize(IGM);
1580+
} else if (cases.size() == 1) {
15741581
// Single payload enum.
15751582
//
15761583
// If there are enough extra inhabitants for all of the cases, then the
@@ -1632,7 +1639,9 @@ EnumTypeLayoutEntry::fixedXICount(IRGenModule &IGM) const {
16321639
return *_fixedXICount;
16331640
assert(!cases.empty());
16341641

1635-
if (cases.size() == 1) {
1642+
if (cases.size() == 1 && numEmptyCases == 0) {
1643+
return cases[0]->fixedXICount(IGM);
1644+
} else if (cases.size() == 1) {
16361645
// Single payload enum.
16371646
// unsigned unusedExtraInhabitants =
16381647
// payloadNumExtraInhabitants >= emptyCases ?
@@ -1677,7 +1686,9 @@ llvm::Value *EnumTypeLayoutEntry::extraInhabitantCount(IRGenFunction &IGF) const
16771686
auto &IGM = IGF.IGM;
16781687
auto &Builder = IGF.Builder;
16791688

1680-
if (cases.size() == 1) {
1689+
if (cases.size() == 1 && numEmptyCases == 0) {
1690+
return cases[0]->extraInhabitantCount(IGF);
1691+
} else if (cases.size() == 1) {
16811692
// Single payload enum.
16821693
// unsigned unusedExtraInhabitants =
16831694
// payloadNumExtraInhabitants >= emptyCases ?
@@ -2211,7 +2222,9 @@ llvm::Value *EnumTypeLayoutEntry::getEnumTagSinglePayloadForSinglePayloadEnum(
22112222
llvm::Value *EnumTypeLayoutEntry::getEnumTagSinglePayload(
22122223
IRGenFunction &IGF, llvm::Value *emptyCases, Address addr) const {
22132224
assert(!cases.empty());
2214-
if (cases.size() == 1) {
2225+
if (cases.size() == 1 && numEmptyCases == 0) {
2226+
return cases[0]->getEnumTagSinglePayload(IGF, emptyCases, addr);
2227+
} else if (cases.size() == 1) {
22152228
return getEnumTagSinglePayloadForSinglePayloadEnum(IGF, addr, emptyCases);
22162229
}
22172230
return getEnumTagSinglePayloadForMultiPayloadEnum(IGF, addr, emptyCases);
@@ -2290,7 +2303,9 @@ void EnumTypeLayoutEntry::storeEnumTagSinglePayload(IRGenFunction &IGF,
22902303
llvm::Value *emptyCases,
22912304
Address addr) const {
22922305
assert(!cases.empty());
2293-
if (cases.size() == 1) {
2306+
if (cases.size() == 1 && numEmptyCases == 0) {
2307+
return cases[0]->storeEnumTagSinglePayload(IGF, tag, emptyCases, addr);
2308+
} else if (cases.size() == 1) {
22942309
storeEnumTagSinglePayloadForSinglePayloadEnum(IGF, tag, emptyCases, addr);
22952310
return;
22962311
}
@@ -2302,6 +2317,10 @@ bool EnumTypeLayoutEntry::isMultiPayloadEnum() const {
23022317
return cases.size() > 1;
23032318
}
23042319

2320+
bool EnumTypeLayoutEntry::isSingleton() const {
2321+
return cases.size() + numEmptyCases == 1;
2322+
}
2323+
23052324
llvm::Value *
23062325
EnumTypeLayoutEntry::getEnumTagMultipayload(IRGenFunction &IGF,
23072326
Address enumAddr) const {
@@ -2376,7 +2395,10 @@ llvm::Value *EnumTypeLayoutEntry::getEnumTag(IRGenFunction &IGF,
23762395
Address enumAddr) const {
23772396
assert(!cases.empty());
23782397

2379-
if (cases.size() == 1) {
2398+
if (isSingleton()) {
2399+
// Singleton tag is always `0`
2400+
return IGF.IGM.getInt32(0);
2401+
} else if (cases.size() == 1) {
23802402
// Single payload enum.
23812403
auto &IGM = IGF.IGM;
23822404
auto payload = cases[0];
@@ -2480,7 +2502,10 @@ void EnumTypeLayoutEntry::storeEnumTagMultipayload(IRGenFunction &IGF,
24802502
void EnumTypeLayoutEntry::destructiveInjectEnumTag(IRGenFunction &IGF,
24812503
llvm::Value *tag,
24822504
Address enumAddr) const {
2483-
if (cases.size() == 1) {
2505+
if (isSingleton()) {
2506+
// No tag, nothing to do
2507+
return;
2508+
} else if (cases.size() == 1) {
24842509
auto payload = cases[0];
24852510
auto emptyCases = IGF.IGM.getInt32(numEmptyCases);
24862511
payload->storeEnumTagSinglePayload(IGF, tag, emptyCases, enumAddr);

lib/IRGen/TypeLayout.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,7 @@ class EnumTypeLayoutEntry : public TypeLayoutEntry,
474474
Address enumAddr) const;
475475

476476
bool isMultiPayloadEnum() const;
477+
bool isSingleton() const;
477478

478479
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
479480
void dump() const override;

test/IRGen/enum_singleton.swift

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// RUN: %target-swift-frontend -emit-ir %s | %FileCheck %s --check-prefix=CHECK
2+
// RUN: %target-swift-frontend -emit-ir -O %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-OPT
3+
4+
public enum Payload {
5+
case c1(Bool)
6+
case c2(Bool)
7+
case c3(Any)
8+
}
9+
10+
public enum SingletonEnum {
11+
case c1(Payload)
12+
}
13+
14+
// CHECK: define internal void @"$s14enum_singleton13SingletonEnumOwxx"
15+
// CHECK-OPT: tail call void @"{{.*}}OwxxTm"
16+
// CHECK: ret void
17+
// CHECK: }
18+
19+
// CHECK: define internal %swift.opaque* @"$s14enum_singleton13SingletonEnumOwcp"
20+
// CHECK-OPT: [[R0:%.*]] = tail call %swift.opaque* @"{{.*}}OwcpTm"
21+
// CHECK-OPT: ret %swift.opaque* [[R0]]
22+
// CHECK: }
23+
24+
// CHECK: define internal %swift.opaque* @"$s14enum_singleton13SingletonEnumOwca"
25+
// CHECK-OPT: [[R1:%.*]] = tail call %swift.opaque* @"{{.*}}OwcaTm"
26+
// CHECK-OPT: ret %swift.opaque* [[R1]]
27+
// CHECK: }
28+
29+
// CHECK: define internal %swift.opaque* @"$s14enum_singleton13SingletonEnumOwta"
30+
// CHECK-OPT: [[R2:%.*]] = tail call %swift.opaque* @"{{.*}}OwtaTm"
31+
// CHECK-OPT: ret %swift.opaque* [[R2]]
32+
// CHECK: }
33+
34+
// CHECK: define internal i32 @"$s14enum_singleton13SingletonEnumOwet"
35+
// CHECK-OPT: [[R2:%.*]] = tail call i32 @"{{.*}}OwetTm"
36+
// CHECK-OPT: ret i32 [[R2]]
37+
// CHECK: }
38+
39+
// CHECK: define internal void @"$s14enum_singleton13SingletonEnumOwst"
40+
// CHECK-OPT: tail call void @"{{.*}}OwstTm"
41+
// CHECK-OPT: ret void
42+
// CHECK: }
43+
44+
// CHECK: define internal i32 @"$s14enum_singleton13SingletonEnumOwug"
45+
// CHECK: ret i32 0
46+
// CHECK: }
47+
48+
// CHECK: define internal void @"$s14enum_singleton13SingletonEnumOwup"
49+
// CHECK: ret void
50+
// CHECK: }
51+
52+
// CHECK: define internal void @"$s14enum_singleton13SingletonEnumOwui"
53+
// CHECK: ret void
54+
// CHECK: }

0 commit comments

Comments
 (0)