@@ -1002,16 +1002,28 @@ namespace {
10021002// / function in postorder. If the definition is an argument of this function,
10031003// / simply replace the function argument with an address representing the
10041004// / caller's storage.
1005- // /
1006- // / TODO: shrink lifetimes by inserting alloc_stack at the dominance LCA and
1007- // / finding the lifetime boundary with a simple backward walk from uses.
10081005class OpaqueStorageAllocation {
10091006 AddressLoweringState &pass;
1007+ // / The alloc_stacks that have been created which eventually need to have
1008+ // / corresponding dealloc_stacks created.
1009+ // /
1010+ // / Supports erasure because created alloc_stacks may be erased when block
1011+ // / arguments are coalesced.
1012+ SmallBlotSetVector<AllocStackInst *, 16 > allocs;
1013+ // / The alloc_stacks that have been created which eventually need to be
1014+ // / positioned appropriately.
1015+ // /
1016+ // / The subset of allocs which aren't for opened existentials.
1017+ InstructionSet allocsToReposition;
10101018
10111019public:
1012- explicit OpaqueStorageAllocation (AddressLoweringState &pass) : pass(pass) {}
1020+ explicit OpaqueStorageAllocation (AddressLoweringState &pass)
1021+ : pass(pass), allocsToReposition(pass.function) {}
10131022
10141023 void allocateOpaqueStorage ();
1024+ // / Position alloc_stacks according to uses and create dealloc_stacks that
1025+ // / jointly postdominate.
1026+ void finalizeOpaqueStorage ();
10151027
10161028protected:
10171029 void allocateValue (SILValue value);
@@ -1037,6 +1049,8 @@ class OpaqueStorageAllocation {
10371049
10381050 AllocStackInst *createStackAllocation (SILValue value);
10391051
1052+ SILBasicBlock *getLeastCommonAncestorOfUses (SILValue value);
1053+
10401054 void createStackAllocationStorage (SILValue value) {
10411055 pass.valueStorageMap .getStorage (value).storageAddress =
10421056 createStackAllocation (value);
@@ -1226,9 +1240,20 @@ void OpaqueStorageAllocation::removeAllocation(SILValue value) {
12261240 for (Operand *use : uses) {
12271241 pass.deleter .forceDelete (cast<DeallocStackInst>(use->getUser ()));
12281242 }
1243+ allocs.erase (allocInst);
12291244 pass.deleter .forceDelete (allocInst);
12301245}
12311246
1247+ SILBasicBlock *
1248+ OpaqueStorageAllocation::getLeastCommonAncestorOfUses (SILValue value) {
1249+ SILBasicBlock *lca = nullptr ;
1250+ for (auto *use : value->getUses ()) {
1251+ auto *block = use->getParentBlock ();
1252+ lca = lca ? pass.domInfo ->findNearestCommonDominator (lca, block) : block;
1253+ }
1254+ return lca;
1255+ }
1256+
12321257// Create alloc_stack that dominates an owned value \p value. Create
12331258// jointly-postdominating dealloc_stack instructions. Nesting will be fixed
12341259// later.
@@ -1250,8 +1275,8 @@ AllocStackInst *OpaqueStorageAllocation::createStackAllocation(SILValue value) {
12501275
12511276 // For opened existential types, allocate stack space at the type
12521277 // definition. Allocating as early as possible provides more opportunity for
1253- // creating use projections into value. But allocation must be no earlier then
1254- // the latest type definition.
1278+ // creating use projections into value. But allocation must be no earlier
1279+ // then the latest type definition.
12551280 SILInstruction *latestOpeningInst = nullptr ;
12561281 allocTy.getASTType ().visit ([&](CanType type) {
12571282 auto archetype = dyn_cast<ArchetypeType>(type);
@@ -1274,31 +1299,44 @@ AllocStackInst *OpaqueStorageAllocation::createStackAllocation(SILValue value) {
12741299 latestOpeningInst = openingInst;
12751300 }
12761301 });
1277- auto allocPt = latestOpeningInst ? std::next (latestOpeningInst->getIterator ())
1278- : pass.function ->begin ()->begin ();
1302+
1303+ auto allocPt = latestOpeningInst
1304+ ? latestOpeningInst->getNextInstruction ()->getIterator ()
1305+ : pass.function ->getEntryBlock ()->front ().getIterator ();
12791306 auto allocBuilder = pass.getBuilder (allocPt);
12801307 AllocStackInst *alloc = allocBuilder.createAllocStack (pass.genLoc (), allocTy);
1308+ allocs.insert (alloc);
1309+ if (latestOpeningInst == nullptr ) {
1310+ allocsToReposition.insert (alloc);
1311+ }
1312+ return alloc;
1313+ }
1314+
1315+ void OpaqueStorageAllocation::finalizeOpaqueStorage () {
1316+ SmallVector<SILBasicBlock *, 4 > boundary;
1317+ for (auto maybeAlloc : allocs) {
1318+ // An allocation may be erased when coalescing block arguments.
1319+ if (!maybeAlloc.hasValue ())
1320+ continue ;
1321+
1322+ auto *alloc = maybeAlloc.value ();
1323+
1324+ if (allocsToReposition.contains (alloc)) {
1325+ auto allocPt = &*getLeastCommonAncestorOfUses (alloc)->begin ();
1326+ alloc->moveBefore (allocPt);
1327+ }
12811328
1282- auto dealloc = [&](SILBasicBlock::iterator insertPt) {
1283- auto deallocBuilder = pass.getBuilder (insertPt);
1284- deallocBuilder.createDeallocStack (pass.genLoc (), alloc);
1285- };
1286- if (latestOpeningInst) {
12871329 // Deallocate at the predecessors of dominance frontier blocks that are
12881330 // dominated by the alloc to ensure that allocation encloses not only the
12891331 // uses of the current value, but also of any values reusing this storage as
12901332 // a use projection.
1291- SmallVector<SILBasicBlock *, 4 > boundary;
12921333 computeDominatedBoundaryBlocks (alloc->getParent (), pass.domInfo , boundary);
12931334 for (SILBasicBlock *deallocBlock : boundary) {
1294- dealloc (deallocBlock->getTerminator ()->getIterator ());
1295- }
1296- } else {
1297- for (SILInstruction *deallocPoint : pass.exitingInsts ) {
1298- dealloc (deallocPoint->getIterator ());
1335+ auto deallocBuilder = pass.getBuilder (deallocBlock->back ().getIterator ());
1336+ deallocBuilder.createDeallocStack (pass.genLoc (), alloc);
12991337 }
1338+ boundary.clear ();
13001339 }
1301- return alloc;
13021340}
13031341
13041342// ===----------------------------------------------------------------------===//
@@ -3850,6 +3888,8 @@ void AddressLowering::runOnFunction(SILFunction *function) {
38503888 // forward order, setting 'storageAddress' for each projection as it goes.
38513889 rewriteFunction (pass);
38523890
3891+ allocator.finalizeOpaqueStorage ();
3892+
38533893 deleteRewrittenInstructions (pass);
38543894
38553895 StackNesting::fixNesting (function);
0 commit comments