@@ -199,22 +199,30 @@ bool isValueAddressOrTrivial(SILValue v);
199
199
// / These operations forward both owned and guaranteed ownership.
200
200
bool isOwnershipForwardingValueKind (SILNodeKind kind);
201
201
202
+ // / Is this an instruction that can forward both owned and guaranteed ownership
203
+ // / kinds.
204
+ bool isOwnershipForwardingInst (SILInstruction *i);
205
+
206
+ // / Is this an instruction that can forward guaranteed ownership.
207
+ bool isGuaranteedForwardingInst (SILInstruction *i);
208
+
202
209
// / These operations forward guaranteed ownership, but don't necessarily forward
203
210
// / owned values.
204
211
bool isGuaranteedForwardingValueKind (SILNodeKind kind);
205
212
213
+ // / Is this a value that is the result of an operation that forwards owned
214
+ // / ownership.
206
215
bool isGuaranteedForwardingValue (SILValue value);
207
216
208
- bool isOwnershipForwardingInst (SILInstruction *i);
209
-
210
- bool isGuaranteedForwardingInst (SILInstruction *i );
217
+ // / Is this a node kind that can forward owned ownership, but may not be able to
218
+ // / forward guaranteed ownership.
219
+ bool isOwnedForwardingValueKind (SILNodeKind kind );
211
220
212
221
struct BorrowScopeOperandKind {
213
- using UnderlyingKindTy = std::underlying_type<SILInstructionKind>::type;
214
-
215
- enum Kind : UnderlyingKindTy {
216
- BeginBorrow = UnderlyingKindTy (SILInstructionKind::BeginBorrowInst),
217
- BeginApply = UnderlyingKindTy (SILInstructionKind::BeginApplyInst),
222
+ enum Kind {
223
+ BeginBorrow,
224
+ BeginApply,
225
+ Branch,
218
226
};
219
227
220
228
Kind value;
@@ -232,6 +240,8 @@ struct BorrowScopeOperandKind {
232
240
return BorrowScopeOperandKind (BeginBorrow);
233
241
case SILInstructionKind::BeginApplyInst:
234
242
return BorrowScopeOperandKind (BeginApply);
243
+ case SILInstructionKind::BranchInst:
244
+ return BorrowScopeOperandKind (Branch);
235
245
}
236
246
}
237
247
@@ -242,9 +252,15 @@ struct BorrowScopeOperandKind {
242
252
llvm::raw_ostream &operator <<(llvm::raw_ostream &os,
243
253
BorrowScopeOperandKind kind);
244
254
255
+ struct BorrowScopeIntroducingValue ;
256
+
245
257
// / An operand whose user instruction introduces a new borrow scope for the
246
258
// / operand's value. The value of the operand must be considered as implicitly
247
259
// / borrowed until the user's corresponding end scope instruction.
260
+ // /
261
+ // / NOTE: We do not require that the guaranteed scope be represented by a
262
+ // / guaranteed value in the same function: see begin_apply. In such cases, we
263
+ // / require instead an end_* instruction to mark the end of the scope's region.
248
264
struct BorrowScopeOperand {
249
265
BorrowScopeOperandKind kind;
250
266
Operand *op;
@@ -270,6 +286,66 @@ struct BorrowScopeOperand {
270
286
271
287
void visitEndScopeInstructions (function_ref<void (Operand *)> func) const ;
272
288
289
+ // / Returns true if this borrow scope operand consumes guaranteed
290
+ // / values and produces a new scope afterwards.
291
+ bool consumesGuaranteedValues () const {
292
+ switch (kind) {
293
+ case BorrowScopeOperandKind::BeginBorrow:
294
+ case BorrowScopeOperandKind::BeginApply:
295
+ return false ;
296
+ case BorrowScopeOperandKind::Branch:
297
+ return true ;
298
+ }
299
+ llvm_unreachable (" Covered switch isn't covered?!" );
300
+ }
301
+
302
+ // / Is this a borrow scope operand that can open new borrow scopes
303
+ // / for owned values.
304
+ bool canAcceptOwnedValues () const {
305
+ switch (kind) {
306
+ case BorrowScopeOperandKind::BeginBorrow:
307
+ case BorrowScopeOperandKind::BeginApply:
308
+ return true ;
309
+ case BorrowScopeOperandKind::Branch:
310
+ return false ;
311
+ }
312
+ llvm_unreachable (" Covered switch isn't covered?!" );
313
+ }
314
+
315
+ // / Is the result of this instruction also a borrow introducer?
316
+ // /
317
+ // / TODO: This needs a better name.
318
+ bool areAnyUserResultsBorrowIntroducers () const {
319
+ // TODO: Can we derive this by running a borrow introducer check ourselves?
320
+ switch (kind) {
321
+ case BorrowScopeOperandKind::BeginBorrow:
322
+ case BorrowScopeOperandKind::Branch:
323
+ return true ;
324
+ case BorrowScopeOperandKind::BeginApply:
325
+ return false ;
326
+ }
327
+ llvm_unreachable (" Covered switch isn't covered?!" );
328
+ }
329
+
330
+ // / Visit all of the results of the operand's user instruction that are
331
+ // / consuming uses.
332
+ void visitUserResultConsumingUses (function_ref<void (Operand *)> visitor);
333
+
334
+ // / Visit all of the "results" of the user of this operand that are borrow
335
+ // / scope introducers for the specific scope that this borrow scope operand
336
+ // / summarizes.
337
+ void visitBorrowIntroducingUserResults (
338
+ function_ref<void (BorrowScopeIntroducingValue)> visitor);
339
+
340
+ // / Passes to visitor all of the consuming uses of this use's using
341
+ // / instruction.
342
+ // /
343
+ // / This enables one to walk the def-use chain of guaranteed phis for a single
344
+ // / guaranteed scope by using a worklist and checking if any of the operands
345
+ // / are BorrowScopeOperands.
346
+ void visitConsumingUsesOfBorrowIntroducingUserResults (
347
+ function_ref<void (Operand *)> visitor);
348
+
273
349
void print (llvm::raw_ostream &os) const ;
274
350
SWIFT_DEBUG_DUMP { print (llvm::dbgs ()); }
275
351
@@ -287,10 +363,11 @@ struct BorrowScopeIntroducingValueKind {
287
363
using UnderlyingKindTy = std::underlying_type<ValueKind>::type;
288
364
289
365
// / Enum we use for exhaustive pattern matching over borrow scope introducers.
290
- enum Kind : UnderlyingKindTy {
291
- LoadBorrow = UnderlyingKindTy (ValueKind::LoadBorrowInst),
292
- BeginBorrow = UnderlyingKindTy (ValueKind::BeginBorrowInst),
293
- SILFunctionArgument = UnderlyingKindTy (ValueKind::SILFunctionArgument),
366
+ enum Kind {
367
+ LoadBorrow,
368
+ BeginBorrow,
369
+ SILFunctionArgument,
370
+ Phi,
294
371
};
295
372
296
373
static Optional<BorrowScopeIntroducingValueKind> get (ValueKind kind) {
@@ -303,6 +380,8 @@ struct BorrowScopeIntroducingValueKind {
303
380
return BorrowScopeIntroducingValueKind (BeginBorrow);
304
381
case ValueKind::SILFunctionArgument:
305
382
return BorrowScopeIntroducingValueKind (SILFunctionArgument);
383
+ case ValueKind::SILPhiArgument:
384
+ return BorrowScopeIntroducingValueKind (Phi);
306
385
}
307
386
}
308
387
@@ -323,6 +402,7 @@ struct BorrowScopeIntroducingValueKind {
323
402
switch (value) {
324
403
case BorrowScopeIntroducingValueKind::BeginBorrow:
325
404
case BorrowScopeIntroducingValueKind::LoadBorrow:
405
+ case BorrowScopeIntroducingValueKind::Phi:
326
406
return true ;
327
407
case BorrowScopeIntroducingValueKind::SILFunctionArgument:
328
408
return false ;
@@ -365,9 +445,28 @@ struct BorrowScopeIntroducingValue {
365
445
: kind(BorrowScopeIntroducingValueKind::SILFunctionArgument), value(arg) {
366
446
assert (arg->getOwnershipKind () == ValueOwnershipKind::Guaranteed);
367
447
}
448
+ BorrowScopeIntroducingValue (SILPhiArgument *arg)
449
+ : kind(BorrowScopeIntroducingValueKind::Phi), value(arg) {
450
+ assert (llvm::all_of (arg->getParent ()->getPredecessorBlocks (),
451
+ [](SILBasicBlock *block) {
452
+ return isa<BranchInst>(block->getTerminator ());
453
+ }) &&
454
+ " Phi argument incoming values must come from branch insts!" );
455
+ assert (arg->isPhiArgument () && " Can only accept a true phi argument!" );
456
+ assert (arg->getOwnershipKind () == ValueOwnershipKind::Guaranteed);
457
+ }
368
458
369
459
BorrowScopeIntroducingValue (SILValue v)
370
460
: kind(*BorrowScopeIntroducingValueKind::get (v->getKind ())), value(v) {
461
+ // Validate that if we have a phi argument that all our predecessors have
462
+ // branches as terminators.
463
+ assert (!isa<SILPhiArgument>(v) ||
464
+ (llvm::all_of (v->getParentBlock ()->getPredecessorBlocks (),
465
+ [](SILBasicBlock *block) {
466
+ return isa<BranchInst>(block->getTerminator ());
467
+ }) &&
468
+ " Phi argument incoming values must come from branch insts!" ));
469
+
371
470
assert (v.getOwnershipKind () == ValueOwnershipKind::Guaranteed);
372
471
}
373
472
@@ -376,6 +475,15 @@ struct BorrowScopeIntroducingValue {
376
475
auto kind = BorrowScopeIntroducingValueKind::get (value->getKind ());
377
476
if (!kind || value.getOwnershipKind () != ValueOwnershipKind::Guaranteed)
378
477
return None;
478
+ // If kind is phi and we were not passed something with all branch
479
+ // predecessors, return None.
480
+ if ((*kind) == BorrowScopeIntroducingValueKind::Phi &&
481
+ llvm::any_of (value->getParentBlock ()->getPredecessorBlocks (),
482
+ [](SILBasicBlock *block) {
483
+ return !isa<BranchInst>(block->getTerminator ());
484
+ }))
485
+ return None;
486
+ // Otherwise, create our value directly.
379
487
return BorrowScopeIntroducingValue (*kind, value);
380
488
}
381
489
@@ -414,6 +522,11 @@ struct BorrowScopeIntroducingValue {
414
522
SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks,
415
523
DeadEndBlocks &deadEndBlocks) const ;
416
524
525
+ // / Given a local borrow scope introducer, visit all non-forwarding consuming
526
+ // / users. This means that this looks through guaranteed block arguments.
527
+ bool visitLocalScopeTransitiveEndingUses (
528
+ function_ref<void (Operand *)> visitor) const ;
529
+
417
530
void print (llvm::raw_ostream &os) const ;
418
531
SWIFT_DEBUG_DUMP { print (llvm::dbgs ()); }
419
532
0 commit comments