Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 64 additions & 54 deletions lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -987,36 +987,21 @@ static bool findNonEscapingPartialApplyUses(PartialApplyInst *pai,
return true;
}

void UseState::initializeLiveness(
FieldSensitiveMultiDefPrunedLiveRange &liveness) {
assert(liveness.getNumSubElements() == getNumSubelements());
// We begin by initializing all of our init uses.
for (auto initInstAndValue : initInsts) {
LLVM_DEBUG(llvm::dbgs() << "Found def: " << *initInstAndValue.first);
static bool
addressBeginsInitialized(MarkUnresolvedNonCopyableValueInst *address) {
// FIXME: Whether the initial use is an initialization ought to be entirely
// derivable from the CheckKind of the mark instruction.

liveness.initializeDef(initInstAndValue.first, initInstAndValue.second);
}
SILValue operand = address->getOperand();

// If we have a reinitInstAndValue that we are going to be able to convert
// into a simple init, add it as an init. We are going to consider the rest of
// our reinit uses to be liveness uses.
for (auto reinitInstAndValue : reinitInsts) {
if (isReinitToInitConvertibleInst(reinitInstAndValue.first)) {
LLVM_DEBUG(llvm::dbgs() << "Found def: " << *reinitInstAndValue.first);
liveness.initializeDef(reinitInstAndValue.first,
reinitInstAndValue.second);
}
if (auto *mdi = dyn_cast<MarkDependenceInst>(operand)) {
operand = mdi->getValue();
}

// FIXME: Whether the initial use is an initialization ought to be entirely
// derivable from the CheckKind of the mark instruction.

// Then check if our markedValue is from an argument that is in,
// in_guaranteed, inout, or inout_aliasable, consider the marked address to be
// the initialization point.
bool beginsInitialized = false;
{
SILValue operand = address->getOperand();
// Then check if our markedValue is from an argument that is in,
// in_guaranteed, inout, or inout_aliasable, consider the marked address to
// be the initialization point.
if (auto *c = dyn_cast<CopyableToMoveOnlyWrapperAddrInst>(operand))
operand = c->getOperand();
if (auto *fArg = dyn_cast<SILFunctionArgument>(operand)) {
Expand All @@ -1034,7 +1019,7 @@ void UseState::initializeLiveness(
"an init... adding mark_unresolved_non_copyable_value as "
"init!\n");
// We cheat here slightly and use our address's operand.
beginsInitialized = true;
return true;
break;
case swift::SILArgumentConvention::Indirect_Out:
llvm_unreachable("Should never have out addresses here");
Expand All @@ -1051,15 +1036,15 @@ void UseState::initializeLiveness(
}

// A read or write access always begins on an initialized value.
if (auto access = dyn_cast<BeginAccessInst>(address->getOperand())) {
if (auto access = dyn_cast<BeginAccessInst>(operand)) {
switch (access->getAccessKind()) {
case SILAccessKind::Deinit:
case SILAccessKind::Read:
case SILAccessKind::Modify:
LLVM_DEBUG(llvm::dbgs()
<< "Found move only arg closure box use... "
"adding mark_unresolved_non_copyable_value as init!\n");
beginsInitialized = true;
return true;
break;
case SILAccessKind::Init:
break;
Expand All @@ -1069,7 +1054,8 @@ void UseState::initializeLiveness(
// See if our address is from a closure guaranteed box that we did not promote
// to an address. In such a case, just treat our
// mark_unresolved_non_copyable_value as the init of our value.
if (auto *projectBox = dyn_cast<ProjectBoxInst>(stripAccessMarkers(address->getOperand()))) {
if (auto *projectBox =
dyn_cast<ProjectBoxInst>(stripAccessMarkers(operand))) {
if (auto *fArg = dyn_cast<SILFunctionArgument>(projectBox->getOperand())) {
if (fArg->isClosureCapture()) {
assert(fArg->getArgumentConvention() ==
Expand All @@ -1081,91 +1067,115 @@ void UseState::initializeLiveness(
LLVM_DEBUG(llvm::dbgs()
<< "Found move only arg closure box use... "
"adding mark_unresolved_non_copyable_value as init!\n");
beginsInitialized = true;
return true;
}
} else if (auto *box = dyn_cast<AllocBoxInst>(
lookThroughOwnershipInsts(projectBox->getOperand()))) {
LLVM_DEBUG(llvm::dbgs()
<< "Found move only var allocbox use... "
"adding mark_unresolved_non_copyable_value as init!\n");
beginsInitialized = true;
return true;
}
}

// Check if our address is from a ref_element_addr. In such a case, we treat
// the mark_unresolved_non_copyable_value as the initialization.
if (auto *refEltAddr = dyn_cast<RefElementAddrInst>(
stripAccessMarkers(address->getOperand()))) {
if (auto *refEltAddr =
dyn_cast<RefElementAddrInst>(stripAccessMarkers(operand))) {
LLVM_DEBUG(llvm::dbgs()
<< "Found ref_element_addr use... "
"adding mark_unresolved_non_copyable_value as init!\n");
beginsInitialized = true;
return true;
}

// Check if our address is from a global_addr. In such a case, we treat the
// mark_unresolved_non_copyable_value as the initialization.
if (auto *globalAddr =
dyn_cast<GlobalAddrInst>(stripAccessMarkers(address->getOperand()))) {
dyn_cast<GlobalAddrInst>(stripAccessMarkers(operand))) {
LLVM_DEBUG(llvm::dbgs()
<< "Found global_addr use... "
"adding mark_unresolved_non_copyable_value as init!\n");
beginsInitialized = true;
return true;
}

if (auto *ptai = dyn_cast<PointerToAddressInst>(
stripAccessMarkers(address->getOperand()))) {
if (auto *ptai =
dyn_cast<PointerToAddressInst>(stripAccessMarkers(operand))) {
assert(ptai->isStrict());
LLVM_DEBUG(llvm::dbgs()
<< "Found pointer to address use... "
"adding mark_unresolved_non_copyable_value as init!\n");
beginsInitialized = true;
return true;
}

if (auto *bai = dyn_cast_or_null<BeginApplyInst>(
stripAccessMarkers(address->getOperand())->getDefiningInstruction())) {
stripAccessMarkers(operand)->getDefiningInstruction())) {
LLVM_DEBUG(llvm::dbgs()
<< "Adding accessor coroutine begin_apply as init!\n");
beginsInitialized = true;
return true;
}

if (auto *eai = dyn_cast<UncheckedTakeEnumDataAddrInst>(
stripAccessMarkers(address->getOperand()))) {
stripAccessMarkers(operand))) {
LLVM_DEBUG(llvm::dbgs()
<< "Adding enum projection as init!\n");
beginsInitialized = true;
return true;
}

// Assume a strict check of a temporary or formal access is initialized
// before the check.
if (auto *asi = dyn_cast<AllocStackInst>(
stripAccessMarkers(address->getOperand()));
if (auto *asi = dyn_cast<AllocStackInst>(stripAccessMarkers(operand));
asi && address->isStrict()) {
LLVM_DEBUG(llvm::dbgs()
<< "Adding strict-marked alloc_stack as init!\n");
beginsInitialized = true;
return true;
}

// Assume a strict-checked value initialized before the check.
if (address->isStrict()) {
LLVM_DEBUG(llvm::dbgs()
<< "Adding strict marker as init!\n");
beginsInitialized = true;
return true;
}

// Assume a value whose deinit has been dropped has been initialized.
if (auto *ddi = dyn_cast<DropDeinitInst>(address->getOperand())) {
if (auto *ddi = dyn_cast<DropDeinitInst>(operand)) {
LLVM_DEBUG(llvm::dbgs()
<< "Adding copyable_to_move_only_wrapper as init!\n");
beginsInitialized = true;
return true;
}

// Assume a value wrapped in a MoveOnlyWrapper is initialized.
if (auto *m2c = dyn_cast<CopyableToMoveOnlyWrapperAddrInst>(address->getOperand())) {
if (auto *m2c = dyn_cast<CopyableToMoveOnlyWrapperAddrInst>(operand)) {
LLVM_DEBUG(llvm::dbgs()
<< "Adding copyable_to_move_only_wrapper as init!\n");
beginsInitialized = true;
return true;
}

return false;
}

void UseState::initializeLiveness(
FieldSensitiveMultiDefPrunedLiveRange &liveness) {
assert(liveness.getNumSubElements() == getNumSubelements());
// We begin by initializing all of our init uses.
for (auto initInstAndValue : initInsts) {
LLVM_DEBUG(llvm::dbgs() << "Found def: " << *initInstAndValue.first);

liveness.initializeDef(initInstAndValue.first, initInstAndValue.second);
}

// If we have a reinitInstAndValue that we are going to be able to convert
// into a simple init, add it as an init. We are going to consider the rest of
// our reinit uses to be liveness uses.
for (auto reinitInstAndValue : reinitInsts) {
if (isReinitToInitConvertibleInst(reinitInstAndValue.first)) {
LLVM_DEBUG(llvm::dbgs() << "Found def: " << *reinitInstAndValue.first);
liveness.initializeDef(reinitInstAndValue.first,
reinitInstAndValue.second);
}
}

bool beginsInitialized = addressBeginsInitialized(address);

if (beginsInitialized) {
recordInitUse(address, address, liveness.getTopLevelSpan());
liveness.initializeDef(SILValue(address), liveness.getTopLevelSpan());
Expand Down
19 changes: 17 additions & 2 deletions test/SILOptimizer/moveonly_addresschecker.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// RUN: %target-swift-emit-sil -sil-verify-all -verify -enable-experimental-feature NoImplicitCopy -enable-experimental-feature MoveOnlyClasses %s -Xllvm -sil-print-final-ossa-module | %FileCheck %s
// RUN: %target-swift-emit-sil -O -sil-verify-all -verify -enable-experimental-feature NoImplicitCopy -enable-experimental-feature MoveOnlyClasses %s
// RUN: %target-swift-emit-sil -sil-verify-all -verify -enable-experimental-feature NoImplicitCopy -enable-experimental-feature MoveOnlyClasses -enable-experimental-feature NonescapableTypes %s -Xllvm -sil-print-final-ossa-module | %FileCheck %s
// RUN: %target-swift-emit-sil -O -sil-verify-all -verify -enable-experimental-feature NoImplicitCopy -enable-experimental-feature MoveOnlyClasses -enable-experimental-feature NonescapableTypes %s

// This file contains tests that used to crash due to verifier errors. It must
// be separate from moveonly_addresschecker_diagnostics since when we fail on
Expand Down Expand Up @@ -46,3 +46,18 @@ struct S
fatalError()
}
}

struct TestCoroAccessorOfCoroAccessor<T : ~Escapable> : ~Copyable & ~Escapable {
var t: T

var inner: TestCoroAccessorOfCoroAccessor<T> {
_read {
fatalError()
}
}
var outer: TestCoroAccessorOfCoroAccessor<T> {
_read {
yield inner
}
}
}