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.
This commit is contained in:
Joe Groff
2015-12-15 18:59:15 -08:00
parent 7f3e98ef9d
commit 8643d146a0
2 changed files with 46 additions and 5 deletions

View File

@@ -1539,10 +1539,17 @@ namespace {
std::tie(payloadTag, extraTag) = getNoPayloadCaseValue(Case);
auto &ti = getFixedPayloadTypeInfo();
bool hasExtraInhabitants = ti.getFixedExtraInhabitantCount(IGF.IGM) > 0;
llvm::Value *payloadResult = nullptr;
if (hasExtraInhabitants)
// We can omit the payload check if this is the only case represented with
// the particular extra tag bit pattern set.
//
// TODO: This logic covers the most common case, when there's exactly one
// more no-payload case than extra inhabitants in the payload. This could
// be slightly generalized to cases where there's multiple tag bits and
// exactly one no-payload case in the highest used tag value.
if (!tagBits ||
ElementsWithNoPayload.size() != getFixedExtraInhabitantCount(IGF.IGM)+1)
payloadResult = payload.emitCompare(IGF,
ti.getFixedExtraInhabitantMask(IGF.IGM),
payloadTag);

View File

@@ -0,0 +1,34 @@
// RUN: %target-swift-frontend %s -emit-ir | FileCheck %s
sil_stage canonical
import Builtin
enum ManyEmptyCases {
case A
case B
case C(Builtin.Int64)
}
// CHECK-LABEL: define i1 @select_enum_A(i64, i1)
// CHECK: [[PAYLOAD:%.*]] = icmp eq i64 %0, 0
// CHECK: [[EXTRA:%.*]] = and i1 %1, [[PAYLOAD]]
// CHECK: ret i1 [[EXTRA]]
sil @select_enum_A : $@convention(thin) (ManyEmptyCases) -> Builtin.Int1 {
entry(%0 : $ManyEmptyCases):
%4 = integer_literal $Builtin.Int1, -1 // user: %6
%5 = integer_literal $Builtin.Int1, 0 // user: %6
%6 = select_enum %0 : $ManyEmptyCases, case #ManyEmptyCases.A!enumelt: %4, default %5 : $Builtin.Int1
return %6 : $Builtin.Int1
}
// CHECK-LABEL: define i1 @select_enum_B(i64, i1)
// CHECK: [[PAYLOAD:%.*]] = icmp eq i64 %0, 1
// CHECK: [[EXTRA:%.*]] = and i1 %1, [[PAYLOAD]]
// CHECK: ret i1 [[EXTRA]]
sil @select_enum_B : $@convention(thin) (ManyEmptyCases) -> Builtin.Int1 {
entry(%0 : $ManyEmptyCases):
%4 = integer_literal $Builtin.Int1, -1 // user: %6
%5 = integer_literal $Builtin.Int1, 0 // user: %6
%6 = select_enum %0 : $ManyEmptyCases, case #ManyEmptyCases.B!enumelt: %4, default %5 : $Builtin.Int1
return %6 : $Builtin.Int1
}