@@ -374,6 +374,189 @@ static void collectLoads(SILInstruction *i,
374374 }
375375}
376376
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+
377560static void
378561replaceLoad (SILInstruction *inst, SILValue newValue, AllocStackInst *asi,
379562 SILBuilderContext &ctx, InstructionDeleter &deleter,
@@ -1664,9 +1847,6 @@ class MemoryToRegisters {
16641847 return *domTreeLevels;
16651848 }
16661849
1667- // / Check if \p def is a write-only allocation.
1668- bool isWriteOnlyAllocation (SILValue def);
1669-
16701850 // / Promote all of the AllocStacks in a single basic block in one
16711851 // / linear scan. Note: This function deletes all of the users of the
16721852 // / AllocStackInst, including the DeallocStackInst but it does not remove the
@@ -1689,189 +1869,6 @@ class MemoryToRegisters {
16891869
16901870} // end anonymous namespace
16911871
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-
18751872void MemoryToRegisters::removeSingleBlockAllocation (AllocStackInst *asi) {
18761873 LLVM_DEBUG (llvm::dbgs () << " *** Promoting in-block: " << *asi);
18771874
0 commit comments