96
96
97
97
#include " swift/SIL/SILBasicBlock.h"
98
98
#include " llvm/ADT/MapVector.h"
99
+ #include " llvm/ADT/PointerIntPair.h"
100
+ #include " llvm/ADT/SmallVector.h"
99
101
100
102
namespace swift {
101
103
@@ -115,6 +117,14 @@ class DeadEndBlocks;
115
117
// / which the def block's predecessors incorrectly remain dead. This situation
116
118
// / could be handled by adding an updateForUseBeforeFirstDef() API.
117
119
// /
120
+ // / We allow for multiple bits of liveness information to be tracked by
121
+ // / internally using a SmallBitVector. The multiple bit tracking is useful when
122
+ // / tracking state for multiple fields of the same root value. To do this, we
123
+ // / actually track 2 bits per actual needed bit so we can represent 3 Dead,
124
+ // / LiveOut, LiveWithin. This was previously unnecessary since we could just
125
+ // / represent dead by not having liveness state for a block. With multiple bits
126
+ // / possible this is no longer true.
127
+ // /
118
128
// / TODO: This can be made space-efficient if all clients can maintain a block
119
129
// / numbering so liveness info can be represented as bitsets across the blocks.
120
130
class PrunedLiveBlocks {
@@ -133,22 +143,96 @@ class PrunedLiveBlocks {
133
143
// /
134
144
// / LiveOut blocks are live on at least one successor path. LiveOut blocks may
135
145
// / or may not contain defs or uses.
136
- enum IsLive { Dead, LiveWithin, LiveOut };
146
+ // /
147
+ // / NOTE: The values below for Dead, LiveWithin, LiveOut were picked to ensure
148
+ // / that given a 2 bit representation of the value, a value is Dead if the
149
+ // / first bit is 0 and is LiveOut if the second bit is set.
150
+ enum IsLive {
151
+ Dead = 0 ,
152
+ LiveWithin = 1 ,
153
+ LiveOut = 3 ,
154
+ };
155
+
156
+ // / A bit vector that stores information about liveness. This is composed
157
+ // / with SmallBitVector since it contains two bits per liveness so that it
158
+ // / can represent 3 states, Dead, LiveWithin, LiveOut. We take advantage of
159
+ // / their numeric values to make testing easier \see documentation on IsLive.
160
+ class LivenessSmallBitVector {
161
+ SmallBitVector bits;
162
+
163
+ public:
164
+ LivenessSmallBitVector () : bits() {}
165
+
166
+ void init (unsigned numBits) {
167
+ assert (bits.size () == 0 );
168
+ assert (numBits != 0 );
169
+ bits.resize (numBits * 2 );
170
+ }
171
+
172
+ unsigned size () const { return bits.size () / 2 ; }
173
+
174
+ IsLive getLiveness (unsigned bitNo) const {
175
+ SmallVector<IsLive, 1 > foundLiveness;
176
+ getLiveness (bitNo, bitNo + 1 , foundLiveness);
177
+ return foundLiveness[0 ];
178
+ }
179
+
180
+ void getLiveness (unsigned startBitNo, unsigned endBitNo,
181
+ SmallVectorImpl<IsLive> &resultingFoundLiveness) const {
182
+ unsigned actualStartBitNo = startBitNo * 2 ;
183
+ unsigned actualEndBitNo = endBitNo * 2 ;
184
+
185
+ // NOTE: We pad both before/after with Dead to ensure that we are
186
+ // returning an array that acts as a bit mask and thus can be directly
187
+ // compared against other such bitmasks. This invariant is used when
188
+ // computing boundaries.
189
+ for (unsigned i = 0 ; i != startBitNo; ++i) {
190
+ resultingFoundLiveness.push_back (Dead);
191
+ }
192
+ for (unsigned i = actualStartBitNo, e = actualEndBitNo; i != e; i += 2 ) {
193
+ if (!bits[i]) {
194
+ resultingFoundLiveness.push_back (Dead);
195
+ continue ;
196
+ }
197
+
198
+ resultingFoundLiveness.push_back (bits[i + 1 ] ? LiveOut : LiveWithin);
199
+ }
200
+ for (unsigned i = endBitNo, e = size (); i != e; ++i) {
201
+ resultingFoundLiveness.push_back (Dead);
202
+ }
203
+ }
204
+
205
+ void setLiveness (unsigned startBitNo, unsigned endBitNo, IsLive isLive) {
206
+ for (unsigned i = startBitNo * 2 , e = endBitNo * 2 ; i != e; i += 2 ) {
207
+ bits[i] = isLive & 1 ;
208
+ bits[i + 1 ] = isLive & 2 ;
209
+ }
210
+ }
211
+
212
+ void setLiveness (unsigned bitNo, IsLive isLive) {
213
+ setLiveness (bitNo, bitNo + 1 , isLive);
214
+ }
215
+ };
137
216
138
217
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;
218
+ // / Map all blocks in which current def is live to a SmallBitVector indicating
219
+ // / whether the value represented by said bit is also liveout of the block.
220
+ llvm::SmallDenseMap<SILBasicBlock *, LivenessSmallBitVector , 4 > liveBlocks;
142
221
143
- // Optional vector of live blocks for clients that deterministically iterate.
222
+ // / Number of bits of liveness to track. By default 1. Used to track multiple
223
+ // / liveness bits.
224
+ unsigned numBitsToTrack;
225
+
226
+ // / Optional vector of live blocks for clients that deterministically iterate.
144
227
SmallVectorImpl<SILBasicBlock *> *discoveredBlocks;
145
228
146
- // Once the first use has been seen, no definitions can be added.
229
+ // / Once the first use has been seen, no definitions can be added.
147
230
SWIFT_ASSERT_ONLY_DECL (bool seenUse = false );
148
231
149
232
public:
150
- PrunedLiveBlocks (SmallVectorImpl<SILBasicBlock *> *discoveredBlocks = nullptr )
151
- : discoveredBlocks(discoveredBlocks) {
233
+ PrunedLiveBlocks (unsigned numBitsToTrack,
234
+ SmallVectorImpl<SILBasicBlock *> *discoveredBlocks = nullptr )
235
+ : numBitsToTrack(numBitsToTrack), discoveredBlocks(discoveredBlocks) {
152
236
assert (!discoveredBlocks || discoveredBlocks->empty ());
153
237
}
154
238
@@ -167,36 +251,77 @@ class PrunedLiveBlocks {
167
251
return *discoveredBlocks;
168
252
}
169
253
170
- void initializeDefBlock (SILBasicBlock *defBB) {
171
- markBlockLive (defBB, LiveWithin);
254
+ void initializeDefBlock (SILBasicBlock *defBB, unsigned bitNo) {
255
+ markBlockLive (defBB, bitNo, LiveWithin);
256
+ }
257
+
258
+ void initializeDefBlock (SILBasicBlock *defBB, unsigned startBitNo,
259
+ unsigned endBitNo) {
260
+ markBlockLive (defBB, startBitNo, endBitNo, LiveWithin);
172
261
}
173
262
174
263
// / Update this liveness result for a single use.
175
- IsLive updateForUse (SILInstruction *user);
264
+ IsLive updateForUse (SILInstruction *user, unsigned bitNo) {
265
+ SmallVector<IsLive, 1 > resultingLiveness;
266
+ updateForUse (user, bitNo, bitNo + 1 , resultingLiveness);
267
+ return resultingLiveness[0 ];
268
+ }
269
+
270
+ // / Update this range of liveness results for a single use.
271
+ void updateForUse (SILInstruction *user, unsigned startBitNo,
272
+ unsigned endBitNo,
273
+ SmallVectorImpl<IsLive> &resultingLiveness);
176
274
177
- IsLive getBlockLiveness (SILBasicBlock *bb) const {
275
+ IsLive getBlockLiveness (SILBasicBlock *bb, unsigned bitNo) const {
276
+ SmallVector<IsLive, 1 > isLive;
277
+ getBlockLiveness (bb, bitNo, bitNo + 1 , isLive);
278
+ return isLive[0 ];
279
+ }
280
+
281
+ void getBlockLiveness (SILBasicBlock *bb, unsigned startBitNo,
282
+ unsigned endBitNo,
283
+ SmallVectorImpl<IsLive> &foundLivenessInfo) const {
178
284
auto liveBlockIter = liveBlocks.find (bb);
179
- if (liveBlockIter == liveBlocks.end ())
180
- return Dead;
181
- return liveBlockIter->second ? LiveOut : LiveWithin;
285
+ if (liveBlockIter == liveBlocks.end ()) {
286
+ for (unsigned i : range (numBitsToTrack)) {
287
+ (void )i;
288
+ foundLivenessInfo.push_back (Dead);
289
+ }
290
+ return ;
291
+ }
292
+
293
+ assert (liveBlockIter->second .size () == 1 );
294
+ liveBlockIter->second .getLiveness (startBitNo, endBitNo, foundLivenessInfo);
182
295
}
183
296
184
297
protected:
185
- void markBlockLive (SILBasicBlock *bb, IsLive isLive) {
298
+ void markBlockLive (SILBasicBlock *bb, unsigned bitNo, IsLive isLive) {
299
+ markBlockLive (bb, bitNo, bitNo + 1 , isLive);
300
+ }
301
+
302
+ void markBlockLive (SILBasicBlock *bb, unsigned startBitNo, unsigned endBitNo,
303
+ IsLive isLive) {
186
304
assert (isLive != Dead && " erasing live blocks isn't implemented." );
187
- bool isLiveOut = (isLive == LiveOut);
188
305
auto iterAndInserted =
189
- liveBlocks.insert (std::make_pair (bb, isLiveOut ));
306
+ liveBlocks.insert (std::make_pair (bb, LivenessSmallBitVector () ));
190
307
if (iterAndInserted.second ) {
308
+ // We initialize the size of the small bit vector here rather than in
309
+ // liveBlocks.insert above to prevent us from allocating upon failure if
310
+ // we have more than SmallBitVector's small size number of bits.
311
+ auto &insertedBV = iterAndInserted.first ->getSecond ();
312
+ insertedBV.init (numBitsToTrack);
313
+ insertedBV.setLiveness (startBitNo, endBitNo, isLive);
191
314
if (discoveredBlocks)
192
315
discoveredBlocks->push_back (bb);
193
- } else if (isLiveOut ) {
316
+ } else if (isLive == LiveOut ) {
194
317
// Update the existing entry to be live-out.
195
- iterAndInserted.first ->getSecond () = true ;
318
+ iterAndInserted.first ->getSecond ().setLiveness (startBitNo, endBitNo,
319
+ LiveOut);
196
320
}
197
321
}
198
322
199
- void computeUseBlockLiveness (SILBasicBlock *userBB);
323
+ void computeUseBlockLiveness (SILBasicBlock *userBB, unsigned startBitNo,
324
+ unsigned endBitNo);
200
325
};
201
326
202
327
// / PrunedLiveness tracks PrunedLiveBlocks along with "interesting" use
@@ -252,7 +377,7 @@ class PrunedLiveness {
252
377
PrunedLiveness (SmallVectorImpl<SILBasicBlock *> *discoveredBlocks = nullptr ,
253
378
SmallSetVector<SILInstruction *, 8 >
254
379
*nonLifetimeEndingUsesInLiveOut = nullptr )
255
- : liveBlocks(discoveredBlocks),
380
+ : liveBlocks(1 /* num bits */ , discoveredBlocks),
256
381
nonLifetimeEndingUsesInLiveOut (nonLifetimeEndingUsesInLiveOut) {}
257
382
258
383
bool empty () const {
@@ -317,7 +442,7 @@ class PrunedLiveness {
317
442
}
318
443
319
444
void initializeDefBlock (SILBasicBlock *defBB) {
320
- liveBlocks.initializeDefBlock (defBB);
445
+ liveBlocks.initializeDefBlock (defBB, 0 );
321
446
}
322
447
323
448
// / For flexibility, \p lifetimeEnding is provided by the
@@ -335,7 +460,7 @@ class PrunedLiveness {
335
460
void extendAcrossLiveness (PrunedLiveness &otherLiveness);
336
461
337
462
PrunedLiveBlocks::IsLive getBlockLiveness (SILBasicBlock *bb) const {
338
- return liveBlocks.getBlockLiveness (bb);
463
+ return liveBlocks.getBlockLiveness (bb, 0 );
339
464
}
340
465
341
466
enum IsInterestingUser { NonUser, NonLifetimeEndingUse, LifetimeEndingUse };
0 commit comments