@@ -121,17 +121,18 @@ static DestroyValueInst *dynCastToDestroyOf(SILInstruction *instruction,
121
121
122
122
bool CanonicalizeOSSALifetime::computeCanonicalLiveness () {
123
123
defUseWorklist.initialize (getCurrentDef ());
124
+ // Only the first level of reborrows need to be consider. All nested inner
125
+ // adjacent reborrows and phis are encapsulated within their lifetimes.
126
+ SILPhiArgument *arg;
127
+ if ((arg = dyn_cast<SILPhiArgument>(getCurrentDef ())) && arg->isPhi ()) {
128
+ visitAdjacentReborrowsOfPhi (arg, [&](SILPhiArgument *reborrow) {
129
+ defUseWorklist.insert (reborrow);
130
+ return true ;
131
+ });
132
+ }
124
133
while (SILValue value = defUseWorklist.pop ()) {
125
- SILPhiArgument *arg;
126
- if ((arg = dyn_cast<SILPhiArgument>(value)) && arg->isPhi ()) {
127
- visitAdjacentReborrowsOfPhi (arg, [&](SILPhiArgument *reborrow) {
128
- defUseWorklist.insert (reborrow);
129
- return true ;
130
- });
131
- }
132
134
for (Operand *use : value->getUses ()) {
133
135
auto *user = use->getUser ();
134
-
135
136
// Recurse through copies.
136
137
if (auto *copy = dyn_cast<CopyValueInst>(user)) {
137
138
defUseWorklist.insert (copy);
@@ -187,31 +188,31 @@ bool CanonicalizeOSSALifetime::computeCanonicalLiveness() {
187
188
case OperandOwnership::InteriorPointer:
188
189
case OperandOwnership::GuaranteedForwarding:
189
190
case OperandOwnership::EndBorrow:
190
- // Guaranteed values are considered uses of the value when the value
191
- // owneed. If user is a guaranteed phi, then the owned lifetime either
192
- // dominates it or its lifetime ends at an outer adjacent reborrow.
191
+ // Guaranteed values are exposed by inner adjacent reborrows. If user is
192
+ // a guaranteed phi (GuaranteedForwarding), then the owned lifetime
193
+ // either dominates it or its lifetime ends at an outer adjacent
194
+ // reborrow. Only instructions that end the reborrow lifetime should
195
+ // actually affect liveness of the outer owned value.
193
196
liveness.updateForUse (user, /* lifetimeEnding*/ false );
194
197
break ;
195
198
case OperandOwnership::Reborrow:
196
- BranchInst *branch;
197
- if (!(branch = dyn_cast<BranchInst>(user))) {
198
- // Non-phi reborrows (tuples, etc) never end the lifetime of the owned
199
- // value.
200
- liveness.updateForUse (user, /* lifetimeEnding*/ false );
201
- defUseWorklist.insert (cast<SingleValueInstruction>(user));
202
- break ;
203
- }
204
- if (is_contained (user->getOperandValues (), getCurrentDef ())) {
205
- // An adjacent phi consumes the value being reborrowed. Although this
206
- // use doesn't end the lifetime, this user does.
207
- liveness.updateForUse (user, /* lifetimeEnding*/ true );
199
+ BranchInst *branch = cast<BranchInst>(user);
200
+ // This is a cheap variation on visitEnclosingDef. We already know that
201
+ // getCurrentDef() is the enclosing def for this use. If the reborrow's
202
+ // has a enclosing def is an outer adjacent phi then this branch must
203
+ // consume getCurrentDef() as the outer phi operand.
204
+ if (is_contained (branch->getOperandValues (), getCurrentDef ())) {
205
+ // An adjacent phi consumes the value being reborrowed. Although this
206
+ // use doesn't end the lifetime, this branch does end the lifetime by
207
+ // consuming the owned value.
208
+ liveness.updateForUse (branch, /* lifetimeEnding*/ true );
208
209
break ;
209
210
}
210
211
// No adjacent phi consumes the value. This use is not lifetime ending.
211
- liveness.updateForUse (user , /* lifetimeEnding*/ false );
212
+ liveness.updateForUse (branch , /* lifetimeEnding*/ false );
212
213
// This branch reborrows a guaranteed phi whose lifetime is dependent on
213
214
// currentDef. Uses of the reborrowing phi extend liveness.
214
- auto *reborrow = branch-> getArgForOperand (use);
215
+ auto *reborrow = PhiOperand (use). getValue ( );
215
216
defUseWorklist.insert (reborrow);
216
217
break ;
217
218
}
0 commit comments