11
11
// ===----------------------------------------------------------------------===//
12
12
13
13
#include " swift/SILOptimizer/Utils/ValueLifetime.h"
14
+ #include " swift/Basic/STLExtras.h"
14
15
#include " swift/SIL/BasicBlockUtils.h"
15
16
#include " swift/SILOptimizer/Utils/CFGOptUtils.h"
16
17
17
18
using namespace swift ;
18
19
19
20
void ValueLifetimeAnalysis::propagateLiveness () {
21
+ bool defIsInstruction = defValue.is <SILInstruction *>();
20
22
assert (liveBlocks.empty () && " frontier computed twice" );
21
- assert (!userSet.count (defValue) && " definition cannot be its own use" );
23
+ assert (
24
+ (!defIsInstruction || !userSet.count (defValue.get <SILInstruction *>())) &&
25
+ " definition cannot be its own use" );
22
26
23
- auto defBB = defValue->getParentBlock ();
24
- llvm::SmallVector<SILBasicBlock *, 64 > worklist;
27
+ // Compute the def block only if we have a SILInstruction. If we have a
28
+ // SILArgument, this will be nullptr.
29
+ auto *defBB = getDefValueParentBlock ();
30
+ SmallVector<SILBasicBlock *, 64 > worklist;
25
31
int numUsersBeforeDef = 0 ;
26
32
27
33
// Find the initial set of blocks where the value is live, because
@@ -31,20 +37,28 @@ void ValueLifetimeAnalysis::propagateLiveness() {
31
37
if (liveBlocks.insert (userBlock))
32
38
worklist.push_back (userBlock);
33
39
34
- // A user in the defBB could potentially be located before the defValue.
35
- if (userBlock == defBB)
40
+ // A user in the defBB could potentially be located before the defValue. If
41
+ // we had a SILArgument, defBB will be nullptr, so we should always have
42
+ // numUsersBeforeDef is 0. We assert this at the end of the loop.
43
+ if (defIsInstruction && userBlock == defBB)
36
44
++numUsersBeforeDef;
37
45
}
38
- // Don't count any users in the defBB which are actually located _after_
39
- // the defValue.
40
- auto instIter = defValue->getIterator ();
41
- while (numUsersBeforeDef > 0 && ++instIter != defBB->end ()) {
42
- if (userSet.count (&*instIter))
43
- --numUsersBeforeDef;
46
+ assert ((defValue.is <SILInstruction *>() || (numUsersBeforeDef == 0 )) &&
47
+ " Non SILInstruction defValue with users before the def?!" );
48
+
49
+ // Don't count any users in the defBB which are actually located _after_ the
50
+ // defValue.
51
+ if (defIsInstruction) {
52
+ auto instIter = defValue.get <SILInstruction *>()->getIterator ();
53
+ while (numUsersBeforeDef > 0 && ++instIter != defBB->end ()) {
54
+ if (userSet.count (&*instIter))
55
+ --numUsersBeforeDef;
56
+ }
44
57
}
45
58
46
59
// Initialize the hasUsersBeforeDef field.
47
60
hasUsersBeforeDef = numUsersBeforeDef > 0 ;
61
+ assert (defIsInstruction || !hasUsersBeforeDef);
48
62
49
63
// Now propagate liveness backwards until we hit the block that defines the
50
64
// value.
@@ -55,30 +69,31 @@ void ValueLifetimeAnalysis::propagateLiveness() {
55
69
if (bb == defBB && !hasUsersBeforeDef)
56
70
continue ;
57
71
58
- for (SILBasicBlock *Pred : bb->getPredecessorBlocks ()) {
72
+ for (auto *predBB : bb->getPredecessorBlocks ()) {
59
73
// If it's already in the set, then we've already queued and/or
60
74
// processed the predecessors.
61
- if (liveBlocks.insert (Pred ))
62
- worklist.push_back (Pred );
75
+ if (liveBlocks.insert (predBB ))
76
+ worklist.push_back (predBB );
63
77
}
64
78
}
65
79
}
66
80
67
81
SILInstruction *ValueLifetimeAnalysis::findLastUserInBlock (SILBasicBlock *bb) {
68
82
// Walk backwards in bb looking for last use of the value.
69
- for (auto ii = bb->rbegin (); ii != bb->rend (); ++ii) {
70
- assert (defValue != &*ii && " Found def before finding use!" );
83
+ for (auto &inst : llvm::reverse (*bb)) {
84
+ assert (defValue.dyn_cast <SILInstruction *>() != &inst &&
85
+ " Found def before finding use!" );
71
86
72
- if (userSet.count (&*ii ))
73
- return &*ii ;
87
+ if (userSet.count (&inst ))
88
+ return &inst ;
74
89
}
75
90
llvm_unreachable (" Expected to find use of value in block!" );
76
91
}
77
92
78
93
bool ValueLifetimeAnalysis::computeFrontier (Frontier &frontier, Mode mode,
79
94
DeadEndBlocks *deBlocks) {
80
- assert (!isAliveAtBeginOfBlock (defValue-> getFunction ()->getEntryBlock ())
81
- && " Can't compute frontier for def which does not dominate all uses" );
95
+ assert (!isAliveAtBeginOfBlock (getFunction ()->getEntryBlock ()) &&
96
+ " Can't compute frontier for def which does not dominate all uses" );
82
97
83
98
bool noCriticalEdges = true ;
84
99
@@ -101,10 +116,16 @@ bool ValueLifetimeAnalysis::computeFrontier(Frontier &frontier, Mode mode,
101
116
for (const SILSuccessor &succ : bb->getSuccessors ()) {
102
117
if (isAliveAtBeginOfBlock (succ)) {
103
118
liveInSucc = true ;
104
- if (succ == defValue-> getParent ()) {
119
+ if (succ == getDefValueParentBlock ()) {
105
120
// Here, the basic block bb uses the value but also redefines the
106
121
// value inside bb. The new value could be used by the successors
107
122
// of succ and therefore could be live at the end of succ as well.
123
+ //
124
+ // This should never happen if we have a SILArgument since the
125
+ // SILArgument can not have any uses before it in a block.
126
+ assert (defValue.is <SILInstruction *>() &&
127
+ " SILArguments dominate all instructions in their defining "
128
+ " blocks" );
108
129
usedAndRedefinedInSucc = true ;
109
130
}
110
131
} else if (!deBlocks || !deBlocks->isDeadEnd (succ)) {
@@ -115,7 +136,10 @@ bool ValueLifetimeAnalysis::computeFrontier(Frontier &frontier, Mode mode,
115
136
// Here, the basic block bb uses the value and later redefines the value.
116
137
// Therefore, this value's lifetime ends after its last use preceding the
117
138
// re-definition of the value.
118
- auto ii = defValue->getReverseIterator ();
139
+ //
140
+ // We know that we can not have a SILArgument here since the SILArgument
141
+ // dominates all instructions in the same block.
142
+ auto ii = defValue.get <SILInstruction *>()->getReverseIterator ();
119
143
for (; ii != bb->rend (); ++ii) {
120
144
if (userSet.count (&*ii)) {
121
145
frontier.push_back (&*std::next (ii));
@@ -245,15 +269,19 @@ bool ValueLifetimeAnalysis::isWithinLifetime(SILInstruction *inst) {
245
269
// Searches \p bb backwards from the instruction before \p frontierInst
246
270
// to the beginning of the list and returns true if we find a dealloc_ref
247
271
// /before/ we find \p defValue (the instruction that defines our target value).
248
- static bool blockContainsDeallocRef (SILBasicBlock *bb, SILInstruction *defValue,
249
- SILInstruction *frontierInst) {
272
+ static bool
273
+ blockContainsDeallocRef (SILBasicBlock *bb,
274
+ PointerUnion<SILInstruction *, SILArgument *> defValue,
275
+ SILInstruction *frontierInst) {
250
276
SILBasicBlock::reverse_iterator End = bb->rend ();
251
277
SILBasicBlock::reverse_iterator iter = frontierInst->getReverseIterator ();
252
278
for (++iter; iter != End; ++iter) {
253
279
SILInstruction *inst = &*iter;
254
280
if (isa<DeallocRefInst>(inst))
255
281
return true ;
256
- if (inst == defValue)
282
+ // We know that inst is not a nullptr, so if we have a SILArgument, this
283
+ // will always fail as we want.
284
+ if (inst == defValue.dyn_cast <SILInstruction *>())
257
285
return false ;
258
286
}
259
287
return false ;
@@ -281,9 +309,14 @@ bool ValueLifetimeAnalysis::containsDeallocRef(const Frontier &frontier) {
281
309
}
282
310
283
311
void ValueLifetimeAnalysis::dump () const {
284
- llvm::errs () << " lifetime of def: " << *defValue;
285
- for (SILInstruction *Use : userSet) {
286
- llvm::errs () << " use: " << *Use;
312
+ llvm::errs () << " lifetime of def: " ;
313
+ if (auto *ii = defValue.dyn_cast <SILInstruction *>()) {
314
+ llvm::errs () << *ii;
315
+ } else {
316
+ llvm::errs () << *defValue.get <SILArgument *>();
317
+ }
318
+ for (SILInstruction *use : userSet) {
319
+ llvm::errs () << " use: " << *use;
287
320
}
288
321
llvm::errs () << " live blocks:" ;
289
322
for (SILBasicBlock *bb : liveBlocks) {
0 commit comments