diff --git a/lib/SILGen/SILGenPattern.cpp b/lib/SILGen/SILGenPattern.cpp index 65f779eca8339..9eef93acd4f8d 100644 --- a/lib/SILGen/SILGenPattern.cpp +++ b/lib/SILGen/SILGenPattern.cpp @@ -2126,8 +2126,12 @@ void PatternMatchEmission::emitEnumElementDispatch( llvm_unreachable("not allowed"); case CastConsumptionKind::CopyOnSuccess: { auto copy = SGF.emitTemporaryAllocation(loc, srcValue->getType()); + // If the element is trivial it won't be destroyed so we need to make + // sure we destroy the enum here. + if (eltTL->isTrivial()) + copy = SGF.emitManagedBufferWithCleanup(copy).getValue(); SGF.B.createCopyAddr(loc, srcValue, copy, IsNotTake, IsInitialization); - // We can always take from the copy. + // We can always take from the managedCopy. eltConsumption = CastConsumptionKind::TakeAlways; eltValue = SGF.B.createUncheckedTakeEnumDataAddr(loc, copy, elt, eltTy); break; @@ -2758,8 +2762,17 @@ void SILGenFunction::emitSwitchStmt(SwitchStmt *S) { // Emit the subject value. If at +1, dispatching will consume it. If it is at // +0, we just forward down borrows. - ManagedValue subjectMV = emitRValueAsSingleValue( - S->getSubjectExpr(), SGFContext::AllowGuaranteedPlusZero); + // If this is an address type, use an initializer. + ManagedValue subjectMV; + if (getTypeLowering(S->getSubjectExpr()->getType()).isAddress()) { + auto init = emitTemporary(S->getSubjectExpr(), getTypeLowering(S->getSubjectExpr()->getType())); + emitExprInto(S->getSubjectExpr(), init.get()); + subjectMV = emitManagedRValueWithCleanup(init->getAddressForInPlaceInitialization(*this, S->getSubjectExpr())); + subjectMV = ManagedValue::forUnmanaged(subjectMV.forward(*this)); + } else { + subjectMV = emitRValueAsSingleValue(S->getSubjectExpr(), + SGFContext::AllowGuaranteedPlusZero); + } // Inline constructor for subject. auto subject = ([&]() -> ConsumableManagedValue { @@ -2787,7 +2800,7 @@ void SILGenFunction::emitSwitchStmt(SwitchStmt *S) { // If we have an address only type returned without a cleanup, we // need to do a copy just to be safe. So for efficiency we pass it // down take_always. - return {subjectMV.copy(*this, S), CastConsumptionKind::TakeAlways}; + return {subjectMV, CastConsumptionKind::CopyOnSuccess}; }()); // If we need to diagnose an unexpected enum case or unexpected enum case diff --git a/test/Interpreter/switch.swift b/test/Interpreter/switch.swift index 397d588e9c42f..6a74298e07af8 100644 --- a/test/Interpreter/switch.swift +++ b/test/Interpreter/switch.swift @@ -282,4 +282,24 @@ SwitchTestSuite.test("Enum Initialization Leaks") { } } +SwitchTestSuite.test("Destroy all elements: protocol and trivial") { + enum ProtocolAndTrivial { + case a(P) + case b(Int) + case c(LifetimeTracked) + } + + func testEnumWithProtocolAndTrivial(_ e: ProtocolAndTrivial) -> Bool { + switch (e) { + case .a(_): return true + case .b(_): return true + case .c(_): return true + } + } + + do { + testEnumWithProtocolAndTrivial(.c(LifetimeTracked(0))) + } +} + runAllTests() diff --git a/test/SILGen/destroy_enum_in_all_cases.swift b/test/SILGen/destroy_enum_in_all_cases.swift new file mode 100644 index 0000000000000..293cb3afcc634 --- /dev/null +++ b/test/SILGen/destroy_enum_in_all_cases.swift @@ -0,0 +1,46 @@ +// RUN: %target-swift-emit-silgen -module-name switch %s > %t.sil +// RUN: %target-sil-opt %t.sil -sil-combine -enable-sil-verify-all | %FileCheck %s + +protocol P { } + +enum ProtocolAndTrivial { + case a(P) + case b(Int) +} + +// This test is mainly checking the verifier doesn't error but, just in case, +// there's also a filecheck test. +// CHECK-LABEL: @$s6switch4testyyAA18ProtocolAndTrivialO_ADtF +// CHECK: [[C1:%[0-9]+]] = alloc_stack $(ProtocolAndTrivial, ProtocolAndTrivial) + +// CHECK: [[CA:%[0-9]+]] = tuple_element_addr [[C1]] : $*(ProtocolAndTrivial, ProtocolAndTrivial), 0 +// CHECK: [[CB:%[0-9]+]] = tuple_element_addr [[C1]] : $*(ProtocolAndTrivial, ProtocolAndTrivial), 1 + +// CHECK: copy_addr %0 to [initialization] [[CA]] +// CHECK: copy_addr %1 to [initialization] [[CB]] + +// CHECK: [[CA:%[0-9]+]] = tuple_element_addr [[C1]] : $*(ProtocolAndTrivial, ProtocolAndTrivial), 0 +// CHECK: [[CB:%[0-9]+]] = tuple_element_addr [[C1]] : $*(ProtocolAndTrivial, ProtocolAndTrivial), 1 + +// CHECK: switch_enum_addr [[CA]] : $*ProtocolAndTrivial, case #ProtocolAndTrivial.a!enumelt: [[BBA:bb[0-9]+]], case #ProtocolAndTrivial.b!enumelt: [[BBB:bb[0-9]+]] + +// We're only testing the trivial case. +// CHECK: [[BBB]]: +// CHECK: [[TMP:%[0-9]+]] = alloc_stack $ProtocolAndTrivial +// CHECK: switch_enum_addr [[CB]] : $*ProtocolAndTrivial, case #ProtocolAndTrivial.b!enumelt: [[BOTH_B:bb[0-9]+]], default [[DEFAULT:bb[0-9]+]] + +// Make sure that we destroy everything. +// CHECK: [[BOTH_B]]: +// CHECK: [[TMP2:%[0-9]+]] = alloc_stack $ProtocolAndTrivial +// CHECK: destroy_addr [[TMP2]] +// CHECK: destroy_addr [[TMP]] +// CHECK: destroy_addr [[C1]] + +// CHECK-LABEL: end sil function '$s6switch4testyyAA18ProtocolAndTrivialO_ADtF' +func test(_ a : ProtocolAndTrivial, _ b : ProtocolAndTrivial) { + switch ((a, b)) { + case (.a(_), .a(_)): _ = () + case (.b(_), .b(_)): _ = () + default: _ = () + } +} diff --git a/test/SILGen/enum_resilience.swift b/test/SILGen/enum_resilience.swift index 5f7af301837f3..b87bf56b032f0 100644 --- a/test/SILGen/enum_resilience.swift +++ b/test/SILGen/enum_resilience.swift @@ -10,26 +10,36 @@ import resilient_enum // a default case // CHECK-LABEL: sil hidden [ossa] @$s15enum_resilience15resilientSwitchyy0c1_A06MediumOF : $@convention(thin) (@in_guaranteed Medium) -> () -// CHECK: [[BOX:%.*]] = alloc_stack $Medium +// CHECK: [[BOX:%.*]] = alloc_stack $Medium // CHECK-NEXT: copy_addr %0 to [initialization] [[BOX]] // CHECK-NEXT: [[METATYPE:%.+]] = value_metatype $@thick Medium.Type, [[BOX]] : $*Medium // CHECK-NEXT: switch_enum_addr [[BOX]] : $*Medium, case #Medium.Paper!enumelt: bb1, case #Medium.Canvas!enumelt: bb2, case #Medium.Pamphlet!enumelt: bb3, case #Medium.Postcard!enumelt: bb4, default bb5 // CHECK: bb1: +// CHECK-NEXT: destroy_addr [[BOX]] // CHECK-NEXT: dealloc_stack [[BOX]] // CHECK-NEXT: br bb6 // CHECK: bb2: +// CHECK-NEXT: destroy_addr [[BOX]] // CHECK-NEXT: dealloc_stack [[BOX]] // CHECK-NEXT: br bb6 // CHECK: bb3: -// CHECK-NEXT: [[INDIRECT_ADDR:%.*]] = unchecked_take_enum_data_addr [[BOX]] +// CHECK-NEXT: [[TMP:%.*]] = alloc_stack $Medium +// CHECK-NEXT: copy_addr +// CHECK-NEXT: [[INDIRECT_ADDR:%.*]] = unchecked_take_enum_data_addr [[TMP]] // CHECK-NEXT: [[INDIRECT:%.*]] = load [take] [[INDIRECT_ADDR]] // CHECK-NEXT: [[PAYLOAD:%.*]] = project_box [[INDIRECT]] // CHECK-NEXT: destroy_value [[INDIRECT]] +// CHECK-NEXT: dealloc_stack [[TMP]] +// CHECK-NEXT: destroy_addr [[BOX]] // CHECK-NEXT: dealloc_stack [[BOX]] // CHECK-NEXT: br bb6 // CHECK: bb4: -// CHECK-NEXT: [[PAYLOAD_ADDR:%.*]] = unchecked_take_enum_data_addr [[BOX]] +// CHECK-NEXT: [[TMP:%.*]] = alloc_stack $Medium +// CHECK-NEXT: copy_addr +// CHECK-NEXT: [[PAYLOAD_ADDR:%.*]] = unchecked_take_enum_data_addr [[TMP]] // CHECK-NEXT: destroy_addr [[PAYLOAD_ADDR]] +// CHECK-NEXT: dealloc_stack [[TMP]] +// CHECK-NEXT: destroy_addr [[BOX]] // CHECK-NEXT: dealloc_stack [[BOX]] // CHECK-NEXT: br bb6 // CHECK: bb5: diff --git a/test/SILGen/enum_resilience_testable.swift b/test/SILGen/enum_resilience_testable.swift index cdcba99198bfd..ce2e8783eef3e 100644 --- a/test/SILGen/enum_resilience_testable.swift +++ b/test/SILGen/enum_resilience_testable.swift @@ -20,21 +20,31 @@ // CHECK-NEXT: [[METATYPE:%.+]] = value_metatype $@thick Medium.Type, [[BOX]] : $*Medium // CHECK-NEXT: switch_enum_addr [[BOX]] : $*Medium, case #Medium.Paper!enumelt: bb1, case #Medium.Canvas!enumelt: bb2, case #Medium.Pamphlet!enumelt: bb3, case #Medium.Postcard!enumelt: bb4, default bb5 // CHECK: bb1: +// CHECK-NEXT: destroy_addr [[BOX]] // CHECK-NEXT: dealloc_stack [[BOX]] // CHECK-NEXT: br bb6 // CHECK: bb2: +// CHECK-NEXT: destroy_addr [[BOX]] // CHECK-NEXT: dealloc_stack [[BOX]] // CHECK-NEXT: br bb6 // CHECK: bb3: -// CHECK-NEXT: [[INDIRECT_ADDR:%.*]] = unchecked_take_enum_data_addr [[BOX]] +// CHECK-NEXT: [[TMP:%.*]] = alloc_stack $Medium +// CHECK-NEXT: copy_addr +// CHECK-NEXT: [[INDIRECT_ADDR:%.*]] = unchecked_take_enum_data_addr [[TMP]] // CHECK-NEXT: [[INDIRECT:%.*]] = load [take] [[INDIRECT_ADDR]] // CHECK-NEXT: [[PAYLOAD:%.*]] = project_box [[INDIRECT]] // CHECK-NEXT: destroy_value [[INDIRECT]] +// CHECK-NEXT: dealloc_stack [[TMP]] +// CHECK-NEXT: destroy_addr [[BOX]] // CHECK-NEXT: dealloc_stack [[BOX]] // CHECK-NEXT: br bb6 // CHECK: bb4: -// CHECK-NEXT: [[PAYLOAD_ADDR:%.*]] = unchecked_take_enum_data_addr [[BOX]] +// CHECK-NEXT: [[TMP:%.*]] = alloc_stack $Medium +// CHECK-NEXT: copy_addr +// CHECK-NEXT: [[PAYLOAD_ADDR:%.*]] = unchecked_take_enum_data_addr [[TMP]] // CHECK-NEXT: destroy_addr [[PAYLOAD_ADDR]] +// CHECK-NEXT: dealloc_stack [[TMP]] +// CHECK-NEXT: destroy_addr [[BOX]] // CHECK-NEXT: dealloc_stack [[BOX]] // CHECK-NEXT: br bb6 // CHECK: bb5: diff --git a/test/SILGen/indirect_enum.swift b/test/SILGen/indirect_enum.swift index 1a8f910a8d897..5845f19eb61c2 100644 --- a/test/SILGen/indirect_enum.swift +++ b/test/SILGen/indirect_enum.swift @@ -225,7 +225,8 @@ func switchTreeA(_ x: TreeA) { // CHECK-LABEL: sil hidden [ossa] @$s13indirect_enum11switchTreeB{{[_0-9a-zA-Z]*}}F func switchTreeB(_ x: TreeB) { - // CHECK: copy_addr %0 to [initialization] [[SCRATCH:%.*]] : + // CHECK: [[SCRATCH:%.*]] = alloc_stack + // CHECK: copy_addr %0 to [initialization] [[SCRATCH]] // CHECK: switch_enum_addr [[SCRATCH]] switch x { diff --git a/test/SILGen/switch.swift b/test/SILGen/switch.swift index a89153cbcfaef..bc447d7f65466 100644 --- a/test/SILGen/switch.swift +++ b/test/SILGen/switch.swift @@ -336,8 +336,8 @@ struct Z : P { func p() {} } // CHECK-LABEL: sil hidden [ossa] @$s6switch10test_isa_11pyAA1P_p_tF func test_isa_1(p: P) { - // CHECK: [[PTMPBUF:%[0-9]+]] = alloc_stack $P - // CHECK-NEXT: copy_addr %0 to [initialization] [[PTMPBUF]] : $*P + // CHECK: [[PTMPBUF1:%[0-9]+]] = alloc_stack $P + // CHECK-NEXT: copy_addr %0 to [initialization] [[PTMPBUF1]] : $*P switch p { // CHECK: [[TMPBUF:%[0-9]+]] = alloc_stack $X // CHECK: checked_cast_addr_br copy_on_success P in [[P:%.*]] : $*P to X in [[TMPBUF]] : $*X, [[IS_X:bb[0-9]+]], [[IS_NOT_X:bb[0-9]+]] @@ -349,8 +349,8 @@ func test_isa_1(p: P) { // CHECK-NEXT: [[FUNC:%.*]] = function_ref @$s6switch1ayyF // CHECK-NEXT: apply [[FUNC]]() // CHECK-NEXT: dealloc_stack [[TMPBUF]] - // CHECK-NEXT: destroy_addr [[PTMPBUF]] - // CHECK-NEXT: dealloc_stack [[PTMPBUF]] + // CHECK-NEXT: destroy_addr [[PTMPBUF1]] + // CHECK-NEXT: dealloc_stack [[PTMPBUF1]] a() // CHECK: br [[CONT:bb[0-9]+]] @@ -828,7 +828,8 @@ func test_union_addr_only_1(u: MaybeAddressOnlyPair) { a() // CHECK: [[IS_LEFT]]: - // CHECK: [[P:%.*]] = unchecked_take_enum_data_addr [[ENUM_ADDR]] : $*MaybeAddressOnlyPair, #MaybeAddressOnlyPair.Left!enumelt + // CHECK: [[TMP:%.*]] = alloc_stack + // CHECK: [[P:%.*]] = unchecked_take_enum_data_addr [[TMP]] : $*MaybeAddressOnlyPair, #MaybeAddressOnlyPair.Left!enumelt case .Left(_): // CHECK: [[FUNC:%.*]] = function_ref @$s6switch1byyF // CHECK-NEXT: apply [[FUNC]]( @@ -837,7 +838,8 @@ func test_union_addr_only_1(u: MaybeAddressOnlyPair) { b() // CHECK: [[IS_RIGHT]]: - // CHECK: [[STR_ADDR:%.*]] = unchecked_take_enum_data_addr [[ENUM_ADDR]] : $*MaybeAddressOnlyPair, #MaybeAddressOnlyPair.Right!enumelt + // CHECK: [[TMP:%.*]] = alloc_stack + // CHECK: [[STR_ADDR:%.*]] = unchecked_take_enum_data_addr [[TMP]] : $*MaybeAddressOnlyPair, #MaybeAddressOnlyPair.Right!enumelt // CHECK: [[STR:%.*]] = load [take] [[STR_ADDR]] case .Right(_): // CHECK: [[FUNC:%.*]] = function_ref @$s6switch1cyyF @@ -847,7 +849,8 @@ func test_union_addr_only_1(u: MaybeAddressOnlyPair) { c() // CHECK: [[IS_BOTH]]: - // CHECK: [[P_STR_TUPLE:%.*]] = unchecked_take_enum_data_addr [[ENUM_ADDR]] : $*MaybeAddressOnlyPair, #MaybeAddressOnlyPair.Both!enumelt + // CHECK: [[TMP:%.*]] = alloc_stack + // CHECK: [[P_STR_TUPLE:%.*]] = unchecked_take_enum_data_addr [[TMP]] : $*MaybeAddressOnlyPair, #MaybeAddressOnlyPair.Both!enumelt case .Both(_): // CHECK: [[FUNC:%.*]] = function_ref @$s6switch1dyyF // CHECK-NEXT: apply [[FUNC]]( @@ -1125,7 +1128,7 @@ func testUninhabitedSwitchScrutinee() { // CHECK: [[INIT_TUP_0:%.*]] = tuple_element_addr [[MEM]] : $*(TrivialSingleCaseEnum, Any), 0 // CHECK: [[INIT_TUP_1:%.*]] = tuple_element_addr [[MEM]] : $*(TrivialSingleCaseEnum, Any), 1 // CHECK: store {{%.*}} to [trivial] [[INIT_TUP_0]] -// CHECK: copy_addr [take] {{%.*}} to [initialization] [[INIT_TUP_1]] +// CHECK: copy_addr {{%.*}} to [initialization] [[INIT_TUP_1]] // CHECK: [[TUP_0:%.*]] = tuple_element_addr [[MEM]] : $*(TrivialSingleCaseEnum, Any), 0 // CHECK: [[TUP_0_VAL:%.*]] = load [trivial] [[TUP_0]] // CHECK: [[TUP_1:%.*]] = tuple_element_addr [[MEM]] : $*(TrivialSingleCaseEnum, Any), 1 @@ -1146,16 +1149,15 @@ func address_only_with_trivial_subtype(_ a: TrivialSingleCaseEnum, _ value: Any) // CHECK: [[INIT_TUP_0:%.*]] = tuple_element_addr [[MEM]] : $*(NonTrivialSingleCaseEnum, Any), 0 // CHECK: [[INIT_TUP_1:%.*]] = tuple_element_addr [[MEM]] : $*(NonTrivialSingleCaseEnum, Any), 1 // CHECK: store {{%.*}} to [init] [[INIT_TUP_0]] -// CHECK: copy_addr [take] {{%.*}} to [initialization] [[INIT_TUP_1]] +// CHECK: copy_addr {{%.*}} to [initialization] [[INIT_TUP_1]] // CHECK: [[TUP_0:%.*]] = tuple_element_addr [[MEM]] : $*(NonTrivialSingleCaseEnum, Any), 0 // CHECK: [[TUP_0_VAL:%.*]] = load_borrow [[TUP_0]] // CHECK: [[TUP_1:%.*]] = tuple_element_addr [[MEM]] : $*(NonTrivialSingleCaseEnum, Any), 1 // CHECK: switch_enum [[TUP_0_VAL]] // // CHECK: bb1([[CASE_VAL:%.*]] : -// CHECK-NEXT: destroy_addr [[TUP_1]] // CHECK-NEXT: end_borrow [[TUP_0_VAL]] -// CHECK-NEXT: destroy_addr [[TUP_0]] +// CHECK-NEXT: destroy_addr [[MEM]] // CHECK-NEXT: dealloc_stack [[MEM]] // // CHECK: bb2: @@ -1176,20 +1178,17 @@ func address_only_with_nontrivial_subtype(_ a: NonTrivialSingleCaseEnum, _ value // load_borrow, we do not lose the +1 from the original tuple formation. // CHECK-LABEL: sil hidden [ossa] @$s6switch35partial_address_only_tuple_dispatchyyAA5KlassC_ypSgtF : $@convention(thin) (@guaranteed Klass, @in_guaranteed Optional) -> () { // CHECK: bb0([[ARG0:%.*]] : @guaranteed $Klass, [[ARG1:%.*]] : $*Optional): -// CHECK: [[ARG0_COPY:%.*]] = copy_value [[ARG0]] -// CHECK: [[ARG1_COPY:%.*]] = alloc_stack $Optional -// CHECK: copy_addr [[ARG1]] to [initialization] [[ARG1_COPY]] // CHECK: [[TUP:%.*]] = alloc_stack $(Klass, Optional) // CHECK: [[TUP_0:%.*]] = tuple_element_addr [[TUP]] : $*(Klass, Optional), 0 // CHECK: [[TUP_1:%.*]] = tuple_element_addr [[TUP]] : $*(Klass, Optional), 1 +// CHECK: [[ARG0_COPY:%.*]] = copy_value [[ARG0]] // CHECK: store [[ARG0_COPY]] to [init] [[TUP_0]] -// CHECK: copy_addr [take] [[ARG1_COPY]] to [initialization] [[TUP_1]] +// CHECK: copy_addr [[ARG1]] to [initialization] [[TUP_1]] // CHECK: [[TUP_0:%.*]] = tuple_element_addr [[TUP]] : $*(Klass, Optional), 0 // CHECK: [[TUP_0_VAL:%.*]] = load_borrow [[TUP_0]] // CHECK: [[TUP_1:%.*]] = tuple_element_addr [[TUP]] : $*(Klass, Optional), 1 -// CHECK: destroy_addr [[TUP_1]] // CHECK: end_borrow [[TUP_0_VAL]] -// CHECK: destroy_addr [[TUP_0]] +// CHECK: destroy_addr [[TUP]] // CHECK: dealloc_stack [[TUP]] // CHECK: br bb2 // @@ -1208,14 +1207,12 @@ func partial_address_only_tuple_dispatch(_ name: Klass, _ value: Any?) { // CHECK-LABEL: sil hidden [ossa] @$s6switch50partial_address_only_tuple_dispatch_with_fail_caseyyAA5KlassC_ypSgtF : $@convention(thin) (@guaranteed Klass, @in_guaranteed Optional) -> () { // CHECK: bb0([[ARG0:%.*]] : @guaranteed $Klass, [[ARG1:%.*]] : $*Optional): -// CHECK: [[ARG0_COPY:%.*]] = copy_value [[ARG0]] -// CHECK: [[ARG1_COPY:%.*]] = alloc_stack $Optional -// CHECK: copy_addr [[ARG1]] to [initialization] [[ARG1_COPY]] // CHECK: [[TUP:%.*]] = alloc_stack $(Klass, Optional) // CHECK: [[TUP_0:%.*]] = tuple_element_addr [[TUP]] : $*(Klass, Optional), 0 // CHECK: [[TUP_1:%.*]] = tuple_element_addr [[TUP]] : $*(Klass, Optional), 1 +// CHECK: [[ARG0_COPY:%.*]] = copy_value [[ARG0]] // CHECK: store [[ARG0_COPY]] to [init] [[TUP_0]] -// CHECK: copy_addr [take] [[ARG1_COPY]] to [initialization] [[TUP_1]] +// CHECK: copy_addr [[ARG1]] to [initialization] [[TUP_1]] // CHECK: [[TUP_0:%.*]] = tuple_element_addr [[TUP]] : $*(Klass, Optional), 0 // CHECK: [[TUP_0_VAL:%.*]] = load_borrow [[TUP_0]] // CHECK: [[TUP_1:%.*]] = tuple_element_addr [[TUP]] : $*(Klass, Optional), 1 @@ -1224,9 +1221,8 @@ func partial_address_only_tuple_dispatch(_ name: Klass, _ value: Any?) { // CHECK: [[IS_ANYOBJECT_BB]]([[ANYOBJECT:%.*]] : @guaranteed $AnyObject): // CHECK: [[ANYOBJECT_COPY:%.*]] = copy_value [[ANYOBJECT]] // ... CASE BODY ... -// CHECK: destroy_addr [[TUP_1]] // CHECK: end_borrow [[TUP_0_VAL]] -// CHECK: destroy_addr [[TUP_0]] +// CHECK: destroy_addr [[TUP]] // CHECK: dealloc_stack [[TUP]] // CHECK: br [[EXIT_BB:bb[0-9]+]] // @@ -1249,11 +1245,9 @@ func partial_address_only_tuple_dispatch(_ name: Klass, _ value: Any?) { // CHECK-NEXT: dealloc_stack [[ANYOBJECT_ADDR]] // CHECK-NEXT: destroy_addr [[SOME_ANY_ADDR]] // CHECK-NEXT: dealloc_stack [[OPT_ANY_ADDR]] -// CHECK-NEXT: destroy_addr [[TUP_1]] // CHECK-NEXT: end_borrow [[TUP_0_VAL]] -// CHECK-NEXT: destroy_addr [[TUP_0]] +// CHECK-NEXT: destroy_addr [[TUP]] // CHECK-NEXT: dealloc_stack [[TUP]] -// CHECK-NEXT: dealloc_stack // CHECK-NEXT: br [[EXIT_BB]] // // CHECK: [[ISNOT_ANY_BB]]: @@ -1336,7 +1330,9 @@ func testVoidType() { // CHECK: switch_enum_addr [[SWITCH_ENUM_ARG]] : $*MultipleAddressOnlyCaseEnum, case #MultipleAddressOnlyCaseEnum.a!enumelt: [[BB_A:bb[0-9]+]], case #MultipleAddressOnlyCaseEnum.b!enumelt: [[BB_B:bb[0-9]+]], case #MultipleAddressOnlyCaseEnum.c!enumelt: [[BB_C:bb[0-9]+]] // // CHECK: [[BB_A]]: -// CHECK: [[SWITCH_ENUM_ARG_PROJ:%.*]] = unchecked_take_enum_data_addr [[SWITCH_ENUM_ARG]] +// CHECK: [[TMP_SWITCH_ENUM_ARG:%.*]] = alloc_stack $MultipleAddressOnlyCaseEnum +// CHECK: copy_addr [[SWITCH_ENUM_ARG]] to [initialization] [[TMP_SWITCH_ENUM_ARG]] +// CHECK: [[SWITCH_ENUM_ARG_PROJ:%.*]] = unchecked_take_enum_data_addr [[TMP_SWITCH_ENUM_ARG]] // CHECK: [[CASE_BODY_VAR_A:%.*]] = alloc_stack $T, let, name "x" // CHECK: copy_addr [take] [[SWITCH_ENUM_ARG_PROJ]] to [initialization] [[CASE_BODY_VAR_A]] // CHECK: copy_addr [[CASE_BODY_VAR_A]] to [initialization] [[AB_PHI]] @@ -1344,7 +1340,9 @@ func testVoidType() { // CHECK: br [[BB_AB:bb[0-9]+]] // // CHECK: [[BB_B]]: -// CHECK: [[SWITCH_ENUM_ARG_PROJ:%.*]] = unchecked_take_enum_data_addr [[SWITCH_ENUM_ARG]] +// CHECK: [[TMP_SWITCH_ENUM_ARG:%.*]] = alloc_stack $MultipleAddressOnlyCaseEnum +// CHECK: copy_addr [[SWITCH_ENUM_ARG]] to [initialization] [[TMP_SWITCH_ENUM_ARG]] +// CHECK: [[SWITCH_ENUM_ARG_PROJ:%.*]] = unchecked_take_enum_data_addr [[TMP_SWITCH_ENUM_ARG]] // CHECK: [[CASE_BODY_VAR_B:%.*]] = alloc_stack $T, let, name "x" // CHECK: copy_addr [[SWITCH_ENUM_ARG_PROJ]] to [initialization] [[CASE_BODY_VAR_B]] // CHECK: [[FUNC_CMP:%.*]] = function_ref @$sSzsE2eeoiySbx_qd__tSzRd__lFZ : @@ -1376,7 +1374,9 @@ func testVoidType() { // CHECK: br [[BB_AB_CONT]] // // CHECK: [[BB_C]]: -// CHECK: [[SWITCH_ENUM_ARG_PROJ:%.*]] = unchecked_take_enum_data_addr [[SWITCH_ENUM_ARG]] +// CHECK: [[TMP_SWITCH_ENUM_ARG:%.*]] = alloc_stack $MultipleAddressOnlyCaseEnum +// CHECK: copy_addr [[SWITCH_ENUM_ARG]] to [initialization] [[TMP_SWITCH_ENUM_ARG]] +// CHECK: [[SWITCH_ENUM_ARG_PROJ:%.*]] = unchecked_take_enum_data_addr [[TMP_SWITCH_ENUM_ARG]] // CHECK: [[CASE_BODY_VAR_C:%.*]] = alloc_stack $T, let, name "x" // CHECK: copy_addr [take] [[SWITCH_ENUM_ARG_PROJ]] to [initialization] [[CASE_BODY_VAR_C]] // CHECK: copy_addr [[CASE_BODY_VAR_C]] to [initialization] [[ABBC_PHI]] @@ -1606,3 +1606,26 @@ struct rdar49990484Struct { } } } + +enum ProtocolAndTrivial { + case a(P) + case b(Int) +} + +// Make sure "e" is destroyed in both cases. +// CHECK-LABEL: sil hidden [ossa] @$s6switch30testEnumWithProtocolAndTrivialySbAA0efG0OF +// CHECK: bb0( +// CHECK: [[TMP:%[0-9]+]] = alloc_stack +// CHECK: bb1: +// CHECK: [[P:%[0-9]+]] = unchecked_take_enum_data_addr +// CHECK: destroy_addr [[P]] +// CHECK: bb2: +// CHECK: destroy_addr [[TMP]] +// CHECK-LABEL: end sil function '$s6switch30testEnumWithProtocolAndTrivialySbAA0efG0OF' +func testEnumWithProtocolAndTrivial(_ e: ProtocolAndTrivial) -> Bool { + switch (e) { + case .a(_): return true + case .b(_): return true + } +} + diff --git a/test/SILGen/switch_abstraction.swift b/test/SILGen/switch_abstraction.swift index f041b64987cb2..4cff318a98b3e 100644 --- a/test/SILGen/switch_abstraction.swift +++ b/test/SILGen/switch_abstraction.swift @@ -34,7 +34,9 @@ enum Wacky { // CHECK-LABEL: sil hidden [ossa] @$s18switch_abstraction45enum_addr_only_to_loadable_with_reabstraction{{[_0-9a-zA-Z]*}}F : $@convention(thin) (@in_guaranteed Wacky, A) -> @out T { // CHECK: switch_enum_addr [[ENUM:%.*]] : $*Wacky, {{.*}} case #Wacky.Bar!enumelt: [[DEST:bb[0-9]+]] // CHECK: [[DEST]]: -// CHECK: [[ORIG_ADDR:%.*]] = unchecked_take_enum_data_addr [[ENUM]] : $*Wacky, #Wacky.Bar +// CHECK: [[TMP:%.*]] = alloc_stack +// CHECK: copy_addr [[ENUM]] to [initialization] [[TMP]] +// CHECK: [[ORIG_ADDR:%.*]] = unchecked_take_enum_data_addr [[TMP]] : $*Wacky, #Wacky.Bar // CHECK: [[ORIG:%.*]] = load [take] [[ORIG_ADDR]] // CHECK: [[CONV:%.*]] = convert_function [[ORIG]] // CHECK: [[REABSTRACT:%.*]] = function_ref @$s{{.*}}TR : diff --git a/test/SILGen/switch_multiple_entry_address_only.swift b/test/SILGen/switch_multiple_entry_address_only.swift index 6b66f1dfa26ab..3fe0e2d490e59 100644 --- a/test/SILGen/switch_multiple_entry_address_only.swift +++ b/test/SILGen/switch_multiple_entry_address_only.swift @@ -19,22 +19,30 @@ func multipleLabelsLet(e: E) { // CHECK-NEXT: switch_enum_addr [[E_COPY]] : $*E, case #E.a!enumelt: bb1, case #E.b!enumelt: bb2, default bb4 // CHECK: bb1: - // CHECK-NEXT: [[E_PAYLOAD:%.*]] = unchecked_take_enum_data_addr [[E_COPY]] : $*E, #E.a!enumelt + // CHECK-NEXT: [[TMP:%.*]] = alloc_stack $E + // CHECK-NEXT: copy_addr [[E_COPY]] to [initialization] [[TMP]] + // CHECK-NEXT: [[E_PAYLOAD:%.*]] = unchecked_take_enum_data_addr [[TMP]] : $*E, #E.a!enumelt // CHECK-NEXT: [[ANY_BOX:%.*]] = alloc_stack $Any // CHECK-NEXT: copy_addr [take] [[E_PAYLOAD]] to [initialization] [[ANY_BOX]] // CHECK-NEXT: copy_addr [[ANY_BOX]] to [initialization] [[X_PHI]] // CHECK-NEXT: destroy_addr [[ANY_BOX]] // CHECK-NEXT: dealloc_stack [[ANY_BOX]] + // CHECK-NEXT: dealloc_stack [[TMP]] + // CHECK-NEXT: destroy_addr [[E_COPY]] // CHECK-NEXT: dealloc_stack [[E_COPY]] // CHECK-NEXT: br bb3 // CHECK: bb2: - // CHECK-NEXT: [[E_PAYLOAD:%.*]] = unchecked_take_enum_data_addr [[E_COPY]] : $*E, #E.b!enumelt + // CHECK-NEXT: [[TMP:%.*]] = alloc_stack $E + // CHECK-NEXT: copy_addr [[E_COPY]] to [initialization] [[TMP]] + // CHECK-NEXT: [[E_PAYLOAD:%.*]] = unchecked_take_enum_data_addr [[TMP]] : $*E, #E.b!enumelt // CHECK-NEXT: [[ANY_BOX:%.*]] = alloc_stack $Any // CHECK-NEXT: copy_addr [take] [[E_PAYLOAD]] to [initialization] [[ANY_BOX]] // CHECK-NEXT: copy_addr [[ANY_BOX]] to [initialization] [[X_PHI]] // CHECK-NEXT: destroy_addr [[ANY_BOX]] // CHECK-NEXT: dealloc_stack [[ANY_BOX]] + // CHECK-NEXT: dealloc_stack [[TMP]] + // CHECK-NEXT: destroy_addr [[E_COPY]] // CHECK-NEXT: dealloc_stack [[E_COPY]] // CHECK-NEXT: br bb3 @@ -71,22 +79,30 @@ func multipleLabelsVar(e: E) { // CHECK-NEXT: switch_enum_addr [[E_COPY]] : $*E, case #E.a!enumelt: bb1, case #E.b!enumelt: bb2, default bb4 // CHECK: bb1: - // CHECK-NEXT: [[E_PAYLOAD:%.*]] = unchecked_take_enum_data_addr [[E_COPY]] : $*E, #E.a!enumelt + // CHECK-NEXT: [[TMP:%.*]] = alloc_stack $E + // CHECK-NEXT: copy_addr [[E_COPY]] to [initialization] [[TMP]] + // CHECK-NEXT: [[E_PAYLOAD:%.*]] = unchecked_take_enum_data_addr [[TMP]] : $*E, #E.a!enumelt // CHECK-NEXT: [[ANY_BOX:%.*]] = alloc_stack $Any // CHECK-NEXT: copy_addr [take] [[E_PAYLOAD]] to [initialization] [[ANY_BOX]] // CHECK-NEXT: copy_addr [[ANY_BOX]] to [initialization] [[X_PHI]] // CHECK-NEXT: destroy_addr [[ANY_BOX]] // CHECK-NEXT: dealloc_stack [[ANY_BOX]] + // CHECK-NEXT: dealloc_stack [[TMP]] + // CHECK-NEXT: destroy_addr [[E_COPY]] // CHECK-NEXT: dealloc_stack [[E_COPY]] // CHECK-NEXT: br bb3 // CHECK: bb2: - // CHECK-NEXT: [[E_PAYLOAD:%.*]] = unchecked_take_enum_data_addr [[E_COPY]] : $*E, #E.b!enumelt + // CHECK-NEXT: [[TMP:%.*]] = alloc_stack $E + // CHECK-NEXT: copy_addr [[E_COPY]] to [initialization] [[TMP]] + // CHECK-NEXT: [[E_PAYLOAD:%.*]] = unchecked_take_enum_data_addr [[TMP]] : $*E, #E.b!enumelt // CHECK-NEXT: [[ANY_BOX:%.*]] = alloc_stack $Any // CHECK-NEXT: copy_addr [take] [[E_PAYLOAD]] to [initialization] [[ANY_BOX]] // CHECK-NEXT: copy_addr [[ANY_BOX]] to [initialization] [[X_PHI]] // CHECK-NEXT: destroy_addr [[ANY_BOX]] // CHECK-NEXT: dealloc_stack [[ANY_BOX]] + // CHECK-NEXT: dealloc_stack [[TMP]] + // CHECK-NEXT: destroy_addr [[E_COPY]] // CHECK-NEXT: dealloc_stack [[E_COPY]] // CHECK-NEXT: br bb3 @@ -132,7 +148,9 @@ func fallthroughWithValue(e: E) { // CHECK-NEXT: switch_enum_addr [[E_COPY]] : $*E, case #E.a!enumelt: bb1, case #E.b!enumelt: bb2, default bb4 // CHECK: bb1: - // CHECK-NEXT: [[E_PAYLOAD:%.*]] = unchecked_take_enum_data_addr [[E_COPY]] : $*E, #E.a!enumelt + // CHECK-NEXT: [[TMP:%.*]] = alloc_stack $E + // CHECK-NEXT: copy_addr [[E_COPY]] to [initialization] [[TMP]] + // CHECK-NEXT: [[E_PAYLOAD:%.*]] = unchecked_take_enum_data_addr [[TMP]] : $*E, #E.a!enumelt // CHECK-NEXT: [[ORIGINAL_ANY_BOX:%.*]] = alloc_stack $Any // CHECK-NEXT: copy_addr [take] [[E_PAYLOAD]] to [initialization] [[ORIGINAL_ANY_BOX]] // CHECK: [[FN1:%.*]] = function_ref @$s34switch_multiple_entry_address_only8takesAnyyyypF @@ -140,16 +158,22 @@ func fallthroughWithValue(e: E) { // CHECK-NEXT: copy_addr [[ORIGINAL_ANY_BOX]] to [initialization] [[X_PHI]] // CHECK-NEXT: destroy_addr [[ORIGINAL_ANY_BOX]] // CHECK-NEXT: dealloc_stack [[ORIGINAL_ANY_BOX]] + // CHECK-NEXT: dealloc_stack [[TMP]] + // CHECK-NEXT: destroy_addr [[E_COPY]] // CHECK-NEXT: dealloc_stack [[E_COPY]] // CHECK-NEXT: br bb3 // CHECK: bb2: - // CHECK-NEXT: [[E_PAYLOAD:%.*]] = unchecked_take_enum_data_addr [[E_COPY]] : $*E, #E.b!enumelt + // CHECK-NEXT: [[TMP:%.*]] = alloc_stack $E + // CHECK-NEXT: copy_addr [[E_COPY]] to [initialization] [[TMP]] + // CHECK-NEXT: [[E_PAYLOAD:%.*]] = unchecked_take_enum_data_addr [[TMP]] : $*E, #E.b!enumelt // CHECK-NEXT: [[ANY_BOX:%.*]] = alloc_stack $Any // CHECK-NEXT: copy_addr [take] [[E_PAYLOAD]] to [initialization] [[ANY_BOX]] // CHECK-NEXT: copy_addr [[ANY_BOX]] to [initialization] [[X_PHI]] // CHECK-NEXT: destroy_addr [[ANY_BOX]] // CHECK-NEXT: dealloc_stack [[ANY_BOX]] + // CHECK-NEXT: dealloc_stack [[TMP]] + // CHECK-NEXT: destroy_addr [[E_COPY]] // CHECK-NEXT: dealloc_stack [[E_COPY]] // CHECK-NEXT: br bb3 diff --git a/test/SILGen/switch_resilience.swift b/test/SILGen/switch_resilience.swift index 311d6762a4d01..c50d35864af32 100644 --- a/test/SILGen/switch_resilience.swift +++ b/test/SILGen/switch_resilience.swift @@ -9,7 +9,8 @@ import resilient_struct // CHECK: [[STACK_SLOT:%.*]] = alloc_stack $Enum // // CHECK: bb1: -// CHECK: [[VALUE:%.*]] = unchecked_take_enum_data_addr [[STACK_SLOT]] : $*Enum +// CHECK: [[TMP:%.*]] = alloc_stack $Enum +// CHECK: [[VALUE:%.*]] = unchecked_take_enum_data_addr [[TMP]] : $*Enum // CHECK: [[STACK_SLOT_COPY:%.*]] = alloc_stack $(url: ResilientRef, void: ()), let, name "value" // CHECK: copy_addr [[VALUE]] to [initialization] [[STACK_SLOT_COPY]] // CHECK: cond_br {{%.*}}, bb2, bb3 @@ -18,6 +19,8 @@ import resilient_struct // CHECK: destroy_addr [[STACK_SLOT_COPY]] // CHECK-NEXT: dealloc_stack [[STACK_SLOT_COPY]] // CHECK-NEXT: destroy_addr [[VALUE]] +// CHECK-NEXT: dealloc_stack [[TMP]] +// CHECK-NEXT: destroy_addr [[STACK_SLOT]] // CHECK-NEXT: dealloc_stack [[STACK_SLOT]] // CHECK-NEXT: br bb4 // @@ -26,6 +29,8 @@ import resilient_struct // CHECK-NEXT: dealloc_stack [[STACK_SLOT_COPY]] // CHECK-NEXT: [[REPROJECT:%.*]] = tuple_element_addr [[VALUE]] // CHECK: destroy_addr [[REPROJECT]] +// CHECK-NEXT: dealloc_stack [[TMP]] +// CHECK-NEXT: destroy_addr [[STACK_SLOT]] // CHECK-NEXT: dealloc_stack [[STACK_SLOT]] // CHECK: br bb4 // diff --git a/test/SILGen/switch_var.swift b/test/SILGen/switch_var.swift index 94b08bab4d676..86b7d96286b84 100644 --- a/test/SILGen/switch_var.swift +++ b/test/SILGen/switch_var.swift @@ -191,9 +191,9 @@ struct Z : P { func p() {} } // CHECK-LABEL: sil hidden [ossa] @$s10switch_var05test_B2_41pyAA1P_p_tF : $@convention(thin) (@in_guaranteed P) -> () { func test_var_4(p p: P) { + // CHECK: [[PAIR:%.*]] = alloc_stack $(P, Int) // CHECK: function_ref @$s10switch_var3fooSiyF switch (p, foo()) { - // CHECK: [[PAIR:%.*]] = alloc_stack $(P, Int) // CHECK: store // CHECK: [[PAIR_0:%.*]] = tuple_element_addr [[PAIR]] : $*(P, Int), 0 // CHECK: [[T0:%.*]] = tuple_element_addr [[PAIR]] : $*(P, Int), 1 @@ -215,7 +215,7 @@ func test_var_4(p p: P) { // CHECK: function_ref @$s10switch_var1a1xySi_tF // CHECK: destroy_value [[XADDR]] // CHECK: dealloc_stack [[TMP]] - // CHECK: destroy_addr [[PAIR_0]] : $*P + // CHECK: destroy_addr [[PAIR]] // CHECK: dealloc_stack [[PAIR]] // CHECK: br [[CONT:bb[0-9]+]] a(x: x) @@ -249,7 +249,7 @@ func test_var_4(p p: P) { // CHECK: function_ref @$s10switch_var1b1xySi_tF // CHECK: destroy_value [[YADDR]] // CHECK: dealloc_stack [[TMP]] - // CHECK: destroy_addr [[PAIR_0]] : $*P + // CHECK: destroy_addr [[PAIR]] // CHECK: dealloc_stack [[PAIR]] // CHECK: br [[CONT]] b(x: y) @@ -291,9 +291,8 @@ func test_var_4(p p: P) { // CHECK: load [trivial] [[READ]] // CHECK: function_ref @$s10switch_var1d1xySi_tF // CHECK: destroy_value [[WADDR]] - // CHECK-NEXT: destroy_addr [[PAIR_0]] : $*P + // CHECK-NEXT: destroy_addr [[PAIR]] // CHECK-NEXT: dealloc_stack [[PAIR]] - // CHECK-NEXT: dealloc_stack // CHECK-NEXT: br [[CONT]] d(x: w) } diff --git a/test/SILOptimizer/access_marker_verify.swift b/test/SILOptimizer/access_marker_verify.swift index 1ed6f62f84fdd..e6675bd62798f 100644 --- a/test/SILOptimizer/access_marker_verify.swift +++ b/test/SILOptimizer/access_marker_verify.swift @@ -559,9 +559,10 @@ enum OptionalWithMap { } } // CHECK-LABEL: sil hidden [ossa] @$s20access_marker_verify15OptionalWithMapO3mapyqd__Sgqd__xKXEKlF : $@convention(method) (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> (@out τ_0_1, @error Error) for , @in_guaranteed OptionalWithMap) -> (@out Optional, @error Error) +// CHECK: [[TMP:%.]] = alloc_stack $OptionalWithMap // CHECK: [[STK:%.]] = alloc_stack $OptionalWithMap // CHECK-NOT: begin_access -// CHECK: copy_addr %2 to [initialization] [[STK]] : $*OptionalWithMap +// CHECK: copy_addr [[TMP]] to [initialization] [[STK]] : $*OptionalWithMap // CHECK: switch_enum_addr [[STK]] : $*OptionalWithMap, case #OptionalWithMap.some!enumelt: [[BBSOME:bb.*]], case #OptionalWithMap.none!enumelt: bb // // CHECK: [[BBSOME]]: