@@ -244,6 +244,18 @@ struct AvailableValue {
244
244
return {NewValue, SubElementNumber, InsertionPoints};
245
245
}
246
246
247
+ AvailableValue emitBeginBorrow (SILBuilder &b, SILLocation loc) const {
248
+ // If we do not have ownership or already are guaranteed, just return a copy
249
+ // of our state.
250
+ if (!b.hasOwnership () || Value.getOwnershipKind ().isCompatibleWith (
251
+ ValueOwnershipKind::Guaranteed)) {
252
+ return {Value, SubElementNumber, InsertionPoints};
253
+ }
254
+
255
+ // Otherwise, return newValue.
256
+ return {b.createBeginBorrow (loc, Value), SubElementNumber, InsertionPoints};
257
+ }
258
+
247
259
void dump () const LLVM_ATTRIBUTE_USED;
248
260
void print (llvm::raw_ostream &os) const ;
249
261
@@ -301,10 +313,17 @@ static SILValue nonDestructivelyExtractSubElement(const AvailableValue &Val,
301
313
SILType EltTy = ValTy.getTupleElementType (EltNo);
302
314
unsigned NumSubElt = getNumSubElements (EltTy, B.getModule ());
303
315
if (SubElementNumber < NumSubElt) {
304
- auto NewVal = Val.emitTupleExtract (B, Loc, EltNo, SubElementNumber);
305
- return nonDestructivelyExtractSubElement (NewVal, B, Loc);
316
+ auto BorrowedVal = Val.emitBeginBorrow (B, Loc);
317
+ auto NewVal =
318
+ BorrowedVal.emitTupleExtract (B, Loc, EltNo, SubElementNumber);
319
+ SILValue result = nonDestructivelyExtractSubElement (NewVal, B, Loc);
320
+ // If our original value wasn't guaranteed and we did actually perform a
321
+ // borrow as a result, insert the end_borrow.
322
+ if (BorrowedVal.getValue () != Val.getValue ())
323
+ B.createEndBorrow (Loc, BorrowedVal.getValue ());
324
+ return result;
306
325
}
307
-
326
+
308
327
SubElementNumber -= NumSubElt;
309
328
}
310
329
@@ -318,19 +337,32 @@ static SILValue nonDestructivelyExtractSubElement(const AvailableValue &Val,
318
337
unsigned NumSubElt = getNumSubElements (fieldType, B.getModule ());
319
338
320
339
if (SubElementNumber < NumSubElt) {
321
- auto NewVal = Val.emitStructExtract (B, Loc, D, SubElementNumber);
322
- return nonDestructivelyExtractSubElement (NewVal, B, Loc);
340
+ auto BorrowedVal = Val.emitBeginBorrow (B, Loc);
341
+ auto NewVal =
342
+ BorrowedVal.emitStructExtract (B, Loc, D, SubElementNumber);
343
+ SILValue result = nonDestructivelyExtractSubElement (NewVal, B, Loc);
344
+ // If our original value wasn't guaranteed and we did actually perform a
345
+ // borrow as a result, insert the end_borrow.
346
+ if (BorrowedVal.getValue () != Val.getValue ())
347
+ B.createEndBorrow (Loc, BorrowedVal.getValue ());
348
+ return result;
323
349
}
324
350
325
351
SubElementNumber -= NumSubElt;
326
352
327
353
}
328
354
llvm_unreachable (" Didn't find field" );
329
355
}
330
-
331
- // Otherwise, we're down to a scalar.
356
+
357
+ // Otherwise, we're down to a scalar. If we have ownership enabled,
358
+ // we return a copy. Otherwise, there we can ignore ownership
359
+ // issues. This is ok since in [ossa] we are going to eliminate a
360
+ // load [copy] or a load [trivial], while in non-[ossa] SIL we will
361
+ // be replacing unqualified loads.
332
362
assert (SubElementNumber == 0 && " Miscalculation indexing subelements" );
333
- return Val.getValue ();
363
+ if (!B.hasOwnership ())
364
+ return Val.getValue ();
365
+ return B.emitCopyValueOperation (Loc, Val.getValue ());
334
366
}
335
367
336
368
// ===----------------------------------------------------------------------===//
@@ -429,29 +461,61 @@ SILValue AvailableValueAggregator::aggregateValues(SILType LoadTy,
429
461
// aggregate. This is a super-common case for single-element structs, but is
430
462
// also a general answer for arbitrary structs and tuples as well.
431
463
SILValue
432
- AvailableValueAggregator::aggregateFullyAvailableValue (SILType LoadTy ,
433
- unsigned FirstElt ) {
434
- if (FirstElt >= AvailableValueList.size ()) { // #Elements may be zero.
464
+ AvailableValueAggregator::aggregateFullyAvailableValue (SILType loadTy ,
465
+ unsigned firstElt ) {
466
+ if (firstElt >= AvailableValueList.size ()) { // #Elements may be zero.
435
467
return SILValue ();
436
468
}
437
469
438
- auto &FirstVal = AvailableValueList[FirstElt ];
470
+ auto &firstVal = AvailableValueList[firstElt ];
439
471
440
472
// Make sure that the first element is available and is the correct type.
441
- if (!FirstVal || FirstVal .getType () != LoadTy )
473
+ if (!firstVal || firstVal .getType () != loadTy )
442
474
return SILValue ();
443
475
444
476
// If the first element of this value is available, check that any extra
445
477
// available values are from the same place as our first value.
446
- if (llvm::any_of (range (getNumSubElements (LoadTy , M)),
447
- [&](unsigned Index ) -> bool {
448
- auto &Val = AvailableValueList[FirstElt + Index ];
449
- return Val .getValue () != FirstVal .getValue () ||
450
- Val .getSubElementNumber () != Index ;
478
+ if (llvm::any_of (range (getNumSubElements (loadTy , M)),
479
+ [&](unsigned index ) -> bool {
480
+ auto &val = AvailableValueList[firstElt + index ];
481
+ return val .getValue () != firstVal .getValue () ||
482
+ val .getSubElementNumber () != index ;
451
483
}))
452
484
return SILValue ();
453
485
454
- return FirstVal.getValue ();
486
+ // Ok, we know that all of our available values are all parts of the same
487
+ // value. Without ownership, we can just return the underlying first value.
488
+ if (!B.hasOwnership ())
489
+ return firstVal.getValue ();
490
+
491
+ // Otherwise, we need to put in a copy. This is b/c we only propagate along +1
492
+ // values and we are eliminating a load [copy].
493
+ ArrayRef<StoreInst *> insertPts = firstVal.getInsertionPoints ();
494
+ if (insertPts.size () == 1 ) {
495
+ // Use the scope and location of the store at the insertion point.
496
+ SILBuilderWithScope builder (insertPts[0 ]);
497
+ SILLocation loc = insertPts[0 ]->getLoc ();
498
+ return builder.emitCopyValueOperation (loc, firstVal.getValue ());
499
+ }
500
+
501
+ // If we have multiple insertion points, put copies at each point and use the
502
+ // SSA updater to get a value. The reason why this is safe is that we can only
503
+ // have multiple insertion points if we are storing exactly the same value
504
+ // implying that we can just copy firstVal at each insertion point.
505
+ SILSSAUpdater updater (B.getModule ());
506
+ updater.Initialize (loadTy);
507
+ for (auto *insertPt : firstVal.getInsertionPoints ()) {
508
+ // Use the scope and location of the store at the insertion point.
509
+ SILBuilderWithScope builder (insertPt);
510
+ SILLocation loc = insertPt->getLoc ();
511
+ SILValue eltVal = builder.emitCopyValueOperation (loc, firstVal.getValue ());
512
+ updater.AddAvailableValue (insertPt->getParent (), eltVal);
513
+ }
514
+
515
+ // Finally, grab the value from the SSA updater.
516
+ SILValue result = updater.GetValueInMiddleOfBlock (B.getInsertionBB ());
517
+ assert (result.getOwnershipKind ().isCompatibleWith (ValueOwnershipKind::Owned));
518
+ return result;
455
519
}
456
520
457
521
SILValue AvailableValueAggregator::aggregateTupleSubElts (TupleType *TT,
@@ -511,8 +575,13 @@ SILValue AvailableValueAggregator::handlePrimitiveValue(SILType LoadTy,
511
575
512
576
// If the value is not available, load the value and update our use list.
513
577
if (!Val) {
514
- auto *Load =
515
- B.createLoad (Loc, Address, LoadOwnershipQualifier::Unqualified);
578
+ LoadInst *Load = ([&]() {
579
+ if (B.hasOwnership ()) {
580
+ return B.createTrivialLoadOr (Loc, Address,
581
+ LoadOwnershipQualifier::Copy);
582
+ }
583
+ return B.createLoad (Loc, Address, LoadOwnershipQualifier::Unqualified);
584
+ }());
516
585
Uses.emplace_back (Load, PMOUseKind::Load);
517
586
return Load;
518
587
}
@@ -527,6 +596,9 @@ SILValue AvailableValueAggregator::handlePrimitiveValue(SILType LoadTy,
527
596
SILBuilderWithScope Builder (InsertPts[0 ]);
528
597
SILLocation Loc = InsertPts[0 ]->getLoc ();
529
598
SILValue EltVal = nonDestructivelyExtractSubElement (Val, Builder, Loc);
599
+ assert (
600
+ !Builder.hasOwnership () ||
601
+ EltVal.getOwnershipKind ().isCompatibleWith (ValueOwnershipKind::Owned));
530
602
assert (EltVal->getType () == LoadTy && " Subelement types mismatch" );
531
603
return EltVal;
532
604
}
@@ -540,11 +612,16 @@ SILValue AvailableValueAggregator::handlePrimitiveValue(SILType LoadTy,
540
612
SILBuilderWithScope Builder (I);
541
613
SILLocation Loc = I->getLoc ();
542
614
SILValue EltVal = nonDestructivelyExtractSubElement (Val, Builder, Loc);
615
+ assert (
616
+ !Builder.hasOwnership () ||
617
+ EltVal.getOwnershipKind ().isCompatibleWith (ValueOwnershipKind::Owned));
543
618
Updater.AddAvailableValue (I->getParent (), EltVal);
544
619
}
545
620
546
621
// Finally, grab the value from the SSA updater.
547
622
SILValue EltVal = Updater.GetValueInMiddleOfBlock (B.getInsertionBB ());
623
+ assert (!B.hasOwnership () ||
624
+ EltVal.getOwnershipKind ().isCompatibleWith (ValueOwnershipKind::Owned));
548
625
assert (EltVal->getType () == LoadTy && " Subelement types mismatch" );
549
626
return EltVal;
550
627
}
@@ -568,7 +645,7 @@ class AvailableValueDataflowContext {
568
645
// / The set of uses that we are tracking. This is only here so we can update
569
646
// / when exploding copy_addr. It would be great if we did not have to store
570
647
// / this.
571
- llvm:: SmallVectorImpl<PMOMemoryUse> &Uses;
648
+ SmallVectorImpl<PMOMemoryUse> &Uses;
572
649
573
650
// / The set of blocks with local definitions.
574
651
// /
@@ -587,7 +664,7 @@ class AvailableValueDataflowContext {
587
664
public:
588
665
AvailableValueDataflowContext (AllocationInst *TheMemory,
589
666
unsigned NumMemorySubElements,
590
- llvm:: SmallVectorImpl<PMOMemoryUse> &Uses);
667
+ SmallVectorImpl<PMOMemoryUse> &Uses);
591
668
592
669
// / Try to compute available values for "TheMemory" at the instruction \p
593
670
// / StartingFrom. We only compute the values for set bits in \p
@@ -666,32 +743,33 @@ void AvailableValueDataflowContext::updateAvailableValues(
666
743
assert (StartSubElt != ~0U && " Store within enum projection not handled" );
667
744
SILType ValTy = SI->getSrc ()->getType ();
668
745
669
- for (unsigned i = 0 , e = getNumSubElements (ValTy, getModule ()); i != e;
670
- ++i) {
746
+ for (unsigned i : range (getNumSubElements (ValTy, getModule ()))) {
671
747
// If this element is not required, don't fill it in.
672
748
if (!RequiredElts[StartSubElt+i]) continue ;
673
-
749
+
750
+ // This element is now provided.
751
+ RequiredElts[StartSubElt + i] = false ;
752
+
674
753
// If there is no result computed for this subelement, record it. If
675
754
// there already is a result, check it for conflict. If there is no
676
755
// conflict, then we're ok.
677
756
auto &Entry = Result[StartSubElt+i];
678
757
if (!Entry) {
679
758
Entry = {SI->getSrc (), i, SI};
680
- } else {
681
- // TODO: This is /really/, /really/, conservative. This basically means
682
- // that if we do not have an identical store, we will not promote.
683
- if (Entry.getValue () != SI->getSrc () ||
684
- Entry.getSubElementNumber () != i) {
685
- ConflictingValues[StartSubElt + i] = true ;
686
- } else {
687
- Entry.addInsertionPoint (SI);
688
- }
759
+ continue ;
689
760
}
690
761
691
- // This element is now provided.
692
- RequiredElts[StartSubElt+i] = false ;
762
+ // TODO: This is /really/, /really/, conservative. This basically means
763
+ // that if we do not have an identical store, we will not promote.
764
+ if (Entry.getValue () != SI->getSrc () ||
765
+ Entry.getSubElementNumber () != i) {
766
+ ConflictingValues[StartSubElt + i] = true ;
767
+ continue ;
768
+ }
769
+
770
+ Entry.addInsertionPoint (SI);
693
771
}
694
-
772
+
695
773
return ;
696
774
}
697
775
@@ -704,8 +782,7 @@ void AvailableValueDataflowContext::updateAvailableValues(
704
782
SILType ValTy = CAI->getDest ()->getType ();
705
783
706
784
bool AnyRequired = false ;
707
- for (unsigned i = 0 , e = getNumSubElements (ValTy, getModule ()); i != e;
708
- ++i) {
785
+ for (unsigned i : range (getNumSubElements (ValTy, getModule ()))) {
709
786
// If this element is not required, don't fill it in.
710
787
AnyRequired = RequiredElts[StartSubElt+i];
711
788
if (AnyRequired) break ;
@@ -1044,9 +1121,11 @@ class AllocOptimize {
1044
1121
// / instruction is loading from. If we can not optimize \p Inst, then just
1045
1122
// / return an empty SILValue.
1046
1123
static SILValue tryFindSrcAddrForLoad (SILInstruction *Inst) {
1047
- // We only handle load [copy], load [trivial] and copy_addr right now.
1124
+ // We only handle load [copy], load [trivial], load and copy_addr right
1125
+ // now. Notably we do not support load [take] when promoting loads.
1048
1126
if (auto *LI = dyn_cast<LoadInst>(Inst))
1049
- return LI->getOperand ();
1127
+ if (LI->getOwnershipQualifier () != LoadOwnershipQualifier::Take)
1128
+ return LI->getOperand ();
1050
1129
1051
1130
// If this is a CopyAddr, verify that the element type is loadable. If not,
1052
1131
// we can't explode to a load.
@@ -1161,19 +1240,19 @@ bool AllocOptimize::canPromoteDestroyAddr(
1161
1240
unsigned FirstElt = computeSubelement (Address, TheMemory);
1162
1241
assert (FirstElt != ~0U && " destroy within enum projection is not valid" );
1163
1242
unsigned NumLoadSubElements = getNumSubElements (LoadTy, Module);
1164
-
1165
- // Set up the bitvector of elements being demanded by the load.
1166
- SmallBitVector RequiredElts (NumMemorySubElements);
1167
- RequiredElts.set (FirstElt, FirstElt+NumLoadSubElements);
1168
1243
1169
1244
// Find out if we have any available values. If no bits are demanded, we
1170
1245
// trivially succeed. This can happen when there is a load of an empty struct.
1171
1246
if (NumLoadSubElements == 0 )
1172
1247
return true ;
1173
1248
1249
+ // Set up the bitvector of elements being demanded by the load.
1250
+ SmallBitVector RequiredElts (NumMemorySubElements);
1251
+ RequiredElts.set (FirstElt, FirstElt + NumLoadSubElements);
1252
+
1174
1253
// Compute our available values. If we do not have any available values,
1175
1254
// return false. We have nothing further to do.
1176
- llvm:: SmallVector<AvailableValue, 8 > TmpList;
1255
+ SmallVector<AvailableValue, 8 > TmpList;
1177
1256
TmpList.resize (NumMemorySubElements);
1178
1257
if (!DataflowContext.computeAvailableValues (DAI, FirstElt, NumLoadSubElements,
1179
1258
RequiredElts, TmpList))
@@ -1208,7 +1287,7 @@ void AllocOptimize::promoteDestroyAddr(
1208
1287
SILValue NewVal = Agg.aggregateValues (LoadTy, Address, FirstElt);
1209
1288
1210
1289
++NumDestroyAddrPromoted;
1211
-
1290
+
1212
1291
LLVM_DEBUG (llvm::dbgs () << " *** Promoting destroy_addr: " << *DAI << " \n " );
1213
1292
LLVM_DEBUG (llvm::dbgs () << " To value: " << *NewVal << " \n " );
1214
1293
0 commit comments