Skip to content

Commit 9f2f7f2

Browse files
committed
Update PrunedLiveness
- To detect instructions occuring before definition - To handle reborrows
1 parent f0ef917 commit 9f2f7f2

File tree

3 files changed

+113
-29
lines changed

3 files changed

+113
-29
lines changed

include/swift/SIL/PrunedLiveness.h

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,6 @@ class PrunedLiveBlocks {
164164
}
165165

166166
void initializeDefBlock(SILBasicBlock *defBB) {
167-
assert(!seenUse && "cannot initialize more defs with partial liveness");
168167
markBlockLive(defBB, LiveWithin);
169168
}
170169

@@ -229,6 +228,16 @@ class PrunedLiveness {
229228
/// ending uses that extend liveness into a loop body.
230229
SmallSetVector<SILInstruction *, 8> *nonLifetimeEndingUsesInLiveOut;
231230

231+
private:
232+
bool isWithinBoundaryHelper(SILInstruction *inst,
233+
SILValue def = SILValue()) const;
234+
235+
bool areUsesWithinBoundaryHelper(ArrayRef<Operand *> uses, SILValue def,
236+
DeadEndBlocks *deadEndBlocks) const;
237+
238+
bool areUsesOutsideBoundaryHelper(ArrayRef<Operand *> uses, SILValue def,
239+
DeadEndBlocks *deadEndBlocks) const;
240+
232241
public:
233242
PrunedLiveness(SmallVectorImpl<SILBasicBlock *> *discoveredBlocks = nullptr,
234243
SmallSetVector<SILInstruction *, 8>
@@ -334,14 +343,26 @@ class PrunedLiveness {
334343
/// client already knows that inst occurs after the start of liveness.
335344
bool isWithinBoundary(SILInstruction *inst) const;
336345

346+
/// Return true if \p inst occurs in between the definition \p def and the
347+
/// liveness boundary.
348+
bool isWithinBoundaryOfDef(SILInstruction *inst, SILValue def) const;
349+
337350
/// \p deadEndBlocks is optional.
338351
bool areUsesWithinBoundary(ArrayRef<Operand *> uses,
339352
DeadEndBlocks *deadEndBlocks) const;
340353

354+
/// \p deadEndBlocks is optional.
355+
bool areUsesWithinBoundaryOfDef(ArrayRef<Operand *> uses, SILValue def,
356+
DeadEndBlocks *deadEndBlocks) const;
357+
341358
/// \p deadEndBlocks is optional.
342359
bool areUsesOutsideBoundary(ArrayRef<Operand *> uses,
343360
DeadEndBlocks *deadEndBlocks) const;
344361

362+
/// \p deadEndBlocks is optional.
363+
bool areUsesOutsideBoundaryOfDef(ArrayRef<Operand *> uses, SILValue def,
364+
DeadEndBlocks *deadEndBlocks) const;
365+
345366
/// Compute liveness for a single SSA definition.
346367
void computeSSALiveness(SILValue def);
347368
};

lib/SIL/Utils/OwnershipUtils.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -689,8 +689,15 @@ llvm::raw_ostream &swift::operator<<(llvm::raw_ostream &os,
689689
/// Add this scopes live blocks into the PrunedLiveness result.
690690
void BorrowedValue::computeLiveness(PrunedLiveness &liveness) const {
691691
liveness.initializeDefBlock(value->getParentBlock());
692-
visitLocalScopeEndingUses([&](Operand *endOp) {
693-
liveness.updateForUse(endOp->getUser(), true);
692+
visitTransitiveLifetimeEndingUses([&](Operand *endOp) {
693+
if (endOp->getOperandOwnership() == OperandOwnership::EndBorrow) {
694+
liveness.updateForUse(endOp->getUser(), true);
695+
return true;
696+
}
697+
assert(endOp->getOperandOwnership() == OperandOwnership::Reborrow);
698+
auto *succBlock = cast<BranchInst>(endOp->getUser())->getDestBB();
699+
liveness.initializeDefBlock(succBlock);
700+
liveness.updateForUse(endOp->getUser(), false);
694701
return true;
695702
});
696703
}

lib/SIL/Utils/PrunedLiveness.cpp

Lines changed: 82 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -127,67 +127,123 @@ bool PrunedLiveness::updateForBorrowingOperand(Operand *op) {
127127
}
128128

129129
void PrunedLiveness::extendAcrossLiveness(PrunedLiveness &otherLivesness) {
130-
// update this liveness for all the interesting users in otherLivesness.
130+
// update this liveness for all the interesting users in otherLiveness.
131131
for (std::pair<SILInstruction *, bool> userAndEnd : otherLivesness.users) {
132132
updateForUse(userAndEnd.first, userAndEnd.second);
133133
}
134134
}
135135

136-
bool PrunedLiveness::isWithinBoundary(SILInstruction *inst) const {
136+
bool PrunedLiveness::isWithinBoundaryHelper(SILInstruction *inst,
137+
SILValue def) const {
137138
SILBasicBlock *block = inst->getParent();
139+
140+
/// Returns true if \p inst is before \p def in this block.
141+
auto foundInBlockBeforeDef = [](SILInstruction *inst, SILBasicBlock *block,
142+
SILValue def) {
143+
if (!def || def->getParentBlock() != block) {
144+
return false;
145+
}
146+
auto *defInst = def->getDefiningInstruction();
147+
if (!defInst) {
148+
return false;
149+
}
150+
for (SILInstruction &it :
151+
make_range(block->begin(), defInst->getIterator())) {
152+
if (&it == inst) {
153+
return true;
154+
}
155+
}
156+
return false;
157+
};
158+
138159
switch (getBlockLiveness(block)) {
139160
case PrunedLiveBlocks::Dead:
140161
return false;
141-
case PrunedLiveBlocks::LiveWithin:
142-
break;
143162
case PrunedLiveBlocks::LiveOut:
144-
return true;
145-
}
146-
// The boundary is within this block. This instruction is before the boundary
147-
// iff any interesting uses occur after it.
148-
for (SILInstruction &inst :
163+
return !foundInBlockBeforeDef(inst, block, def);
164+
case PrunedLiveBlocks::LiveWithin:
165+
if (foundInBlockBeforeDef(inst, block, def)) {
166+
return false;
167+
}
168+
// The boundary is within this block. This instruction is before the
169+
// boundary iff any interesting uses occur after it.
170+
for (SILInstruction &it :
149171
make_range(std::next(inst->getIterator()), block->end())) {
150-
switch (isInterestingUser(&inst)) {
151-
case PrunedLiveness::NonUser:
152-
break;
153-
case PrunedLiveness::NonLifetimeEndingUse:
154-
case PrunedLiveness::LifetimeEndingUse:
155-
return true;
172+
switch (isInterestingUser(&it)) {
173+
case PrunedLiveness::NonUser:
174+
break;
175+
case PrunedLiveness::NonLifetimeEndingUse:
176+
case PrunedLiveness::LifetimeEndingUse:
177+
return true;
178+
}
156179
}
180+
return false;
157181
}
158-
return false;
159182
}
160183

161-
bool PrunedLiveness::areUsesWithinBoundary(ArrayRef<Operand *> uses,
162-
DeadEndBlocks *deadEndBlocks) const {
184+
bool PrunedLiveness::isWithinBoundary(SILInstruction *inst) const {
185+
return isWithinBoundaryHelper(inst);
186+
}
187+
188+
bool PrunedLiveness::isWithinBoundaryOfDef(SILInstruction *inst,
189+
SILValue def) const {
190+
return isWithinBoundaryHelper(inst, def);
191+
}
192+
193+
bool PrunedLiveness::areUsesWithinBoundaryHelper(
194+
ArrayRef<Operand *> uses, SILValue def,
195+
DeadEndBlocks *deadEndBlocks) const {
163196
auto checkDeadEnd = [deadEndBlocks](SILInstruction *inst) {
164197
return deadEndBlocks && deadEndBlocks->isDeadEnd(inst->getParent());
165198
};
166199

167200
for (auto *use : uses) {
168201
auto *user = use->getUser();
169-
if (!isWithinBoundary(user) && !checkDeadEnd(user))
202+
if (!isWithinBoundaryHelper(user, def) && !checkDeadEnd(user))
170203
return false;
171204
}
172205
return true;
173206
}
174207

175-
bool PrunedLiveness::areUsesOutsideBoundary(
176-
ArrayRef<Operand *> uses, DeadEndBlocks *deadEndBlocks) const {
208+
bool PrunedLiveness::areUsesWithinBoundary(ArrayRef<Operand *> uses,
209+
DeadEndBlocks *deadEndBlocks) const {
210+
return areUsesWithinBoundaryHelper(uses, SILValue(), deadEndBlocks);
211+
}
212+
213+
bool PrunedLiveness::areUsesWithinBoundaryOfDef(
214+
ArrayRef<Operand *> uses, SILValue def,
215+
DeadEndBlocks *deadEndBlocks) const {
216+
return areUsesWithinBoundaryHelper(uses, def, deadEndBlocks);
217+
}
218+
219+
bool PrunedLiveness::areUsesOutsideBoundaryHelper(
220+
ArrayRef<Operand *> uses, SILValue def,
221+
DeadEndBlocks *deadEndBlocks) const {
177222
auto checkDeadEnd = [deadEndBlocks](SILInstruction *inst) {
178223
return deadEndBlocks && deadEndBlocks->isDeadEnd(inst->getParent());
179224
};
180225

181226
for (auto *use : uses) {
182227
auto *user = use->getUser();
183-
if (isWithinBoundary(user) || checkDeadEnd(user))
228+
if (isWithinBoundaryHelper(user, def) || checkDeadEnd(user))
184229
return false;
185230
}
186231
return true;
187232
}
188233

189-
// An SSA def meets all the criteria for pruned liveness--def dominates all uses
190-
// with no holes in the liverange. The lifetime-ending uses are also
234+
bool PrunedLiveness::areUsesOutsideBoundary(
235+
ArrayRef<Operand *> uses, DeadEndBlocks *deadEndBlocks) const {
236+
return areUsesOutsideBoundaryHelper(uses, SILValue(), deadEndBlocks);
237+
}
238+
239+
bool PrunedLiveness::areUsesOutsideBoundaryOfDef(
240+
ArrayRef<Operand *> uses, SILValue def,
241+
DeadEndBlocks *deadEndBlocks) const {
242+
return areUsesOutsideBoundaryHelper(uses, def, deadEndBlocks);
243+
}
244+
245+
// An SSA def meets all the criteria for pruned liveness--def dominates all
246+
// uses with no holes in the liverange. The lifetime-ending uses are also
191247
// recorded--destroy_value or end_borrow. However destroy_values may not
192248
// jointly-post dominate if dead-end blocks are present.
193249
void PrunedLiveness::computeSSALiveness(SILValue def) {
@@ -278,8 +334,8 @@ void PrunedLivenessBoundary::compute(const PrunedLiveness &liveness,
278334
// Process each block that has not been visited and is not LiveOut.
279335
switch (liveness.getBlockLiveness(bb)) {
280336
case PrunedLiveBlocks::LiveOut:
281-
// A lifetimeEndBlock may be determined to be LiveOut after analyzing the
282-
// extended liveness. It is irrelevant for finding the boundary.
337+
// A lifetimeEndBlock may be determined to be LiveOut after analyzing
338+
// the extended liveness. It is irrelevant for finding the boundary.
283339
break;
284340
case PrunedLiveBlocks::LiveWithin: {
285341
// The liveness boundary is inside this block. Insert a final destroy

0 commit comments

Comments
 (0)