mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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:
@@ -1539,13 +1539,20 @@ namespace {
|
||||
std::tie(payloadTag, extraTag) = getNoPayloadCaseValue(Case);
|
||||
|
||||
auto &ti = getFixedPayloadTypeInfo();
|
||||
bool hasExtraInhabitants = ti.getFixedExtraInhabitantCount(IGF.IGM) > 0;
|
||||
|
||||
|
||||
llvm::Value *payloadResult = nullptr;
|
||||
if (hasExtraInhabitants)
|
||||
payloadResult = payload.emitCompare(IGF,
|
||||
// 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);
|
||||
payloadTag);
|
||||
|
||||
// If any tag bits are present, they must match.
|
||||
llvm::Value *tagResult = nullptr;
|
||||
|
||||
34
test/IRGen/select_enum_single_payload.sil
Normal file
34
test/IRGen/select_enum_single_payload.sil
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user