Skip to content

Commit 1c9f7f5

Browse files
committed
SIL: Add verification of open_existential_addr instructions
Make sure that all uses of "immutable_access" instructions are not mutating the opened value. Only enable verification if we have COW existentials enabled.
1 parent 6218482 commit 1c9f7f5

File tree

1 file changed

+88
-0
lines changed

1 file changed

+88
-0
lines changed

lib/SIL/SILVerifier.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,10 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
122122
return F.getModule().getOptions().EnableSILOwnership;
123123
}
124124

125+
bool areCOWExistentialsEnabled() const {
126+
return F.getModule().getOptions().UseCOWExistentials;
127+
}
128+
125129
void _require(bool condition, const Twine &complaint,
126130
const std::function<void()> &extraContext = nullptr) {
127131
if (condition) return;
@@ -2178,6 +2182,90 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
21782182
require(OpenedArchetypes.getOpenedArchetypeDef(archetype) == OEI,
21792183
"Archetype opened by open_existential_addr should be registered in "
21802184
"SILFunction");
2185+
2186+
if (!areCOWExistentialsEnabled())
2187+
return;
2188+
2189+
// Check all the uses. Consuming or mutating uses must have mutable access
2190+
// to the opened value.
2191+
auto allowedAccessKind = OEI->getAccessKind();
2192+
if (allowedAccessKind == OpenedExistentialAccess::Mutable)
2193+
return;
2194+
2195+
auto isConsumingOrMutatingApplyUse = [](Operand *use) -> bool {
2196+
ApplySite apply(use->getUser());
2197+
assert(apply && "Not an apply instruction kind");
2198+
auto conv = apply.getArgumentConvention(use->getOperandNumber() - 1);
2199+
switch (conv) {
2200+
case SILArgumentConvention::Indirect_In_Guaranteed:
2201+
return false;
2202+
2203+
case SILArgumentConvention::Indirect_Out:
2204+
case SILArgumentConvention::Indirect_In:
2205+
case SILArgumentConvention::Indirect_Inout:
2206+
case SILArgumentConvention::Indirect_InoutAliasable:
2207+
return true;
2208+
2209+
case SILArgumentConvention::Direct_Unowned:
2210+
case SILArgumentConvention::Direct_Guaranteed:
2211+
case SILArgumentConvention::Direct_Owned:
2212+
case SILArgumentConvention::Direct_Deallocating:
2213+
assert(conv.isIndirectConvention() && "Expect an indirect convention");
2214+
return true; // return something "conservative".
2215+
}
2216+
llvm_unreachable("covered switch isn't covered?!");
2217+
};
2218+
2219+
// A "copy_addr %src [take] to *" is consuming on "%src".
2220+
// A "copy_addr * to * %dst" is mutating on "%dst".
2221+
auto isConsumingOrMutatingCopyAddrUse = [](Operand *use) -> bool {
2222+
auto *copyAddr = cast<CopyAddrInst>(use->getUser());
2223+
if (copyAddr->getDest() == use->get())
2224+
return true;
2225+
if (copyAddr->getSrc() == use->get() && copyAddr->isTakeOfSrc() == IsTake)
2226+
return true;
2227+
return false;
2228+
};
2229+
2230+
auto isMutatingOrConsuming = [=](OpenExistentialAddrInst *OEI) -> bool {
2231+
for (auto *use : OEI->getUses()) {
2232+
auto *inst = use->getUser();
2233+
if (inst->isTypeDependentOperand(*use))
2234+
continue;
2235+
switch (inst->getKind()) {
2236+
case ValueKind::ApplyInst:
2237+
case ValueKind::TryApplyInst:
2238+
case ValueKind::PartialApplyInst:
2239+
if (isConsumingOrMutatingApplyUse(use))
2240+
return true;
2241+
else
2242+
break;
2243+
case ValueKind::CopyAddrInst:
2244+
if (isConsumingOrMutatingCopyAddrUse(use))
2245+
return true;
2246+
else
2247+
break;
2248+
case ValueKind::DestroyAddrInst:
2249+
return true;
2250+
case ValueKind::UncheckedAddrCastInst:
2251+
// Escaping use lets be conservative here.
2252+
return true;
2253+
case ValueKind::CheckedCastAddrBranchInst:
2254+
if (cast<CheckedCastAddrBranchInst>(inst)->getConsumptionKind() !=
2255+
CastConsumptionKind::CopyOnSuccess)
2256+
return true;
2257+
break;
2258+
default:
2259+
assert(false && "Unhandled unexpected instruction");
2260+
break;
2261+
}
2262+
}
2263+
return false;
2264+
};
2265+
require(!isMutatingOrConsuming(OEI) ||
2266+
allowedAccessKind == OpenedExistentialAccess::Mutable,
2267+
"open_existential_addr uses that consumes or mutates but is not "
2268+
"opened for mutation");
21812269
}
21822270

21832271
void checkOpenExistentialRefInst(OpenExistentialRefInst *OEI) {

0 commit comments

Comments
 (0)