Skip to content

Commit 0734267

Browse files
committed
ManualOwnership: fix simple var assign
Was mistakenly counting a 'store' as a copying instruction, when it's only a consuming one. SILGen was not handling lvalues that are addresses for loadable types correctly, when emitting a CopyExpr in ManualOwnership.
1 parent 75bc2b5 commit 0734267

File tree

4 files changed

+63
-10
lines changed

4 files changed

+63
-10
lines changed

lib/SILGen/SILGenExpr.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7283,10 +7283,17 @@ RValue RValueEmitter::visitCopyExpr(CopyExpr *E, SGFContext C) {
72837283
// If we're relying on ManualOwnership for explicit-copies enforcement,
72847284
// avoid doing address-based emission for loadable types.
72857285
if (subType.isLoadableOrOpaque(SGF.F) && SGF.B.hasManualOwnershipAttr()) {
7286-
// Interpret this 'load' as a borrow + copy instead.
7286+
// Do a read on the lvalue. If we get back an address, do a load before
7287+
// emitting the explicit copy.
72877288
LValue lv =
72887289
SGF.emitLValue(li->getSubExpr(), SGFAccessKind::BorrowedObjectRead);
7289-
auto value = SGF.emitBorrowedLValue(li, std::move(lv));
7290+
auto value = SGF.emitRawProjectedLValue(E, std::move(lv));
7291+
if (value.getType().isAddress()) {
7292+
// We don't have 'load [explicit_copy]' so do this instead:
7293+
// %x = load [copy] %value
7294+
// %y = explicit_copy_value %x
7295+
value = SGF.emitManagedLoadCopy(E, value.getUnmanagedValue());
7296+
}
72907297
ManagedValue copy = SGF.B.createExplicitCopyValue(E, value);
72917298
return RValue(SGF, {copy}, subType.getASTType());
72927299
}

lib/SILOptimizer/Mandatory/PerformanceDiagnostics.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,7 @@ bool PerformanceDiagnostics::visitInst(SILInstruction *inst,
383383
case SILInstructionKind::PartialApplyInst:
384384
case SILInstructionKind::DestroyAddrInst:
385385
case SILInstructionKind::DestroyValueInst:
386+
case SILInstructionKind::StoreInst:
386387
break; // These modify reference counts, but aren't copies.
387388
case SILInstructionKind::ExplicitCopyAddrInst:
388389
case SILInstructionKind::ExplicitCopyValueInst:
@@ -441,7 +442,11 @@ bool PerformanceDiagnostics::visitInst(SILInstruction *inst,
441442

442443
// There's no hope of borrowing access if there's a consuming use.
443444
for (auto op : svi->getUses()) {
444-
if (op->getOperandOwnership() == OperandOwnership::ForwardingConsume) {
445+
auto useKind = op->getOperandOwnership();
446+
447+
// Only some DestroyingConsume's, like 'store', are interesting.
448+
if (useKind == OperandOwnership::ForwardingConsume
449+
|| isa<StoreInst>(op->getUser())) {
445450
LLVM_DEBUG(llvm::dbgs() << "demanded by "<< *(op->getUser()));
446451
diagnose(loc, diag::manualownership_copy_demanded, *name);
447452
return false;

test/SIL/manual_ownership.swift

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ func return_borrowed_fixed(_ t: borrowing Triangle) -> Triangle {
7474

7575
// FIXME: copy propagation isn't able to simplify this. No copy should be required.
7676
@_manualOwnership
77-
func return_consumingParam(_ t: consuming Triangle) -> Triangle { // expected-error {{accessing 't' produces a copy of it}}
77+
func return_consumingParam(_ t: consuming Triangle) -> Triangle { // expected-error {{ownership of 't' is demanded and cannot not be consumed}}
7878
return t
7979
}
8080

@@ -156,13 +156,32 @@ func basic_function_call(_ t1: Triangle) {
156156

157157
/// MARK: control-flow
158158

159+
@_manualOwnership
160+
func check_vars(_ t: Triangle, _ b: Bool) -> Triangle {
161+
var x = Triangle()
162+
if b { x = t } // expected-error {{ownership of 't' is demanded and cannot not be consumed}}
163+
return x // expected-error {{ownership of 'x' is demanded and cannot not be consumed}}
164+
}
165+
@_manualOwnership
166+
func check_vars_fixed(_ t: Triangle, _ b: Bool) -> Triangle {
167+
var x = Triangle()
168+
if b { x = copy t }
169+
return copy x
170+
}
159171

160-
// FIXME: var assignments are somtimes impossible to satisfy with 'copy'
172+
// FIXME: var's still have some issues.
173+
// (1) MandatoryRedundantLoadElimination introduces a 'copy_value' in place of a 'load [copy]'
161174

175+
// @_manualOwnership
176+
// func reassignments_0() -> Triangle {
177+
// var t3 = Triangle()
178+
// t3 = Triangle()
179+
// return t3
180+
// }
162181
// @_manualOwnership
163182
// func reassignments_1() {
164183
// var t3 = Triangle()
165-
// t3 = copy Triangle() // FIXME: should not be needed
184+
// t3 = Triangle()
166185
// t3.borrowing()
167186
// }
168187
// @_manualOwnership

test/SILGen/manual_ownership.swift

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend %s -emit-silgen -verify \
1+
// RUN: %target-swift-frontend %s -emit-silgen -verify -sil-verify-all \
22
// RUN: -enable-experimental-feature ManualOwnership -o %t.silgen
33

44
// RUN: %FileCheck %s --input-file %t.silgen
@@ -15,9 +15,7 @@ class TriangleClass {
1515
// CHECK-NEXT: debug_value %0
1616
// CHECK-NEXT: [[M:%.*]] = class_method %0, #TriangleClass.shape!getter
1717
// CHECK-NEXT: [[SHAPE:%.*]] = apply [[M]](%0)
18-
// CHECK-NEXT: [[B:%.*]] = begin_borrow [[SHAPE]]
19-
// CHECK-NEXT: [[COPY:%.*]] = explicit_copy_value [[B]]
20-
// CHECK-NEXT: end_borrow [[B]]
18+
// CHECK-NEXT: [[COPY:%.*]] = explicit_copy_value [[SHAPE]]
2119
// CHECK-NEXT: destroy_value [[SHAPE]]
2220
// CHECK-NEXT: return [[COPY]]
2321
// CHECK-NEXT: } // end sil function 'basic_access_of_loadable'
@@ -27,6 +25,30 @@ func basic_access_of_loadable(_ t: TriangleClass) -> ShapeClass {
2725
return copy t.shape
2826
}
2927

28+
// CHECK-LABEL: sil {{.*}} @var_assign
29+
// CHECK: alloc_box ${ var TriangleClass }, var, name "x"
30+
// CHECK-NEXT: begin_borrow [lexical] [var_decl]
31+
// CHECK-NEXT: [[VAR:%.*]] = project_box {{.*}}, 0
32+
// CHECK: bb1:
33+
// CHECK-NEXT: [[T_COPY:%.*]] = explicit_copy_value %0
34+
// CHECK-NEXT: [[ADDR1:%.*]] = begin_access [modify] [unknown] [[VAR]]
35+
// CHECK-NEXT: assign [[T_COPY]] to [[ADDR1]]
36+
// CHECK-NEXT: end_access [[ADDR1]]
37+
// CHECK: bb3:
38+
// CHECK-NEXT: [[ADDR2:%.*]] = begin_access [read] [unknown] [[VAR]]
39+
// CHECK-NEXT: [[LOAD:%.*]] = load [copy] [[ADDR2]]
40+
// CHECK-NEXT: [[X_COPY:%.*]] = explicit_copy_value [[LOAD]]
41+
// CHECK-NEXT: end_access [[ADDR2]]
42+
// CHECK: return [[X_COPY]]
43+
// CHECK-NEXT: } // end sil function 'var_assign'
44+
@_manualOwnership
45+
@_silgen_name("var_assign")
46+
func var_assign(_ t: TriangleClass, _ b: Bool) -> TriangleClass {
47+
var x = TriangleClass()
48+
if b { x = copy t }
49+
return copy x
50+
}
51+
3052
// CHECK-LABEL: sil {{.*}} [manual_ownership] [ossa] @return_borrowed
3153
// CHECK: bb0(%0 : @guaranteed $TriangleClass):
3254
// CHECK-NEXT: debug_value %0

0 commit comments

Comments
 (0)