Skip to content

Commit 542c395

Browse files
committed
Addressed more review feedback
1 parent 32616ee commit 542c395

File tree

4 files changed

+112
-150
lines changed

4 files changed

+112
-150
lines changed

lib/SILGen/SILGenDestructor.cpp

Lines changed: 91 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -220,131 +220,111 @@ void SILGenFunction::destroyClassMember(SILLocation cleanupLoc,
220220
}
221221
}
222222

223-
llvm::SmallSetVector<VarDecl *, 4> findRecursiveLinks(ClassDecl *cd) {
223+
void findRecursiveLinks(ClassDecl *cd, llvm::SmallSetVector<VarDecl*, 4> &result) {
224224
auto SelfTy = cd->getDeclaredInterfaceType();
225225

226226
// Collect all stored properties that would form a recursive structure,
227227
// so we can remove the recursion and prevent the call stack from
228228
// overflowing.
229-
llvm::SmallSetVector<VarDecl *, 4> recursiveLinks;
230229
for (VarDecl *vd : cd->getStoredProperties()) {
231230
auto Ty = vd->getInterfaceType()->getOptionalObjectType();
232231
if (Ty && Ty->getCanonicalType() == SelfTy->getCanonicalType()) {
233-
recursiveLinks.insert(vd);
232+
result.insert(vd);
234233
}
235234
}
236235

237236
// NOTE: Right now we only optimize linear recursion, so if there is more than
238237
// one link, clear out the set and don't perform any recursion optimization.
239-
if (recursiveLinks.size() > 1) {
240-
recursiveLinks.clear();
238+
if (result.size() > 1) {
239+
result.clear();
241240
}
242-
243-
return recursiveLinks;
244241
}
245242

246-
void SILGenFunction::emitRecursiveChainDestruction(
247-
ManagedValue selfValue, ClassDecl *cd,
248-
SmallSetVector<VarDecl *, 4> recursiveLinks, CleanupLocation cleanupLoc) {
243+
void SILGenFunction::emitRecursiveChainDestruction(ManagedValue selfValue,
244+
ClassDecl *cd,
245+
VarDecl *recursiveLink,
246+
CleanupLocation cleanupLoc) {
249247
auto SelfTy = F.mapTypeIntoContext(cd->getDeclaredInterfaceType());
250248

251-
assert(recursiveLinks.size() <= 1 && "Only linear recursion supported.");
252-
253249
auto SelfTyLowered = getTypeLowering(SelfTy).getLoweredType();
254-
for (VarDecl *vd : recursiveLinks) {
255-
SILBasicBlock *cleanBB = createBasicBlock();
256-
SILBasicBlock *noneBB = createBasicBlock();
257-
SILBasicBlock *notUniqueBB = createBasicBlock();
258-
SILBasicBlock *uniqueBB = createBasicBlock();
259-
SILBasicBlock *someBB = createBasicBlock();
260-
SILBasicBlock *loopBB = createBasicBlock();
261-
262-
// var iter = self.link
263-
// self.link = nil
264-
auto Ty = getTypeLowering(F.mapTypeIntoContext(vd->getInterfaceType()))
265-
.getLoweredType();
266-
auto optionalNone = B.createOptionalNone(cleanupLoc, Ty);
267-
SILValue varAddr = B.createRefElementAddr(cleanupLoc, selfValue.getValue(),
268-
vd, Ty.getAddressType());
269-
auto iterAddr = B.createAllocStack(cleanupLoc, Ty);
270-
SILValue addr =
271-
B.createBeginAccess(cleanupLoc, varAddr, SILAccessKind::Modify,
272-
SILAccessEnforcement::Static,
273-
false /*noNestedConflict*/, false /*fromBuiltin*/);
274-
SILValue iter =
275-
B.createLoad(cleanupLoc, addr, LoadOwnershipQualifier::Copy);
276-
B.createStore(cleanupLoc, optionalNone, addr,
277-
StoreOwnershipQualifier::Assign);
278-
B.createEndAccess(cleanupLoc, addr, false /*is aborting*/);
279-
B.createStore(cleanupLoc, iter, iterAddr, StoreOwnershipQualifier::Init);
280-
281-
B.createBranch(cleanupLoc, loopBB);
282-
283-
// while iter != nil {
284-
B.emitBlock(loopBB);
285-
SILValue operand =
286-
B.createLoad(cleanupLoc, iterAddr, LoadOwnershipQualifier::Copy);
287-
auto operandCopy = B.createCopyValue(cleanupLoc, operand);
288-
auto operandAddr = B.createAllocStack(cleanupLoc, Ty);
289-
B.createStore(cleanupLoc, operandCopy, operandAddr,
290-
StoreOwnershipQualifier::Init);
291-
B.createDestroyValue(cleanupLoc, operand);
292-
B.createSwitchEnumAddr(
293-
cleanupLoc, operandAddr, nullptr,
294-
{{getASTContext().getOptionalSomeDecl(), someBB},
295-
{std::make_pair(getASTContext().getOptionalNoneDecl(), noneBB)}});
296-
297-
// if isKnownUniquelyReferenced(&iter) {
298-
B.emitBlock(someBB);
299-
B.createDestroyAddr(cleanupLoc, operandAddr);
300-
B.createDeallocStack(cleanupLoc, operandAddr);
301-
auto isUnique = B.createIsUnique(cleanupLoc, iterAddr);
302-
B.createCondBranch(cleanupLoc, isUnique, uniqueBB, notUniqueBB);
303-
304-
// we have a uniquely referenced link, so we need to deinit
305-
B.emitBlock(uniqueBB);
306-
307-
// NOTE: We increment the ref count of the tail instead of unlinking it,
308-
// because custom deinit implementations of subclasses may access
309-
// it and it would be semantically wrong to unset it before that.
310-
// Making the tail non-uniquely referenced prevents the recursion.
311-
312-
// let tail = iter.unsafelyUnwrapped.next
313-
// iter = tail
314-
SILValue _iter =
315-
B.createLoad(cleanupLoc, iterAddr, LoadOwnershipQualifier::Copy);
316-
auto iterBorrow = B.createBeginBorrow(cleanupLoc, _iter);
317-
auto *link = B.createUncheckedEnumData(
318-
cleanupLoc, iterBorrow, getASTContext().getOptionalSomeDecl(),
319-
SelfTyLowered);
320-
varAddr = B.createRefElementAddr(cleanupLoc, link, vd, Ty.getAddressType());
321-
322-
addr = B.createBeginAccess(
323-
cleanupLoc, varAddr, SILAccessKind::Read, SILAccessEnforcement::Static,
324-
false /* noNestedConflict */, false /*fromBuiltin*/);
325-
iter = B.createLoad(cleanupLoc, addr, LoadOwnershipQualifier::Copy);
326-
B.createEndAccess(cleanupLoc, addr, false /*is aborting*/);
327-
B.createStore(cleanupLoc, iter, iterAddr, StoreOwnershipQualifier::Assign);
328250

329-
B.createEndBorrow(cleanupLoc, iterBorrow);
330-
331-
B.createDestroyValue(cleanupLoc, _iter);
332-
333-
B.createBranch(cleanupLoc, loopBB);
334-
335-
// the next link in the chain is not unique, so we are done here
336-
B.emitBlock(notUniqueBB);
337-
B.createBranch(cleanupLoc, cleanBB);
338-
339-
// we reached the end of the chain
340-
B.emitBlock(noneBB);
341-
B.createDeallocStack(cleanupLoc, operandAddr);
342-
B.createBranch(cleanupLoc, cleanBB);
343-
344-
B.emitBlock(cleanBB);
345-
B.createDestroyAddr(cleanupLoc, iterAddr);
346-
B.createDeallocStack(cleanupLoc, iterAddr);
347-
}
251+
SILBasicBlock *cleanBB = createBasicBlock();
252+
SILBasicBlock *noneBB = createBasicBlock();
253+
SILBasicBlock *notUniqueBB = createBasicBlock();
254+
SILBasicBlock *uniqueBB = createBasicBlock();
255+
SILBasicBlock *someBB = createBasicBlock();
256+
SILBasicBlock *loopBB = createBasicBlock();
257+
258+
// var iter = self.link
259+
// self.link = nil
260+
auto Ty = getTypeLowering(F.mapTypeIntoContext(recursiveLink->getInterfaceType())).getLoweredType();
261+
auto optionalNone = B.createOptionalNone(cleanupLoc, Ty);
262+
SILValue varAddr =
263+
B.createRefElementAddr(cleanupLoc, selfValue.getValue(), recursiveLink,
264+
Ty.getAddressType());
265+
auto iterAddr = B.createAllocStack(cleanupLoc, Ty);
266+
SILValue addr = B.createBeginAccess(
267+
cleanupLoc, varAddr, SILAccessKind::Modify, SILAccessEnforcement::Static,
268+
true /*noNestedConflict*/, false /*fromBuiltin*/);
269+
SILValue iter = B.createLoad(cleanupLoc, addr, LoadOwnershipQualifier::Take);
270+
B.createStore(cleanupLoc, optionalNone, addr, StoreOwnershipQualifier::Init);
271+
B.createEndAccess(cleanupLoc, addr, false /*is aborting*/);
272+
B.createStore(cleanupLoc, iter, iterAddr, StoreOwnershipQualifier::Init);
273+
274+
B.createBranch(cleanupLoc, loopBB);
275+
276+
// while iter != nil {
277+
B.emitBlock(loopBB);
278+
B.createSwitchEnumAddr(
279+
cleanupLoc, iterAddr, nullptr,
280+
{{getASTContext().getOptionalSomeDecl(), someBB},
281+
{std::make_pair(getASTContext().getOptionalNoneDecl(), noneBB)}});
282+
283+
// if isKnownUniquelyReferenced(&iter) {
284+
B.emitBlock(someBB);
285+
auto isUnique = B.createIsUnique(cleanupLoc, iterAddr);
286+
B.createCondBranch(cleanupLoc, isUnique, uniqueBB, notUniqueBB);
287+
288+
// we have a uniquely referenced link, so we need to deinit
289+
B.emitBlock(uniqueBB);
290+
291+
// NOTE: We increment the ref count of the tail instead of unlinking it,
292+
// because custom deinit implementations of subclasses may access
293+
// it and it would be semantically wrong to unset it before that.
294+
// Making the tail non-uniquely referenced prevents the recursion.
295+
296+
// let tail = iter.unsafelyUnwrapped.next
297+
// iter = tail
298+
SILValue iterBorrow = B.createLoadBorrow(cleanupLoc, iterAddr);
299+
auto *link = B.createUncheckedEnumData(cleanupLoc, iterBorrow,
300+
getASTContext().getOptionalSomeDecl(),
301+
SelfTyLowered);
302+
303+
varAddr = B.createRefElementAddr(cleanupLoc, link, recursiveLink,
304+
Ty.getAddressType());
305+
306+
addr = B.createBeginAccess(
307+
cleanupLoc, varAddr, SILAccessKind::Read, SILAccessEnforcement::Static,
308+
true /* noNestedConflict */, false /*fromBuiltin*/);
309+
iter = B.createLoad(cleanupLoc, addr, LoadOwnershipQualifier::Copy);
310+
B.createEndAccess(cleanupLoc, addr, false /*is aborting*/);
311+
B.createEndBorrow(cleanupLoc, iterBorrow);
312+
313+
B.createStore(cleanupLoc, iter, iterAddr, StoreOwnershipQualifier::Assign);
314+
315+
B.createBranch(cleanupLoc, loopBB);
316+
317+
// the next link in the chain is not unique, so we are done here
318+
B.emitBlock(notUniqueBB);
319+
B.createBranch(cleanupLoc, cleanBB);
320+
321+
// we reached the end of the chain
322+
B.emitBlock(noneBB);
323+
B.createBranch(cleanupLoc, cleanBB);
324+
325+
B.emitBlock(cleanBB);
326+
B.createDestroyAddr(cleanupLoc, iterAddr);
327+
B.createDeallocStack(cleanupLoc, iterAddr);
348328
}
349329

350330
void SILGenFunction::emitClassMemberDestruction(ManagedValue selfValue,
@@ -375,7 +355,8 @@ void SILGenFunction::emitClassMemberDestruction(ManagedValue selfValue,
375355
finishBB);
376356
}
377357

378-
auto recursiveLinks = findRecursiveLinks(cd);
358+
llvm::SmallSetVector<VarDecl*, 4> recursiveLinks;
359+
findRecursiveLinks(cd, recursiveLinks);
379360

380361
/// Destroy all members.
381362
{
@@ -388,8 +369,10 @@ void SILGenFunction::emitClassMemberDestruction(ManagedValue selfValue,
388369
destroyClassMember(cleanupLoc, selfValue, vd);
389370
}
390371

391-
if (!recursiveLinks.empty())
392-
emitRecursiveChainDestruction(selfValue, cd, recursiveLinks, cleanupLoc);
372+
if (!recursiveLinks.empty()) {
373+
assert(recursiveLinks.size() == 1 && "Only linear recursion supported.");
374+
emitRecursiveChainDestruction(selfValue, cd, recursiveLinks[0], cleanupLoc);
375+
}
393376

394377
if (finishBB)
395378
B.createBranch(cleanupLoc, finishBB);

lib/SILGen/SILGenFunction.h

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -680,17 +680,16 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
680680
void emitClassMemberDestruction(ManagedValue selfValue, ClassDecl *cd,
681681
CleanupLocation cleanupLoc);
682682

683-
/// Generates code to destroy recursive data structures, without building
684-
/// up the call stack.
683+
/// Generates code to destroy linearly recursive data structures, without
684+
/// building up the call stack.
685685
///
686686
/// \param selfValue The 'self' value.
687687
/// \param cd The class declaration whose members are being destroyed.
688-
/// \param recursiveLinks The set of stored properties that form the
689-
/// recursive data structure.
690-
void emitRecursiveChainDestruction(
691-
ManagedValue selfValue, ClassDecl *cd,
692-
llvm::SmallSetVector<VarDecl *, 4> recursiveLinks,
693-
CleanupLocation cleanupLoc);
688+
/// \param recursiveLink The property that forms the recursive structure.
689+
void emitRecursiveChainDestruction(ManagedValue selfValue,
690+
ClassDecl *cd,
691+
VarDecl* recursiveLink,
692+
CleanupLocation cleanupLoc);
694693

695694
/// Generates a thunk from a foreign function to the native Swift convention.
696695
void emitForeignToNativeThunk(SILDeclRef thunk);

test/SILGen/deinit_recursive_linear.swift

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,45 +15,35 @@ class Node {
1515
// CHECK: [[NIL:%.*]] = enum $Optional<Node>, #Optional.none!enumelt
1616
// CHECK: [[SELF_NEXT:%.*]] = ref_element_addr [[SELF]] : $Node, #Node.next
1717
// CHECK: [[ITER:%.*]] = alloc_stack $Optional<Node>
18-
// CHECK: [[SELF_NEXT_ACCESS:%.*]] = begin_access [modify] [static] [[SELF_NEXT]] : $*Optional<Node>
19-
// CHECK: [[SELF_NEXT_COPY:%.*]] = load [copy] [[SELF_NEXT_ACCESS]] : $*Optional<Node>
20-
// CHECK: store [[NIL]] to [assign] [[SELF_NEXT_ACCESS]] : $*Optional<Node>
18+
// CHECK: [[SELF_NEXT_ACCESS:%.*]] = begin_access [modify] [static] [no_nested_conflict] [[SELF_NEXT]] : $*Optional<Node>
19+
// CHECK: [[SELF_NEXT_COPY:%.*]] = load [take] [[SELF_NEXT_ACCESS]] : $*Optional<Node>
20+
// CHECK: store [[NIL]] to [init] [[SELF_NEXT_ACCESS]] : $*Optional<Node>
2121
// CHECK: end_access [[SELF_NEXT_ACCESS]] : $*Optional<Node>
2222
// CHECK: store [[SELF_NEXT_COPY]] to [init] [[ITER]] : $*Optional<Node>
2323
// CHECK: br [[LOOPBB:bb.*]] //
2424

2525
// CHECK: [[LOOPBB]]:
26-
// CHECK: [[ITER_ADDR:%.*]] = load [copy] [[ITER]] : $*Optional<Node>
27-
// CHECK: [[ITER_COPY:%.*]] = copy_value [[ITER_ADDR]] : $Optional<Node>
28-
// CHECK: [[ITER_COPY_ADDR:%.*]] = alloc_stack $Optional<Node>
29-
// CHECK: store [[ITER_COPY]] to [init] [[ITER_COPY_ADDR]] : $*Optional<Node>
30-
// CHECK: destroy_value [[ITER_ADDR]] : $Optional<Node>
31-
// CHECK: switch_enum_addr [[ITER_COPY_ADDR]] : $*Optional<Node>, case #Optional.some!enumelt: [[IS_SOME_BB:bb.*]], case #Optional.none!enumelt: [[IS_NONE_BB:bb[0-9]+]]
26+
// CHECK: switch_enum_addr [[ITER]] : $*Optional<Node>, case #Optional.some!enumelt: [[IS_SOME_BB:bb.*]], case #Optional.none!enumelt: [[IS_NONE_BB:bb[0-9]+]]
3227

3328
// CHECK: [[IS_SOME_BB]]:
34-
// CHECK: destroy_addr [[ITER_COPY_ADDR]] : $*Optional<Node>
35-
// CHECK: dealloc_stack [[ITER_COPY_ADDR]] : $*Optional<Node>
3629
// CHECK: [[IS_UNIQUE:%.*]] = is_unique [[ITER]] : $*Optional<Node>
3730
// CHECK: cond_br [[IS_UNIQUE]], [[IS_UNIQUE_BB:bb.*]], [[NOT_UNIQUE_BB:bb[0-9]*]]
3831

3932
// CHECK: [[IS_UNIQUE_BB]]:
40-
// CHECK: [[ITER_ADDR:%.*]] = load [copy] [[ITER]] : $*Optional<Node>
41-
// CHECK: [[ITER_BORROW:%.*]] = begin_borrow [[ITER_ADDR]] : $Optional<Node>
33+
// CHECK: [[ITER_BORROW:%.*]] = load_borrow [[ITER]] : $*Optional<Node>
4234
// CHECK: [[ITER_UNWRAPPED:%.*]] = unchecked_enum_data [[ITER_BORROW]] : $Optional<Node>, #Optional.some!enumelt
4335
// CHECK: [[NEXT_ADDR:%.*]] = ref_element_addr [[ITER_UNWRAPPED]] : $Node, #Node.next
44-
// CHECK: [[NEXT_ADDR_ACCESS:%.*]] = begin_access [read] [static] [[NEXT_ADDR]] : $*Optional<Node>
36+
// CHECK: [[NEXT_ADDR_ACCESS:%.*]] = begin_access [read] [static] [no_nested_conflict] [[NEXT_ADDR]] : $*Optional<Node>
4537
// CHECK: [[NEXT_COPY:%.*]] = load [copy] [[NEXT_ADDR_ACCESS]] : $*Optional<Node>
4638
// CHECK: end_access [[NEXT_ADDR_ACCESS]] : $*Optional<Node>
47-
// CHECK: store [[NEXT_COPY]] to [assign] [[ITER]] : $*Optional<Node>
4839
// CHECK: end_borrow [[ITER_BORROW]] : $Optional<Node>
49-
// CHECK: destroy_value [[ITER_ADDR]] : $Optional<Node>
40+
// CHECK: store [[NEXT_COPY]] to [assign] [[ITER]] : $*Optional<Node>
5041
// CHECK: br [[LOOPBB]]
5142

5243
// CHECK: [[NOT_UNIQUE_BB]]:
5344
// CHECK: br bb6
5445

5546
// CHECK: [[IS_NONE_BB]]:
56-
// CHECK: dealloc_stack [[ITER_COPY_ADDR]] : $*Optional<Node>
5747
// CHECK: br [[CLEAN_BB:bb[0-9]+]]
5848

5949
// CHECK: [[CLEAN_BB]]:

test/SILGen/deinit_recursive_linear_generic.swift

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,45 +10,35 @@ class Node<A, B> {
1010
// CHECK: [[NIL:%.*]] = enum $Optional<Node<A, B>>, #Optional.none!enumelt
1111
// CHECK: [[SELF_NEXT:%.*]] = ref_element_addr [[SELF]] : $Node<A, B>, #Node.next
1212
// CHECK: [[ITER:%.*]] = alloc_stack $Optional<Node<A, B>>
13-
// CHECK: [[SELF_NEXT_ACCESS:%.*]] = begin_access [modify] [static] [[SELF_NEXT]] : $*Optional<Node<A, B>>
14-
// CHECK: [[SELF_NEXT_COPY:%.*]] = load [copy] [[SELF_NEXT_ACCESS]] : $*Optional<Node<A, B>>
15-
// CHECK: store [[NIL]] to [assign] [[SELF_NEXT_ACCESS]] : $*Optional<Node<A, B>>
13+
// CHECK: [[SELF_NEXT_ACCESS:%.*]] = begin_access [modify] [static] [no_nested_conflict] [[SELF_NEXT]] : $*Optional<Node<A, B>>
14+
// CHECK: [[SELF_NEXT_COPY:%.*]] = load [take] [[SELF_NEXT_ACCESS]] : $*Optional<Node<A, B>>
15+
// CHECK: store [[NIL]] to [init] [[SELF_NEXT_ACCESS]] : $*Optional<Node<A, B>>
1616
// CHECK: end_access [[SELF_NEXT_ACCESS]] : $*Optional<Node<A, B>>
1717
// CHECK: store [[SELF_NEXT_COPY]] to [init] [[ITER]] : $*Optional<Node<A, B>>
1818
// CHECK: br [[LOOPBB:bb.*]] //
1919

2020
// CHECK: [[LOOPBB]]:
21-
// CHECK: [[ITER_ADDR:%.*]] = load [copy] [[ITER]] : $*Optional<Node<A, B>>
22-
// CHECK: [[ITER_COPY:%.*]] = copy_value [[ITER_ADDR]] : $Optional<Node<A, B>>
23-
// CHECK: [[ITER_COPY_ADDR:%.*]] = alloc_stack $Optional<Node<A, B>>
24-
// CHECK: store [[ITER_COPY]] to [init] [[ITER_COPY_ADDR]] : $*Optional<Node<A, B>>
25-
// CHECK: destroy_value [[ITER_ADDR]] : $Optional<Node<A, B>>
26-
// CHECK: switch_enum_addr [[ITER_COPY_ADDR]] : $*Optional<Node<A, B>>, case #Optional.some!enumelt: [[IS_SOME_BB:bb.*]], case #Optional.none!enumelt: [[IS_NONE_BB:bb[0-9]+]]
21+
// CHECK: switch_enum_addr [[ITER]] : $*Optional<Node<A, B>>, case #Optional.some!enumelt: [[IS_SOME_BB:bb.*]], case #Optional.none!enumelt: [[IS_NONE_BB:bb[0-9]+]]
2722

2823
// CHECK: [[IS_SOME_BB]]:
29-
// CHECK: destroy_addr [[ITER_COPY_ADDR]] : $*Optional<Node<A, B>>
30-
// CHECK: dealloc_stack [[ITER_COPY_ADDR]] : $*Optional<Node<A, B>>
3124
// CHECK: [[IS_UNIQUE:%.*]] = is_unique [[ITER]] : $*Optional<Node<A, B>>
3225
// CHECK: cond_br [[IS_UNIQUE]], [[IS_UNIQUE_BB:bb.*]], [[NOT_UNIQUE_BB:bb[0-9]*]]
3326

3427
// CHECK: [[IS_UNIQUE_BB]]:
35-
// CHECK: [[ITER_ADDR:%.*]] = load [copy] [[ITER]] : $*Optional<Node<A, B>>
36-
// CHECK: [[ITER_BORROW:%.*]] = begin_borrow [[ITER_ADDR]] : $Optional<Node<A, B>>
28+
// CHECK: [[ITER_BORROW:%.*]] = load_borrow [[ITER]] : $*Optional<Node<A, B>>
3729
// CHECK: [[ITER_UNWRAPPED:%.*]] = unchecked_enum_data [[ITER_BORROW]] : $Optional<Node<A, B>>, #Optional.some!enumelt
3830
// CHECK: [[NEXT_ADDR:%.*]] = ref_element_addr [[ITER_UNWRAPPED]] : $Node<A, B>, #Node.next
39-
// CHECK: [[NEXT_ADDR_ACCESS:%.*]] = begin_access [read] [static] [[NEXT_ADDR]] : $*Optional<Node<A, B>>
31+
// CHECK: [[NEXT_ADDR_ACCESS:%.*]] = begin_access [read] [static] [no_nested_conflict] [[NEXT_ADDR]] : $*Optional<Node<A, B>>
4032
// CHECK: [[NEXT_COPY:%.*]] = load [copy] [[NEXT_ADDR_ACCESS]] : $*Optional<Node<A, B>>
4133
// CHECK: end_access [[NEXT_ADDR_ACCESS]] : $*Optional<Node<A, B>>
42-
// CHECK: store [[NEXT_COPY]] to [assign] [[ITER]] : $*Optional<Node<A, B>>
4334
// CHECK: end_borrow [[ITER_BORROW]] : $Optional<Node<A, B>>
44-
// CHECK: destroy_value [[ITER_ADDR]] : $Optional<Node<A, B>>
35+
// CHECK: store [[NEXT_COPY]] to [assign] [[ITER]] : $*Optional<Node<A, B>>
4536
// CHECK: br [[LOOPBB]]
4637

4738
// CHECK: [[NOT_UNIQUE_BB]]:
4839
// CHECK: br bb6
4940

5041
// CHECK: [[IS_NONE_BB]]:
51-
// CHECK: dealloc_stack [[ITER_COPY_ADDR]] : $*Optional<Node<A, B>>
5242
// CHECK: br [[CLEAN_BB:bb[0-9]+]]
5343

5444
// CHECK: [[CLEAN_BB]]:

0 commit comments

Comments
 (0)