[llvm-commits] [Please review][PATCH] Implement the block_iterator of Region based on df_iterator.
Tobias Grosser
tobias at grosser.es
Thu Aug 2 05:08:15 PDT 2012
On 08/01/2012 11:32 AM, Hongbin Zheng wrote:
> Hi,
>
> A few days ago in the polly-dev list,
> Antoine<trouve.antoine at gmail.com> pointed out that the implementation
> of block_iterator of the (single-entry single-exit) Region class is
> hard to understand,
> so I try to implement the block_iterator of Region based on
> df_iterator, which is simpler.
>
> The general idea is, by iterate the BB in DF order from the entry of
> the region and marking the exit block of the single-entry single-exit
> region as visited when we build the begin iterator, the iteration will
> never visit the exit block and its successors, i.e. the blocks may be
> visited by the DF iterator but outside the region.
Hi ether,
thanks for the patch. Here some comments:
> diff --git a/include/llvm/Analysis/RegionInfo.h
> b/include/llvm/Analysis/RegionInfo.h
> index eae94e7..310dcd6 100644
> --- a/include/llvm/Analysis/RegionInfo.h
> +++ b/include/llvm/Analysis/RegionInfo.h
> @@ -500,50 +500,59 @@ public:
> /// Region. The iterator also iterates over BasicBlocks that are elements of
> /// a subregion of this Region. It is therefore called a flat iterator.
> //@{
> - template <typename RegionNodeItT>
> + template <bool IsConst>
> class block_iterator_wrapper
> - : public std::iterator<std::forward_iterator_tag, BasicBlock, ptrdiff_t> {
> - typedef std::iterator<std::forward_iterator_tag, BasicBlock, ptrdiff_t>
> + : public df_iterator<typename conditional<IsConst,
> + const BasicBlock,
> + BasicBlock>::type*> {
> + typedef df_iterator<typename conditional<IsConst,
> + const BasicBlock,
> + BasicBlock>::type*>
> super;
> -
> - RegionNodeItT Iter;
> -
> public:
> - typedef block_iterator_wrapper<RegionNodeItT> Self;
> + typedef block_iterator_wrapper<IsConst> Self;
> typedef typename super::pointer pointer;
>
> - block_iterator_wrapper(RegionNodeItT Iter) : Iter(Iter) {}
> -
> - bool operator==(const Self &RHS) const { return Iter == RHS.Iter; }
> - bool operator!=(const Self &RHS) const { return Iter != RHS.Iter; }
> - pointer operator*() const {
> - return (*Iter)->template getNodeAs<BasicBlock>();
I think we should define our own operator* as follows.
// FIXME: Even a const_iterator returns a non-const BasicBlock pointer.
// This was introduced for backwards compatibility, but should
// be removed as soon as all users are fixed.
BasicBlock *operator*() const {
return const_cast<BasicBlock*>(super::operator*());
}
> + // Construct the end iterator.
> + block_iterator_wrapper() : super(df_end<pointer>(0)) {}
> +
> + block_iterator_wrapper(super I) : super(I) {}
> +
> Self& operator++() {
> - ++Iter;
> + super::operator++();
> return *this;
> }
Is it necessary to redefine that function?
I believe you can just remove it and calls will automatically be
forwarded to the definition in df_iterator.
> Self operator++(int) {
> - Self tmp = *this;
> - ++*this;
> - return tmp;
> - }
> -
> - const Self &operator=(const Self &I) {
> - Iter = I.Iter;
> - return *this;
> + return super::operator++(0);
> }
Is it necessary to redefine that function?
I believe you can just remove it and calls will automatically be
forwarded to the definition in df_iterator.
(Also, both implementations (the old and the new one) look incorrect.
The old one was always incrementing by one, the new one is not
incremented at all. I believe the iterator should be incremented by as
many steps as defined by the parameter. Removing our implementation,
should give us the correct implementation from df_iterator)
> };
> - typedef block_iterator_wrapper<block_node_iterator> block_iterator;
> - typedef block_iterator_wrapper<const_block_node_iterator>
> - const_block_iterator;
>
> - block_iterator block_begin();
> - block_iterator block_end();
> + typedef block_iterator_wrapper<false> block_iterator;
> + typedef block_iterator_wrapper<true> const_block_iterator;
> +
> + block_iterator block_begin() const {
> + return block_iterator(getEntry(), getExit());
> + }
>
> - const_block_iterator block_begin() const;
> - const_block_iterator block_end() const;
> + block_iterator block_end() const {
> + return block_iterator();
> + }
> +
> + const_block_iterator const_block_begin() const {
> + return const_block_iterator(getEntry(), getExit());
> + }
> + const_block_iterator const_block_end() const {
> + return const_block_iterator();
> + }
This changes the interface of the iterator in a surprising way. Being
able to get a non-const iterator from a const Region is surprising. I
think we should keep the signatures of block_begin() and block_end() as
they are today. Meaning:
block_iterator block_begin();
block_iterator block_end();
const_block_iterator block_begin() const;
const_block_iterator block_end() const;
> --- a/lib/Analysis/RegionPrinter.cpp
> +++ b/lib/Analysis/RegionPrinter.cpp
> @@ -121,7 +121,7 @@ struct DOTGraphTraits<RegionInfo*> : public
> DOTGraphTraits<RegionNode*> {
>
> RegionInfo *RI = R->getRegionInfo();
>
> - for (Region::const_block_iterator BI = R->block_begin(),
> + for (Region::block_iterator BI = R->block_begin(),
> BE = R->block_end(); BI != BE; ++BI)
> if (RI->getRegionFor(*BI) == R)
> O.indent(2 * (depth + 1)) << "Node"
I don't think this change is correct. We should rather add a version of
RI->getRegionFor() that returns a const BasicBlock in case a const
Region is passed in.
With the FIXME I proposed above, fixing this (and similar problems in
Polly) is not immediately required. I propose to first commit the
df_iterator improvement and then to fix the unrelated const correctness
issues in subsequent patches.
Cheers
Tobi
More information about the llvm-commits
mailing list