@@ -374,6 +374,189 @@ static void collectLoads(SILInstruction *i,
374
374
}
375
375
}
376
376
377
+ // / Returns true if \p I is an address of a LoadInst, skipping struct and
378
+ // / tuple address projections. Sets \p singleBlock to null if the load (or
379
+ // / it's address is not in \p singleBlock.
380
+ // / This function looks for these patterns:
381
+ // / 1. (load %ASI)
382
+ // / 2. (load (struct_element_addr/tuple_element_addr/unchecked_addr_cast %ASI))
383
+ static bool isAddressForLoad (SILInstruction *load, SILBasicBlock *&singleBlock,
384
+ bool &involvesUntakableProjection) {
385
+ if (auto *li = dyn_cast<LoadInst>(load)) {
386
+ // SILMem2Reg is disabled when we find a load [take] of an untakable
387
+ // projection. See below for further discussion.
388
+ if (involvesUntakableProjection &&
389
+ li->getOwnershipQualifier () == LoadOwnershipQualifier::Take) {
390
+ return false ;
391
+ }
392
+ return true ;
393
+ }
394
+
395
+ if (isa<LoadBorrowInst>(load)) {
396
+ if (involvesUntakableProjection) {
397
+ return false ;
398
+ }
399
+ return true ;
400
+ }
401
+
402
+ if (!isa<UncheckedAddrCastInst>(load) && !isa<StructElementAddrInst>(load) &&
403
+ !isa<TupleElementAddrInst>(load))
404
+ return false ;
405
+
406
+ // None of the projections are lowered to owned values:
407
+ //
408
+ // struct_element_addr and tuple_element_addr instructions are lowered to
409
+ // struct_extract and tuple_extract instructions respectively. These both
410
+ // have guaranteed ownership (since they forward ownership and can only be
411
+ // used on a guaranteed value).
412
+ //
413
+ // unchecked_addr_cast instructions are lowered to unchecked_bitwise_cast
414
+ // instructions. These have unowned ownership.
415
+ //
416
+ // So in no case can a load [take] be lowered into the new projected value
417
+ // (some sequence of struct_extract, tuple_extract, and
418
+ // unchecked_bitwise_cast instructions) taking over ownership of the original
419
+ // value. Without additional changes.
420
+ //
421
+ // For example, for a sequence of element_addr projections could be
422
+ // transformed into a sequence of destructure instructions, followed by a
423
+ // sequence of structure instructions where all the original values are
424
+ // kept in place but the taken value is "knocked out" and replaced with
425
+ // undef. The running value would then be set to the newly structed
426
+ // "knockout" value.
427
+ //
428
+ // Alternatively, a new copy of the running value could be created and a new
429
+ // set of destroys placed after its last uses.
430
+ involvesUntakableProjection = true ;
431
+
432
+ // Recursively search for other (non-)loads in the instruction's uses.
433
+ auto *svi = cast<SingleValueInstruction>(load);
434
+ for (auto *use : svi->getUses ()) {
435
+ SILInstruction *user = use->getUser ();
436
+ if (user->getParent () != singleBlock)
437
+ singleBlock = nullptr ;
438
+
439
+ if (!isAddressForLoad (user, singleBlock, involvesUntakableProjection))
440
+ return false ;
441
+ }
442
+ return true ;
443
+ }
444
+
445
+ // / Returns true if \p I is a dead struct_element_addr or tuple_element_addr.
446
+ static bool isDeadAddrProjection (SILInstruction *inst) {
447
+ if (!isa<UncheckedAddrCastInst>(inst) && !isa<StructElementAddrInst>(inst) &&
448
+ !isa<TupleElementAddrInst>(inst))
449
+ return false ;
450
+
451
+ // Recursively search for uses which are dead themselves.
452
+ for (auto UI : cast<SingleValueInstruction>(inst)->getUses ()) {
453
+ SILInstruction *II = UI->getUser ();
454
+ if (!isDeadAddrProjection (II))
455
+ return false ;
456
+ }
457
+ return true ;
458
+ }
459
+
460
+ // / Returns true if this \p def is captured.
461
+ // / Sets \p inSingleBlock to true if all uses of \p def are in a single block.
462
+ static bool isCaptured (SILValue def, bool *inSingleBlock) {
463
+ SILBasicBlock *singleBlock = def->getParentBlock ();
464
+
465
+ // For all users of the def
466
+ for (auto *use : def->getUses ()) {
467
+ SILInstruction *user = use->getUser ();
468
+
469
+ if (user->getParent () != singleBlock)
470
+ singleBlock = nullptr ;
471
+
472
+ // Loads are okay.
473
+ bool involvesUntakableProjection = false ;
474
+ if (isAddressForLoad (user, singleBlock, involvesUntakableProjection))
475
+ continue ;
476
+
477
+ // We can store into an AllocStack (but not the pointer).
478
+ if (auto *si = dyn_cast<StoreInst>(user))
479
+ if (si->getDest () == def)
480
+ continue ;
481
+
482
+ if (auto *sbi = dyn_cast<StoreBorrowInst>(user)) {
483
+ if (sbi->getDest () == def) {
484
+ if (isCaptured (sbi, inSingleBlock)) {
485
+ return true ;
486
+ }
487
+ continue ;
488
+ }
489
+ }
490
+
491
+ // Deallocation is also okay, as are DebugValue w/ address value. We will
492
+ // promote the latter into normal DebugValue.
493
+ if (isa<DeallocStackInst>(user) || DebugValueInst::hasAddrVal (user))
494
+ continue ;
495
+
496
+ if (isa<EndBorrowInst>(user))
497
+ continue ;
498
+
499
+ // Destroys of loadable types can be rewritten as releases, so
500
+ // they are fine.
501
+ if (auto *dai = dyn_cast<DestroyAddrInst>(user))
502
+ if (dai->getOperand ()->getType ().isLoadable (*dai->getFunction ()))
503
+ continue ;
504
+
505
+ // Other instructions are assumed to capture the AllocStack.
506
+ LLVM_DEBUG (llvm::dbgs () << " *** AllocStack is captured by: " << *user);
507
+ return true ;
508
+ }
509
+
510
+ // None of the users capture the AllocStack.
511
+ *inSingleBlock = (singleBlock != nullptr );
512
+ return false ;
513
+ }
514
+
515
+ // / Returns true if the \p def is only stored into.
516
+ static bool isWriteOnlyAllocation (SILValue def) {
517
+ assert (isa<AllocStackInst>(def) || isa<StoreBorrowInst>(def));
518
+
519
+ // For all users of the def:
520
+ for (auto *use : def->getUses ()) {
521
+ SILInstruction *user = use->getUser ();
522
+
523
+ // It is okay to store into the AllocStack.
524
+ if (auto *si = dyn_cast<StoreInst>(user))
525
+ if (!isa<AllocStackInst>(si->getSrc ()))
526
+ continue ;
527
+
528
+ if (auto *sbi = dyn_cast<StoreBorrowInst>(user)) {
529
+ // Since all uses of the alloc_stack will be via store_borrow, check if
530
+ // there are any non-writes from the store_borrow location.
531
+ if (!isWriteOnlyAllocation (sbi)) {
532
+ return false ;
533
+ }
534
+ continue ;
535
+ }
536
+
537
+ // Deallocation is also okay.
538
+ if (isa<DeallocStackInst>(user))
539
+ continue ;
540
+
541
+ if (isa<EndBorrowInst>(user))
542
+ continue ;
543
+
544
+ // If we haven't already promoted the AllocStack, we may see
545
+ // DebugValue uses.
546
+ if (DebugValueInst::hasAddrVal (user))
547
+ continue ;
548
+
549
+ if (isDeadAddrProjection (user))
550
+ continue ;
551
+
552
+ // Can't do anything else with it.
553
+ LLVM_DEBUG (llvm::dbgs () << " *** AllocStack has non-write use: " << *user);
554
+ return false ;
555
+ }
556
+
557
+ return true ;
558
+ }
559
+
377
560
static void
378
561
replaceLoad (SILInstruction *inst, SILValue newValue, AllocStackInst *asi,
379
562
SILBuilderContext &ctx, InstructionDeleter &deleter,
@@ -1664,9 +1847,6 @@ class MemoryToRegisters {
1664
1847
return *domTreeLevels;
1665
1848
}
1666
1849
1667
- // / Check if \p def is a write-only allocation.
1668
- bool isWriteOnlyAllocation (SILValue def);
1669
-
1670
1850
// / Promote all of the AllocStacks in a single basic block in one
1671
1851
// / linear scan. Note: This function deletes all of the users of the
1672
1852
// / AllocStackInst, including the DeallocStackInst but it does not remove the
@@ -1689,189 +1869,6 @@ class MemoryToRegisters {
1689
1869
1690
1870
} // end anonymous namespace
1691
1871
1692
- // / Returns true if \p I is an address of a LoadInst, skipping struct and
1693
- // / tuple address projections. Sets \p singleBlock to null if the load (or
1694
- // / it's address is not in \p singleBlock.
1695
- // / This function looks for these patterns:
1696
- // / 1. (load %ASI)
1697
- // / 2. (load (struct_element_addr/tuple_element_addr/unchecked_addr_cast %ASI))
1698
- static bool isAddressForLoad (SILInstruction *load, SILBasicBlock *&singleBlock,
1699
- bool &involvesUntakableProjection) {
1700
- if (auto *li = dyn_cast<LoadInst>(load)) {
1701
- // SILMem2Reg is disabled when we find a load [take] of an untakable
1702
- // projection. See below for further discussion.
1703
- if (involvesUntakableProjection &&
1704
- li->getOwnershipQualifier () == LoadOwnershipQualifier::Take) {
1705
- return false ;
1706
- }
1707
- return true ;
1708
- }
1709
-
1710
- if (isa<LoadBorrowInst>(load)) {
1711
- if (involvesUntakableProjection) {
1712
- return false ;
1713
- }
1714
- return true ;
1715
- }
1716
-
1717
- if (!isa<UncheckedAddrCastInst>(load) && !isa<StructElementAddrInst>(load) &&
1718
- !isa<TupleElementAddrInst>(load))
1719
- return false ;
1720
-
1721
- // None of the projections are lowered to owned values:
1722
- //
1723
- // struct_element_addr and tuple_element_addr instructions are lowered to
1724
- // struct_extract and tuple_extract instructions respectively. These both
1725
- // have guaranteed ownership (since they forward ownership and can only be
1726
- // used on a guaranteed value).
1727
- //
1728
- // unchecked_addr_cast instructions are lowered to unchecked_bitwise_cast
1729
- // instructions. These have unowned ownership.
1730
- //
1731
- // So in no case can a load [take] be lowered into the new projected value
1732
- // (some sequence of struct_extract, tuple_extract, and
1733
- // unchecked_bitwise_cast instructions) taking over ownership of the original
1734
- // value. Without additional changes.
1735
- //
1736
- // For example, for a sequence of element_addr projections could be
1737
- // transformed into a sequence of destructure instructions, followed by a
1738
- // sequence of structure instructions where all the original values are
1739
- // kept in place but the taken value is "knocked out" and replaced with
1740
- // undef. The running value would then be set to the newly structed
1741
- // "knockout" value.
1742
- //
1743
- // Alternatively, a new copy of the running value could be created and a new
1744
- // set of destroys placed after its last uses.
1745
- involvesUntakableProjection = true ;
1746
-
1747
- // Recursively search for other (non-)loads in the instruction's uses.
1748
- auto *svi = cast<SingleValueInstruction>(load);
1749
- for (auto *use : svi->getUses ()) {
1750
- SILInstruction *user = use->getUser ();
1751
- if (user->getParent () != singleBlock)
1752
- singleBlock = nullptr ;
1753
-
1754
- if (!isAddressForLoad (user, singleBlock, involvesUntakableProjection))
1755
- return false ;
1756
- }
1757
- return true ;
1758
- }
1759
-
1760
- // / Returns true if \p I is a dead struct_element_addr or tuple_element_addr.
1761
- static bool isDeadAddrProjection (SILInstruction *inst) {
1762
- if (!isa<UncheckedAddrCastInst>(inst) && !isa<StructElementAddrInst>(inst) &&
1763
- !isa<TupleElementAddrInst>(inst))
1764
- return false ;
1765
-
1766
- // Recursively search for uses which are dead themselves.
1767
- for (auto UI : cast<SingleValueInstruction>(inst)->getUses ()) {
1768
- SILInstruction *II = UI->getUser ();
1769
- if (!isDeadAddrProjection (II))
1770
- return false ;
1771
- }
1772
- return true ;
1773
- }
1774
-
1775
- // / Returns true if this \p def is captured.
1776
- // / Sets \p inSingleBlock to true if all uses of \p def are in a single block.
1777
- static bool isCaptured (SILValue def, bool *inSingleBlock) {
1778
- SILBasicBlock *singleBlock = def->getParentBlock ();
1779
-
1780
- // For all users of the def
1781
- for (auto *use : def->getUses ()) {
1782
- SILInstruction *user = use->getUser ();
1783
-
1784
- if (user->getParent () != singleBlock)
1785
- singleBlock = nullptr ;
1786
-
1787
- // Loads are okay.
1788
- bool involvesUntakableProjection = false ;
1789
- if (isAddressForLoad (user, singleBlock, involvesUntakableProjection))
1790
- continue ;
1791
-
1792
- // We can store into an AllocStack (but not the pointer).
1793
- if (auto *si = dyn_cast<StoreInst>(user))
1794
- if (si->getDest () == def)
1795
- continue ;
1796
-
1797
- if (auto *sbi = dyn_cast<StoreBorrowInst>(user)) {
1798
- if (sbi->getDest () == def) {
1799
- if (isCaptured (sbi, inSingleBlock)) {
1800
- return true ;
1801
- }
1802
- continue ;
1803
- }
1804
- }
1805
-
1806
- // Deallocation is also okay, as are DebugValue w/ address value. We will
1807
- // promote the latter into normal DebugValue.
1808
- if (isa<DeallocStackInst>(user) || DebugValueInst::hasAddrVal (user))
1809
- continue ;
1810
-
1811
- if (isa<EndBorrowInst>(user))
1812
- continue ;
1813
-
1814
- // Destroys of loadable types can be rewritten as releases, so
1815
- // they are fine.
1816
- if (auto *dai = dyn_cast<DestroyAddrInst>(user))
1817
- if (dai->getOperand ()->getType ().isLoadable (*dai->getFunction ()))
1818
- continue ;
1819
-
1820
- // Other instructions are assumed to capture the AllocStack.
1821
- LLVM_DEBUG (llvm::dbgs () << " *** AllocStack is captured by: " << *user);
1822
- return true ;
1823
- }
1824
-
1825
- // None of the users capture the AllocStack.
1826
- *inSingleBlock = (singleBlock != nullptr );
1827
- return false ;
1828
- }
1829
-
1830
- // / Returns true if the \p def is only stored into.
1831
- bool MemoryToRegisters::isWriteOnlyAllocation (SILValue def) {
1832
- assert (isa<AllocStackInst>(def) || isa<StoreBorrowInst>(def));
1833
-
1834
- // For all users of the def:
1835
- for (auto *use : def->getUses ()) {
1836
- SILInstruction *user = use->getUser ();
1837
-
1838
- // It is okay to store into the AllocStack.
1839
- if (auto *si = dyn_cast<StoreInst>(user))
1840
- if (!isa<AllocStackInst>(si->getSrc ()))
1841
- continue ;
1842
-
1843
- if (auto *sbi = dyn_cast<StoreBorrowInst>(user)) {
1844
- // Since all uses of the alloc_stack will be via store_borrow, check if
1845
- // there are any non-writes from the store_borrow location.
1846
- if (!isWriteOnlyAllocation (sbi)) {
1847
- return false ;
1848
- }
1849
- continue ;
1850
- }
1851
-
1852
- // Deallocation is also okay.
1853
- if (isa<DeallocStackInst>(user))
1854
- continue ;
1855
-
1856
- if (isa<EndBorrowInst>(user))
1857
- continue ;
1858
-
1859
- // If we haven't already promoted the AllocStack, we may see
1860
- // DebugValue uses.
1861
- if (DebugValueInst::hasAddrVal (user))
1862
- continue ;
1863
-
1864
- if (isDeadAddrProjection (user))
1865
- continue ;
1866
-
1867
- // Can't do anything else with it.
1868
- LLVM_DEBUG (llvm::dbgs () << " *** AllocStack has non-write use: " << *user);
1869
- return false ;
1870
- }
1871
-
1872
- return true ;
1873
- }
1874
-
1875
1872
void MemoryToRegisters::removeSingleBlockAllocation (AllocStackInst *asi) {
1876
1873
LLVM_DEBUG (llvm::dbgs () << " *** Promoting in-block: " << *asi);
1877
1874
0 commit comments