14
14
#define SWIFT_SIL_FIELDSENSITIVEPRUNTEDLIVENESS_H
15
15
16
16
#include " swift/AST/TypeExpansionContext.h"
17
+ #include " swift/Basic/Debug.h"
18
+ #include " swift/Basic/FrozenMultiMap.h"
17
19
#include " swift/SIL/PrunedLiveness.h"
20
+ #include " llvm/ADT/SmallBitVector.h"
21
+ #include " llvm/Support/raw_ostream.h"
18
22
19
23
namespace swift {
20
24
@@ -234,11 +238,10 @@ struct TypeTreeLeafTypeRange {
234
238
SubElementNumber startEltOffset;
235
239
SubElementNumber endEltOffset;
236
240
237
- private :
241
+ public :
238
242
TypeTreeLeafTypeRange (SubElementNumber start, SubElementNumber end)
239
243
: startEltOffset(start), endEltOffset(end) {}
240
244
241
- public:
242
245
// / The leaf type range for the entire type tree.
243
246
TypeTreeLeafTypeRange (SILValue rootAddress)
244
247
: startEltOffset(0 ), endEltOffset(TypeSubElementCount(rootAddress)) {}
@@ -280,6 +283,17 @@ struct TypeTreeLeafTypeRange {
280
283
SILValue rootValue, SILInstruction *insertPt, SmallBitVector &neededElements,
281
284
SmallVectorImpl<SILValue> &resultingProjections);
282
285
286
+ static void constructProjectionsForNeededElements (
287
+ SILValue rootValue, SILInstruction *insertPt,
288
+ SmallBitVector &neededElements,
289
+ SmallVectorImpl<std::pair<SILValue, TypeTreeLeafTypeRange>>
290
+ &resultingProjections);
291
+
292
+ static void constructProjectionsForNeededElements (
293
+ SILValue rootValue, SILInstruction *insertPt, TypeTreeLeafTypeRange span,
294
+ SmallVectorImpl<std::pair<SILValue, TypeTreeLeafTypeRange>>
295
+ &resultingProjections);
296
+
283
297
bool operator ==(const TypeTreeLeafTypeRange &other) const {
284
298
return startEltOffset == other.startEltOffset &&
285
299
endEltOffset == other.endEltOffset ;
@@ -289,27 +303,32 @@ struct TypeTreeLeafTypeRange {
289
303
return !(*this == other);
290
304
}
291
305
306
+ // / Return the type tree leaf type range that is the intersection of \p this
307
+ // / and \p other.
308
+ Optional<TypeTreeLeafTypeRange>
309
+ setIntersection (const TypeTreeLeafTypeRange &other) const {
310
+ unsigned start = startEltOffset;
311
+ if (startEltOffset < other.startEltOffset )
312
+ start = other.startEltOffset ;
313
+ unsigned end = endEltOffset;
314
+ if (endEltOffset >= other.endEltOffset )
315
+ end = other.endEltOffset ;
316
+ if (start >= end)
317
+ return None;
318
+ return TypeTreeLeafTypeRange (start, end);
319
+ }
320
+
292
321
// / Is the given leaf type specified by \p singleLeafElementNumber apart of
293
322
// / our \p range of leaf type values in the our larger type.
294
323
bool contains (SubElementNumber singleLeafElementNumber) const {
295
324
return startEltOffset <= singleLeafElementNumber &&
296
325
singleLeafElementNumber < endEltOffset;
297
326
}
298
327
299
- // / Returns true if either of this overlaps at all with the given range.
328
+ // / Returns true if \p range is completely within this range.
300
329
bool contains (TypeTreeLeafTypeRange range) const {
301
- if (startEltOffset <= range.startEltOffset &&
302
- range.startEltOffset < endEltOffset)
303
- return true ;
304
-
305
- // If our start and end offsets, our extent is only 1 and we know that our
306
- // value
307
- unsigned rangeLastElt = range.endEltOffset - 1 ;
308
- if (range.startEltOffset == rangeLastElt)
309
- return false ;
310
-
311
- // Othrwise, see if endEltOffset - 1 is within the range.
312
- return startEltOffset <= rangeLastElt && rangeLastElt < endEltOffset;
330
+ return startEltOffset <= range.startEltOffset &&
331
+ endEltOffset >= range.endEltOffset ;
313
332
}
314
333
315
334
IntRange<unsigned > getRange () const {
@@ -320,12 +339,21 @@ struct TypeTreeLeafTypeRange {
320
339
321
340
unsigned size () const { return endEltOffset - startEltOffset; }
322
341
323
- void getPerFieldTypeRange (SILType type, SILFunction *fn, llvm::function_ref<void (SILType, TypeTreeLeafTypeRange)> callback);
342
+ void getPerFieldTypeRange (
343
+ SILType type, SILFunction *fn,
344
+ llvm::function_ref<void (SILType, TypeTreeLeafTypeRange)> callback);
324
345
325
346
// / Construct per field projections if the projection range has any bits in
326
347
// / common with filterBitVector.
327
- void constructFilteredProjections (SILValue value, SILInstruction *insertPt, SmallBitVector &filterBitVector,
328
- llvm::function_ref<void (SILValue, TypeTreeLeafTypeRange)> callback);
348
+ void constructFilteredProjections (
349
+ SILValue value, SILInstruction *insertPt, SmallBitVector &filterBitVector,
350
+ llvm::function_ref<void (SILValue, TypeTreeLeafTypeRange)> callback);
351
+
352
+ void print (llvm::raw_ostream &os) const {
353
+ os << " TypeTreeLeafTypeRange: (start: " << startEltOffset
354
+ << " , end: " << endEltOffset << " )" ;
355
+ }
356
+ void dump () const { print (llvm::dbgs ()); }
329
357
};
330
358
331
359
// / This is exactly like pruned liveness except that instead of tracking a
@@ -417,7 +445,8 @@ class FieldSensitivePrunedLiveness {
417
445
return UserBlockRange (getAllUsers (), op);
418
446
}
419
447
420
- void initializeDefBlock (SILBasicBlock *defBB, TypeTreeLeafTypeRange span) {
448
+ void initializeDefBlock (SILBasicBlock *defBB, TypeTreeLeafTypeRange span)
449
+ __attribute__((optnone)) {
421
450
liveBlocks.initializeDefBlock (defBB, span.startEltOffset ,
422
451
span.endEltOffset );
423
452
}
@@ -443,10 +472,7 @@ class FieldSensitivePrunedLiveness {
443
472
// / Return the liveness for this specific sub-element of our root value.
444
473
PrunedLiveBlocks::IsLive getBlockLiveness (SILBasicBlock *bb,
445
474
unsigned subElementNumber) const {
446
- SmallVector<PrunedLiveBlocks::IsLive, 1 > isLive;
447
- liveBlocks.getBlockLiveness (bb, subElementNumber, subElementNumber + 1 ,
448
- isLive);
449
- return isLive[0 ];
475
+ return liveBlocks.getBlockLiveness (bb, subElementNumber);
450
476
}
451
477
452
478
void getBlockLiveness (
@@ -456,6 +482,10 @@ class FieldSensitivePrunedLiveness {
456
482
foundLiveness);
457
483
}
458
484
485
+ void getBlockLiveness (SILBasicBlock *bb, SmallBitVector &liveWithinBits,
486
+ SmallBitVector &liveOutBits,
487
+ SmallBitVector &deadBits) const ;
488
+
459
489
enum IsInterestingUser { NonUser, NonLifetimeEndingUse, LifetimeEndingUse };
460
490
461
491
// / Return a result indicating whether the given user was identified as an
@@ -471,6 +501,96 @@ class FieldSensitivePrunedLiveness {
471
501
}
472
502
473
503
unsigned getNumSubElements () const { return liveBlocks.getNumBitsToTrack (); }
504
+
505
+ void print (llvm::raw_ostream &os) const { liveBlocks.print (os); }
506
+ SWIFT_DEBUG_DUMP { print (llvm::dbgs ()); }
507
+ };
508
+
509
+ // / Record the last use points and CFG edges that form the boundary of
510
+ // / PrunedLiveness.
511
+ // /
512
+ // / Dead defs may occur even when the liveness result has uses for every
513
+ // / definition because those uses may occur in unreachable blocks. A dead def
514
+ // / must either be a SILInstruction or SILArgument. This supports memory
515
+ // / location liveness, so there isn't necessary a defining SILValue.
516
+ // /
517
+ // / Each boundary edge is identified by its target block. The source of the edge
518
+ // / is the target block's single predecessor which must have at least one other
519
+ // / non-boundary successor.
520
+ class FieldSensitivePrunedLivenessBoundary {
521
+ llvm::SmallMapVector<SILInstruction *, SmallBitVector, 8 > lastUsers;
522
+ llvm::SmallMapVector<SILBasicBlock *, SmallBitVector, 8 > boundaryEdges;
523
+ llvm::SmallMapVector<SILNode *, SmallBitVector, 1 > deadDefs;
524
+ unsigned numBits;
525
+
526
+ public:
527
+ FieldSensitivePrunedLivenessBoundary (unsigned numBits) : numBits(numBits) {}
528
+
529
+ // / Sanity check meant for NDEBUG mode.
530
+ unsigned getNumLastUsersAndDeadDefs (unsigned bitNo) const {
531
+ #ifdef NDEBUG
532
+ llvm_unreachable (" Only call in asserts build!\n " );
533
+ #else
534
+ unsigned count = 0 ;
535
+ for (auto &pair : lastUsers) {
536
+ count += unsigned (pair.second [bitNo]);
537
+ }
538
+ for (auto &pair : deadDefs) {
539
+ count += unsigned (pair.second [bitNo]);
540
+ }
541
+ return count;
542
+ #endif
543
+ }
544
+
545
+ using LastUserRange = iterator_range<decltype (lastUsers)::iterator>;
546
+ LastUserRange getLastUsers () {
547
+ return make_range (lastUsers.begin (), lastUsers.end ());
548
+ }
549
+
550
+ using BoundaryEdgeRange = iterator_range<decltype (boundaryEdges)::iterator>;
551
+ BoundaryEdgeRange getBoundaryEdges () {
552
+ return make_range (boundaryEdges.begin (), boundaryEdges.end ());
553
+ }
554
+
555
+ using DeadDefRange = iterator_range<decltype (deadDefs)::iterator>;
556
+ DeadDefRange getDeadDefs () {
557
+ return make_range (deadDefs.begin (), deadDefs.end ());
558
+ }
559
+
560
+ // / Helper entry point to get the last user that creates the correct size
561
+ // / small bit vector if we haven't seen this last user yet.
562
+ SmallBitVector &getLastUserBits (SILInstruction *inst) {
563
+ auto iter = lastUsers.insert ({inst, SmallBitVector ()});
564
+ if (iter.second ) {
565
+ iter.first ->second .resize (numBits);
566
+ }
567
+ return iter.first ->second ;
568
+ }
569
+
570
+ SmallBitVector &getBoundaryEdgeBits (SILBasicBlock *block) {
571
+ auto iter = boundaryEdges.insert ({block, SmallBitVector ()});
572
+ if (iter.second ) {
573
+ iter.first ->second .resize (numBits);
574
+ }
575
+ return iter.first ->second ;
576
+ }
577
+
578
+ SmallBitVector &getDeadDefsBits (SILNode *def) {
579
+ auto iter = deadDefs.insert ({def, SmallBitVector ()});
580
+ if (iter.second ) {
581
+ iter.first ->second .resize (numBits);
582
+ }
583
+ return iter.first ->second ;
584
+ }
585
+
586
+ void clear () {
587
+ lastUsers.clear ();
588
+ boundaryEdges.clear ();
589
+ deadDefs.clear ();
590
+ }
591
+
592
+ void print (llvm::raw_ostream &os) const ;
593
+ void dump () const ;
474
594
};
475
595
476
596
template <typename LivenessWithDefs>
@@ -489,7 +609,18 @@ class FieldSensitivePrunedLiveRange : public FieldSensitivePrunedLiveness {
489
609
// / liveness boundary for bits in \p span.
490
610
// /
491
611
// / NOTE: It is assumed that \p inst is correctly described by span.
492
- bool isWithinBoundary (SILInstruction *inst, TypeTreeLeafTypeRange span) const __attribute__((optnone));
612
+ bool isWithinBoundary (SILInstruction *inst, TypeTreeLeafTypeRange span) const ;
613
+
614
+ // / Compute the boundary from the blocks discovered during liveness analysis.
615
+ // /
616
+ // / Precondition: \p liveness.getDiscoveredBlocks() is a valid list of all
617
+ // / live blocks with no duplicates.
618
+ // /
619
+ // / The computed boundary will completely post-dominate, including dead end
620
+ // / paths. The client should query DeadEndBlocks to ignore those dead end
621
+ // / paths.
622
+ void computeBoundary (FieldSensitivePrunedLivenessBoundary &boundary) const
623
+ __attribute__((optnone));
493
624
};
494
625
495
626
// / Single defined liveness.
@@ -549,6 +680,10 @@ class FieldSensitiveSSAPrunedLiveRange
549
680
bool isDefBlock (SILBasicBlock *block, unsigned bit) const {
550
681
return def.first ->getParentBlock () == block && def.second ->contains (bit);
551
682
}
683
+
684
+ void
685
+ findBoundariesInBlock (SILBasicBlock *block, unsigned bitNo, bool isLiveOut,
686
+ FieldSensitivePrunedLivenessBoundary &boundary) const ;
552
687
};
553
688
554
689
// / MultiDefPrunedLiveness is computed incrementally by calling updateForUse.
@@ -594,6 +729,13 @@ class FieldSensitiveMultiDefPrunedLiveRange
594
729
return iter->second .contains (bit);
595
730
}
596
731
732
+ bool isDefBlock (SILBasicBlock *block, TypeTreeLeafTypeRange span) const {
733
+ auto iter = defBlocks.find (block);
734
+ if (iter == defBlocks.end ())
735
+ return false ;
736
+ return span.setIntersection (iter->second ).hasValue ();
737
+ }
738
+
597
739
bool isDef (SILInstruction *inst, unsigned bit) const {
598
740
auto iter = defs.find (cast<SILNode>(inst));
599
741
if (iter == defs.end ())
@@ -607,6 +749,26 @@ class FieldSensitiveMultiDefPrunedLiveRange
607
749
return false ;
608
750
return iter->second .contains (bit);
609
751
}
752
+
753
+ bool isDef (SILInstruction *inst, TypeTreeLeafTypeRange span) const {
754
+ auto iter = defs.find (cast<SILNode>(inst));
755
+ if (iter == defs.end ())
756
+ return false ;
757
+ return span.setIntersection (iter->second ).hasValue ();
758
+ }
759
+
760
+ bool isDef (SILValue value, TypeTreeLeafTypeRange span) const
761
+ __attribute__((optnone)) {
762
+ auto iter = defs.find (cast<SILNode>(value));
763
+ if (iter == defs.end ())
764
+ return false ;
765
+ return span.setIntersection (iter->second ).hasValue ();
766
+ }
767
+
768
+ void
769
+ findBoundariesInBlock (SILBasicBlock *block, unsigned bitNo, bool isLiveOut,
770
+ FieldSensitivePrunedLivenessBoundary &boundary) const
771
+ __attribute__ ((optnone));
610
772
};
611
773
612
774
} // namespace swift
0 commit comments