mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[capture-promotion] When checking if a (struct_element_addr (project_box box)) is written to, check that all of the operands are loads, instead of returning early when we find one.
I found this bug by inspection. This is an important bug to fix since this pass runs at -Onone and the bug results in the compiler hitting an unreachable. The way the unreachable is triggered is that when we detect that we are going to promote a box, if we see a (struct_element_addr (project_box box)), we don't map the struct_element_addr to a cloned value. If we have a load, this is not an issue, since we are mapping the load to the struct_extract. But if we have /any/ other non-load users of the struct_element_addr, the cloner will attempt to look up the struct_element_addr and will be unable to find it, hitting an unreachable. rdar://32776202
This commit is contained in:
@@ -694,6 +694,13 @@ static SILArgument *getBoxFromIndex(SILFunction *F, unsigned Index) {
|
||||
return Entry.getArgument(Index);
|
||||
}
|
||||
|
||||
static bool isNonMutatingLoad(SILInstruction *I) {
|
||||
auto *LI = dyn_cast<LoadInst>(I);
|
||||
if (!LI)
|
||||
return false;
|
||||
return LI->getOwnershipQualifier() != LoadOwnershipQualifier::Take;
|
||||
}
|
||||
|
||||
/// \brief Given a partial_apply instruction and the argument index into its
|
||||
/// callee's argument list of a box argument (which is followed by an argument
|
||||
/// for the address of the box's contents), return true if the closure is known
|
||||
@@ -726,16 +733,15 @@ isNonMutatingCapture(SILArgument *BoxArg) {
|
||||
// function that mirrors isNonEscapingUse.
|
||||
auto checkAddrUse = [](SILInstruction *AddrInst) {
|
||||
if (auto *SEAI = dyn_cast<StructElementAddrInst>(AddrInst)) {
|
||||
for (auto *UseOper : SEAI->getUses()) {
|
||||
if (isa<LoadInst>(UseOper->getUser()))
|
||||
return true;
|
||||
}
|
||||
} else if (isa<LoadInst>(AddrInst) || isa<DebugValueAddrInst>(AddrInst)
|
||||
|| isa<MarkFunctionEscapeInst>(AddrInst)
|
||||
|| isa<EndAccessInst>(AddrInst)) {
|
||||
return true;
|
||||
return all_of(SEAI->getUses(),
|
||||
[](Operand *Op) -> bool {
|
||||
return isNonMutatingLoad(Op->getUser());
|
||||
});
|
||||
}
|
||||
return false;
|
||||
|
||||
return isNonMutatingLoad(AddrInst) || isa<DebugValueAddrInst>(AddrInst)
|
||||
|| isa<MarkFunctionEscapeInst>(AddrInst)
|
||||
|| isa<EndAccessInst>(AddrInst);
|
||||
};
|
||||
for (auto *Projection : Projections) {
|
||||
for (auto *UseOper : Projection->getUses()) {
|
||||
@@ -744,7 +750,10 @@ isNonMutatingCapture(SILArgument *BoxArg) {
|
||||
if (!checkAddrUse(AccessUseOper->getUser()))
|
||||
return false;
|
||||
}
|
||||
} else if (!checkAddrUse(UseOper->getUser()))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!checkAddrUse(UseOper->getUser()))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user