@@ -1489,7 +1489,9 @@ class AllocOptimize {
1489
1489
bool tryToRemoveDeadAllocation ();
1490
1490
1491
1491
private:
1492
- bool promoteLoadCopy (SILInstruction *Inst);
1492
+ bool promoteLoadCopy (LoadInst *Inst);
1493
+ bool promoteLoadBorrow (LoadBorrowInst *Inst);
1494
+ bool promoteCopyAddr (CopyAddrInst *CAI);
1493
1495
void promoteLoadTake (LoadInst *Inst, MutableArrayRef<AvailableValue> values);
1494
1496
void promoteDestroyAddr (DestroyAddrInst *dai,
1495
1497
MutableArrayRef<AvailableValue> values);
@@ -1528,7 +1530,89 @@ static SILValue tryFindSrcAddrForLoad(SILInstruction *i) {
1528
1530
// / cross element accesses have been scalarized.
1529
1531
// /
1530
1532
// / This returns true if the load has been removed from the program.
1531
- bool AllocOptimize::promoteLoadCopy (SILInstruction *Inst) {
1533
+ bool AllocOptimize::promoteLoadCopy (LoadInst *Inst) {
1534
+ // Note that we intentionally don't support forwarding of weak pointers,
1535
+ // because the underlying value may drop be deallocated at any time. We would
1536
+ // have to prove that something in this function is holding the weak value
1537
+ // live across the promoted region and that isn't desired for a stable
1538
+ // diagnostics pass this like one.
1539
+
1540
+ // First attempt to find a source addr for our "load" instruction. If we fail
1541
+ // to find a valid value, just return.
1542
+ SILValue SrcAddr = tryFindSrcAddrForLoad (Inst);
1543
+ if (!SrcAddr)
1544
+ return false ;
1545
+
1546
+ // If the box has escaped at this instruction, we can't safely promote the
1547
+ // load.
1548
+ if (DataflowContext.hasEscapedAt (Inst))
1549
+ return false ;
1550
+
1551
+ SILType LoadTy = SrcAddr->getType ().getObjectType ();
1552
+
1553
+ // If this is a load/copy_addr from a struct field that we want to promote,
1554
+ // compute the access path down to the field so we can determine precise
1555
+ // def/use behavior.
1556
+ unsigned FirstElt = computeSubelement (SrcAddr, TheMemory);
1557
+
1558
+ // If this is a load from within an enum projection, we can't promote it since
1559
+ // we don't track subelements in a type that could be changing.
1560
+ if (FirstElt == ~0U )
1561
+ return false ;
1562
+
1563
+ unsigned NumLoadSubElements = getNumSubElements (LoadTy, Module);
1564
+
1565
+ // Set up the bitvector of elements being demanded by the load.
1566
+ SmallBitVector RequiredElts (NumMemorySubElements);
1567
+ RequiredElts.set (FirstElt, FirstElt + NumLoadSubElements);
1568
+
1569
+ SmallVector<AvailableValue, 8 > AvailableValues;
1570
+ AvailableValues.resize (NumMemorySubElements);
1571
+
1572
+ // Find out if we have any available values. If no bits are demanded, we
1573
+ // trivially succeed. This can happen when there is a load of an empty struct.
1574
+ if (NumLoadSubElements != 0 &&
1575
+ !DataflowContext.computeAvailableValues (
1576
+ Inst, FirstElt, NumLoadSubElements, RequiredElts, AvailableValues))
1577
+ return false ;
1578
+
1579
+ // Aggregate together all of the subelements into something that has the same
1580
+ // type as the load did, and emit smaller loads for any subelements that were
1581
+ // not available. We are "propagating" a +1 available value from the store
1582
+ // points.
1583
+ auto *load = dyn_cast<SingleValueInstruction>(Inst);
1584
+ AvailableValueAggregator agg (load, AvailableValues, Uses, deadEndBlocks,
1585
+ false /* isTake*/ );
1586
+ SILValue newVal = agg.aggregateValues (LoadTy, load->getOperand (0 ), FirstElt);
1587
+
1588
+ LLVM_DEBUG (llvm::dbgs () << " *** Promoting load: " << *load << " \n " );
1589
+ LLVM_DEBUG (llvm::dbgs () << " To value: " << *newVal << " \n " );
1590
+
1591
+ // If we inserted any copies, we created the copies at our stores. We know
1592
+ // that in our load block, we will reform the aggregate as appropriate at the
1593
+ // load implying that the value /must/ be fully consumed. If we promoted a +0
1594
+ // value, we created dominating destroys along those paths. Thus any leaking
1595
+ // blocks that we may have can be found by performing a linear lifetime check
1596
+ // over all copies that we found using the load as the "consuming uses" (just
1597
+ // for the purposes of identifying the consuming block).
1598
+ auto *oldLoad = agg.addMissingDestroysForCopiedValues (load, newVal);
1599
+
1600
+ ++NumLoadPromoted;
1601
+
1602
+ // If we are returned the load, eliminate it. Otherwise, it was already
1603
+ // handled for us... so return true.
1604
+ if (!oldLoad)
1605
+ return true ;
1606
+
1607
+ oldLoad->replaceAllUsesWith (newVal);
1608
+ SILValue addr = oldLoad->getOperand (0 );
1609
+ oldLoad->eraseFromParent ();
1610
+ if (auto *addrI = addr->getDefiningInstruction ())
1611
+ recursivelyDeleteTriviallyDeadInstructions (addrI);
1612
+ return true ;
1613
+ }
1614
+
1615
+ bool AllocOptimize::promoteCopyAddr (CopyAddrInst *Inst) {
1532
1616
// Note that we intentionally don't support forwarding of weak pointers,
1533
1617
// because the underlying value may drop be deallocated at any time. We would
1534
1618
// have to prove that something in this function is holding the weak value
@@ -1577,16 +1661,64 @@ bool AllocOptimize::promoteLoadCopy(SILInstruction *Inst) {
1577
1661
// Ok, we have some available values. If we have a copy_addr, explode it now,
1578
1662
// exposing the load operation within it. Subsequent optimization passes will
1579
1663
// see the load and propagate the available values into it.
1580
- if (auto *CAI = dyn_cast<CopyAddrInst>(Inst)) {
1581
- DataflowContext.explodeCopyAddr (CAI);
1664
+ DataflowContext.explodeCopyAddr (Inst);
1665
+
1666
+ // This is removing the copy_addr, but explodeCopyAddr takes care of
1667
+ // removing the instruction from Uses for us, so we return false.
1668
+ return false ;
1669
+ }
1670
+
1671
+ // / At this point, we know that this element satisfies the definitive init
1672
+ // / requirements, so we can try to promote loads to enable SSA-based dataflow
1673
+ // / analysis. We know that accesses to this element only access this element,
1674
+ // / cross element accesses have been scalarized.
1675
+ // /
1676
+ // / This returns true if the load has been removed from the program.
1677
+ bool AllocOptimize::promoteLoadBorrow (LoadBorrowInst *Inst) {
1678
+ // Note that we intentionally don't support forwarding of weak pointers,
1679
+ // because the underlying value may drop be deallocated at any time. We would
1680
+ // have to prove that something in this function is holding the weak value
1681
+ // live across the promoted region and that isn't desired for a stable
1682
+ // diagnostics pass this like one.
1683
+
1684
+ // First attempt to find a source addr for our "load" instruction. If we fail
1685
+ // to find a valid value, just return.
1686
+ SILValue SrcAddr = tryFindSrcAddrForLoad (Inst);
1687
+ if (!SrcAddr)
1688
+ return false ;
1582
1689
1583
- // This is removing the copy_addr, but explodeCopyAddr takes care of
1584
- // removing the instruction from Uses for us, so we return false.
1690
+ // If the box has escaped at this instruction, we can't safely promote the
1691
+ // load.
1692
+ if (DataflowContext.hasEscapedAt (Inst))
1693
+ return false ;
1694
+
1695
+ SILType LoadTy = SrcAddr->getType ().getObjectType ();
1696
+
1697
+ // If this is a load/copy_addr from a struct field that we want to promote,
1698
+ // compute the access path down to the field so we can determine precise
1699
+ // def/use behavior.
1700
+ unsigned FirstElt = computeSubelement (SrcAddr, TheMemory);
1701
+
1702
+ // If this is a load from within an enum projection, we can't promote it since
1703
+ // we don't track subelements in a type that could be changing.
1704
+ if (FirstElt == ~0U )
1585
1705
return false ;
1586
- }
1587
1706
1588
- assert ((isa<LoadBorrowInst>(Inst) || isa<LoadInst>(Inst)) &&
1589
- " Unhandled instruction for this code path!" );
1707
+ unsigned NumLoadSubElements = getNumSubElements (LoadTy, Module);
1708
+
1709
+ // Set up the bitvector of elements being demanded by the load.
1710
+ SmallBitVector RequiredElts (NumMemorySubElements);
1711
+ RequiredElts.set (FirstElt, FirstElt + NumLoadSubElements);
1712
+
1713
+ SmallVector<AvailableValue, 8 > AvailableValues;
1714
+ AvailableValues.resize (NumMemorySubElements);
1715
+
1716
+ // Find out if we have any available values. If no bits are demanded, we
1717
+ // trivially succeed. This can happen when there is a load of an empty struct.
1718
+ if (NumLoadSubElements != 0 &&
1719
+ !DataflowContext.computeAvailableValues (
1720
+ Inst, FirstElt, NumLoadSubElements, RequiredElts, AvailableValues))
1721
+ return false ;
1590
1722
1591
1723
// Aggregate together all of the subelements into something that has the same
1592
1724
// type as the load did, and emit smaller loads for any subelements that were
@@ -1618,10 +1750,9 @@ bool AllocOptimize::promoteLoadCopy(SILInstruction *Inst) {
1618
1750
1619
1751
// If our load was a +0 value, borrow the value and the RAUW. We reuse the
1620
1752
// end_borrows of our load_borrow.
1621
- if (isa<LoadBorrowInst>(oldLoad)) {
1622
- newVal = SILBuilderWithScope (oldLoad).createBeginBorrow (oldLoad->getLoc (),
1623
- newVal);
1624
- }
1753
+ newVal =
1754
+ SILBuilderWithScope (oldLoad).createBeginBorrow (oldLoad->getLoc (), newVal);
1755
+
1625
1756
oldLoad->replaceAllUsesWith (newVal);
1626
1757
SILValue addr = oldLoad->getOperand (0 );
1627
1758
oldLoad->eraseFromParent ();
@@ -1954,9 +2085,28 @@ bool AllocOptimize::optimizeMemoryAccesses() {
1954
2085
auto &use = Uses[i];
1955
2086
// Ignore entries for instructions that got expanded along the way.
1956
2087
if (use.Inst && use.Kind == PMOUseKind::Load) {
1957
- if (promoteLoadCopy (use.Inst )) {
1958
- Uses[i].Inst = nullptr ; // remove entry if load got deleted.
1959
- changed = true ;
2088
+ if (auto *cai = dyn_cast<CopyAddrInst>(use.Inst )) {
2089
+ if (promoteCopyAddr (cai)) {
2090
+ Uses[i].Inst = nullptr ; // remove entry if load got deleted.
2091
+ changed = true ;
2092
+ }
2093
+ continue ;
2094
+ }
2095
+
2096
+ if (auto *lbi = dyn_cast<LoadBorrowInst>(use.Inst )) {
2097
+ if (promoteLoadBorrow (lbi)) {
2098
+ Uses[i].Inst = nullptr ; // remove entry if load got deleted.
2099
+ changed = true ;
2100
+ }
2101
+ continue ;
2102
+ }
2103
+
2104
+ if (auto *li = dyn_cast<LoadInst>(use.Inst )) {
2105
+ if (promoteLoadCopy (li)) {
2106
+ Uses[i].Inst = nullptr ; // remove entry if load got deleted.
2107
+ changed = true ;
2108
+ }
2109
+ continue ;
1960
2110
}
1961
2111
}
1962
2112
}
0 commit comments