32
32
33
33
using namespace swift ;
34
34
35
+ // ===----------------------------------------------------------------------===//
36
+ // Utility Helper Functions
37
+ // ===----------------------------------------------------------------------===//
38
+
39
+ static void cleanupOperandsBeforeDeletion (SILInstruction *oldValue,
40
+ InstModCallbacks &callbacks) {
41
+ SILBuilderWithScope builder (oldValue);
42
+ for (auto &op : oldValue->getAllOperands ()) {
43
+ if (!op.isLifetimeEnding ()) {
44
+ continue ;
45
+ }
46
+
47
+ switch (op.get ().getOwnershipKind ()) {
48
+ case OwnershipKind::Any:
49
+ llvm_unreachable (" Invalid ownership for value" );
50
+ case OwnershipKind::Owned: {
51
+ auto *dvi = builder.createDestroyValue (oldValue->getLoc (), op.get ());
52
+ callbacks.createdNewInst (dvi);
53
+ continue ;
54
+ }
55
+ case OwnershipKind::Guaranteed: {
56
+ // Should only happen once we model destructures as true reborrows.
57
+ auto *ebi = builder.createEndBorrow (oldValue->getLoc (), op.get ());
58
+ callbacks.createdNewInst (ebi);
59
+ continue ;
60
+ }
61
+ case OwnershipKind::None:
62
+ continue ;
63
+ case OwnershipKind::Unowned:
64
+ llvm_unreachable (" Unowned object can never be consumed?!" );
65
+ }
66
+ llvm_unreachable (" Covered switch isn't covered" );
67
+ }
68
+ }
69
+
70
+ static SILPhiArgument *
71
+ insertOwnedBaseValueAlongBranchEdge (BranchInst *bi, SILValue innerCopy,
72
+ InstModCallbacks &callbacks) {
73
+ auto *destBB = bi->getDestBB ();
74
+ // We need to create the phi argument before calling addNewEdgeValueToBranch
75
+ // since it checks that the destination block has enough arguments for the
76
+ // argument.
77
+ auto *phiArg =
78
+ destBB->createPhiArgument (innerCopy->getType (), OwnershipKind::Owned);
79
+ addNewEdgeValueToBranch (bi, destBB, innerCopy, callbacks);
80
+
81
+ // Grab our predecessor blocks, ignoring us, add to the branch edge an
82
+ // undef corresponding to our value.
83
+ //
84
+ // We gather all predecessor blocks in a separate array to avoid
85
+ // iterator invalidation issues as we mess with terminators.
86
+ SmallVector<SILBasicBlock *, 8 > predecessorBlocks (
87
+ destBB->getPredecessorBlocks ());
88
+
89
+ for (auto *predBlock : predecessorBlocks) {
90
+ if (predBlock == innerCopy->getParentBlock ())
91
+ continue ;
92
+ addNewEdgeValueToBranch (
93
+ predBlock->getTerminator (), destBB,
94
+ SILUndef::get (innerCopy->getType (), *destBB->getParent ()), callbacks);
95
+ }
96
+
97
+ return phiArg;
98
+ }
99
+
100
+ static void getAllNonTrivialUsePointsOfBorrowedValue (
101
+ SILValue value, SmallVectorImpl<Operand *> &usePoints,
102
+ SmallVectorImpl<BorrowingOperand> &reborrowPoints) {
103
+ assert (value.getOwnershipKind () == OwnershipKind::Guaranteed);
104
+
105
+ unsigned firstOffset = usePoints.size ();
106
+ llvm::copy (value->getUses (), std::back_inserter (usePoints));
107
+
108
+ if (usePoints.size () == firstOffset)
109
+ return ;
110
+
111
+ // NOTE: Use points resizes in this loop so usePoints.size() may be
112
+ // different every time.
113
+ for (unsigned i = firstOffset; i < usePoints.size (); ++i) {
114
+ if (auto fOperand = ForwardingOperand::get (usePoints[i])) {
115
+ fOperand ->visitForwardedValues ([&](SILValue transitiveValue) {
116
+ // Do not include transitive uses with 'none' ownership
117
+ if (transitiveValue.getOwnershipKind () == OwnershipKind::None)
118
+ return true ;
119
+ for (auto *transitiveUse : transitiveValue->getUses ())
120
+ usePoints.push_back (transitiveUse);
121
+ return true ;
122
+ });
123
+ continue ;
124
+ }
125
+
126
+ if (auto borrowingOp = BorrowingOperand::get (usePoints[i])) {
127
+ // If we have a reborrow, we have no further work to do, our reborrow is
128
+ // already a use and we will handle the reborrow separately.
129
+ if (borrowingOp->isReborrow ())
130
+ continue ;
131
+
132
+ // Otherwise, try to grab additional end scope instructions to find more
133
+ // liveness info. Stash any reborrow uses so that we can eliminate the
134
+ // reborrow before we are done processing.
135
+ borrowingOp->visitLocalEndScopeUses ([&](Operand *scopeEndingUse) {
136
+ if (auto scopeEndingBorrowingOp =
137
+ BorrowingOperand::get (scopeEndingUse)) {
138
+ if (scopeEndingBorrowingOp->isReborrow ()) {
139
+ reborrowPoints.push_back (scopeEndingUse);
140
+ return true ;
141
+ }
142
+ }
143
+ usePoints.push_back (scopeEndingUse);
144
+ return true ;
145
+ });
146
+
147
+ // Now break up all of the reborrows
148
+ continue ;
149
+ }
150
+
151
+ // If our base guaranteed value does not have any consuming uses (consider
152
+ // function arguments), we need to be sure to include interior pointer
153
+ // operands since we may not get a use from a end_scope instruction.
154
+ if (auto intPtrOperand = InteriorPointerOperand::get (usePoints[i])) {
155
+ intPtrOperand->getImplicitUses (usePoints);
156
+ continue ;
157
+ }
158
+ }
159
+ }
160
+
35
161
// ===----------------------------------------------------------------------===//
36
162
// Ownership Lifetime Extender
37
163
// ===----------------------------------------------------------------------===//
@@ -247,170 +373,14 @@ OwnershipLifetimeExtender::copyBorrowAndExtendForLifetimeEndingRAUW(
247
373
}
248
374
249
375
// ===----------------------------------------------------------------------===//
250
- // Ownership Fixup RAUW
376
+ // Reborrow Elimination
251
377
// ===----------------------------------------------------------------------===//
252
378
253
- // / Given an old value and a new value, lifetime extend new value as appropriate
254
- // / so we can RAUW new value with old value and preserve ownership
255
- // / invariants. We leave fixing up the lifetime of old value to our caller.
256
- namespace {
257
-
258
- struct OwnershipRAUWUtility {
259
- SingleValueInstruction *oldValue;
260
- SILValue newValue;
261
- OwnershipFixupContext &ctx;
262
-
263
- void rewriteReborrows (SILValue borrow, ArrayRef<BorrowingOperand> reborrows);
264
- void eliminateReborrowsOfRecursiveBorrows (
265
- ArrayRef<BorrowingOperand> transitiveReborrows,
266
- SmallVectorImpl<Operand *> &usePoints);
267
-
268
- SILBasicBlock::iterator handleUnowned ();
269
-
270
- SILBasicBlock::iterator handleGuaranteed ();
271
-
272
- SILBasicBlock::iterator perform ();
273
-
274
- // / Insert copies/borrows as appropriate to eliminate any reborrows of
275
- // / borrowed value, given we are going to replace it with newValue.
276
- void eliminateReborrows (BorrowedValue oldBorrowedValue, SILValue newValue);
277
-
278
- OwnershipLifetimeExtender getLifetimeExtender () { return {ctx}; }
279
-
280
- const InstModCallbacks &getCallbacks () const { return ctx.callbacks ; }
281
- };
282
-
283
- } // anonymous namespace
284
-
285
- static void cleanupOperandsBeforeDeletion (SILInstruction *oldValue,
286
- InstModCallbacks &callbacks) {
287
- SILBuilderWithScope builder (oldValue);
288
- for (auto &op : oldValue->getAllOperands ()) {
289
- if (!op.isLifetimeEnding ()) {
290
- continue ;
291
- }
292
-
293
- switch (op.get ().getOwnershipKind ()) {
294
- case OwnershipKind::Any:
295
- llvm_unreachable (" Invalid ownership for value" );
296
- case OwnershipKind::Owned: {
297
- auto *dvi = builder.createDestroyValue (oldValue->getLoc (), op.get ());
298
- callbacks.createdNewInst (dvi);
299
- continue ;
300
- }
301
- case OwnershipKind::Guaranteed: {
302
- // Should only happen once we model destructures as true reborrows.
303
- auto *ebi = builder.createEndBorrow (oldValue->getLoc (), op.get ());
304
- callbacks.createdNewInst (ebi);
305
- continue ;
306
- }
307
- case OwnershipKind::None:
308
- continue ;
309
- case OwnershipKind::Unowned:
310
- llvm_unreachable (" Unowned object can never be consumed?!" );
311
- }
312
- llvm_unreachable (" Covered switch isn't covered" );
313
- }
314
- }
315
-
316
- static SILPhiArgument *
317
- insertOwnedBaseValueAlongBranchEdge (BranchInst *bi, SILValue innerCopy,
318
- InstModCallbacks &callbacks) {
319
- auto *destBB = bi->getDestBB ();
320
- // We need to create the phi argument before calling addNewEdgeValueToBranch
321
- // since it checks that the destination block has enough arguments for the
322
- // argument.
323
- auto *phiArg =
324
- destBB->createPhiArgument (innerCopy->getType (), OwnershipKind::Owned);
325
- addNewEdgeValueToBranch (bi, destBB, innerCopy, callbacks);
326
-
327
- // Grab our predecessor blocks, ignoring us, add to the branch edge an
328
- // undef corresponding to our value.
329
- //
330
- // We gather all predecessor blocks in a separate array to avoid
331
- // iterator invalidation issues as we mess with terminators.
332
- SmallVector<SILBasicBlock *, 8 > predecessorBlocks (
333
- destBB->getPredecessorBlocks ());
334
-
335
- for (auto *predBlock : predecessorBlocks) {
336
- if (predBlock == innerCopy->getParentBlock ())
337
- continue ;
338
- addNewEdgeValueToBranch (
339
- predBlock->getTerminator (), destBB,
340
- SILUndef::get (innerCopy->getType (), *destBB->getParent ()), callbacks);
341
- }
342
-
343
- return phiArg;
344
- }
345
-
346
- static void getAllNonTrivialUsePointsOfBorrowedValue (
347
- SILValue value, SmallVectorImpl<Operand *> &usePoints,
348
- SmallVectorImpl<BorrowingOperand> &reborrowPoints) {
349
- assert (value.getOwnershipKind () == OwnershipKind::Guaranteed);
350
-
351
- unsigned firstOffset = usePoints.size ();
352
- llvm::copy (value->getUses (), std::back_inserter (usePoints));
353
-
354
- if (usePoints.size () == firstOffset)
355
- return ;
356
-
357
- // NOTE: Use points resizes in this loop so usePoints.size() may be
358
- // different every time.
359
- for (unsigned i = firstOffset; i < usePoints.size (); ++i) {
360
- if (auto fOperand = ForwardingOperand::get (usePoints[i])) {
361
- fOperand ->visitForwardedValues ([&](SILValue transitiveValue) {
362
- // Do not include transitive uses with 'none' ownership
363
- if (transitiveValue.getOwnershipKind () == OwnershipKind::None)
364
- return true ;
365
- for (auto *transitiveUse : transitiveValue->getUses ())
366
- usePoints.push_back (transitiveUse);
367
- return true ;
368
- });
369
- continue ;
370
- }
371
-
372
- if (auto borrowingOp = BorrowingOperand::get (usePoints[i])) {
373
- // If we have a reborrow, we have no further work to do, our reborrow is
374
- // already a use and we will handle the reborrow separately.
375
- if (borrowingOp->isReborrow ())
376
- continue ;
377
-
378
- // Otherwise, try to grab additional end scope instructions to find more
379
- // liveness info. Stash any reborrow uses so that we can eliminate the
380
- // reborrow before we are done processing.
381
- borrowingOp->visitLocalEndScopeUses ([&](Operand *scopeEndingUse) {
382
- if (auto scopeEndingBorrowingOp =
383
- BorrowingOperand::get (scopeEndingUse)) {
384
- if (scopeEndingBorrowingOp->isReborrow ()) {
385
- reborrowPoints.push_back (scopeEndingUse);
386
- return true ;
387
- }
388
- }
389
- usePoints.push_back (scopeEndingUse);
390
- return true ;
391
- });
392
-
393
- // Now break up all of the reborrows
394
- continue ;
395
- }
396
-
397
- // If our base guaranteed value does not have any consuming uses (consider
398
- // function arguments), we need to be sure to include interior pointer
399
- // operands since we may not get a use from a end_scope instruction.
400
- if (auto intPtrOperand = InteriorPointerOperand::get (usePoints[i])) {
401
- intPtrOperand->getImplicitUses (usePoints);
402
- continue ;
403
- }
404
- }
405
- }
406
-
407
- void OwnershipRAUWUtility::eliminateReborrowsOfRecursiveBorrows (
379
+ static void eliminateReborrowsOfRecursiveBorrows (
408
380
ArrayRef<BorrowingOperand> transitiveReborrows,
409
- SmallVectorImpl<Operand *> &usePoints) {
381
+ SmallVectorImpl<Operand *> &usePoints, InstModCallbacks &callbacks ) {
410
382
SmallVector<std::pair<SILPhiArgument *, SILPhiArgument *>, 8 >
411
383
baseBorrowedValuePair;
412
- auto &callbacks = ctx.callbacks ;
413
-
414
384
// Ok, we have transitive reborrows.
415
385
for (auto borrowingOperand : transitiveReborrows) {
416
386
// We eliminate the reborrow by creating a new copy+borrow at the reborrow
@@ -478,13 +448,13 @@ void OwnershipRAUWUtility::eliminateReborrowsOfRecursiveBorrows(
478
448
}
479
449
}
480
450
481
- void OwnershipRAUWUtility::rewriteReborrows (
482
- SILValue newBorrowedValue, ArrayRef<BorrowingOperand> foundReborrows) {
451
+ static void rewriteReborrows (SILValue newBorrowedValue,
452
+ ArrayRef<BorrowingOperand> foundReborrows,
453
+ InstModCallbacks &callbacks) {
483
454
// Each initial reborrow that we have is a use of oldValue, so we know
484
455
// that copy should be valid at the reborrow.
485
456
SmallVector<std::pair<SILPhiArgument *, SILPhiArgument *>, 8 >
486
457
baseBorrowedValuePair;
487
- auto &callbacks = ctx.callbacks ;
488
458
for (auto reborrow : foundReborrows) {
489
459
auto *bi = cast<BranchInst>(reborrow.op ->getUser ());
490
460
SILBuilderWithScope reborrowBuilder (bi);
@@ -539,6 +509,37 @@ void OwnershipRAUWUtility::rewriteReborrows(
539
509
}
540
510
}
541
511
512
+ // ===----------------------------------------------------------------------===//
513
+ // Ownership Fixup RAUW
514
+ // ===----------------------------------------------------------------------===//
515
+
516
+ // / Given an old value and a new value, lifetime extend new value as appropriate
517
+ // / so we can RAUW new value with old value and preserve ownership
518
+ // / invariants. We leave fixing up the lifetime of old value to our caller.
519
+ namespace {
520
+
521
+ struct OwnershipRAUWUtility {
522
+ SingleValueInstruction *oldValue;
523
+ SILValue newValue;
524
+ OwnershipFixupContext &ctx;
525
+
526
+ SILBasicBlock::iterator handleUnowned ();
527
+
528
+ SILBasicBlock::iterator handleGuaranteed ();
529
+
530
+ SILBasicBlock::iterator perform ();
531
+
532
+ // / Insert copies/borrows as appropriate to eliminate any reborrows of
533
+ // / borrowed value, given we are going to replace it with newValue.
534
+ void eliminateReborrows (BorrowedValue oldBorrowedValue, SILValue newValue);
535
+
536
+ OwnershipLifetimeExtender getLifetimeExtender () { return {ctx}; }
537
+
538
+ const InstModCallbacks &getCallbacks () const { return ctx.callbacks ; }
539
+ };
540
+
541
+ } // anonymous namespace
542
+
542
543
SILBasicBlock::iterator OwnershipRAUWUtility::handleUnowned () {
543
544
auto &callbacks = ctx.callbacks ;
544
545
switch (newValue.getOwnershipKind ()) {
@@ -639,7 +640,7 @@ SILBasicBlock::iterator OwnershipRAUWUtility::handleGuaranteed() {
639
640
// If we have any transitive reborrows on sub-borrows.
640
641
if (recursiveBorrowScopeReborrows.size ())
641
642
eliminateReborrowsOfRecursiveBorrows (recursiveBorrowScopeReborrows,
642
- usePoints);
643
+ usePoints, ctx. callbacks );
643
644
644
645
auto extender = getLifetimeExtender ();
645
646
SILValue newBorrowedValue =
@@ -663,7 +664,7 @@ SILBasicBlock::iterator OwnershipRAUWUtility::handleGuaranteed() {
663
664
if (auto oldValueBorrowedVal = BorrowedValue::get (oldValue)) {
664
665
SmallVector<BorrowingOperand, 8 > foundReborrows;
665
666
if (oldValueBorrowedVal->gatherReborrows (foundReborrows)) {
666
- rewriteReborrows (newBorrowedValue, foundReborrows);
667
+ rewriteReborrows (newBorrowedValue, foundReborrows, ctx. callbacks );
667
668
}
668
669
}
669
670
0 commit comments