Skip to content

Commit e1f2a20

Browse files
authored
Merge pull request #65604 from gottesmm/address-only-stuff
[move-only] Address Only Patches
2 parents 73e749d + d25cd0b commit e1f2a20

File tree

10 files changed

+1776
-211
lines changed

10 files changed

+1776
-211
lines changed

include/swift/SIL/SILUndef.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ class SILUndef : public ValueBase {
3030
void operator delete(void *, size_t) = delete;
3131

3232
static SILUndef *get(SILType ty, SILModule &m);
33+
34+
/// Return a SILUndef with the same type as the passed in value.
35+
static SILUndef *get(SILValue value) {
36+
return SILUndef::get(value->getType(), *value->getModule());
37+
}
38+
3339
static SILUndef *get(SILType ty, const SILFunction &f);
3440

3541
template <class OwnerTy>

lib/SILGen/SILGenLValue.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3183,7 +3183,8 @@ RValue SILGenFunction::emitRValueForNonMemberVarDecl(SILLocation loc,
31833183
SILValue accessAddr = UnenforcedFormalAccess::enter(*this, loc, destAddr,
31843184
SILAccessKind::Read);
31853185

3186-
if (accessAddr->getType().isMoveOnly()) {
3186+
if (accessAddr->getType().isMoveOnly() &&
3187+
!isa<MarkMustCheckInst>(accessAddr)) {
31873188
// When loading an rvalue, we should never need to modify the place
31883189
// we're loading from.
31893190
accessAddr = B.createMarkMustCheckInst(

lib/SILGen/SILGenProlog.cpp

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -748,7 +748,6 @@ class ArgumentInitHelper {
748748
/// if not null.
749749
void makeArgumentIntoBinding(SILLocation loc, ParamDecl *pd) {
750750
ManagedValue argrv = makeArgument(loc, pd);
751-
752751
SILValue value = argrv.getValue();
753752
if (pd->isInOut()) {
754753
assert(argrv.getType().isAddress() && "expected inout to be address");
@@ -768,18 +767,52 @@ class ArgumentInitHelper {
768767
if (!argrv.getType().isAddress()) {
769768
// NOTE: We setup SGF.VarLocs[pd] in updateArgumentValueForBinding.
770769
updateArgumentValueForBinding(argrv, loc, pd, value, varinfo);
771-
} else {
772-
if (auto *allocStack = dyn_cast<AllocStackInst>(value)) {
773-
allocStack->setArgNo(ArgNo);
774-
if (SGF.getASTContext().SILOpts.supportsLexicalLifetimes(
775-
SGF.getModule()) &&
776-
SGF.F.getLifetime(pd, value->getType()).isLexical())
777-
allocStack->setIsLexical();
778-
} else {
779-
SGF.B.createDebugValueAddr(loc, value, varinfo);
780-
}
770+
return;
771+
}
772+
773+
if (auto *allocStack = dyn_cast<AllocStackInst>(value)) {
774+
allocStack->setArgNo(ArgNo);
775+
if (SGF.getASTContext().SILOpts.supportsLexicalLifetimes(
776+
SGF.getModule()) &&
777+
SGF.F.getLifetime(pd, value->getType()).isLexical())
778+
allocStack->setIsLexical();
781779
SGF.VarLocs[pd] = SILGenFunction::VarLoc::get(value);
780+
return;
781+
}
782+
783+
if (value->getType().isMoveOnly()) {
784+
switch (pd->getValueOwnership()) {
785+
case ValueOwnership::Default:
786+
if (pd->isSelfParameter()) {
787+
assert(!isa<MarkMustCheckInst>(value) &&
788+
"Should not have inserted mark must check inst in EmitBBArgs");
789+
if (!pd->isInOut()) {
790+
value = SGF.B.createMarkMustCheckInst(
791+
loc, value, MarkMustCheckInst::CheckKind::NoConsumeOrAssign);
792+
}
793+
} else {
794+
assert(isa<MarkMustCheckInst>(value) &&
795+
"Should have inserted mark must check inst in EmitBBArgs");
796+
}
797+
break;
798+
case ValueOwnership::InOut:
799+
assert(isa<MarkMustCheckInst>(value) &&
800+
"Expected mark must check inst with inout to be handled in "
801+
"emitBBArgs earlier");
802+
break;
803+
case ValueOwnership::Owned:
804+
value = SGF.B.createMarkMustCheckInst(
805+
loc, value, MarkMustCheckInst::CheckKind::ConsumableAndAssignable);
806+
break;
807+
case ValueOwnership::Shared:
808+
value = SGF.B.createMarkMustCheckInst(
809+
loc, value, MarkMustCheckInst::CheckKind::NoConsumeOrAssign);
810+
break;
811+
}
782812
}
813+
814+
SGF.B.createDebugValueAddr(loc, value, varinfo);
815+
SGF.VarLocs[pd] = SILGenFunction::VarLoc::get(value);
783816
}
784817

785818
void emitParam(ParamDecl *PD) {

lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1511,6 +1511,19 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
15111511
assert(op->getOperandNumber() == CopyAddrInst::Src &&
15121512
"Should have dest above in memInstMust{Rei,I}nitialize");
15131513

1514+
auto leafRange = TypeTreeLeafTypeRange::get(op->get(), getRootAddress());
1515+
if (!leafRange)
1516+
return false;
1517+
1518+
// If we have a non-move only type, just treat this as a liveness use.
1519+
if (!copyAddr->getSrc()->getType().isMoveOnly()) {
1520+
LLVM_DEBUG(llvm::dbgs()
1521+
<< "Found copy of copyable type. Treating as liveness use! "
1522+
<< *user);
1523+
useState.livenessUses.insert({user, *leafRange});
1524+
return true;
1525+
}
1526+
15141527
if (markedValue->getCheckKind() ==
15151528
MarkMustCheckInst::CheckKind::NoConsumeOrAssign) {
15161529
LLVM_DEBUG(llvm::dbgs()
@@ -1520,17 +1533,11 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
15201533
return true;
15211534
}
15221535

1523-
auto leafRange = TypeTreeLeafTypeRange::get(op->get(), getRootAddress());
1524-
if (!leafRange)
1525-
return false;
1526-
15271536
// TODO: Add borrow checking here like below.
15281537

15291538
// TODO: Add destructure deinit checking here once address only checking is
15301539
// completely brought up.
15311540

1532-
// TODO: Add check here that we don't error on trivial/copyable types.
1533-
15341541
if (copyAddr->isTakeOfSrc()) {
15351542
LLVM_DEBUG(llvm::dbgs() << "Found take: " << *user);
15361543
useState.takeInsts.insert({user, *leafRange});
@@ -1721,9 +1728,30 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
17211728
// Now that we have handled or loadTakeOrCopy, we need to now track our
17221729
// additional pure takes.
17231730
if (::memInstMustConsume(op)) {
1731+
// If we don't have a consumeable and assignable check kind, then we can't
1732+
// consume. Emit an error.
1733+
//
1734+
// NOTE: Since SILGen eagerly loads loadable types from memory, this
1735+
// generally will only handle address only types.
1736+
if (markedValue->getCheckKind() !=
1737+
MarkMustCheckInst::CheckKind::ConsumableAndAssignable) {
1738+
auto *fArg = dyn_cast<SILFunctionArgument>(
1739+
stripAccessMarkers(markedValue->getOperand()));
1740+
if (fArg && fArg->isClosureCapture() && fArg->getType().isAddress()) {
1741+
moveChecker.diagnosticEmitter.emitPromotedBoxArgumentError(markedValue,
1742+
fArg);
1743+
} else {
1744+
moveChecker.diagnosticEmitter
1745+
.emitAddressEscapingClosureCaptureLoadedAndConsumed(markedValue);
1746+
}
1747+
emittedEarlyDiagnostic = true;
1748+
return true;
1749+
}
1750+
17241751
auto leafRange = TypeTreeLeafTypeRange::get(op->get(), getRootAddress());
17251752
if (!leafRange)
17261753
return false;
1754+
17271755
LLVM_DEBUG(llvm::dbgs() << "Pure consuming use: " << *user);
17281756
useState.takeInsts.insert({user, *leafRange});
17291757
return true;
@@ -2423,7 +2451,6 @@ bool MoveOnlyAddressCheckerPImpl::performSingleCheck(
24232451
LLVM_DEBUG(llvm::dbgs() << "Failed access path visit: " << *markedAddress);
24242452
return false;
24252453
}
2426-
addressUseState.initializeInOutTermUsers();
24272454

24282455
// If we found a load [copy] or copy_addr that requires multiple copies or an
24292456
// exclusivity error, then we emitted an early error. Bail now and allow the
@@ -2438,9 +2465,14 @@ bool MoveOnlyAddressCheckerPImpl::performSingleCheck(
24382465
if (diagCount != diagnosticEmitter.getDiagnosticCount())
24392466
return true;
24402467

2441-
// Then check if we emitted an error. If we did not, return true.
2442-
if (diagCount != diagnosticEmitter.getDiagnosticCount())
2443-
return true;
2468+
// Now that we know that we have run our visitor and did not emit any errors
2469+
// and successfully visited everything, see if have any
2470+
// assignable_but_not_consumable of address only types that are consumed.
2471+
//
2472+
// DISCUSSION: For non address only types, this is not an issue since we
2473+
// eagerly load
2474+
2475+
addressUseState.initializeInOutTermUsers();
24442476

24452477
//===---
24462478
// Liveness Checking

test/Interpreter/moveonly.swift

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ Tests.test("global destroyed once") {
4545
do {
4646
global = FD()
4747
}
48-
expectEqual(0, LifetimeTracked.instances)
48+
expectEqual(0, LifetimeTracked.instances)
4949
}
5050

5151
@_moveOnly
@@ -104,3 +104,31 @@ Tests.test("empty struct") {
104104
let _ = consume e
105105
}
106106
}
107+
108+
protocol P {
109+
var name: String { get }
110+
}
111+
112+
Tests.test("AddressOnly") {
113+
class Klass : P {
114+
var name: String { "myName" }
115+
}
116+
117+
@_moveOnly
118+
struct S<T : P> {
119+
var t: T
120+
}
121+
122+
let e = S(t: Klass())
123+
expectEqual(e.t.name, "myName")
124+
125+
func testGeneric<T : P>(_ x: borrowing S<T>) {
126+
expectEqual(x.t.name, "myName")
127+
}
128+
testGeneric(e)
129+
130+
if e.t.name.count == 5 {
131+
let _ = consume e
132+
}
133+
}
134+

test/SILGen/moveonly.swift

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,18 @@ public enum NonTrivialEnum {
4444
case third(NonTrivialStruct)
4545
}
4646

47+
@_moveOnly
48+
public struct AddressOnlyGeneric<T> {
49+
var t: T
50+
}
51+
52+
public protocol P {}
53+
54+
@_moveOnly
55+
public struct AddressOnlyProtocol {
56+
var t: P
57+
}
58+
4759
var varGlobal = NonTrivialStruct()
4860
let letGlobal = NonTrivialStruct()
4961

@@ -54,6 +66,8 @@ public func borrowVal(_ k: borrowing NonTrivialCopyableStruct) {}
5466
public func borrowVal(_ k: borrowing NonTrivialCopyableStruct2) {}
5567
public func borrowVal(_ s: borrowing NonTrivialStruct) {}
5668
public func borrowVal(_ s: borrowing NonTrivialStruct2) {}
69+
public func borrowVal<T>(_ s: borrowing AddressOnlyGeneric<T>) {}
70+
public func borrowVal(_ s: borrowing AddressOnlyProtocol) {}
5771

5872
public func consumeVal(_ e : __owned NonTrivialEnum) {}
5973
public func consumeVal(_ e : __owned FD) {}
@@ -62,6 +76,8 @@ public func consumeVal(_ k: __owned NonTrivialCopyableStruct) {}
6276
public func consumeVal(_ k: __owned NonTrivialCopyableStruct2) {}
6377
public func consumeVal(_ s: __owned NonTrivialStruct) {}
6478
public func consumeVal(_ s: __owned NonTrivialStruct2) {}
79+
public func consumeVal<T>(_ s: __owned AddressOnlyGeneric<T>) {}
80+
public func consumeVal(_ s: __owned AddressOnlyProtocol) {}
6581

6682
var bool: Bool { false }
6783

@@ -137,6 +153,58 @@ public func useNonTrivialOwnedEnum(_ s: __owned NonTrivialEnum) {
137153
let _ = s2
138154
}
139155

156+
// CHECK-LABEL: sil [ossa] @$s8moveonly21useAddressOnlyGenericyyAA0cdE0VyxGhlF : $@convention(thin) <T> (@in_guaranteed AddressOnlyGeneric<T>) -> () {
157+
// CHECK: bb0([[ARG:%.*]] :
158+
// CHECK: mark_must_check [no_consume_or_assign] [[ARG]]
159+
// CHECK: } // end sil function '$s8moveonly21useAddressOnlyGenericyyAA0cdE0VyxGhlF'
160+
public func useAddressOnlyGeneric<T>(_ s: __shared AddressOnlyGeneric<T>) {
161+
borrowVal(s)
162+
let s2 = s
163+
let k = s.t
164+
let _ = k
165+
borrowVal(s)
166+
let _ = s2
167+
}
168+
169+
// CHECK-LABEL: sil [ossa] @$s8moveonly26useOwnedAddressOnlyGenericyyAA0deF0VyxGnlF : $@convention(thin) <T> (@in AddressOnlyGeneric<T>) -> () {
170+
// CHECK: bb0([[ARG:%.*]] :
171+
// CHECK: mark_must_check [consumable_and_assignable] [[ARG]]
172+
// CHECK: } // end sil function '$s8moveonly26useOwnedAddressOnlyGenericyyAA0deF0VyxGnlF'
173+
public func useOwnedAddressOnlyGeneric<T>(_ s: __owned AddressOnlyGeneric<T>) {
174+
borrowVal(s)
175+
let s2 = s
176+
let k = s.t
177+
let _ = k
178+
borrowVal(s)
179+
let _ = s2
180+
}
181+
182+
// CHECK-LABEL: sil [ossa] @$s8moveonly22useAddressOnlyProtocolyyAA0cdE0VhF : $@convention(thin) (@in_guaranteed AddressOnlyProtocol) -> () {
183+
// CHECK: bb0([[ARG:%.*]] :
184+
// CHECK: mark_must_check [no_consume_or_assign] [[ARG]]
185+
// CHECK: } // end sil function '$s8moveonly22useAddressOnlyProtocolyyAA0cdE0VhF'
186+
public func useAddressOnlyProtocol(_ s: __shared AddressOnlyProtocol) {
187+
borrowVal(s)
188+
let s2 = s
189+
let k = s.t
190+
let _ = k
191+
borrowVal(s)
192+
let _ = s2
193+
}
194+
195+
// CHECK-LABEL: sil [ossa] @$s8moveonly27useOwnedAddressOnlyProtocolyyAA0deF0VnF : $@convention(thin) (@in AddressOnlyProtocol) -> () {
196+
// CHECK: bb0([[ARG:%.*]] :
197+
// CHECK: mark_must_check [consumable_and_assignable] [[ARG]]
198+
// CHECK: } // end sil function '$s8moveonly27useOwnedAddressOnlyProtocolyyAA0deF0VnF'
199+
public func useOwnedAddressOnlyProtocol(_ s: __owned AddressOnlyProtocol) {
200+
borrowVal(s)
201+
let s2 = s
202+
let k = s.t
203+
let _ = k
204+
borrowVal(s)
205+
let _ = s2
206+
}
207+
140208
//===---
141209
// Self in Init
142210
//
@@ -169,6 +237,73 @@ extension NonTrivialEnum {
169237
}
170238
}
171239

240+
extension AddressOnlyGeneric {
241+
// CHECK-LABEL: sil hidden [ossa] @$s8moveonly18AddressOnlyGenericV13testNoUseSelfyyF : $@convention(method) <T> (@in_guaranteed AddressOnlyGeneric<T>) -> () {
242+
// CHECK: bb0([[ARG_IN:%.*]] :
243+
// CHECK: [[ARG:%.*]] = mark_must_check [no_consume_or_assign] [[ARG_IN]] :
244+
//
245+
// CHECK: [[ALLOC_X:%.*]] = alloc_box $<τ_0_0> { let AddressOnlyGeneric<τ_0_0> } <T>, let, name "x"
246+
// CHECK: [[X:%.*]] = begin_borrow [lexical] [[ALLOC_X]]
247+
// CHECK: [[PROJECT_X:%.*]] = project_box [[X]]
248+
// CHECK: copy_addr [[ARG]] to [init] [[PROJECT_X]]
249+
// CHECK: [[MARKED_X:%.*]] = mark_must_check [no_consume_or_assign] [[PROJECT_X]]
250+
// CHECK: [[BLACKHOLE_ADDR:%.*]] = alloc_stack $AddressOnlyGeneric<T>
251+
// CHECK: copy_addr [[MARKED_X]] to [init] [[BLACKHOLE_ADDR]]
252+
// CHECK: destroy_addr [[BLACKHOLE_ADDR]]
253+
// CHECK: dealloc_stack [[BLACKHOLE_ADDR]]
254+
//
255+
// CHECK: [[ALLOC_Y:%.*]] = alloc_box $<τ_0_0> { let AddressOnlyGeneric<τ_0_0> } <T>, let, name "y"
256+
// CHECK: [[Y:%.*]] = begin_borrow [lexical] [[ALLOC_Y]]
257+
// CHECK: [[PROJECT_Y:%.*]] = project_box [[Y]]
258+
// CHECK: copy_addr [[ARG]] to [init] [[PROJECT_Y]]
259+
// CHECK: [[MARKED_Y:%.*]] = mark_must_check [no_consume_or_assign] [[PROJECT_Y]]
260+
// CHECK: [[BLACKHOLE_ADDR:%.*]] = alloc_stack $AddressOnlyGeneric<T>
261+
// CHECK: copy_addr [[MARKED_Y]] to [init] [[BLACKHOLE_ADDR]]
262+
// CHECK: destroy_addr [[BLACKHOLE_ADDR]]
263+
// CHECK: dealloc_stack [[BLACKHOLE_ADDR]]
264+
//
265+
// CHECK: } // end sil function '$s8moveonly18AddressOnlyGenericV13testNoUseSelfyyF'
266+
func testNoUseSelf() {
267+
let x = self
268+
let _ = x
269+
let y = self
270+
let _ = y
271+
}
272+
}
273+
274+
extension AddressOnlyProtocol {
275+
// CHECK-LABEL: sil hidden [ossa] @$s8moveonly19AddressOnlyProtocolV13testNoUseSelfyyF : $@convention(method) (@in_guaranteed AddressOnlyProtocol) -> () {
276+
// CHECK: bb0([[ARG_IN:%.*]] :
277+
// CHECK: [[ARG:%.*]] = mark_must_check [no_consume_or_assign] [[ARG_IN]] :
278+
//
279+
// CHECK: [[ALLOC_X:%.*]] = alloc_box ${ let AddressOnlyProtocol }, let, name "x"
280+
// CHECK: [[X:%.*]] = begin_borrow [lexical] [[ALLOC_X]]
281+
// CHECK: [[PROJECT_X:%.*]] = project_box [[X]]
282+
// CHECK: copy_addr [[ARG]] to [init] [[PROJECT_X]]
283+
// CHECK: [[MARKED_X:%.*]] = mark_must_check [no_consume_or_assign] [[PROJECT_X]]
284+
// CHECK: [[BLACKHOLE_ADDR:%.*]] = alloc_stack $AddressOnlyProtocol
285+
// CHECK: copy_addr [[MARKED_X]] to [init] [[BLACKHOLE_ADDR]]
286+
// CHECK: destroy_addr [[BLACKHOLE_ADDR]]
287+
// CHECK: dealloc_stack [[BLACKHOLE_ADDR]]
288+
//
289+
// CHECK: [[ALLOC_Y:%.*]] = alloc_box ${ let AddressOnlyProtocol }, let, name "y"
290+
// CHECK: [[Y:%.*]] = begin_borrow [lexical] [[ALLOC_Y]]
291+
// CHECK: [[PROJECT_Y:%.*]] = project_box [[Y]]
292+
// CHECK: copy_addr [[ARG]] to [init] [[PROJECT_Y]]
293+
// CHECK: [[MARKED_Y:%.*]] = mark_must_check [no_consume_or_assign] [[PROJECT_Y]]
294+
// CHECK: [[BLACKHOLE_ADDR:%.*]] = alloc_stack $AddressOnlyProtocol
295+
// CHECK: copy_addr [[MARKED_Y]] to [init] [[BLACKHOLE_ADDR]]
296+
// CHECK: destroy_addr [[BLACKHOLE_ADDR]]
297+
// CHECK: dealloc_stack [[BLACKHOLE_ADDR]]
298+
// CHECK: } // end sil function '$s8moveonly19AddressOnlyProtocolV13testNoUseSelfyyF'
299+
func testNoUseSelf() {
300+
let x = self
301+
let _ = x
302+
let y = self
303+
let _ = y
304+
}
305+
}
306+
172307
///////////////////////////////
173308
// Black Hole Initialization //
174309
///////////////////////////////

0 commit comments

Comments
 (0)