Merge pull request #85691 from eeckstein/fix-sil-combine

SILCombine: fix propagation of concrete existentials in enums
This commit is contained in:
eeckstein
2025-12-01 09:34:55 +01:00
committed by GitHub
4 changed files with 33 additions and 71 deletions

View File

@@ -213,14 +213,6 @@ castValueToABICompatibleType(SILBuilder *builder, SILPassManager *pm,
/// ```
bool layoutIsTypeDependent(NominalTypeDecl *decl);
/// Peek through trivial Enum initialization, typically for pointless
/// Optionals.
///
/// The returned InitEnumDataAddr dominates the given
/// UncheckedTakeEnumDataAddrInst.
InitEnumDataAddrInst *
findInitAddressForTrivialEnum(UncheckedTakeEnumDataAddrInst *utedai);
/// Returns a project_box if it is the next instruction after \p ABI and
/// and has \p ABI as operand. Otherwise it creates a new project_box right
/// after \p ABI and returns it.

View File

@@ -171,20 +171,6 @@ static SILInstruction *getStackInitInst(SILValue allocStackAddr,
if (auto *ASI = dyn_cast<AllocStackInst>(CAI->getSrc()))
return getStackInitInst(ASI, CAI, isCopied);
// Peek through a stack location holding an Enum.
// %stack_adr = alloc_stack
// %data_adr = init_enum_data_addr %stk_adr
// %enum_adr = inject_enum_addr %stack_adr
// %copy_src = unchecked_take_enum_data_addr %enum_adr
// Replace %copy_src with %data_adr and recurse.
//
// TODO: a general Optional elimination sil-combine could
// supersede this check.
if (auto *UTEDAI = dyn_cast<UncheckedTakeEnumDataAddrInst>(CAI->getSrc())) {
if (InitEnumDataAddrInst *IEDAI = findInitAddressForTrivialEnum(UTEDAI))
return getStackInitInst(IEDAI, CAI, isCopied);
}
// Check if the CAISrc is a global_addr.
if (auto *GAI = dyn_cast<GlobalAddrInst>(CAI->getSrc()))
return findInitExistentialFromGlobalAddr(GAI, CAI);

View File

@@ -886,55 +886,6 @@ ProjectBoxInst *swift::getOrCreateProjectBox(AllocBoxInst *abi,
return builder.createProjectBox(abi->getLoc(), abi, index);
}
// Peek through trivial Enum initialization, typically for pointless
// Optionals.
//
// Given an UncheckedTakeEnumDataAddrInst, check that there are no
// other uses of the Enum value and return the address used to initialized the
// enum's payload:
//
// %stack_adr = alloc_stack
// %data_adr = init_enum_data_addr %stk_adr
// %enum_adr = inject_enum_addr %stack_adr
// %copy_src = unchecked_take_enum_data_addr %enum_adr
// dealloc_stack %stack_adr
// (No other uses of %stack_adr.)
InitEnumDataAddrInst *
swift::findInitAddressForTrivialEnum(UncheckedTakeEnumDataAddrInst *utedai) {
auto *asi = dyn_cast<AllocStackInst>(utedai->getOperand());
if (!asi)
return nullptr;
InjectEnumAddrInst *singleInject = nullptr;
InitEnumDataAddrInst *singleInit = nullptr;
for (auto use : asi->getUses()) {
auto *user = use->getUser();
if (user == utedai)
continue;
// If there is a single init_enum_data_addr and a single inject_enum_addr,
// those instructions must dominate the unchecked_take_enum_data_addr.
// Otherwise the enum wouldn't be initialized on all control flow paths.
if (auto *inj = dyn_cast<InjectEnumAddrInst>(user)) {
if (singleInject)
return nullptr;
singleInject = inj;
continue;
}
if (auto *init = dyn_cast<InitEnumDataAddrInst>(user)) {
if (singleInit)
return nullptr;
singleInit = init;
continue;
}
if (isa<DeallocStackInst>(user) || isa<DebugValueInst>(user))
continue;
}
return singleInit;
}
//===----------------------------------------------------------------------===//
// Closure Deletion
//===----------------------------------------------------------------------===//

View File

@@ -786,6 +786,39 @@ bb0(%0 : $S):
return %20 : $()
}
protocol Q2 {
func f()
}
struct S2 : Q2 {
func f()
}
// CHECK-LABEL: sil [ossa] @overridden_enum_in_alloc_stack :
// CHECK: witness_method $@opened
// CHECK-LABEL: } // end sil function 'overridden_enum_in_alloc_stack'
sil [ossa] @overridden_enum_in_alloc_stack : $@convention(thin) (S2, @in_guaranteed Optional<any Q2>) -> () {
bb0(%0 : $S2, %1 : $*Optional<any Q2>):
%2 = alloc_stack $Optional<any Q2>
%3 = init_enum_data_addr %2, #Optional.some!enumelt
%4 = init_existential_addr %3, $S2
store %0 to [trivial] %4
inject_enum_addr %2, #Optional.some!enumelt
copy_addr %1 to %2
%8 = unchecked_take_enum_data_addr %2, #Optional.some!enumelt
%9 = alloc_stack $any Q2
copy_addr %8 to [init] %9
%11 = open_existential_addr immutable_access %9 to $*@opened("9EED66EA-C9C5-11F0-85FF-0EA13E3AABB2", any Q2) Self
%12 = witness_method $@opened("9EED66EA-C9C5-11F0-85FF-0EA13E3AABB2", any Q2) Self, #Q2.f : <Self where Self : Q2> (Self) -> () -> (), %11 : $*@opened("9EED66EA-C9C5-11F0-85FF-0EA13E3AABB2", any Q2) Self : $@convention(witness_method: Q2) <τ_0_0 where τ_0_0 : Q2> (@in_guaranteed τ_0_0) -> ()
%13 = apply %12<@opened("9EED66EA-C9C5-11F0-85FF-0EA13E3AABB2", any Q2) Self>(%11) : $@convention(witness_method: Q2) <τ_0_0 where τ_0_0 : Q2> (@in_guaranteed τ_0_0) -> ()
destroy_addr %9
dealloc_stack %9
destroy_addr %2
dealloc_stack %2
%18 = tuple ()
return %18
}
sil_vtable SubscriptionViewControllerBuilder {}
sil_vtable SubscriptionViewController {}
sil_vtable ViewController {}