@@ -153,10 +153,18 @@ class TileAllocator {
153
153
return failure ();
154
154
}
155
155
156
+ // / Acquires a specific tile ID. Asserts the tile is initially free.
157
+ void acquireTileId (ArmSMETileType tileType, unsigned tileId) {
158
+ TileMask tileMask = getMasks (tileType)[tileId];
159
+ assert ((tilesInUse & tileMask) == TileMask::kNone &&
160
+ " cannot acquire allocated tile!" );
161
+ tilesInUse |= tileMask;
162
+ }
163
+
156
164
// / Releases a previously allocated tile ID.
157
165
void releaseTileId (ArmSMETileType tileType, unsigned tileId) {
158
166
TileMask tileMask = getMasks (tileType)[tileId];
159
- assert ((tilesInUse & tileMask) != TileMask:: kNone &&
167
+ assert ((tilesInUse & tileMask) == tileMask &&
160
168
" cannot release unallocated tile!" );
161
169
tilesInUse ^= tileMask;
162
170
}
@@ -289,6 +297,11 @@ struct LiveRange {
289
297
.valid ();
290
298
}
291
299
300
+ // / Returns true if this range overlaps with `point`.
301
+ bool overlaps (uint64_t point) const {
302
+ return ranges->lookup (point) == kValidLiveRange ;
303
+ }
304
+
292
305
// / Unions this live range with `otherRange`, aborts if the ranges overlap.
293
306
void unionWith (LiveRange const &otherRange) {
294
307
for (auto it = otherRange.ranges ->begin (); it != otherRange.ranges ->end ();
@@ -488,76 +501,126 @@ coalesceTileLiveRanges(DenseMap<Value, LiveRange> &initialLiveRanges) {
488
501
return std::move (coalescedLiveRanges);
489
502
}
490
503
491
- // / Choose a live range to spill (via some heuristics). This picks either an
492
- // / active live range from `activeRanges` or the new live range `newRange`.
504
+ // / Choose a live range to spill (via some heuristics). This picks either a live
505
+ // / range from `activeRanges`, `inactiveRanges`, or the new live range
506
+ // / `newRange`. Note: All live ranges in `activeRanges` and `inactiveRanges` are
507
+ // / assumed to overlap with `newRange`.
493
508
LiveRange *chooseSpillUsingHeuristics (ArrayRef<LiveRange *> activeRanges,
509
+ ArrayRef<LiveRange *> inactiveRanges,
494
510
LiveRange *newRange) {
511
+ auto allOverlappingRanges =
512
+ llvm::concat<LiveRange>(llvm::make_pointee_range (activeRanges),
513
+ llvm::make_pointee_range (inactiveRanges));
514
+
495
515
// Heuristic: Spill trivially copyable operations (usually free).
496
- auto isTrivialSpill = [&](LiveRange * allocatedRange) {
497
- return isTileTypeGreaterOrEqual (allocatedRange-> getTileType (),
516
+ auto isTrivialSpill = [&](LiveRange & allocatedRange) {
517
+ return isTileTypeGreaterOrEqual (allocatedRange. getTileType (),
498
518
newRange->getTileType ()) &&
499
- allocatedRange-> values .size () == 1 &&
519
+ allocatedRange. values .size () == 1 &&
500
520
isTriviallyCloneableTileOp (
501
- allocatedRange->values [0 ]
502
- .getDefiningOp <ArmSMETileOpInterface>());
521
+ allocatedRange.values [0 ].getDefiningOp <ArmSMETileOpInterface>());
503
522
};
504
- if (isTrivialSpill (newRange))
523
+ if (isTrivialSpill (* newRange))
505
524
return newRange;
506
- auto trivialSpill = llvm::find_if (activeRanges , isTrivialSpill);
507
- if (trivialSpill != activeRanges .end ())
508
- return *trivialSpill;
525
+ auto trivialSpill = llvm::find_if (allOverlappingRanges , isTrivialSpill);
526
+ if (trivialSpill != allOverlappingRanges .end ())
527
+ return & *trivialSpill;
509
528
510
529
// Heuristic: Spill the range that ends last (with a compatible tile type).
511
- auto isSmallerTileTypeOrEndsEarlier = [](LiveRange * a, LiveRange * b) {
512
- return !isTileTypeGreaterOrEqual (a-> getTileType (), b-> getTileType ()) ||
513
- a-> end () < b-> end ();
530
+ auto isSmallerTileTypeOrEndsEarlier = [](LiveRange & a, LiveRange & b) {
531
+ return !isTileTypeGreaterOrEqual (a. getTileType (), b. getTileType ()) ||
532
+ a. end () < b. end ();
514
533
};
515
- LiveRange *lastActiveLiveRange = *std::max_element (
516
- activeRanges.begin (), activeRanges.end (), isSmallerTileTypeOrEndsEarlier);
517
- if (!isSmallerTileTypeOrEndsEarlier (lastActiveLiveRange, newRange))
518
- return lastActiveLiveRange;
534
+ LiveRange &lastActiveLiveRange = *std::max_element (
535
+ allOverlappingRanges.begin (), allOverlappingRanges.end (),
536
+ isSmallerTileTypeOrEndsEarlier);
537
+ if (!isSmallerTileTypeOrEndsEarlier (lastActiveLiveRange, *newRange))
538
+ return &lastActiveLiveRange;
519
539
return newRange;
520
540
}
521
541
522
542
// / Greedily allocate tile IDs to live ranges. Spill using simple heuristics.
523
- // / Note: This does not attempt to fill holes in active live ranges.
524
543
void allocateTilesToLiveRanges (
525
544
ArrayRef<LiveRange *> liveRangesSortedByStartPoint) {
526
545
TileAllocator tileAllocator;
527
546
SetVector<LiveRange *> activeRanges;
547
+ SetVector<LiveRange *> inactiveRanges;
528
548
for (LiveRange *nextRange : liveRangesSortedByStartPoint) {
529
- // Release tile IDs from live ranges that have ended.
530
549
activeRanges.remove_if ([&](LiveRange *activeRange) {
550
+ // Check for live ranges that have expired.
531
551
if (activeRange->end () <= nextRange->start ()) {
532
552
tileAllocator.releaseTileId (activeRange->getTileType (),
533
553
*activeRange->tileId );
534
554
return true ;
535
555
}
556
+ // Check for live ranges that have become inactive.
557
+ if (!activeRange->overlaps (nextRange->start ())) {
558
+ tileAllocator.releaseTileId (activeRange->getTileType (),
559
+ *activeRange->tileId );
560
+ inactiveRanges.insert (activeRange);
561
+ return true ;
562
+ }
563
+ return false ;
564
+ });
565
+ inactiveRanges.remove_if ([&](LiveRange *inactiveRange) {
566
+ // Check for live ranges that have expired.
567
+ if (inactiveRange->end () <= nextRange->start ()) {
568
+ return true ;
569
+ }
570
+ // Check for live ranges that have become active.
571
+ if (inactiveRange->overlaps (nextRange->start ())) {
572
+ tileAllocator.acquireTileId (inactiveRange->getTileType (),
573
+ *inactiveRange->tileId );
574
+ activeRanges.insert (inactiveRange);
575
+ return true ;
576
+ }
536
577
return false ;
537
578
});
538
579
580
+ // Collect inactive live ranges that overlap with the current new live
581
+ // range. We need to acquire the tile IDs of overlapping inactive ranges to
582
+ // prevent two (overlapping) live ranges from getting the same tile ID.
583
+ SmallVector<LiveRange *> overlappingInactiveRanges;
584
+ for (LiveRange *inactiveRange : inactiveRanges) {
585
+ if (inactiveRange->overlaps (*nextRange)) {
586
+ tileAllocator.acquireTileId (inactiveRange->getTileType (),
587
+ *inactiveRange->tileId );
588
+ overlappingInactiveRanges.push_back (inactiveRange);
589
+ }
590
+ }
591
+
539
592
// Allocate a tile ID to `nextRange`.
540
593
auto rangeTileType = nextRange->getTileType ();
541
594
auto tileId = tileAllocator.allocateTileId (rangeTileType);
542
595
if (succeeded (tileId)) {
543
596
nextRange->tileId = *tileId;
544
597
} else {
545
- LiveRange *rangeToSpill =
546
- chooseSpillUsingHeuristics ( activeRanges.getArrayRef (), nextRange);
598
+ LiveRange *rangeToSpill = chooseSpillUsingHeuristics (
599
+ activeRanges.getArrayRef (), overlappingInactiveRanges , nextRange);
547
600
if (rangeToSpill != nextRange) {
548
- // Spill an active live range (so release its tile ID first).
601
+ // Spill an (in) active live range (so release its tile ID first).
549
602
tileAllocator.releaseTileId (rangeToSpill->getTileType (),
550
603
*rangeToSpill->tileId );
551
- activeRanges.remove (rangeToSpill);
552
604
// This will always succeed after a spill (of an active live range).
553
605
nextRange->tileId = *tileAllocator.allocateTileId (rangeTileType);
606
+ // Remove the live range from the active/inactive sets.
607
+ if (!activeRanges.remove (rangeToSpill)) {
608
+ bool removed = inactiveRanges.remove (rangeToSpill);
609
+ assert (removed && " expected a range to be removed!" );
610
+ }
554
611
}
555
612
rangeToSpill->tileId = tileAllocator.allocateInMemoryTileId ();
556
613
}
557
614
558
615
// Insert the live range into the active ranges.
559
616
if (nextRange->tileId < kInMemoryTileIdBase )
560
617
activeRanges.insert (nextRange);
618
+
619
+ // Release tiles reserved for inactive live ranges.
620
+ for (LiveRange *range : overlappingInactiveRanges) {
621
+ if (*range->tileId < kInMemoryTileIdBase )
622
+ tileAllocator.releaseTileId (range->getTileType (), *range->tileId );
623
+ }
561
624
}
562
625
}
563
626
0 commit comments