@@ -394,6 +394,7 @@ class AvailableValueAggregator {
394
394
MutableArrayRef<AvailableValue> AvailableValueList;
395
395
SmallVectorImpl<PMOMemoryUse> &Uses;
396
396
DeadEndBlocks &deadEndBlocks;
397
+ bool isTake;
397
398
398
399
// / Keep track of all instructions that we have added. Once we are done
399
400
// / promoting a value, we need to make sure that if we need to balance any
@@ -405,10 +406,10 @@ class AvailableValueAggregator {
405
406
AvailableValueAggregator (SILInstruction *Inst,
406
407
MutableArrayRef<AvailableValue> AvailableValueList,
407
408
SmallVectorImpl<PMOMemoryUse> &Uses,
408
- DeadEndBlocks &deadEndBlocks)
409
+ DeadEndBlocks &deadEndBlocks, bool isTake )
409
410
: M(Inst->getModule ()), B(Inst), Loc(Inst->getLoc ()),
410
411
AvailableValueList(AvailableValueList), Uses(Uses),
411
- deadEndBlocks(deadEndBlocks) {}
412
+ deadEndBlocks(deadEndBlocks), isTake(isTake) {}
412
413
413
414
// This is intended to be passed by reference only once constructed.
414
415
AvailableValueAggregator (const AvailableValueAggregator &) = delete;
@@ -417,7 +418,13 @@ class AvailableValueAggregator {
417
418
operator =(const AvailableValueAggregator &) = delete;
418
419
AvailableValueAggregator &operator =(AvailableValueAggregator &&) = delete ;
419
420
420
- SILValue aggregateValues (SILType LoadTy, SILValue Address, unsigned FirstElt);
421
+ SILValue aggregateValues (SILType LoadTy, SILValue Address, unsigned FirstElt,
422
+ bool isTopLevel = true );
423
+ bool canTake (SILType loadTy, unsigned firstElt) const ;
424
+
425
+ // / If as a result of us copying values, we may have unconsumed destroys, find
426
+ // / the appropriate location and place the values there. Only used when
427
+ // / ownership is enabled.
421
428
void addMissingDestroysForCopiedValues (LoadInst *li);
422
429
423
430
void print (llvm::raw_ostream &os) const ;
@@ -465,11 +472,58 @@ bool AvailableValueAggregator::isFullyAvailable(SILType loadTy,
465
472
});
466
473
}
467
474
475
+ // We can only take if we never have to split a larger value to promote this
476
+ // address.
477
+ bool AvailableValueAggregator::canTake (SILType loadTy,
478
+ unsigned firstElt) const {
479
+ // If we do not have ownership, we can always take since we do not need to
480
+ // keep any ownership invariants up to date. In the future, we should be able
481
+ // to chop up larger values before they are being stored.
482
+ if (!B.hasOwnership ())
483
+ return true ;
484
+
485
+ // If we are trivially fully available, just return true.
486
+ if (isFullyAvailable (loadTy, firstElt))
487
+ return true ;
488
+
489
+ // Otherwise see if we are an aggregate with fully available leaf types.
490
+ if (TupleType *tt = loadTy.getAs <TupleType>()) {
491
+ return llvm::all_of (indices (tt->getElements ()), [&](unsigned eltNo) {
492
+ SILType eltTy = loadTy.getTupleElementType (eltNo);
493
+ unsigned numSubElt = getNumSubElements (eltTy, M);
494
+ bool success = canTake (eltTy, firstElt);
495
+ firstElt += numSubElt;
496
+ return success;
497
+ });
498
+ }
499
+
500
+ if (auto *sd = getFullyReferenceableStruct (loadTy)) {
501
+ return llvm::all_of (sd->getStoredProperties (), [&](VarDecl *decl) -> bool {
502
+ SILType eltTy = loadTy.getFieldType (decl, M);
503
+ unsigned numSubElt = getNumSubElements (eltTy, M);
504
+ bool success = canTake (eltTy, firstElt);
505
+ firstElt += numSubElt;
506
+ return success;
507
+ });
508
+ }
509
+
510
+ // Otherwise, fail. The value is not fully available at its leafs. We can not
511
+ // perform a take.
512
+ return false ;
513
+ }
514
+
468
515
// / Given a bunch of primitive subelement values, build out the right aggregate
469
516
// / type (LoadTy) by emitting tuple and struct instructions as necessary.
470
517
SILValue AvailableValueAggregator::aggregateValues (SILType LoadTy,
471
518
SILValue Address,
472
- unsigned FirstElt) {
519
+ unsigned FirstElt,
520
+ bool isTopLevel) {
521
+ // If we are performing a take, make sure that we have available values for
522
+ // /all/ of our values. Otherwise, bail.
523
+ if (isTopLevel && isTake && !canTake (LoadTy, FirstElt)) {
524
+ return SILValue ();
525
+ }
526
+
473
527
// Check to see if the requested value is fully available, as an aggregate.
474
528
// This is a super-common case for single-element structs, but is also a
475
529
// general answer for arbitrary structs and tuples as well.
@@ -515,6 +569,10 @@ AvailableValueAggregator::aggregateFullyAvailableValue(SILType loadTy,
515
569
// Use the scope and location of the store at the insertion point.
516
570
SILBuilderWithScope builder (insertPts[0 ], &insertedInsts);
517
571
SILLocation loc = insertPts[0 ]->getLoc ();
572
+ // If we have a take, just return the value.
573
+ if (isTake)
574
+ return firstVal.getValue ();
575
+ // Otherwise, return a copy of the value.
518
576
return builder.emitCopyValueOperation (loc, firstVal.getValue ());
519
577
}
520
578
@@ -524,11 +582,19 @@ AvailableValueAggregator::aggregateFullyAvailableValue(SILType loadTy,
524
582
// implying that we can just copy firstVal at each insertion point.
525
583
SILSSAUpdater updater (B.getModule ());
526
584
updater.Initialize (loadTy);
527
- for (auto *insertPt : firstVal.getInsertionPoints ()) {
585
+
586
+ for (auto *insertPt : insertPts) {
528
587
// Use the scope and location of the store at the insertion point.
529
588
SILBuilderWithScope builder (insertPt, &insertedInsts);
530
589
SILLocation loc = insertPt->getLoc ();
531
- SILValue eltVal = builder.emitCopyValueOperation (loc, firstVal.getValue ());
590
+ SILValue eltVal = firstVal.getValue ();
591
+
592
+ // If we are not taking, copy the element value.
593
+ if (!isTake) {
594
+ eltVal = builder.emitCopyValueOperation (loc, eltVal);
595
+ }
596
+
597
+ // And then put the value into the SSA updater.
532
598
updater.AddAvailableValue (insertPt->getParent (), eltVal);
533
599
}
534
600
@@ -551,38 +617,45 @@ SILValue AvailableValueAggregator::aggregateTupleSubElts(TupleType *TT,
551
617
// If we are missing any of the available values in this struct element,
552
618
// compute an address to load from.
553
619
SILValue EltAddr;
554
- if (anyMissing (FirstElt, NumSubElt, AvailableValueList))
620
+ if (anyMissing (FirstElt, NumSubElt, AvailableValueList)) {
621
+ assert (!isTake && " When taking, values should never be missing?!" );
555
622
EltAddr =
556
623
B.createTupleElementAddr (Loc, Address, EltNo, EltTy.getAddressType ());
624
+ }
557
625
558
- ResultElts.push_back (aggregateValues (EltTy, EltAddr, FirstElt));
626
+ ResultElts.push_back (
627
+ aggregateValues (EltTy, EltAddr, FirstElt, /* isTopLevel*/ false ));
559
628
FirstElt += NumSubElt;
560
629
}
561
630
562
631
return B.createTuple (Loc, LoadTy, ResultElts);
563
632
}
564
633
565
- SILValue AvailableValueAggregator::aggregateStructSubElts (StructDecl *SD ,
566
- SILType LoadTy ,
567
- SILValue Address ,
568
- unsigned FirstElt ) {
569
- SmallVector<SILValue, 4 > ResultElts ;
634
+ SILValue AvailableValueAggregator::aggregateStructSubElts (StructDecl *sd ,
635
+ SILType loadTy ,
636
+ SILValue address ,
637
+ unsigned firstElt ) {
638
+ SmallVector<SILValue, 4 > resultElts ;
570
639
571
- for (auto *FD : SD ->getStoredProperties ()) {
572
- SILType EltTy = LoadTy .getFieldType (FD , M);
573
- unsigned NumSubElt = getNumSubElements (EltTy , M);
640
+ for (auto *decl : sd ->getStoredProperties ()) {
641
+ SILType eltTy = loadTy .getFieldType (decl , M);
642
+ unsigned numSubElt = getNumSubElements (eltTy , M);
574
643
575
644
// If we are missing any of the available values in this struct element,
576
645
// compute an address to load from.
577
- SILValue EltAddr;
578
- if (anyMissing (FirstElt, NumSubElt, AvailableValueList))
579
- EltAddr =
580
- B.createStructElementAddr (Loc, Address, FD, EltTy.getAddressType ());
646
+ SILValue eltAddr;
647
+ if (anyMissing (firstElt, numSubElt, AvailableValueList)) {
648
+ assert (!isTake && " When taking, values should never be missing?!" );
649
+ eltAddr =
650
+ B.createStructElementAddr (Loc, address, decl, eltTy.getAddressType ());
651
+ }
581
652
582
- ResultElts.push_back (aggregateValues (EltTy, EltAddr, FirstElt));
583
- FirstElt += NumSubElt;
653
+ resultElts.push_back (
654
+ aggregateValues (eltTy, eltAddr, firstElt, /* isTopLevel*/ false ));
655
+ firstElt += numSubElt;
584
656
}
585
- return B.createStruct (Loc, LoadTy, ResultElts);
657
+
658
+ return B.createStruct (Loc, loadTy, resultElts);
586
659
}
587
660
588
661
// We have looked through all of the aggregate values and finally found a
@@ -595,6 +668,7 @@ SILValue AvailableValueAggregator::handlePrimitiveValue(SILType loadTy,
595
668
596
669
// If the value is not available, load the value and update our use list.
597
670
if (!val) {
671
+ assert (!isTake && " Should only take fully available values?!" );
598
672
LoadInst *load = ([&]() {
599
673
if (B.hasOwnership ()) {
600
674
return B.createTrivialLoadOr (Loc, address,
@@ -1178,10 +1252,10 @@ class AllocOptimize {
1178
1252
1179
1253
private:
1180
1254
bool promoteLoad (SILInstruction *Inst);
1181
- void promoteDestroyAddr (DestroyAddrInst *DAI ,
1182
- MutableArrayRef<AvailableValue> Values );
1183
- bool canPromoteDestroyAddr (DestroyAddrInst *DAI ,
1184
- SmallVectorImpl<AvailableValue> &AvailableValues );
1255
+ void promoteDestroyAddr (DestroyAddrInst *dai ,
1256
+ MutableArrayRef<AvailableValue> values );
1257
+ bool canPromoteDestroyAddr (DestroyAddrInst *dai ,
1258
+ SmallVectorImpl<AvailableValue> &availableValues );
1185
1259
};
1186
1260
1187
1261
} // end anonymous namespace
@@ -1272,7 +1346,8 @@ bool AllocOptimize::promoteLoad(SILInstruction *Inst) {
1272
1346
// type as the load did, and emit smaller loads for any subelements that were
1273
1347
// not available.
1274
1348
auto *Load = cast<LoadInst>(Inst);
1275
- AvailableValueAggregator Agg (Load, AvailableValues, Uses, deadEndBlocks);
1349
+ AvailableValueAggregator Agg (Load, AvailableValues, Uses, deadEndBlocks,
1350
+ false /* isTake*/ );
1276
1351
SILValue NewVal = Agg.aggregateValues (LoadTy, Load->getOperand (), FirstElt);
1277
1352
1278
1353
// If we inserted any copies, we created the copies at our stores. We know
@@ -1299,78 +1374,90 @@ bool AllocOptimize::promoteLoad(SILInstruction *Inst) {
1299
1374
1300
1375
// / Return true if we can promote the given destroy.
1301
1376
bool AllocOptimize::canPromoteDestroyAddr (
1302
- DestroyAddrInst *DAI , SmallVectorImpl<AvailableValue> &AvailableValues ) {
1303
- SILValue Address = DAI ->getOperand ();
1377
+ DestroyAddrInst *dai , SmallVectorImpl<AvailableValue> &availableValues ) {
1378
+ SILValue address = dai ->getOperand ();
1304
1379
1305
1380
// We cannot promote destroys of address-only types, because we can't expose
1306
1381
// the load.
1307
- SILType LoadTy = Address ->getType ().getObjectType ();
1308
- if (LoadTy .isAddressOnly (Module))
1382
+ SILType loadTy = address ->getType ().getObjectType ();
1383
+ if (loadTy .isAddressOnly (Module))
1309
1384
return false ;
1310
1385
1311
1386
// If the box has escaped at this instruction, we can't safely promote the
1312
1387
// load.
1313
- if (DataflowContext.hasEscapedAt (DAI ))
1388
+ if (DataflowContext.hasEscapedAt (dai ))
1314
1389
return false ;
1315
1390
1316
1391
// Compute the access path down to the field so we can determine precise
1317
1392
// def/use behavior.
1318
- unsigned FirstElt = computeSubelement (Address , TheMemory);
1319
- assert (FirstElt != ~0U && " destroy within enum projection is not valid" );
1320
- unsigned NumLoadSubElements = getNumSubElements (LoadTy , Module);
1393
+ unsigned firstElt = computeSubelement (address , TheMemory);
1394
+ assert (firstElt != ~0U && " destroy within enum projection is not valid" );
1395
+ unsigned numLoadSubElements = getNumSubElements (loadTy , Module);
1321
1396
1322
1397
// Find out if we have any available values. If no bits are demanded, we
1323
1398
// trivially succeed. This can happen when there is a load of an empty struct.
1324
- if (NumLoadSubElements == 0 )
1399
+ if (numLoadSubElements == 0 )
1325
1400
return true ;
1326
1401
1327
1402
// Set up the bitvector of elements being demanded by the load.
1328
- SmallBitVector RequiredElts (NumMemorySubElements);
1329
- RequiredElts .set (FirstElt, FirstElt + NumLoadSubElements );
1403
+ SmallBitVector requiredElts (NumMemorySubElements);
1404
+ requiredElts .set (firstElt, firstElt + numLoadSubElements );
1330
1405
1331
1406
// Compute our available values. If we do not have any available values,
1332
1407
// return false. We have nothing further to do.
1333
- SmallVector<AvailableValue, 8 > TmpList;
1334
- TmpList.resize (NumMemorySubElements);
1335
- if (!DataflowContext.computeAvailableValues (DAI, FirstElt, NumLoadSubElements,
1336
- RequiredElts, TmpList))
1408
+ SmallVector<AvailableValue, 8 > tmpList;
1409
+ tmpList.resize (NumMemorySubElements);
1410
+ if (!DataflowContext.computeAvailableValues (dai, firstElt, numLoadSubElements,
1411
+ requiredElts, tmpList))
1412
+ return false ;
1413
+
1414
+ // Now check that we can perform a take upon our available values. This
1415
+ // implies today that our value is fully available. If the value is not fully
1416
+ // available, we would need to split stores to promote this destroy_addr. We
1417
+ // do not support that yet.
1418
+ AvailableValueAggregator agg (dai, tmpList, Uses, deadEndBlocks,
1419
+ true /* isTake*/ );
1420
+ if (!agg.canTake (loadTy, firstElt))
1337
1421
return false ;
1338
1422
1339
- // Now that we have our final list, move the temporary lists contents into
1340
- // AvailableValues.
1341
- std::move (TmpList .begin (), TmpList .end (),
1342
- std::back_inserter (AvailableValues ));
1423
+ // Ok, we can promote this destroy_addr... move the temporary lists contents
1424
+ // into the final AvailableValues list .
1425
+ std::move (tmpList .begin (), tmpList .end (),
1426
+ std::back_inserter (availableValues ));
1343
1427
1344
1428
return true ;
1345
1429
}
1346
1430
1347
- // / promoteDestroyAddr - DestroyAddr is a composed operation merging
1348
- // / load+strong_release. If the implicit load's value is available, explode it.
1349
- // /
1350
- // / Note that we handle the general case of a destroy_addr of a piece of the
1351
- // / memory object, not just destroy_addrs of the entire thing.
1431
+ // DestroyAddr is a composed operation merging load [take] + destroy_value. If
1432
+ // the implicit load's value is available, explode it.
1433
+ //
1434
+ // NOTE: We only do this if we have a fully available value.
1435
+ //
1436
+ // Note that we handle the general case of a destroy_addr of a piece of the
1437
+ // memory object, not just destroy_addrs of the entire thing.
1352
1438
void AllocOptimize::promoteDestroyAddr (
1353
- DestroyAddrInst *DAI , MutableArrayRef<AvailableValue> AvailableValues ) {
1354
- SILValue Address = DAI ->getOperand ();
1355
- SILType LoadTy = Address ->getType ().getObjectType ();
1439
+ DestroyAddrInst *dai , MutableArrayRef<AvailableValue> availableValues ) {
1440
+ SILValue address = dai ->getOperand ();
1441
+ SILType loadTy = address ->getType ().getObjectType ();
1356
1442
1357
1443
// Compute the access path down to the field so we can determine precise
1358
1444
// def/use behavior.
1359
- unsigned FirstElt = computeSubelement (Address , TheMemory);
1445
+ unsigned firstElt = computeSubelement (address , TheMemory);
1360
1446
1361
1447
// Aggregate together all of the subelements into something that has the same
1362
1448
// type as the load did, and emit smaller) loads for any subelements that were
1363
1449
// not available.
1364
- AvailableValueAggregator Agg (DAI, AvailableValues, Uses, deadEndBlocks);
1365
- SILValue NewVal = Agg.aggregateValues (LoadTy, Address, FirstElt);
1450
+ AvailableValueAggregator agg (dai, availableValues, Uses, deadEndBlocks,
1451
+ true /* isTake*/ );
1452
+ SILValue newVal = agg.aggregateValues (loadTy, address, firstElt);
1366
1453
1367
1454
++NumDestroyAddrPromoted;
1368
1455
1369
- LLVM_DEBUG (llvm::dbgs () << " *** Promoting destroy_addr: " << *DAI << " \n " );
1370
- LLVM_DEBUG (llvm::dbgs () << " To value: " << *NewVal << " \n " );
1456
+ LLVM_DEBUG (llvm::dbgs () << " *** Promoting destroy_addr: " << *dai << " \n " );
1457
+ LLVM_DEBUG (llvm::dbgs () << " To value: " << *newVal << " \n " );
1371
1458
1372
- SILBuilderWithScope (DAI ).emitDestroyValueOperation (DAI ->getLoc (), NewVal );
1373
- DAI ->eraseFromParent ();
1459
+ SILBuilderWithScope (dai ).emitDestroyValueOperation (dai ->getLoc (), newVal );
1460
+ dai ->eraseFromParent ();
1374
1461
}
1375
1462
1376
1463
namespace {
0 commit comments