[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:
Michael Gottesman
2017-06-14 16:51:12 -07:00
parent 4b0597a893
commit cf99e5c522
4 changed files with 71 additions and 12 deletions

View File

@@ -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;
}
}