Skip to content

Commit 406a7c9

Browse files
committed
[loop-region] Track the backedges of all loop regions.
We already computed this information so this is just storing information we were already computing. One thing to note is that in code with canonicalized loops, we will always only have one backedge. But we would like loop region to be correct even in the case of non-canonicalized code so we support having multiple back edges. But since the common case is 1 backedge, we optimize for that case. This commit contains updated tests and also updates to the loop region graph viewer so that it draws backedges as green arrows from the loop to its backedge subregions. The test updates were done by examining each test case by hand.
1 parent 3fd5e80 commit 406a7c9

File tree

3 files changed

+719
-254
lines changed

3 files changed

+719
-254
lines changed

include/swift/SILOptimizer/Analysis/LoopRegionAnalysis.h

Lines changed: 160 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,9 @@
131131
namespace swift {
132132

133133
/// A loop region is a data structure which represents one of a basic block,
134-
/// loop, or function. In the case of a loop, function, it contains an internal
134+
/// loop, or function.
135+
///
136+
/// In the case of a loop, function, it contains an internal
135137
/// data structure that represents the subregions of the loop/function. This
136138
/// data is tail allocated so that the basic block case is not penalized by
137139
/// storing this unnecessary information.
@@ -319,6 +321,66 @@ class LoopRegion {
319321
};
320322
using subregion_reverse_iterator = std::reverse_iterator<subregion_iterator>;
321323

324+
/// An iterator that knows how to iterate over the backedge indices of a
325+
/// region.
326+
class backedge_iterator
327+
: public std::iterator<std::bidirectional_iterator_tag, unsigned> {
328+
friend struct SubregionData;
329+
using InnerIterTy = llvm::SmallVectorImpl<unsigned>::const_iterator;
330+
llvm::Optional<InnerIterTy> InnerIter;
331+
332+
backedge_iterator(llvm::SmallVectorImpl<unsigned>::const_iterator iter)
333+
: InnerIter(iter) {}
334+
335+
public:
336+
using value_type = unsigned;
337+
using reference = unsigned;
338+
using pointer = void;
339+
using iterator_category = std::bidirectional_iterator_tag;
340+
using difference_type = int;
341+
342+
/// Construct a backedge_iterator suitable for use with a basic block. It
343+
/// does not contain any data and can only be compared against another
344+
/// invalid iterator (for which it will return true). Any other usage
345+
/// results in an unreachable being hit.
346+
backedge_iterator() : InnerIter() {}
347+
348+
bool hasValue() const { return InnerIter.hasValue(); }
349+
350+
/// Return the index of the current backedge index.
351+
unsigned operator*() const { return **InnerIter; }
352+
353+
backedge_iterator &operator++() {
354+
++(*InnerIter);
355+
return *this;
356+
}
357+
backedge_iterator operator++(int) {
358+
backedge_iterator iter = *this;
359+
++iter;
360+
return iter;
361+
}
362+
backedge_iterator &operator--() {
363+
--(*InnerIter);
364+
return *this;
365+
}
366+
backedge_iterator operator--(int) {
367+
backedge_iterator iter = *this;
368+
--iter;
369+
return iter;
370+
}
371+
bool operator==(backedge_iterator rhs) const {
372+
if (InnerIter.hasValue() != rhs.InnerIter.hasValue())
373+
llvm_unreachable("Comparing uncomparable iterators");
374+
// Now we know that the two either both have values or both do not have
375+
// values.
376+
if (!InnerIter.hasValue())
377+
return true;
378+
return *InnerIter == *rhs.InnerIter;
379+
}
380+
bool operator!=(backedge_iterator rhs) const { return !(*this == rhs); }
381+
};
382+
using backedge_reverse_iterator = std::reverse_iterator<backedge_iterator>;
383+
322384
private:
323385
/// A pointer to one of a Loop, Basic Block, or Function represented by this
324386
/// region.
@@ -383,6 +445,13 @@ class LoopRegion {
383445
/// used as the RPO number for the whole region.
384446
unsigned RPONumOfHeaderBlock;
385447

448+
/// The RPO number of the back edge blocks of this loop. We use a
449+
/// SmallVector of size 1 since after loop canonicalization we will always
450+
/// have exactly one back edge block. But we want to be correct even in a
451+
/// non-canonicalized case implying that we need to be able to support
452+
/// multiple backedge blocks.
453+
llvm::SmallVector<unsigned, 1> BackedgeRegions;
454+
386455
/// A list of subregion IDs of this region sorted in RPO order.
387456
///
388457
/// This takes advantage of the fact that the ID of a basic block is the
@@ -430,6 +499,29 @@ class LoopRegion {
430499
Subloops.push_back({Header->ID, L->ID});
431500
}
432501

502+
void addBackedgeSubregion(unsigned ID) {
503+
if (count(BackedgeRegions, ID))
504+
return;
505+
BackedgeRegions.push_back(ID);
506+
}
507+
508+
backedge_iterator backedge_begin() const {
509+
return backedge_iterator(BackedgeRegions.begin());
510+
}
511+
backedge_iterator backedge_end() const {
512+
return backedge_iterator(BackedgeRegions.end());
513+
}
514+
backedge_reverse_iterator backedge_rbegin() const {
515+
return backedge_reverse_iterator(backedge_begin());
516+
}
517+
backedge_reverse_iterator backedge_rend() const {
518+
return backedge_reverse_iterator(backedge_end());
519+
}
520+
bool backedge_empty() const { return BackedgeRegions.empty(); }
521+
unsigned backedge_size() const { return BackedgeRegions.size(); }
522+
523+
ArrayRef<unsigned> getBackedgeRegions() const { return BackedgeRegions; }
524+
433525
/// Once we finish processing a loop, we sort its subregions so that they
434526
/// are guaranteed to be in RPO order. This works because each BB's ID is
435527
/// its RPO number and we represent loops by the RPO number of their
@@ -441,7 +533,6 @@ class LoopRegion {
441533
/// going to sort just to be careful while bringing this up.
442534
void sortSubregions() { std::sort(Subregions.begin(), Subregions.end()); }
443535
};
444-
445536
public:
446537
~LoopRegion();
447538

@@ -476,21 +567,34 @@ class LoopRegion {
476567
return getSubregionData().end();
477568
}
478569

479-
bool subregions_empty() const { return getSubregionData().empty(); }
480-
unsigned subregions_size() const { return getSubregionData().size(); }
570+
bool subregions_empty() const {
571+
if (isBlock())
572+
return true;
573+
return getSubregionData().empty();
574+
}
575+
576+
unsigned subregions_size() const {
577+
if (isBlock())
578+
return 0;
579+
return getSubregionData().size();
580+
}
581+
481582
subregion_reverse_iterator subregion_rbegin() const {
482583
if (isBlock())
483584
return subregion_reverse_iterator();
484585
return getSubregionData().rbegin();
485586
}
587+
486588
subregion_reverse_iterator subregion_rend() const {
487589
if (isBlock())
488590
return subregion_reverse_iterator();
489591
return getSubregionData().rend();
490592
}
593+
491594
llvm::iterator_range<subregion_iterator> getSubregions() const {
492595
return {subregion_begin(), subregion_end()};
493596
}
597+
494598
llvm::iterator_range<subregion_reverse_iterator>
495599
getReverseSubregions() const {
496600
return {subregion_rbegin(), subregion_rend()};
@@ -510,6 +614,50 @@ class LoopRegion {
510614
return getSubregionData().ExitingSubregions;
511615
}
512616

617+
bool isBackedgeRegion(unsigned ID) const {
618+
if (isBlock())
619+
return false;
620+
return count(getSubregionData().getBackedgeRegions(), ID);
621+
}
622+
623+
ArrayRef<unsigned> getBackedgeRegions() const {
624+
if (isBlock())
625+
return ArrayRef<unsigned>();
626+
return getSubregionData().getBackedgeRegions();
627+
}
628+
629+
Optional<unsigned> getBackedgeRegion() const {
630+
if (isBlock())
631+
return None;
632+
auto bedge_begin = getSubregionData().backedge_begin();
633+
auto bedge_end = getSubregionData().backedge_end();
634+
if (bedge_begin == bedge_end)
635+
return None;
636+
return *bedge_begin;
637+
}
638+
639+
using backedge_iterator = backedge_iterator;
640+
backedge_iterator backedge_begin() const {
641+
if (isBlock())
642+
return backedge_iterator();
643+
return getSubregionData().backedge_begin();
644+
}
645+
backedge_iterator backedge_end() const {
646+
if (isBlock())
647+
return backedge_iterator();
648+
return getSubregionData().backedge_end();
649+
}
650+
bool backedge_empty() const {
651+
if (isBlock())
652+
return true;
653+
return getSubregionData().backedge_empty();
654+
}
655+
unsigned backedge_size() const {
656+
if (isBlock())
657+
return 0;
658+
return getSubregionData().backedge_size();
659+
}
660+
513661
using pred_const_iterator = decltype(Preds)::const_iterator;
514662
pred_const_iterator pred_begin() const { return Preds.begin(); }
515663
pred_const_iterator pred_end() const { return Preds.end(); }
@@ -781,9 +929,16 @@ class LoopRegionFunctionInfo {
781929
return IDToRegionMap[RegionID];
782930
}
783931

784-
RegionTy *getRegionForNonLocalSuccessor(const LoopRegion *Child,
932+
RegionTy *getRegionForNonLocalSuccessor(const RegionTy *Child,
785933
unsigned SuccID) const;
786934

935+
Optional<unsigned> getGrandparentID(const RegionTy *GrandChild) {
936+
if (auto ParentID = GrandChild->getParentID()) {
937+
return getRegion(*ParentID)->getParentID();
938+
}
939+
return None;
940+
}
941+
787942
/// Look up the region associated with this block and return it. Asserts if
788943
/// the block does not have a region associated with it.
789944
///

0 commit comments

Comments
 (0)