Skip to content

Commit c72ddcf

Browse files
authored
Merge pull request #61143 from gottesmm/pr-7e04f5d62651e78c425d1a21b829abaf5096b2b0
[move-only] Add support for trivial move only var/mutating self/inout.
2 parents 2fb3f46 + 724449d commit c72ddcf

File tree

6 files changed

+1536
-43
lines changed

6 files changed

+1536
-43
lines changed

include/swift/SIL/PrunedLiveness.h

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -752,17 +752,30 @@ struct TypeTreeLeafTypeRange {
752752
SubElementNumber startEltOffset;
753753
SubElementNumber endEltOffset;
754754

755+
private:
756+
TypeTreeLeafTypeRange(SubElementNumber start, SubElementNumber end)
757+
: startEltOffset(start), endEltOffset(end) {}
758+
759+
public:
755760
/// The leaf type range for the entire type tree.
756761
TypeTreeLeafTypeRange(SILValue rootAddress)
757762
: startEltOffset(0), endEltOffset(TypeSubElementCount(rootAddress)) {}
758763

759764
/// The leaf type sub-range of the type tree of \p rootAddress, consisting of
760765
/// \p projectedAddress and all of \p projectedAddress's descendent fields in
761766
/// the type tree.
762-
TypeTreeLeafTypeRange(SILValue projectedAddress, SILValue rootAddress)
763-
: startEltOffset(
764-
*SubElementNumber::compute(projectedAddress, rootAddress)),
765-
endEltOffset(startEltOffset + TypeSubElementCount(projectedAddress)) {}
767+
///
768+
/// \returns None if we are unable to understand the path in between \p
769+
/// projectedAddress and \p rootAddress.
770+
static Optional<TypeTreeLeafTypeRange> get(SILValue projectedAddress,
771+
SILValue rootAddress) {
772+
auto startEltOffset =
773+
SubElementNumber::compute(projectedAddress, rootAddress);
774+
if (!startEltOffset)
775+
return None;
776+
return {{*startEltOffset,
777+
*startEltOffset + TypeSubElementCount(projectedAddress)}};
778+
}
766779

767780
/// Is the given leaf type specified by \p singleLeafElementNumber apart of
768781
/// our \p range of leaf type values in the our larger type.

lib/SIL/Utils/PrunedLiveness.cpp

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -507,14 +507,12 @@ SubElementNumber::compute(SILValue projectionDerivedFromRoot,
507507
continue;
508508
}
509509

510-
#ifndef NDEBUG
511-
if (!isa<InitExistentialAddrInst>(projectionDerivedFromRoot)) {
512-
llvm::errs() << "Unknown access path instruction!\n";
513-
llvm::errs() << "Value: " << *projectionDerivedFromRoot;
514-
llvm_unreachable("standard error");
515-
}
516-
#endif
517-
// Cannot promote loads and stores from within an existential projection.
510+
// If we do not know how to handle this case, just return None.
511+
//
512+
// NOTE: We use to assert here, but since this is used for diagnostics, we
513+
// really do not want to abort. Instead, our caller can choose to abort if
514+
// they get back a None. This ensures that we do not abort in cases where we
515+
// just want to emit to the user a "I do not understand" error.
518516
return None;
519517
}
520518
}

lib/SILOptimizer/Mandatory/MoveOnlyAddressChecker.cpp

Lines changed: 62 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -841,17 +841,22 @@ bool GatherUsesVisitor::visitUse(Operand *op, AccessUseType useTy) {
841841

842842
// TODO: What about copy_addr of itself. We really should just pre-process
843843
// those maybe.
844+
auto leafRange = TypeTreeLeafTypeRange::get(op->get(), getRootAddress());
845+
if (!leafRange)
846+
return false;
847+
844848
assert(!useState.initInsts.count(user));
845-
useState.initInsts.insert(
846-
{user, TypeTreeLeafTypeRange(op->get(), getRootAddress())});
849+
useState.initInsts.insert({user, *leafRange});
847850
return true;
848851
}
849852

