Skip to content

Commit 04144d8

Browse files
committed
[pruned-liveness] Change PrunedLiveBlocks so that it can propagate multiple bits of liveness rather than just one.
This is useful for making a form of PrunedLiveness that is sensitive to address fields. I wired up the current PrunedLiveness to just use PrunedLiveBlocks with num bits set to 1.
1 parent 0f1a132 commit 04144d8

File tree

2 files changed

+43
-29
lines changed

2 files changed

+43
-29
lines changed

include/swift/SIL/PrunedLiveness.h

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,11 @@ class DeadEndBlocks;
115115
/// which the def block's predecessors incorrectly remain dead. This situation
116116
/// could be handled by adding an updateForUseBeforeFirstDef() API.
117117
///
118+
/// We allow for multiple bits of liveness information to be tracked by
119+
/// internally using a SmallBitVector. We default to only tracking a single
120+
/// bit. The multiple bit tracking is useful when tracking state for multiple
121+
/// fields of the same root value.
122+
///
118123
/// TODO: This can be made space-efficient if all clients can maintain a block
119124
/// numbering so liveness info can be represented as bitsets across the blocks.
120125
class PrunedLiveBlocks {
@@ -136,19 +141,24 @@ class PrunedLiveBlocks {
136141
enum IsLive { Dead, LiveWithin, LiveOut };
137142

138143
private:
139-
// Map all blocks in which current def is live to a flag indicating whether
140-
// the value is also liveout of the block.
141-
llvm::SmallDenseMap<SILBasicBlock *, bool, 4> liveBlocks;
144+
/// Map all blocks in which current def is live to a SmallBitVector indicating
145+
/// whether the value represented by said bit is also liveout of the block.
146+
llvm::SmallDenseMap<SILBasicBlock *, SmallBitVector, 4> liveBlocks;
147+
148+
/// Number of bits of liveness to track. By default 1. Used to track multiple
149+
/// liveness bits.
150+
unsigned numBitsToTrack;
142151

143-
// Optional vector of live blocks for clients that deterministically iterate.
152+
/// Optional vector of live blocks for clients that deterministically iterate.
144153
SmallVectorImpl<SILBasicBlock *> *discoveredBlocks;
145154

146-
// Once the first use has been seen, no definitions can be added.
155+
/// Once the first use has been seen, no definitions can be added.
147156
SWIFT_ASSERT_ONLY_DECL(bool seenUse = false);
148157

149158
public:
150-
PrunedLiveBlocks(SmallVectorImpl<SILBasicBlock *> *discoveredBlocks = nullptr)
151-
: discoveredBlocks(discoveredBlocks) {
159+
PrunedLiveBlocks(unsigned numBitsToTrack,
160+
SmallVectorImpl<SILBasicBlock *> *discoveredBlocks = nullptr)
161+
: numBitsToTrack(numBitsToTrack), discoveredBlocks(discoveredBlocks) {
152162
assert(!discoveredBlocks || discoveredBlocks->empty());
153163
}
154164

@@ -167,36 +177,38 @@ class PrunedLiveBlocks {
167177
return *discoveredBlocks;
168178
}
169179

170-
void initializeDefBlock(SILBasicBlock *defBB) {
171-
markBlockLive(defBB, LiveWithin);
180+
void initializeDefBlock(SILBasicBlock *defBB, unsigned bitNo) {
181+
markBlockLive(defBB, LiveWithin, bitNo);
172182
}
173183

174184
/// Update this liveness result for a single use.
175-
IsLive updateForUse(SILInstruction *user);
185+
IsLive updateForUse(SILInstruction *user, unsigned bitNo);
176186

177-
IsLive getBlockLiveness(SILBasicBlock *bb) const {
187+
IsLive getBlockLiveness(SILBasicBlock *bb, unsigned bitNo) const {
178188
auto liveBlockIter = liveBlocks.find(bb);
179189
if (liveBlockIter == liveBlocks.end())
180190
return Dead;
181-
return liveBlockIter->second ? LiveOut : LiveWithin;
191+
assert(liveBlockIter->second.size() == 1);
192+
return liveBlockIter->second[bitNo] ? LiveOut : LiveWithin;
182193
}
183194

184195
protected:
185-
void markBlockLive(SILBasicBlock *bb, IsLive isLive) {
196+
void markBlockLive(SILBasicBlock *bb, IsLive isLive, unsigned bitNo) {
186197
assert(isLive != Dead && "erasing live blocks isn't implemented.");
187198
bool isLiveOut = (isLive == LiveOut);
188199
auto iterAndInserted =
189-
liveBlocks.insert(std::make_pair(bb, isLiveOut));
200+
liveBlocks.insert(std::make_pair(bb, SmallBitVector(numBitsToTrack)));
190201
if (iterAndInserted.second) {
202+
iterAndInserted.first->getSecond()[bitNo] = isLiveOut;
191203
if (discoveredBlocks)
192204
discoveredBlocks->push_back(bb);
193205
} else if (isLiveOut) {
194206
// Update the existing entry to be live-out.
195-
iterAndInserted.first->getSecond() = true;
207+
iterAndInserted.first->getSecond()[bitNo] = true;
196208
}
197209
}
198210

199-
void computeUseBlockLiveness(SILBasicBlock *userBB);
211+
void computeUseBlockLiveness(SILBasicBlock *userBB, unsigned bitNo);
200212
};
201213

202214
/// PrunedLiveness tracks PrunedLiveBlocks along with "interesting" use
@@ -252,7 +264,7 @@ class PrunedLiveness {
252264
PrunedLiveness(SmallVectorImpl<SILBasicBlock *> *discoveredBlocks = nullptr,
253265
SmallSetVector<SILInstruction *, 8>
254266
*nonLifetimeEndingUsesInLiveOut = nullptr)
255-
: liveBlocks(discoveredBlocks),
267+
: liveBlocks(1 /*num bits*/, discoveredBlocks),
256268
nonLifetimeEndingUsesInLiveOut(nonLifetimeEndingUsesInLiveOut) {}
257269

258270
bool empty() const {
@@ -317,7 +329,7 @@ class PrunedLiveness {
317329
}
318330

319331
void initializeDefBlock(SILBasicBlock *defBB) {
320-
liveBlocks.initializeDefBlock(defBB);
332+
liveBlocks.initializeDefBlock(defBB, 0);
321333
}
322334

323335
/// For flexibility, \p lifetimeEnding is provided by the
@@ -335,7 +347,7 @@ class PrunedLiveness {
335347
void extendAcrossLiveness(PrunedLiveness &otherLiveness);
336348

337349
PrunedLiveBlocks::IsLive getBlockLiveness(SILBasicBlock *bb) const {
338-
return liveBlocks.getBlockLiveness(bb);
350+
return liveBlocks.getBlockLiveness(bb, 0);
339351
}
340352

341353
enum IsInterestingUser { NonUser, NonLifetimeEndingUse, LifetimeEndingUse };

lib/SIL/Utils/PrunedLiveness.cpp

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,11 @@ using namespace swift;
1919

2020
/// Mark blocks live during a reverse CFG traversal from one specific block
2121
/// containing a user.
22-
void PrunedLiveBlocks::computeUseBlockLiveness(SILBasicBlock *userBB) {
23-
// If we are visiting this block, then it is not already LiveOut. Mark it
22+
void PrunedLiveBlocks::computeUseBlockLiveness(SILBasicBlock *userBB,
23+
unsigned bitNo) {
24+
// If, we are visiting this block, then it is not already LiveOut. Mark it
2425
// LiveWithin to indicate a liveness boundary within the block.
25-
markBlockLive(userBB, LiveWithin);
26+
markBlockLive(userBB, LiveWithin, bitNo);
2627

2728
SmallVector<SILBasicBlock *, 8> predBBWorklist({userBB});
2829
while (!predBBWorklist.empty()) {
@@ -33,12 +34,12 @@ void PrunedLiveBlocks::computeUseBlockLiveness(SILBasicBlock *userBB) {
3334
// Traversal terminates at any previously visited block, including the
3435
// blocks initialized as definition blocks.
3536
for (auto *predBB : bb->getPredecessorBlocks()) {
36-
switch (getBlockLiveness(predBB)) {
37+
switch (getBlockLiveness(predBB, bitNo)) {
3738
case Dead:
3839
predBBWorklist.push_back(predBB);
3940
LLVM_FALLTHROUGH;
4041
case LiveWithin:
41-
markBlockLive(predBB, LiveOut);
42+
markBlockLive(predBB, LiveOut, bitNo);
4243
break;
4344
case LiveOut:
4445
break;
@@ -52,20 +53,21 @@ void PrunedLiveBlocks::computeUseBlockLiveness(SILBasicBlock *userBB) {
5253
/// Return the updated liveness of the \p use block (LiveOut or LiveWithin).
5354
///
5455
/// Terminators are not live out of the block.
55-
PrunedLiveBlocks::IsLive PrunedLiveBlocks::updateForUse(SILInstruction *user) {
56+
PrunedLiveBlocks::IsLive PrunedLiveBlocks::updateForUse(SILInstruction *user,
57+
unsigned bitNo) {
5658
SWIFT_ASSERT_ONLY(seenUse = true);
5759

5860
auto *bb = user->getParent();
59-
switch (getBlockLiveness(bb)) {
61+
switch (getBlockLiveness(bb, bitNo)) {
6062
case LiveOut:
6163
return LiveOut;
6264
case LiveWithin:
6365
return LiveWithin;
6466
case Dead: {
6567
// This use block has not yet been marked live. Mark it and its predecessor
6668
// blocks live.
67-
computeUseBlockLiveness(bb);
68-
return getBlockLiveness(bb);
69+
computeUseBlockLiveness(bb, bitNo);
70+
return getBlockLiveness(bb, bitNo);
6971
}
7072
}
7173
llvm_unreachable("covered switch");
@@ -76,7 +78,7 @@ PrunedLiveBlocks::IsLive PrunedLiveBlocks::updateForUse(SILInstruction *user) {
7678
//===----------------------------------------------------------------------===//
7779

7880
void PrunedLiveness::updateForUse(SILInstruction *user, bool lifetimeEnding) {
79-
auto useBlockLive = liveBlocks.updateForUse(user);
81+
auto useBlockLive = liveBlocks.updateForUse(user, 0);
8082
// Record all uses of blocks on the liveness boundary. For blocks marked
8183
// LiveWithin, the boundary is considered to be the last use in the block.
8284
//

0 commit comments

Comments
 (0)