17
17
#include " swift/SILOptimizer/Analysis/DominanceAnalysis.h"
18
18
#include " swift/SIL/SILArgument.h"
19
19
#include " swift/SIL/SILBuilder.h"
20
+ #include " swift/SIL/CFG.h"
21
+ #include " llvm/Support/GenericDomTree.h"
22
+ #include " llvm/Support/GenericDomTreeConstruction.h"
20
23
#include " llvm/ADT/Statistic.h"
21
24
22
25
STATISTIC (NumStackPromoted, " Number of objects promoted to the stack" );
@@ -48,9 +51,23 @@ class StackPromoter {
48
51
SILFunction *F;
49
52
EscapeAnalysis::ConnectionGraph *ConGraph;
50
53
DominanceInfo *DT;
51
- PostDominanceInfo *PDT;
52
54
EscapeAnalysis *EA;
53
55
56
+ // We use our own post-dominator tree instead of PostDominatorAnalysis,
57
+ // because we ignore unreachable blocks (actually all unreachable sub-graphs).
58
+ // Example:
59
+ // |
60
+ // bb1
61
+ // / \
62
+ // unreachable bb2
63
+ // \
64
+ //
65
+ // We want to get bb2 as immediate post-domiator of bb1. This is not the case
66
+ // with the regualar post-dominator tree.
67
+ llvm::DominatorTreeBase<SILBasicBlock> PostDomTree;
68
+
69
+ bool PostDomTreeValid;
70
+
54
71
// Pseudo-functions for (de-)allocating array buffers on the stack.
55
72
56
73
SILFunction *BufferAllocFunc = nullptr ;
@@ -120,30 +137,54 @@ class StackPromoter {
120
137
SILInstruction *&AllocInsertionPoint,
121
138
SILInstruction *&DeallocInsertionPoint);
122
139
140
+ // / Returns the place where to insert the deallocation.
141
+ // / Returns null if this doesn't succeed or, in case \p RestartPoint is set,
142
+ // / a new iteration should be triggered.
143
+ SILInstruction *findDeallocPoint (SILInstruction *StartInst,
144
+ SILInstruction *&RestartPoint,
145
+ EscapeAnalysis::CGNode *Node,
146
+ int NumUsePointsToFind);
147
+
123
148
bool strictlyDominates (SILBasicBlock *A, SILBasicBlock *B) {
124
149
return A != B && DT->dominates (A, B);
125
150
}
126
151
127
152
bool strictlyPostDominates (SILBasicBlock *A, SILBasicBlock *B) {
128
- return A != B && PDT->dominates (A, B);
153
+ calculatePostDomTree ();
154
+ return A != B && PostDomTree.dominates (A, B);
155
+ }
156
+
157
+ bool postDominates (SILBasicBlock *A, SILBasicBlock *B) {
158
+ calculatePostDomTree ();
159
+ return PostDomTree.dominates (A, B);
129
160
}
130
161
131
162
SILBasicBlock *getImmediatePostDom (SILBasicBlock *BB) {
132
- auto *Node = PDT->getNode (BB);
163
+ calculatePostDomTree ();
164
+ auto *Node = PostDomTree.getNode (BB);
133
165
if (!Node)
134
166
return nullptr ;
135
167
auto *IDomNode = Node->getIDom ();
136
168
if (!IDomNode)
137
169
return nullptr ;
138
170
return IDomNode->getBlock ();
139
171
}
172
+
173
+ void calculatePostDomTree () {
174
+ if (!PostDomTreeValid) {
175
+ // The StackPromoter acts as a "graph" for which the post-dominator-tree
176
+ // is calculated.
177
+ PostDomTree.recalculate (*this );
178
+ PostDomTreeValid = true ;
179
+ }
180
+ }
140
181
141
182
public:
142
183
143
184
StackPromoter (SILFunction *F, EscapeAnalysis::ConnectionGraph *ConGraph,
144
- DominanceInfo *DT, PostDominanceInfo *PDT,
145
- EscapeAnalysis *EA) :
146
- F (F), ConGraph(ConGraph), DT(DT), PDT(PDT), EA(EA ) { }
185
+ DominanceInfo *DT, EscapeAnalysis *EA) :
186
+ F (F), ConGraph(ConGraph), DT(DT), EA(EA), PostDomTree( true ),
187
+ PostDomTreeValid ( false ) { }
147
188
148
189
// / What did the optimization change?
149
190
enum class ChangeState {
@@ -152,6 +193,8 @@ class StackPromoter {
152
193
Calls
153
194
};
154
195
196
+ SILFunction *getFunction () const { return F; }
197
+
155
198
// / The main entry point for the optimization.
156
199
ChangeState promote ();
157
200
};
@@ -284,6 +327,87 @@ SILFunction *StackPromoter::getBufferDeallocFunc(SILFunction *OrigFunc,
284
327
return BufferDeallocFunc;
285
328
}
286
329
330
+ namespace {
331
+
332
+ // / Iterator which iterates over all basic blocks of a function which are not
333
+ // / terminated by an unreachable inst.
334
+ class NonUnreachableBlockIter :
335
+ public std::iterator<std::forward_iterator_tag, SILBasicBlock, ptrdiff_t > {
336
+
337
+ SILFunction::iterator BaseIterator;
338
+ SILFunction::iterator End;
339
+
340
+ void skipUnreachables () {
341
+ while (true ) {
342
+ if (BaseIterator == End)
343
+ return ;
344
+ if (!isa<UnreachableInst>(BaseIterator->getTerminator ()))
345
+ return ;
346
+ BaseIterator++;
347
+ }
348
+ }
349
+
350
+ public:
351
+ NonUnreachableBlockIter (SILFunction::iterator BaseIterator,
352
+ SILFunction::iterator End) :
353
+ BaseIterator (BaseIterator), End(End) {
354
+ skipUnreachables ();
355
+ }
356
+
357
+ NonUnreachableBlockIter () = default ;
358
+
359
+ SILBasicBlock &operator *() const { return *BaseIterator; }
360
+ SILBasicBlock &operator ->() const { return *BaseIterator; }
361
+
362
+ NonUnreachableBlockIter &operator ++() {
363
+ BaseIterator++;
364
+ skipUnreachables ();
365
+ return *this ;
366
+ }
367
+
368
+ NonUnreachableBlockIter operator ++(int unused) {
369
+ NonUnreachableBlockIter Copy = *this ;
370
+ ++*this ;
371
+ return Copy;
372
+ }
373
+
374
+ friend bool operator ==(NonUnreachableBlockIter lhs,
375
+ NonUnreachableBlockIter rhs) {
376
+ return lhs.BaseIterator == rhs.BaseIterator ;
377
+ }
378
+ friend bool operator !=(NonUnreachableBlockIter lhs,
379
+ NonUnreachableBlockIter rhs) {
380
+ return !(lhs == rhs);
381
+ }
382
+ };
383
+ }
384
+
385
+ namespace llvm {
386
+
387
+ // / Use the StackPromoter as a wrapper for the function. It holds the list of
388
+ // / basic blocks excluding all unreachable blocks.
389
+ template <> struct GraphTraits <StackPromoter *>
390
+ : public GraphTraits<swift::SILBasicBlock*> {
391
+ typedef StackPromoter *GraphType;
392
+
393
+ static NodeType *getEntryNode (GraphType SP) {
394
+ return &SP->getFunction ()->front ();
395
+ }
396
+
397
+ typedef NonUnreachableBlockIter nodes_iterator;
398
+ static nodes_iterator nodes_begin (GraphType SP) {
399
+ return nodes_iterator (SP->getFunction ()->begin (), SP->getFunction ()->end ());
400
+ }
401
+ static nodes_iterator nodes_end (GraphType SP) {
402
+ return nodes_iterator (SP->getFunction ()->end (), SP->getFunction ()->end ());
403
+ }
404
+ static unsigned size (GraphType SP) {
405
+ return std::distance (nodes_begin (SP), nodes_end (SP));
406
+ }
407
+ };
408
+
409
+ }
410
+
287
411
bool StackPromoter::canPromoteAlloc (SILInstruction *AI,
288
412
SILInstruction *&AllocInsertionPoint,
289
413
SILInstruction *&DeallocInsertionPoint) {
@@ -311,13 +435,42 @@ bool StackPromoter::canPromoteAlloc(SILInstruction *AI,
311
435
return false ;
312
436
}
313
437
438
+ // Try to find the point where to insert the deallocation.
439
+ // This might need more than one try in case we need to move the allocation
440
+ // out of a stack-alloc-dealloc pair. See findDeallocPoint().
441
+ SILInstruction *StartInst = AI;
442
+ for (;;) {
443
+ SILInstruction *RestartPoint = nullptr ;
444
+ DeallocInsertionPoint = findDeallocPoint (StartInst, RestartPoint, Node,
445
+ NumUsePointsToFind);
446
+ if (DeallocInsertionPoint)
447
+ return true ;
448
+
449
+ if (!RestartPoint)
450
+ return false ;
451
+
452
+ // Moving a buffer allocation call is not trivial because we would need to
453
+ // move all the parameter calculations as well. So we just don't do it.
454
+ if (!isa<AllocRefInst>(AI))
455
+ return false ;
456
+
457
+ // Retry with moving the allocation up.
458
+ AllocInsertionPoint = RestartPoint;
459
+ StartInst = RestartPoint;
460
+ }
461
+ }
462
+
463
+ SILInstruction *StackPromoter::findDeallocPoint (SILInstruction *StartInst,
464
+ SILInstruction *&RestartPoint,
465
+ EscapeAnalysis::CGNode *Node,
466
+ int NumUsePointsToFind) {
314
467
// In the following we check two requirements for stack promotion:
315
468
// 1) Are all uses in the same control region as the alloc? E.g. if the
316
469
// allocation is in a loop then there may not be any uses of the object
317
470
// outside the loop.
318
471
// 2) We need to find an insertion place for the deallocation so that it
319
472
// preserves a properly nested stack allocation-deallocation structure.
320
- SILBasicBlock *StartBlock = AI ->getParent ();
473
+ SILBasicBlock *StartBlock = StartInst ->getParent ();
321
474
322
475
// The block where we assume we can insert the deallocation.
323
476
SILBasicBlock *EndBlock = StartBlock;
@@ -336,7 +489,7 @@ bool StackPromoter::canPromoteAlloc(SILInstruction *AI,
336
489
if (BB == StartBlock) {
337
490
// In the first block we start at the allocation instruction and not at
338
491
// the begin of the block.
339
- Iter = AI ->getIterator ();
492
+ Iter = StartInst ->getIterator ();
340
493
} else {
341
494
// Track all uses in the block arguments.
342
495
for (SILArgument *BBArg : BB->getBBArgs ()) {
@@ -359,7 +512,7 @@ bool StackPromoter::canPromoteAlloc(SILInstruction *AI,
359
512
while (!strictlyPostDominates (EndBlock, Pred)) {
360
513
EndBlock = getImmediatePostDom (EndBlock);
361
514
if (!EndBlock)
362
- return false ;
515
+ return nullptr ;
363
516
}
364
517
}
365
518
Iter = BB->begin ();
@@ -370,8 +523,7 @@ bool StackPromoter::canPromoteAlloc(SILInstruction *AI,
370
523
SILInstruction &I = *Iter++;
371
524
if (BB == EndBlock && StackDepth == 0 && NumUsePointsToFind == 0 ) {
372
525
// We found a place to insert the stack deallocation.
373
- DeallocInsertionPoint = &I;
374
- return true ;
526
+ return &I;
375
527
}
376
528
if (I.isAllocatingStack ()) {
377
529
StackDepth++;
@@ -388,16 +540,17 @@ bool StackPromoter::canPromoteAlloc(SILInstruction *AI,
388
540
//
389
541
// In this case we can move the alloc_ref before the alloc_stack
390
542
// to fix the nesting.
391
- if (!isa<AllocRefInst>(AI))
392
- return false ;
393
543
auto *Alloc = dyn_cast<SILInstruction>(I.getOperand (0 ));
394
544
if (!Alloc)
395
- return false ;
545
+ return nullptr ;
546
+
396
547
// This should always be the case, but let's be on the safe side.
397
- if (!PDT->dominates (StartBlock, Alloc->getParent ()))
398
- return false ;
399
- AllocInsertionPoint = Alloc;
400
- StackDepth++;
548
+ if (!postDominates (StartBlock, Alloc->getParent ()))
549
+ return nullptr ;
550
+
551
+ // Trigger another iteration with a new start point;
552
+ RestartPoint = Alloc;
553
+ return nullptr ;
401
554
}
402
555
StackDepth--;
403
556
}
@@ -422,7 +575,7 @@ bool StackPromoter::canPromoteAlloc(SILInstruction *AI,
422
575
// dealloc_stack %1 // this is the new EndBlock
423
576
EndBlock = getImmediatePostDom (EndBlock);
424
577
if (!EndBlock)
425
- return false ;
578
+ return nullptr ;
426
579
}
427
580
// Again, it's important that the EndBlock is the first in the WorkList.
428
581
WorkList.insert (EndBlock, -1 );
@@ -441,7 +594,7 @@ bool StackPromoter::canPromoteAlloc(SILInstruction *AI,
441
594
// cond_br ..., loop, exit
442
595
// exit:
443
596
// use(%container)
444
- return false ;
597
+ return nullptr ;
445
598
}
446
599
WorkList.insert (Succ, StackDepth);
447
600
}
@@ -466,20 +619,18 @@ class StackPromotion : public SILFunctionTransform {
466
619
467
620
auto *EA = PM->getAnalysis <EscapeAnalysis>();
468
621
auto *DA = PM->getAnalysis <DominanceAnalysis>();
469
- auto *PDA = PM->getAnalysis <PostDominanceAnalysis>();
470
622
471
623
SILFunction *F = getFunction ();
472
624
if (auto *ConGraph = EA->getConnectionGraph (F)) {
473
- StackPromoter promoter (F, ConGraph, DA->get (F), PDA-> get (F), EA);
625
+ StackPromoter promoter (F, ConGraph, DA->get (F), EA);
474
626
switch (promoter.promote ()) {
475
627
case StackPromoter::ChangeState::None:
476
628
break ;
477
629
case StackPromoter::ChangeState::Insts:
478
630
invalidateAnalysis (SILAnalysis::InvalidationKind::Instructions);
479
631
break ;
480
- case StackPromoter::ChangeState::Calls: {
632
+ case StackPromoter::ChangeState::Calls:
481
633
invalidateAnalysis (SILAnalysis::InvalidationKind::CallsAndInstructions);
482
- }
483
634
break ;
484
635
}
485
636
}
0 commit comments