Skip to content

Commit 63141b6

Browse files
committed
Optimizer: when propagating the concrete type of an existential, make sure to not violate dominance order
Make sure that an enum is only initialized once before it is taken. This implies that the initialization must dominate the take. Fixes a verifier crash: rdar://139381701
1 parent e12e968 commit 63141b6

File tree

2 files changed

+59
-15
lines changed

2 files changed

+59
-15
lines changed

lib/SILOptimizer/Utils/InstOptUtils.cpp

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -904,30 +904,34 @@ swift::findInitAddressForTrivialEnum(UncheckedTakeEnumDataAddrInst *utedai) {
904904
if (!asi)
905905
return nullptr;
906906

907-
SILInstruction *singleUser = nullptr;
907+
InjectEnumAddrInst *singleInject = nullptr;
908+
InitEnumDataAddrInst *singleInit = nullptr;
908909
for (auto use : asi->getUses()) {
909910
auto *user = use->getUser();
910911
if (user == utedai)
911912
continue;
912913

913-
// As long as there's only one UncheckedTakeEnumDataAddrInst and one
914-
// InitEnumDataAddrInst, we don't care how many InjectEnumAddr and
915-
// DeallocStack users there are.
916-
if (isa<InjectEnumAddrInst>(user) || isa<DeallocStackInst>(user))
914+
// If there is a single init_enum_data_addr and a single inject_enum_addr,
915+
// those instructions must dominate the unchecked_take_enum_data_addr.
916+
// Otherwise the enum wouldn't be initialized on all control flow paths.
917+
if (auto *inj = dyn_cast<InjectEnumAddrInst>(user)) {
918+
if (singleInject)
919+
return nullptr;
920+
singleInject = inj;
917921
continue;
922+
}
918923

919-
if (singleUser)
920-
return nullptr;
924+
if (auto *init = dyn_cast<InitEnumDataAddrInst>(user)) {
925+
if (singleInit)
926+
return nullptr;
927+
singleInit = init;
928+
continue;
929+
}
921930

922-
singleUser = user;
931+
if (isa<DeallocStackInst>(user) || isa<DebugValueInst>(user))
932+
continue;
923933
}
924-
if (!singleUser)
925-
return nullptr;
926-
927-
// Assume, without checking, that the returned InitEnumDataAddr dominates the
928-
// given UncheckedTakeEnumDataAddrInst, because that's how SIL is defined. I
929-
// don't know where this is actually verified.
930-
return dyn_cast<InitEnumDataAddrInst>(singleUser);
934+
return singleInit;
931935
}
932936

933937
//===----------------------------------------------------------------------===//

test/SILOptimizer/sil_combine_enums.sil

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ enum Numerals {
1616
case Four
1717
}
1818

19+
protocol P {
20+
mutating func foo()
21+
}
22+
23+
sil @createit : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@thick τ_0_0.Type) -> @out τ_0_0
1924
sil @external_func: $@convention(thin) () -> ()
2025

2126
//CHECK-LABEL: eliminate_sw_enum_addr
@@ -663,3 +668,38 @@ bb0(%0 : $S):
663668
return %11 : $()
664669
}
665670

671+
// CHECK-LABEL: sil @dont_promote_existential_type_from_non_dominating_block :
672+
// Just check that this doesn't crash
673+
// CHECK: } // end sil function 'dont_promote_existential_type_from_non_dominating_block'
674+
sil @dont_promote_existential_type_from_non_dominating_block : $@convention(thin) (@thick any P.Type) -> () {
675+
bb0(%0 : $@thick any P.Type):
676+
%1 = alloc_stack $Optional<any P>
677+
cond_br undef, bb1, bb2
678+
679+
bb1:
680+
inject_enum_addr %1 : $*Optional<any P>, #Optional.none!enumelt
681+
br bb3
682+
683+
bb2:
684+
%5 = init_enum_data_addr %1 : $*Optional<any P>, #Optional.some!enumelt
685+
%6 = open_existential_metatype %0 : $@thick any P.Type to $@thick (@opened("B0100688-9C78-11EF-8A3C-4EA2A866E4C4", any P) Self).Type
686+
%7 = init_existential_addr %5 : $*any P, $@opened("B0100688-9C78-11EF-8A3C-4EA2A866E4C4", any P) Self
687+
%f = function_ref @createit : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@thick τ_0_0.Type) -> @out τ_0_0
688+
%a = apply %f<@opened("B0100688-9C78-11EF-8A3C-4EA2A866E4C4", any P) Self>(%7, %6) : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@thick τ_0_0.Type) -> @out τ_0_0
689+
inject_enum_addr %1 : $*Optional<any P>, #Optional.some!enumelt
690+
br bb3
691+
692+
bb3:
693+
%9 = unchecked_take_enum_data_addr %1 : $*Optional<any P>, #Optional.some!enumelt
694+
dealloc_stack %1 : $*Optional<any P>
695+
%11 = alloc_stack [lexical] [var_decl] $any P, var, name "comp"
696+
copy_addr [take] %9 to [init] %11 : $*any P
697+
%13 = open_existential_addr mutable_access %11 : $*any P to $*@opened("36EE10D8-9C78-11EF-8A3C-4EA2A866E4C4", any P) Self
698+
%14 = witness_method $@opened("36EE10D8-9C78-11EF-8A3C-4EA2A866E4C4", any P) Self, #P.foo : <Self where Self : P> (inout Self) -> () -> (), %13 : $*@opened("36EE10D8-9C78-11EF-8A3C-4EA2A866E4C4", any P) Self : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@inout τ_0_0) -> ()
699+
%15 = apply %14<@opened("36EE10D8-9C78-11EF-8A3C-4EA2A866E4C4", any P) Self>(%13) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@inout τ_0_0) -> ()
700+
destroy_addr %11 : $*any P
701+
dealloc_stack %11 : $*any P
702+
%18 = tuple ()
703+
return %18 : $()
704+
}
705+

0 commit comments

Comments
 (0)