850853
if (::memInstMustReinitialize(op)) {
851854
LLVM_DEBUG(llvm::dbgs() << "Found reinit: " << *user);
852855
assert(!useState.reinitInsts.count(user));
853-
useState.reinitInsts.insert(
854-
{user, TypeTreeLeafTypeRange(op->get(), getRootAddress())});
856+
auto leafRange = TypeTreeLeafTypeRange::get(op->get(), getRootAddress());
857+
if (!leafRange)
858+
return false;
859+
useState.reinitInsts.insert({user, *leafRange});
855860
return true;
856861
}
857862

@@ -891,9 +896,12 @@ bool GatherUsesVisitor::visitUse(Operand *op, AccessUseType useTy) {
891896
return true;
892897
}
893898

899+
auto leafRange = TypeTreeLeafTypeRange::get(op->get(), getRootAddress());
900+
if (!leafRange)
901+
return false;
902+
894903
LLVM_DEBUG(llvm::dbgs() << "Found take: " << *user);
895-
useState.takeInsts.insert(
896-
{user, TypeTreeLeafTypeRange(op->get(), getRootAddress())});
904+
useState.takeInsts.insert({user, *leafRange});
897905
return true;
898906
}
899907

@@ -935,9 +943,13 @@ bool GatherUsesVisitor::visitUse(Operand *op, AccessUseType useTy) {
935943

936944
// If set, this will tell the checker that we can change this load into
937945
// a load_borrow.
946+
auto leafRange =
947+
TypeTreeLeafTypeRange::get(op->get(), getRootAddress());
948+
if (!leafRange)
949+
return false;
950+
938951
LLVM_DEBUG(llvm::dbgs() << "Found potential borrow: " << *user);
939-
useState.borrows.insert(
940-
{user, TypeTreeLeafTypeRange(op->get(), getRootAddress())});
952+
useState.borrows.insert({user, *leafRange});
941953
return true;
942954
}
943955

@@ -963,33 +975,41 @@ bool GatherUsesVisitor::visitUse(Operand *op, AccessUseType useTy) {
963975

964976
// Then if we had any final consuming uses, mark that this liveness use is
965977
// a take and if not, mark this as a borrow.
978+
auto leafRange = TypeTreeLeafTypeRange::get(op->get(), getRootAddress());
979+
if (!leafRange)
980+
return false;
981+
966982
if (moveChecker.finalConsumingUses.empty()) {
967983
LLVM_DEBUG(llvm::dbgs() << "Found borrow inst: " << *user);
968-
useState.borrows.insert(
969-
{user, TypeTreeLeafTypeRange(op->get(), getRootAddress())});
984+
useState.borrows.insert({user, *leafRange});
970985
} else {
971986
LLVM_DEBUG(llvm::dbgs() << "Found take inst: " << *user);
972-
useState.takeInsts.insert(
973-
{user, TypeTreeLeafTypeRange(op->get(), getRootAddress())});
987+
useState.takeInsts.insert({user, *leafRange});
974988
}
975989
return true;
976990
}
977991
}
978992

979993
// Now that we have handled or loadTakeOrCopy, we need to now track our Takes.
980994
if (::memInstMustConsume(op)) {
995+
auto leafRange = TypeTreeLeafTypeRange::get(op->get(), getRootAddress());
996+
if (!leafRange)
997+
return false;
981998
LLVM_DEBUG(llvm::dbgs() << "Pure consuming use: " << *user);
982-
useState.takeInsts.insert(
983-
{user, TypeTreeLeafTypeRange(op->get(), getRootAddress())});
999+
useState.takeInsts.insert({user, *leafRange});
9841000
return true;
9851001
}
9861002

