@@ -1002,16 +1002,28 @@ namespace {
1002
1002
// / function in postorder. If the definition is an argument of this function,
1003
1003
// / simply replace the function argument with an address representing the
1004
1004
// / 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.
1008
1005
class OpaqueStorageAllocation {
1009
1006
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;
1010
1018
1011
1019
public:
1012
- explicit OpaqueStorageAllocation (AddressLoweringState &pass) : pass(pass) {}
1020
+ explicit OpaqueStorageAllocation (AddressLoweringState &pass)
1021
+ : pass(pass), allocsToReposition(pass.function) {}
1013
1022
1014
1023
void allocateOpaqueStorage ();
1024
+ // / Position alloc_stacks according to uses and create dealloc_stacks that
1025
+ // / jointly postdominate.
1026
+ void finalizeOpaqueStorage ();
1015
1027
1016
1028
protected:
1017
1029
void allocateValue (SILValue value);
@@ -1037,6 +1049,8 @@ class OpaqueStorageAllocation {
1037
1049
1038
1050
AllocStackInst *createStackAllocation (SILValue value);
1039
1051
1052
+ SILBasicBlock *getLeastCommonAncestorOfUses (SILValue value);
1053
+
1040
1054
void createStackAllocationStorage (SILValue value) {
1041
1055
pass.valueStorageMap .getStorage (value).storageAddress =
1042
1056
createStackAllocation (value);
@@ -1226,9 +1240,20 @@ void OpaqueStorageAllocation::removeAllocation(SILValue value) {
1226
1240
for (Operand *use : uses) {
1227
1241
pass.deleter .forceDelete (cast<DeallocStackInst>(use->getUser ()));
1228
1242
}
1243
+ allocs.erase (allocInst);
1229
1244
pass.deleter .forceDelete (allocInst);
1230
1245
}
1231
1246
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
+
1232
1257
// Create alloc_stack that dominates an owned value \p value. Create
1233
1258
// jointly-postdominating dealloc_stack instructions. Nesting will be fixed
1234
1259
// later.
@@ -1250,8 +1275,8 @@ AllocStackInst *OpaqueStorageAllocation::createStackAllocation(SILValue value) {
1250
1275
1251
1276
// For opened existential types, allocate stack space at the type
1252
1277
// 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.
1255
1280
SILInstruction *latestOpeningInst = nullptr ;
1256
1281
allocTy.getASTType ().visit ([&](CanType type) {
1257
1282
auto archetype = dyn_cast<ArchetypeType>(type);
@@ -1274,31 +1299,44 @@ AllocStackInst *OpaqueStorageAllocation::createStackAllocation(SILValue value) {
1274
1299
latestOpeningInst = openingInst;
1275
1300
}
1276
1301
});
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 ();
1279
1306
auto allocBuilder = pass.getBuilder (allocPt);
1280
1307
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
+ }
1281
1328
1282
- auto dealloc = [&](SILBasicBlock::iterator insertPt) {
1283
- auto deallocBuilder = pass.getBuilder (insertPt);
1284
- deallocBuilder.createDeallocStack (pass.genLoc (), alloc);
1285
- };
1286
- if (latestOpeningInst) {
1287
1329
// Deallocate at the predecessors of dominance frontier blocks that are
1288
1330
// dominated by the alloc to ensure that allocation encloses not only the
1289
1331
// uses of the current value, but also of any values reusing this storage as
1290
1332
// a use projection.
1291
- SmallVector<SILBasicBlock *, 4 > boundary;
1292
1333
computeDominatedBoundaryBlocks (alloc->getParent (), pass.domInfo , boundary);
1293
1334
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);
1299
1337
}
1338
+ boundary.clear ();
1300
1339
}
1301
- return alloc;
1302
1340
}
1303
1341
1304
1342
// ===----------------------------------------------------------------------===//
@@ -3850,6 +3888,8 @@ void AddressLowering::runOnFunction(SILFunction *function) {
3850
3888
// forward order, setting 'storageAddress' for each projection as it goes.
3851
3889
rewriteFunction (pass);
3852
3890
3891
+ allocator.finalizeOpaqueStorage ();
3892
+
3853
3893
deleteRewrittenInstructions (pass);
3854
3894
3855
3895
StackNesting::fixNesting (function);
0 commit comments