Skip to content

Commit 885eb21

Browse files
committed
[noimplicitcopy] Changes to borrow+gep -> destructure transform to support noimplicitcopy.
1 parent c3c61b4 commit 885eb21

File tree

7 files changed

+375
-57
lines changed

7 files changed

+375
-57
lines changed

lib/SIL/Utils/FieldSensitivePrunedLiveness.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,8 @@ SubElementOffset::computeForValue(SILValue projectionDerivedFromRoot,
188188

189189
// Look through these single operand instructions.
190190
if (isa<BeginBorrowInst>(projectionDerivedFromRoot) ||
191-
isa<CopyValueInst>(projectionDerivedFromRoot)) {
191+
isa<CopyValueInst>(projectionDerivedFromRoot) ||
192+
isa<MoveOnlyWrapperToCopyableValueInst>(projectionDerivedFromRoot)) {
192193
projectionDerivedFromRoot =
193194
cast<SingleValueInstruction>(projectionDerivedFromRoot)
194195
->getOperand(0);

lib/SILOptimizer/Mandatory/MoveOnlyDiagnostics.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,8 @@ void DiagnosticEmitter::emitObjectDestructureNeededWithinBorrowBoundary(
438438
markedValue->getDefiningInstruction()->getLoc().getSourceLoc(),
439439
diag::sil_moveonlychecker_moveonly_field_consumed, varName);
440440
diagnose(astContext, destructureNeedingUse->getLoc().getSourceLoc(),
441-
diag::sil_moveonlychecker_moveonly_field_consumed_here);
441+
diag::sil_moveonlychecker_consuming_use_here);
442+
442443
// Only emit errors for last users that overlap with our needed destructure
443444
// bits.
444445
for (auto pair : boundary.getLastUsers()) {

lib/SILOptimizer/Mandatory/MoveOnlyObjectChecker.cpp

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -278,18 +278,21 @@ bool swift::siloptimizer::cleanupSILAfterEmittingObjectMoveOnlyDiagnostics(
278278
bool localChanged = false;
279279
for (auto &block : *fn) {
280280
for (auto ii = block.begin(), ie = block.end(); ii != ie;) {
281-
auto *cvi = dyn_cast<CopyValueInst>(&*ii);
282-
++ii;
283-
284-
if (!cvi || !cvi->getOperand()->getType().isMoveOnly())
285-
continue;
281+
if (auto *cvi = dyn_cast<CopyValueInst>(&*ii)) {
282+
++ii;
283+
284+
if (!cvi || !cvi->getOperand()->getType().isMoveOnly())
285+
continue;
286+
287+
SILBuilderWithScope b(cvi);
288+
auto *expCopy =
289+
b.createExplicitCopyValue(cvi->getLoc(), cvi->getOperand());
290+
cvi->replaceAllUsesWith(expCopy);
291+
cvi->eraseFromParent();
292+
localChanged = true;
293+
}
286294

287-
SILBuilderWithScope b(cvi);
288-
auto *expCopy =
289-
b.createExplicitCopyValue(cvi->getLoc(), cvi->getOperand());
290-
cvi->replaceAllUsesWith(expCopy);
291-
cvi->eraseFromParent();
292-
localChanged = true;
295+
++ii;
293296
}
294297
}
295298
return localChanged;
@@ -454,7 +457,7 @@ void MoveOnlyChecker::check(NonLocalAccessBlockAnalysis *accessBlockAnalysis,
454457
"understand part of the SIL\n");
455458
diagnosticEmitter.emitCheckerDoesntUnderstandDiagnostic(markedValue);
456459
cleanupAfterEmittingDiagnostic();
457-
return;
460+
continue;
458461
}
459462

460463
// If we emitted any non-exceptional diagnostics in

lib/SILOptimizer/Mandatory/MoveOnlyUtils.cpp

Lines changed: 60 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,20 +1007,51 @@ void BorrowToDestructureTransform::rewriteUses() {
10071007
<< " of inst: " << *operand.getUser()
10081008
<< " Type Span: " << span << '\n'
10091009
<< " AvailableValue: " << *first);
1010+
10101011
// Then see if first at a type level is equal to our operand's value
10111012
// type. If so, we can just reuse it.
1012-
if (first->getType() == operand.get()->getType()) {
1013+
if (first->getType().removingMoveOnlyWrapper() ==
1014+
operand.get()->getType().removingMoveOnlyWrapper()) {
10131015
LLVM_DEBUG(llvm::dbgs() << " Found a value that completely covers "
10141016
"the operand!\n Value: "
10151017
<< *first);
1016-
if (operand.isConsuming()) {
1018+
// If we have:
1019+
//
1020+
// 1. A consuming use.
1021+
// 2. A value that is /not/ move only wrapped and an operand that is
1022+
// non-consuming but can accept an owned value.
1023+
//
1024+
// Just use the owned value. In the case of 2, we need to use a borrow
1025+
// so we can insert the moveonlywrapper_to_copyable [guaranteed] for
1026+
// the use.
1027+
if (operand.isConsuming() ||
1028+
(operand.canAcceptKind(OwnershipKind::Owned) &&
1029+
(first->getType().isMoveOnlyWrapped() ==
1030+
operand.get()->getType().isMoveOnlyWrapped()))) {
1031+
// If we get to this point and have a move only wrapped type and our
1032+
// operand is not a move only wrapped type, then we need to insert
1033+
// an owned moveonlywrapper_to_copyable. We know it must be owned
1034+
// since we can only reach this point if we are consuming.
1035+
if (first->getType().isMoveOnlyWrapped() &&
1036+
!operand.get()->getType().isMoveOnlyWrapped()) {
1037+
SILBuilderWithScope builder(inst);
1038+
first = builder.createOwnedMoveOnlyWrapperToCopyableValue(
1039+
getSafeLoc(inst), first);
1040+
}
10171041
operand.set(first);
10181042
continue;
10191043
}
10201044

1045+
// Otherwise, we need to insert a borrow.
10211046
SILBuilderWithScope borrowBuilder(inst);
1022-
auto *borrow =
1047+
SILValue borrow =
10231048
borrowBuilder.createBeginBorrow(getSafeLoc(inst), first);
1049+
SILValue innerValue = borrow;
1050+
if (innerValue->getType().isMoveOnlyWrapped()) {
1051+
innerValue =
1052+
borrowBuilder.createGuaranteedMoveOnlyWrapperToCopyableValue(
1053+
getSafeLoc(inst), innerValue);
1054+
}
10241055

10251056
if (auto op = InteriorPointerOperand::get(&operand)) {
10261057
op.visitBaseValueScopeEndingUses([&](Operand *endScope) -> bool {
@@ -1035,7 +1066,10 @@ void BorrowToDestructureTransform::rewriteUses() {
10351066
endBuilder.createEndBorrow(getSafeLoc(nextInst), borrow);
10361067
}
10371068

1038-
operand.set(borrow);
1069+
// NOTE: This needs to be /after/the interior pointer operand usage
1070+
// above so that we can use the end scope of our interior pointer base
1071+
// value.
1072+
operand.set(innerValue);
10391073
continue;
10401074
}
10411075

@@ -1075,14 +1109,24 @@ void BorrowToDestructureTransform::rewriteUses() {
10751109
// First walk until we find the same size use as our element and our
10761110
// type that also equals our type. The second part of the check allows
10771111
// us to skip through single level types.
1078-
while (operand.get()->getType() != value->getType()) {
1112+
SILType operandUnwrappedType =
1113+
operand.get()->getType().removingMoveOnlyWrapper();
1114+
while (operandUnwrappedType !=
1115+
value->getType().removingMoveOnlyWrapper()) {
10791116
std::tie(firstValueOffsetSize, value) =
10801117
*useOffsetSize.walkOneLevelTowardsChild(
10811118
borrowBuilder, loc, firstValueOffsetSize, value);
10821119
}
10831120

10841121
// At this point, we know we have a type of the same size and the same
1085-
// type.
1122+
// type (modulo moveonlywrapped). If we need to wrap our gepped value,
1123+
// do so now and then set operand to take this new value.
1124+
if (!operand.get()->getType().isMoveOnlyWrapped() &&
1125+
value->getType().isMoveOnlyWrapped()) {
1126+
value =
1127+
borrowBuilder.createGuaranteedMoveOnlyWrapperToCopyableValue(
1128+
loc, value);
1129+
}
10861130
operand.set(value);
10871131

10881132
// If we have a terminator that is a trivial use (e.x.: we
@@ -1114,13 +1158,13 @@ void BorrowToDestructureTransform::rewriteUses() {
11141158
SILType iterType = iterValue->getType();
11151159
SWIFT_DEFER { typeSpanToValue.clear(); };
11161160

1117-
while (operand.get()->getType() != iterType) {
1118-
// First erase our input type.
1119-
auto parentOffsetSize = iterOffsetSize;
1120-
1161+
SILType unwrappedOperandType =
1162+
operand.get()->getType().removingMoveOnlyWrapper();
1163+
while (unwrappedOperandType != iterType.removingMoveOnlyWrapper()) {
11211164
// NOTE: We purposely do not erase our parent offset from the
11221165
// typeSpanToValue. We never insert any element along our walk path
11231166
// (including the initial value) into the interval map.
1167+
auto parentOffsetSize = iterOffsetSize;
11241168

11251169
// Then walk one level towards our target type.
11261170
std::tie(iterOffsetSize, iterType) =
@@ -1145,7 +1189,12 @@ void BorrowToDestructureTransform::rewriteUses() {
11451189
}
11461190

11471191
// Now that we have finished destructuring, set operand to our iter
1148-
// value.
1192+
// value... unwrapping iterValue if we need to do so.
1193+
if (iterValue->getType().isMoveOnlyWrapped() &&
1194+
!operand.get()->getType().isMoveOnlyWrapped()) {
1195+
iterValue = consumeBuilder.createOwnedMoveOnlyWrapperToCopyableValue(
1196+
loc, iterValue);
1197+
}
11491198
operand.set(iterValue);
11501199

11511200
// Then go through our available values and use the interval map to

test/SILOptimizer/noimplicitcopy.swift

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -866,24 +866,26 @@ public func aggStructAccessFieldOwnedArg(@_noImplicitCopy _ x2: __owned AggStruc
866866

867867
public func aggStructConsumeField(_ x: AggStruct) {
868868
@_noImplicitCopy let x2 = x
869+
// expected-error @-1 {{'x2' has a move only field that was consumed before later uses}}
869870
classConsume(x2.lhs)
870871
for _ in 0..<1024 {
871-
classConsume(x2.lhs)
872+
classConsume(x2.lhs) // expected-note {{consuming use}}
872873
}
873874
}
874875

875-
// TODO: We should error here!
876876
public func aggStructConsumeFieldArg(@_noImplicitCopy _ x2: AggStruct) {
877+
// expected-error @-1 {{'x2' has a move only field that was consumed before later uses}}
877878
classConsume(x2.lhs)
878879
for _ in 0..<1024 {
879-
classConsume(x2.lhs)
880+
classConsume(x2.lhs) // expected-note {{consuming use}}
880881
}
881882
}
882883

883884
public func aggStructConsumeFieldOwnedArg(@_noImplicitCopy _ x2: __owned AggStruct) {
885+
// expected-error @-1 {{'x2' has a move only field that was consumed before later uses}}
884886
classConsume(x2.lhs)
885887
for _ in 0..<1024 {
886-
classConsume(x2.lhs)
888+
classConsume(x2.lhs) // expected-note {{consuming use}}
887889
}
888890
}
889891

@@ -911,24 +913,26 @@ public func aggStructAccessGrandFieldOwnedArg(@_noImplicitCopy _ x2: __owned Agg
911913

912914
public func aggStructConsumeGrandField(_ x: AggStruct) {
913915
@_noImplicitCopy let x2 = x
916+
// expected-error @-1 {{'x2' has a move only field that was consumed before later uses}}
914917
classConsume(x2.pair.lhs)
915918
for _ in 0..<1024 {
916-
classConsume(x2.pair.lhs)
919+
classConsume(x2.pair.lhs) // expected-note {{consuming use}}
917920
}
918921
}
919922

920-
// TODO: This needs to error.
921923
public func aggStructConsumeGrandFieldArg(@_noImplicitCopy _ x2: AggStruct) {
924+
// expected-error @-1 {{'x2' has a move only field that was consumed before later uses}}
922925
classConsume(x2.pair.lhs)
923926
for _ in 0..<1024 {
924-
classConsume(x2.pair.lhs)
927+
classConsume(x2.pair.lhs) // expected-note {{consuming use}}
925928
}
926929
}
927930

928931
public func aggStructConsumeGrandFieldOwnedArg(@_noImplicitCopy _ x2: __owned AggStruct) {
932+
// expected-error @-1 {{'x2' has a move only field that was consumed before later uses}}
929933
classConsume(x2.pair.lhs)
930934
for _ in 0..<1024 {
931-
classConsume(x2.pair.lhs)
935+
classConsume(x2.pair.lhs) // expected-note {{consuming use}}
932936
}
933937
}
934938

@@ -1132,23 +1136,26 @@ public func aggGenericStructAccessFieldOwnedArg(@_noImplicitCopy _ x2: __owned A
11321136

11331137
public func aggGenericStructConsumeField(_ x: AggGenericStruct<Klass>) {
11341138
@_noImplicitCopy let x2 = x
1139+
// expected-error @-1 {{'x2' has a move only field that was consumed before later uses}}
11351140
classConsume(x2.lhs)
11361141
for _ in 0..<1024 {
1137-
classConsume(x2.lhs)
1142+
classConsume(x2.lhs) // expected-note {{consuming use}}
11381143
}
11391144
}
11401145

11411146
public func aggGenericStructConsumeFieldArg(@_noImplicitCopy _ x2: AggGenericStruct<Klass>) {
1147+
// expected-error @-1 {{'x2' has a move only field that was consumed before later uses}}
11421148
classConsume(x2.lhs)
11431149
for _ in 0..<1024 {
1144-
classConsume(x2.lhs)
1150+
classConsume(x2.lhs) // expected-note {{consuming use}}
11451151
}
11461152
}
11471153

11481154
public func aggGenericStructConsumeFieldOwnedArg(@_noImplicitCopy _ x2: __owned AggGenericStruct<Klass>) {
1155+
// expected-error @-1 {{'x2' has a move only field that was consumed before later uses}}
11491156
classConsume(x2.lhs)
11501157
for _ in 0..<1024 {
1151-
classConsume(x2.lhs)
1158+
classConsume(x2.lhs) // expected-note {{consuming use}}
11521159
}
11531160
}
11541161

@@ -1176,23 +1183,26 @@ public func aggGenericStructAccessGrandFieldOwnedArg(@_noImplicitCopy _ x2: __ow
11761183

11771184
public func aggGenericStructConsumeGrandField(_ x: AggGenericStruct<Klass>) {
11781185
@_noImplicitCopy let x2 = x
1186+
// expected-error @-1 {{'x2' has a move only field that was consumed before later uses}}
11791187
classConsume(x2.pair.lhs)
11801188
for _ in 0..<1024 {
1181-
classConsume(x2.pair.lhs)
1189+
classConsume(x2.pair.lhs) // expected-note {{consuming use}}
11821190
}
11831191
}
11841192

11851193
public func aggGenericStructConsumeGrandFieldArg(@_noImplicitCopy _ x2: AggGenericStruct<Klass>) {
1194+
// expected-error @-1 {{'x2' has a move only field that was consumed before later uses}}
11861195
classConsume(x2.pair.lhs)
11871196
for _ in 0..<1024 {
1188-
classConsume(x2.pair.lhs)
1197+
classConsume(x2.pair.lhs) // expected-note {{consuming use}}
11891198
}
11901199
}
11911200

11921201
public func aggGenericStructConsumeGrandFieldOwnedArg(@_noImplicitCopy _ x2: __owned AggGenericStruct<Klass>) {
1202+
// expected-error @-1 {{'x2' has a move only field that was consumed before later uses}}
11931203
classConsume(x2.pair.lhs)
11941204
for _ in 0..<1024 {
1195-
classConsume(x2.pair.lhs)
1205+
classConsume(x2.pair.lhs) // expected-note {{consuming use}}
11961206
}
11971207
}
11981208

@@ -1390,23 +1400,26 @@ public func aggGenericStructAccessFieldOwnedArg<T>(@_noImplicitCopy _ x2: __owne
13901400

13911401
public func aggGenericStructConsumeField<T>(_ x: AggGenericStruct<T>) {
13921402
@_noImplicitCopy let x2 = x
1403+
// expected-error @-1 {{'x2' has a move only field that was consumed before later uses}}
13931404
classConsume(x2.lhs)
13941405
for _ in 0..<1024 {
1395-
classConsume(x2.lhs)
1406+
classConsume(x2.lhs) // expected-note {{consuming use}}
13961407
}
13971408
}
13981409

13991410
public func aggGenericStructConsumeFieldArg<T>(@_noImplicitCopy _ x2: AggGenericStruct<T>) {
1411+
// expected-error @-1 {{'x2' has a move only field that was consumed before later uses}}
14001412
classConsume(x2.lhs)
14011413
for _ in 0..<1024 {
1402-
classConsume(x2.lhs)
1414+
classConsume(x2.lhs) // expected-note {{consuming use}}
14031415
}
14041416
}
14051417

14061418
public func aggGenericStructConsumeFieldOwnedArg<T>(@_noImplicitCopy _ x2: __owned AggGenericStruct<T>) {
1419+
// expected-error @-1 {{'x2' has a move only field that was consumed before later uses}}
14071420
classConsume(x2.lhs)
14081421
for _ in 0..<1024 {
1409-
classConsume(x2.lhs)
1422+
classConsume(x2.lhs) // expected-note {{consuming use}}
14101423
}
14111424
}
14121425

@@ -1434,23 +1447,26 @@ public func aggGenericStructAccessGrandFieldOwnedArg<T>(@_noImplicitCopy _ x2: _
14341447

14351448
public func aggGenericStructConsumeGrandField<T>(_ x: AggGenericStruct<T>) {
14361449
@_noImplicitCopy let x2 = x
1450+
// expected-error @-1 {{'x2' has a move only field that was consumed before later uses}}
14371451
classConsume(x2.pair.lhs)
14381452
for _ in 0..<1024 {
1439-
classConsume(x2.pair.lhs)
1453+
classConsume(x2.pair.lhs) // expected-note {{consuming use}}
14401454
}
14411455
}
14421456

14431457
public func aggGenericStructConsumeGrandFieldArg<T>(@_noImplicitCopy _ x2: AggGenericStruct<T>) {
1458+
// expected-error @-1 {{'x2' has a move only field that was consumed before later uses}}
14441459
classConsume(x2.pair.lhs)
14451460
for _ in 0..<1024 {
1446-
classConsume(x2.pair.lhs)
1461+
classConsume(x2.pair.lhs) // expected-note {{consuming use}}
14471462
}
14481463
}
14491464

14501465
public func aggGenericStructConsumeGrandFieldOwnedArg<T>(@_noImplicitCopy _ x2: __owned AggGenericStruct<T>) {
1466+
// expected-error @-1 {{'x2' has a move only field that was consumed before later uses}}
14511467
classConsume(x2.pair.lhs)
14521468
for _ in 0..<1024 {
1453-
classConsume(x2.pair.lhs)
1469+
classConsume(x2.pair.lhs) // expected-note {{consuming use}}
14541470
}
14551471
}
14561472

0 commit comments

Comments
 (0)