@@ -155,14 +155,6 @@ class DeadEndBlocks;
155
155
// / not dominated by a def block, then liveness will include the entry block,
156
156
// / as if defined by a function argument
157
157
// /
158
- // / We allow for multiple bits of liveness information to be tracked by
159
- // / internally using a SmallBitVector. The multiple bit tracking is useful when
160
- // / tracking state for multiple fields of the same root value. To do this, we
161
- // / actually track 2 bits per actual needed bit so we can represent 3 Dead,
162
- // / LiveOut, LiveWithin. This was previously unnecessary since we could just
163
- // / represent dead by not having liveness state for a block. With multiple bits
164
- // / possible this is no longer true.
165
- // /
166
158
// / TODO: For efficiency, use BasicBlockBitfield rather than SmallDenseMap.
167
159
class PrunedLiveBlocks {
168
160
public:
@@ -181,210 +173,101 @@ class PrunedLiveBlocks {
181
173
// / LiveOut blocks are live on at least one successor path. LiveOut blocks may
182
174
// / or may not contain defs or uses.
183
175
// /
184
- // / NOTE: The values below for Dead, LiveWithin, LiveOut were picked to ensure
185
- // / that given a 2 bit representation of the value, a value is Dead if the
186
- // / first bit is 0 and is LiveOut if the second bit is set.
176
+ // / NOTE: The values below for Dead, LiveWithin, LiveOut were picked to
177
+ // / establish a lattice such that:
178
+ // / - Dead is the initial state (zero bitfield)
179
+ // / - Merging liveness information is a bitwise-or
187
180
enum IsLive {
188
181
Dead = 0 ,
189
182
LiveWithin = 1 ,
190
183
LiveOut = 3 ,
191
184
};
192
185
193
- // / A bit vector that stores information about liveness. This is composed
194
- // / with SmallBitVector since it contains two bits per liveness so that it
195
- // / can represent 3 states, Dead, LiveWithin, LiveOut. We take advantage of
196
- // / their numeric values to make testing easier \see documentation on IsLive.
197
- class LivenessSmallBitVector {
198
- SmallBitVector bits;
199
-
200
- public:
201
- LivenessSmallBitVector () : bits() {}
202
-
203
- void init (unsigned numBits) {
204
- assert (bits.size () == 0 );
205
- assert (numBits != 0 );
206
- bits.resize (numBits * 2 );
207
- }
208
-
209
- unsigned size () const { return bits.size () / 2 ; }
210
-
211
- IsLive getLiveness (unsigned bitNo) const {
212
- if (!bits[bitNo * 2 ])
213
- return IsLive::Dead;
214
- return bits[bitNo * 2 + 1 ] ? LiveOut : LiveWithin;
215
- }
216
-
217
- // / Returns the liveness in \p resultingFoundLiveness. We only return the
218
- // / bits for endBitNo - startBitNo.
219
- void getLiveness (unsigned startBitNo, unsigned endBitNo,
220
- SmallVectorImpl<IsLive> &resultingFoundLiveness) const {
221
- unsigned actualStartBitNo = startBitNo * 2 ;
222
- unsigned actualEndBitNo = endBitNo * 2 ;
223
-
224
- for (unsigned i = actualStartBitNo, e = actualEndBitNo; i != e; i += 2 ) {
225
- if (!bits[i]) {
226
- resultingFoundLiveness.push_back (Dead);
227
- continue ;
228
- }
229
-
230
- resultingFoundLiveness.push_back (bits[i + 1 ] ? LiveOut : LiveWithin);
231
- }
232
- }
233
-
234
- void setLiveness (unsigned startBitNo, unsigned endBitNo, IsLive isLive) {
235
- for (unsigned i = startBitNo * 2 , e = endBitNo * 2 ; i != e; i += 2 ) {
236
- bits[i] = isLive & 1 ;
237
- bits[i + 1 ] = isLive & 2 ;
238
- }
239
- }
240
-
241
- void setLiveness (unsigned bitNo, IsLive isLive) {
242
- setLiveness (bitNo, bitNo + 1 , isLive);
243
- }
244
- };
245
-
246
186
private:
247
- // / Map all blocks in which current def is live to a SmallBitVector indicating
248
- // / whether the value represented by said bit is also liveout of the block.
249
- llvm::SmallDenseMap<SILBasicBlock *, LivenessSmallBitVector, 4 > liveBlocks;
250
-
251
- // / Number of bits of liveness to track. By default 1. Used to track multiple
252
- // / liveness bits.
253
- unsigned numBitsToTrack;
187
+ // / Map all blocks to an IsLive state.
188
+ BasicBlockBitfield liveBlocks;
254
189
255
190
// / Optional vector of live blocks for clients that deterministically iterate.
256
- SmallVectorImpl<SILBasicBlock *> *discoveredBlocks;
191
+ SmallVectorImpl<SILBasicBlock *> *discoveredBlocks = nullptr ;
192
+
193
+ // / Only a clean bitfield can be initialized.
194
+ SWIFT_ASSERT_ONLY_DECL (bool cleanFlag = true );
257
195
258
- // / Once the first use has been seen, no definitions can be added.
259
- SWIFT_ASSERT_ONLY_DECL (bool seenUse = false );
196
+ // / Once the first def has been initialized, uses can be added.
197
+ SWIFT_ASSERT_ONLY_DECL (bool initializedFlag = false );
260
198
261
199
public:
262
- PrunedLiveBlocks (unsigned numBitsToTrack ,
200
+ PrunedLiveBlocks (SILFunction *function ,
263
201
SmallVectorImpl<SILBasicBlock *> *discoveredBlocks = nullptr )
264
- : numBitsToTrack(numBitsToTrack ), discoveredBlocks(discoveredBlocks) {
202
+ : liveBlocks(function, 2 ), discoveredBlocks(discoveredBlocks) {
265
203
assert (!discoveredBlocks || discoveredBlocks->empty ());
266
204
}
267
205
268
- unsigned getNumBitsToTrack () const { return numBitsToTrack; }
269
-
270
- bool empty () const { return liveBlocks.empty (); }
206
+ bool isInitialized () const { return initializedFlag; }
271
207
272
- void clear () {
273
- liveBlocks. clear () ;
274
- SWIFT_ASSERT_ONLY (seenUse = false ) ;
208
+ void invalidate () {
209
+ initializedFlag = false ;
210
+ cleanFlag = false ;
275
211
}
276
212
277
- unsigned numLiveBlocks () const { return liveBlocks.size (); }
213
+ void initializeDiscoveredBlocks (
214
+ SmallVectorImpl<SILBasicBlock *> *discoveredBlocks) {
215
+ assert (!isInitialized () && " cannot reinitialize after blocks are live" );
216
+
217
+ this ->discoveredBlocks = discoveredBlocks;
218
+ }
278
219
279
220
// / If the constructor was provided with a vector to populate, then this
280
221
// / returns the list of all live blocks with no duplicates.
281
222
ArrayRef<SILBasicBlock *> getDiscoveredBlocks () const {
282
223
return *discoveredBlocks;
283
224
}
284
225
285
- void initializeDefBlock (SILBasicBlock *defBB, unsigned bitNo) {
286
- markBlockLive (defBB, bitNo, LiveWithin);
287
- }
288
-
289
- void initializeDefBlock (SILBasicBlock *defBB, unsigned startBitNo,
290
- unsigned endBitNo) {
291
- markBlockLive (defBB, startBitNo, endBitNo, LiveWithin);
226
+ void initializeDefBlock (SILBasicBlock *defBB) {
227
+ initializedFlag = true ;
228
+ markBlockLive (defBB, LiveWithin);
292
229
}
293
230
294
231
// / Update this liveness result for a single use.
295
- IsLive updateForUse (SILInstruction *user, unsigned bitNo) {
232
+ IsLive updateForUse (SILInstruction *user) {
233
+ assert (isInitialized () && " at least one definition must be initialized" );
234
+
296
235
auto *block = user->getParent ();
297
- auto liveness = getBlockLiveness (block, bitNo);
236
+ auto liveness = getBlockLiveness (block);
237
+ // If a block is already marked live, assume that liveness was propagated to
238
+ // its predecessors. This assumes that uses will never be added above a def
239
+ // in the same block.
298
240
if (liveness != Dead)
299
241
return liveness;
300
- computeScalarUseBlockLiveness (block, bitNo);
301
- return getBlockLiveness (block, bitNo);
302
- }
303
242
304
- // / Update this range of liveness results for a single use.
305
- void updateForUse (SILInstruction *user, unsigned startBitNo,
306
- unsigned endBitNo,
307
- SmallVectorImpl<IsLive> &resultingLiveness);
308
-
309
- IsLive getBlockLiveness (SILBasicBlock *bb, unsigned bitNo) const {
310
- auto liveBlockIter = liveBlocks.find (bb);
311
- if (liveBlockIter == liveBlocks.end ()) {
312
- return Dead;
313
- }
314
-
315
- return liveBlockIter->second .getLiveness (bitNo);
243
+ computeUseBlockLiveness (block);
244
+ return getBlockLiveness (block);
316
245
}
317
246
318
- // / FIXME: This API should directly return the live bitset. The live bitset
319
- // / type should have an api for querying and iterating over the live fields.
320
- void getBlockLiveness (SILBasicBlock *bb, unsigned startBitNo,
321
- unsigned endBitNo,
322
- SmallVectorImpl<IsLive> &foundLivenessInfo) const {
323
- auto liveBlockIter = liveBlocks.find (bb);
324
- if (liveBlockIter == liveBlocks.end ()) {
325
- for (unsigned i : range (endBitNo - startBitNo)) {
326
- (void )i;
327
- foundLivenessInfo.push_back (Dead);
328
- }
329
- return ;
330
- }
331
-
332
- liveBlockIter->second .getLiveness (startBitNo, endBitNo, foundLivenessInfo);
247
+ IsLive getBlockLiveness (SILBasicBlock *bb) const {
248
+ assert (isInitialized ());
249
+ return (IsLive)liveBlocks.get (bb);
333
250
}
334
251
335
252
llvm::StringRef getStringRef (IsLive isLive) const ;
253
+
336
254
void print (llvm::raw_ostream &OS) const ;
255
+
337
256
void dump () const ;
338
257
339
258
protected:
340
- void markBlockLive (SILBasicBlock *bb, unsigned bitNo, IsLive isLive) {
259
+ void markBlockLive (SILBasicBlock *bb, IsLive isLive) {
341
260
assert (isLive != Dead && " erasing live blocks isn't implemented." );
342
- auto iterAndInserted =
343
- liveBlocks.insert (std::make_pair (bb, LivenessSmallBitVector ()));
344
- if (iterAndInserted.second ) {
345
- // We initialize the size of the small bit vector here rather than in
346
- // liveBlocks.insert above to prevent us from allocating upon failure if
347
- // we have more than SmallBitVector's small size number of bits.
348
- auto &insertedBV = iterAndInserted.first ->getSecond ();
349
- insertedBV.init (numBitsToTrack);
350
- insertedBV.setLiveness (bitNo, bitNo + 1 , isLive);
261
+ auto state = (IsLive)liveBlocks.get (bb);
262
+ liveBlocks.set (bb, state | isLive);
263
+ if (state == IsLive::Dead) {
351
264
if (discoveredBlocks)
352
265
discoveredBlocks->push_back (bb);
353
- } else {
354
- // If we are dead, always update to the new liveness.
355
- switch (iterAndInserted.first ->getSecond ().getLiveness (bitNo)) {
356
- case Dead:
357
- iterAndInserted.first ->getSecond ().setLiveness (bitNo, bitNo + 1 ,
358
- isLive);
359
- break ;
360
- case LiveWithin:
361
- if (isLive == LiveOut) {
362
- // Update the existing entry to be live-out.
363
- iterAndInserted.first ->getSecond ().setLiveness (bitNo, bitNo + 1 ,
364
- LiveOut);
365
- }
366
- break ;
367
- case LiveOut:
368
- break ;
369
- }
370
- }
371
- }
372
-
373
- void markBlockLive (SILBasicBlock *bb, unsigned startBitNo, unsigned endBitNo,
374
- IsLive isLive) {
375
- for (unsigned index : range (startBitNo, endBitNo)) {
376
- markBlockLive (bb, index, isLive);
377
266
}
378
267
}
379
268
380
269
private:
381
- // / A helper routine that as a fast path handles the scalar case. We do not
382
- // / handle the mult-bit case today since the way the code is written today
383
- // / assumes we process a bit at a time.
384
- // /
385
- // / TODO: Make a multi-bit query for efficiency reasons.
386
- void computeScalarUseBlockLiveness (SILBasicBlock *userBB,
387
- unsigned startBitNo);
270
+ void computeUseBlockLiveness (SILBasicBlock *userBB);
388
271
};
389
272
390
273
// / If inner borrows are 'Contained', then liveness is fully described by the
@@ -483,17 +366,19 @@ class PrunedLiveness {
483
366
SmallVectorImpl<SILBasicBlock *> *discoveredBlocks = nullptr )
484
367
: liveBlocks(function, discoveredBlocks) {}
485
368
486
- bool empty () const {
487
- assert (!liveBlocks.empty () || users.empty ());
488
- return liveBlocks.empty ();
489
- }
369
+ bool isInitialized () const { return liveBlocks.isInitialized (); }
370
+
371
+ bool empty () const { return users.empty (); }
490
372
491
373
void invalidate () {
492
374
liveBlocks.invalidate ();
493
375
users.clear ();
494
376
}
495
377
496
- unsigned numLiveBlocks () const { return liveBlocks.numLiveBlocks (); }
378
+ void initializeDiscoveredBlocks (
379
+ SmallVectorImpl<SILBasicBlock *> *discoveredBlocks) {
380
+ liveBlocks.initializeDiscoveredBlocks (discoveredBlocks);
381
+ }
497
382
498
383
// / If the constructor was provided with a vector to populate, then this
499
384
// / returns the list of all live blocks with no duplicates.
@@ -502,7 +387,7 @@ class PrunedLiveness {
502
387
}
503
388
504
389
void initializeDefBlock (SILBasicBlock *defBB) {
505
- liveBlocks.initializeDefBlock (defBB, 0 );
390
+ liveBlocks.initializeDefBlock (defBB);
506
391
}
507
392
508
393
// / For flexibility, \p lifetimeEnding is provided by the
@@ -527,7 +412,7 @@ class PrunedLiveness {
527
412
void extendAcrossLiveness (PrunedLiveness &otherLiveness);
528
413
529
414
PrunedLiveBlocks::IsLive getBlockLiveness (SILBasicBlock *bb) const {
530
- return liveBlocks.getBlockLiveness (bb, 0 );
415
+ return liveBlocks.getBlockLiveness (bb);
531
416
}
532
417
533
418
enum IsInterestingUser {
@@ -671,8 +556,9 @@ class PrunedLiveRange : public PrunedLiveness {
671
556
return static_cast <const LivenessWithDefs &>(*this );
672
557
}
673
558
674
- PrunedLiveRange (SmallVectorImpl<SILBasicBlock *> *discoveredBlocks = nullptr )
675
- : PrunedLiveness(discoveredBlocks) {}
559
+ PrunedLiveRange (SILFunction *function,
560
+ SmallVectorImpl<SILBasicBlock *> *discoveredBlocks = nullptr )
561
+ : PrunedLiveness(function, discoveredBlocks) {}
676
562
677
563
LiveRangeSummary recursivelyUpdateForDef (SILValue initialDef,
678
564
ValueSet &visited,
@@ -821,8 +707,6 @@ class MultiDefPrunedLiveness : public PrunedLiveRange<MultiDefPrunedLiveness> {
821
707
defBlocks (function) {}
822
708
823
709
void invalidate () {
824
- defs.invalidate ();
825
- defBlocks.invalidate ();
826
710
PrunedLiveRange::invalidate ();
827
711
}
828
712
0 commit comments