Skip to content

Commit 8643d14

Browse files
committed
IRGen: Fix select_enum for single-payload, multi-empty-case enums.
If the payload has insufficient extra inhabitants and there's more than one empty case that requires spilling extra tag bits, we need to check the payload part of the value to discriminate them.
1 parent 7f3e98e commit 8643d14

File tree

2 files changed

+46
-5
lines changed

2 files changed

+46
-5
lines changed

lib/IRGen/GenEnum.cpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1539,13 +1539,20 @@ namespace {
15391539
std::tie(payloadTag, extraTag) = getNoPayloadCaseValue(Case);
15401540

15411541
auto &ti = getFixedPayloadTypeInfo();
1542-
bool hasExtraInhabitants = ti.getFixedExtraInhabitantCount(IGF.IGM) > 0;
1543-
1542+
15441543
llvm::Value *payloadResult = nullptr;
1545-
if (hasExtraInhabitants)
1546-
payloadResult = payload.emitCompare(IGF,
1544+
// We can omit the payload check if this is the only case represented with
1545+
// the particular extra tag bit pattern set.
1546+
//
1547+
// TODO: This logic covers the most common case, when there's exactly one
1548+
// more no-payload case than extra inhabitants in the payload. This could
1549+
// be slightly generalized to cases where there's multiple tag bits and
1550+
// exactly one no-payload case in the highest used tag value.
1551+
if (!tagBits ||
1552+
ElementsWithNoPayload.size() != getFixedExtraInhabitantCount(IGF.IGM)+1)
1553+
payloadResult = payload.emitCompare(IGF,
15471554
ti.getFixedExtraInhabitantMask(IGF.IGM),
1548-
payloadTag);
1555+
payloadTag);
15491556

15501557
// If any tag bits are present, they must match.
15511558
llvm::Value *tagResult = nullptr;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: %target-swift-frontend %s -emit-ir | FileCheck %s
2+
sil_stage canonical
3+
4+
import Builtin
5+
6+
enum ManyEmptyCases {
7+
case A
8+
case B
9+
case C(Builtin.Int64)
10+
}
11+
12+
// CHECK-LABEL: define i1 @select_enum_A(i64, i1)
13+
// CHECK: [[PAYLOAD:%.*]] = icmp eq i64 %0, 0
14+
// CHECK: [[EXTRA:%.*]] = and i1 %1, [[PAYLOAD]]
15+
// CHECK: ret i1 [[EXTRA]]
16+
sil @select_enum_A : $@convention(thin) (ManyEmptyCases) -> Builtin.Int1 {
17+
entry(%0 : $ManyEmptyCases):
18+
%4 = integer_literal $Builtin.Int1, -1 // user: %6
19+
%5 = integer_literal $Builtin.Int1, 0 // user: %6
20+
%6 = select_enum %0 : $ManyEmptyCases, case #ManyEmptyCases.A!enumelt: %4, default %5 : $Builtin.Int1
21+
return %6 : $Builtin.Int1
22+
}
23+
24+
// CHECK-LABEL: define i1 @select_enum_B(i64, i1)
25+
// CHECK: [[PAYLOAD:%.*]] = icmp eq i64 %0, 1
26+
// CHECK: [[EXTRA:%.*]] = and i1 %1, [[PAYLOAD]]
27+
// CHECK: ret i1 [[EXTRA]]
28+
sil @select_enum_B : $@convention(thin) (ManyEmptyCases) -> Builtin.Int1 {
29+
entry(%0 : $ManyEmptyCases):
30+
%4 = integer_literal $Builtin.Int1, -1 // user: %6
31+
%5 = integer_literal $Builtin.Int1, 0 // user: %6
32+
%6 = select_enum %0 : $ManyEmptyCases, case #ManyEmptyCases.B!enumelt: %4, default %5 : $Builtin.Int1
33+
return %6 : $Builtin.Int1
34+
}

0 commit comments

Comments
 (0)