9871003
if (auto fas = FullApplySite::isa(op->getUser())) {
9881004
switch (fas.getArgumentConvention(*op)) {
989-
case SILArgumentConvention::Indirect_In_Guaranteed:
990-
useState.livenessUses.insert(
991-
{user, TypeTreeLeafTypeRange(op->get(), getRootAddress())});
1005+
case SILArgumentConvention::Indirect_In_Guaranteed: {
1006+
auto leafRange = TypeTreeLeafTypeRange::get(op->get(), getRootAddress());
1007+
if (!leafRange)
1008+
return false;
1009+
1010+
useState.livenessUses.insert({user, *leafRange});
9921011
return true;
1012+
}
9931013

9941014
case SILArgumentConvention::Indirect_Inout:
9951015
case SILArgumentConvention::Indirect_InoutAliasable:
@@ -1006,6 +1026,10 @@ bool GatherUsesVisitor::visitUse(Operand *op, AccessUseType useTy) {
10061026
// If we don't fit into any of those categories, just track as a liveness
10071027
// use. We assume all such uses must only be reads to the memory. So we assert
10081028
// to be careful.
1029+
auto leafRange = TypeTreeLeafTypeRange::get(op->get(), getRootAddress());
1030+
if (!leafRange)
1031+
return false;
1032+
10091033
LLVM_DEBUG(llvm::dbgs() << "Found liveness use: " << *user);
10101034
#ifndef NDEBUG
10111035
if (user->mayWriteToMemory()) {
@@ -1014,8 +1038,7 @@ bool GatherUsesVisitor::visitUse(Operand *op, AccessUseType useTy) {
10141038
llvm_unreachable("standard failure");
10151039
}
10161040
#endif
1017-
useState.livenessUses.insert(
1018-
{user, TypeTreeLeafTypeRange(op->get(), getRootAddress())});
1041+
useState.livenessUses.insert({user, *leafRange});
10191042

10201043
return true;
10211044
}
@@ -1036,8 +1059,26 @@ void MoveOnlyChecker::searchForCandidateMarkMustChecks() {
10361059
// Skip any alloc_box due to heap to stack failing on a box capture. This
10371060
// will just cause an error.
10381061
if (auto *pbi = dyn_cast<ProjectBoxInst>(mmci->getOperand())) {
1062+
if (isa<AllocBoxInst>(pbi->getOperand())) {
1063+
LLVM_DEBUG(
1064+
llvm::dbgs()
1065+
<< "Early emitting diagnostic for unsupported alloc box!\n");
1066+
if (mmci->getType().isMoveOnlyWrapped()) {
1067+
diagnose(fn->getASTContext(), mmci->getLoc().getSourceLoc(),
1068+
diag::sil_moveonlychecker_not_understand_no_implicit_copy);
1069+
} else {
1070+
diagnose(fn->getASTContext(), mmci->getLoc().getSourceLoc(),
1071+
diag::sil_moveonlychecker_not_understand_moveonly);
1072+
}
1073+
valuesWithDiagnostics.insert(mmci);
1074+
continue;
1075+
}
1076+
10391077
if (auto *bbi = dyn_cast<BeginBorrowInst>(pbi->getOperand())) {
10401078
if (isa<AllocBoxInst>(bbi->getOperand())) {
1079+
LLVM_DEBUG(
1080+
llvm::dbgs()
1081+
<< "Early emitting diagnostic for unsupported alloc box!\n");
10411082
if (mmci->getType().isMoveOnlyWrapped()) {
10421083
diagnose(
10431084
fn->getASTContext(), mmci->getLoc().getSourceLoc(),
@@ -1604,6 +1645,8 @@ bool MoveOnlyChecker::check() {
16041645

16051646
// Perform our address check.
16061647
if (!performSingleCheck(markedValue)) {
1648+
LLVM_DEBUG(llvm::dbgs()
1649+
<< "Failed to perform single check! Emitting error!\n");
16071650
// If we fail the address check in some way, set the diagnose!
16081651
if (markedValue->getType().isMoveOnlyWrapped()) {
16091652
diagnose(fn->getASTContext(), markedValue->getLoc().getSourceLoc(),

lib/SILOptimizer/Mandatory/MoveOnlyObjectChecker.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ bool MoveOnlyChecker::searchForCandidateMarkMustChecks() {
114114
auto *mmci = dyn_cast<MarkMustCheckInst>(&*ii);
115115
++ii;
116116

117-
if (!mmci || !mmci->hasMoveCheckerKind())
117+
if (!mmci || !mmci->hasMoveCheckerKind() || !mmci->getType().isObject())
118118
continue;
119119

120120
// Handle guaranteed/owned move arguments and values.

test/SILOptimizer/moveonly_addresschecker_diagnostics.swift

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1836,7 +1836,6 @@ public func closureClassUseAfterConsumeArg(_ argX: inout Klass) {
18361836
public func closureCaptureClassUseAfterConsume() {
18371837
var x2 = Klass()
18381838
// expected-error @-1 {{Usage of a move only type that the move checker does not know how to check!}}
1839-
// expected-error @-2 {{Usage of a move only type that the move checker does not know how to check!}}
18401839
x2 = Klass()
18411840
let f = {
18421841
classUseMoveOnlyWithoutEscaping(x2)
@@ -1849,7 +1848,6 @@ public func closureCaptureClassUseAfterConsume() {
18491848
public func closureCaptureClassUseAfterConsumeError() {
18501849
var x2 = Klass()
18511850
// expected-error @-1 {{Usage of a move only type that the move checker does not know how to check!}}
1852-
// expected-error @-2 {{Usage of a move only type that the move checker does not know how to check!}}
18531851
x2 = Klass()
18541852
let f = {
18551853
classUseMoveOnlyWithoutEscaping(x2)
@@ -1925,9 +1923,8 @@ public func deferCaptureClassArgUseAfterConsume(_ x2: inout Klass) {
19251923
public func closureAndDeferCaptureClassUseAfterConsume() {
19261924
var x2 = Klass()
19271925
// expected-error @-1 {{Usage of a move only type that the move checker does not know how to check!}}
1928-
// expected-error @-2 {{Usage of a move only type that the move checker does not know how to check!}}
1929-
// expected-error @-3 {{'x2' consumed but not reinitialized before end of function}}
1930-
// expected-error @-4 {{'x2' consumed more than once}}
1926+
// expected-error @-2 {{'x2' consumed but not reinitialized before end of function}}
1927+
// expected-error @-3 {{'x2' consumed more than once}}
19311928
x2 = Klass()
19321929
let f = {
19331930
defer {
@@ -1946,8 +1943,7 @@ public func closureAndDeferCaptureClassUseAfterConsume2() {
19461943
var x2 = Klass()
19471944
// expected-error @-1 {{'x2' consumed but not reinitialized before end of function}}
19481945
// expected-error @-2 {{Usage of a move only type that the move checker does not know how to check!}}
1949-
// expected-error @-3 {{Usage of a move only type that the move checker does not know how to check!}}
1950-
// expected-error @-4 {{'x2' consumed more than once}}
1946+
// expected-error @-3 {{'x2' consumed more than once}}
19511947
x2 = Klass()
19521948
let f = {
19531949
classConsume(x2)
@@ -1967,8 +1963,7 @@ public func closureAndDeferCaptureClassUseAfterConsume3() {
19671963
var x2 = Klass()
19681964
// expected-error @-1 {{'x2' consumed but not reinitialized before end of function}}
19691965
// expected-error @-2 {{Usage of a move only type that the move checker does not know how to check!}}
1970-
// expected-error @-3 {{Usage of a move only type that the move checker does not know how to check!}}
1971-
// expected-error @-4 {{'x2' consumed more than once}}
1966+
// expected-error @-3 {{'x2' consumed more than once}}
19721967
x2 = Klass()
19731968
let f = {
19741969
classConsume(x2)
@@ -2008,7 +2003,6 @@ public func closureAndDeferCaptureClassArgUseAfterConsume(_ x2: inout Klass) {
20082003
public func closureAndClosureCaptureClassUseAfterConsume() {
20092004
var x2 = Klass()
20102005
// expected-error @-1 {{Usage of a move only type that the move checker does not know how to check!}}
2011-
// expected-error @-2 {{Usage of a move only type that the move checker does not know how to check!}}
20122006
x2 = Klass()
20132007
let f = {
20142008
let g = {
@@ -2024,7 +2018,6 @@ public func closureAndClosureCaptureClassUseAfterConsume() {
20242018
public func closureAndClosureCaptureClassUseAfterConsume2() {
20252019
var x2 = Klass()
20262020
// expected-error @-1 {{Usage of a move only type that the move checker does not know how to check!}}
2027-
// expected-error @-2 {{Usage of a move only type that the move checker does not know how to check!}}
20282021
x2 = Klass()
20292022
let f = {
20302023
let g = {

0 commit comments

Comments
 (0)