[PATCH] D27792: IfConversion: Use reverse_iterator to simplify. NFC

Duncan P. N. Exon Smith via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 20 15:32:50 PST 2016


Normally, reverse iterators are not off-by-one.  See the reverse iterators provided by containers like std::set, std::map, std::list, etc..  All of these have a handle to the same node that is getting dereferenced.  They work by having a sentinel, rend(), that's past the final (reverse) element.  They have similar guarantees to the forward iterators: they are only invalidated when the pointed-to-node gets deleted.

std::reverse_iterator is an adaptor meant for "abnormal" situations.  Array containers (like std::vector) can't implement the "normal" semantics, since you can't have a handle to something past the final-reverse/first-forward element of the array.  In array containers, iterators are always invalidated by operations that mutate the container.

Before my commits, std::reverse_iterator was being used to implement ilist::reverse_iterator.  This was somewhat of an abomination.
- It would get invalidated only if you deleted the handled-node (one past the pointed-to-node).
- It would get incremented if you deleted the pointed-to-node.
- rend() would get invalidated if you deleted the first node (final reverse node).

After my commits, ilist::reverse_iterator has similar behaviour to ilist::iterator (and std::{list,set,map}::{reverse_,}iterater).  The same goes for MachineBasicBlock::reverse_iterator, which is actually a higher-level wrapper around an ilist::reverse_iterator.


In order to try to find some of the code that relied on the old/broken behaviour, I didn't implement explicit constructors between ilist::iterator and ilist::reverse_iterator.
- We should probably do that at some point.
- I left a note saying so (which is perhaps what was found here).


I haven't looked at this patch; from the limited context here, I don't understand why you'd *want* off-by-one accounting.  Off-by-one accounting is usually complicated and hard to reason about...

> On 2016-Dec-20, at 13:43, David Blaikie <dblaikie at gmail.com> wrote:
> 
> Duncan - looks like you were working on ilist when you added this comment about the reverse iterator - any particular insight that might be relevant here?
> 
> Conversely, Kyle - is the comment needed? If getReverse gives a reverse iterator that points to the current element of the original iterator, it seems like that'd be obvious & not require a comment (& perhaps that was the point of the ilist API change there)? (If I'm understanding correctly)
> 
> On Tue, Dec 20, 2016 at 1:01 PM Kyle Butt via Phabricator <reviews at reviews.llvm.org> wrote:
> iteratee added inline comments.
> 
> 
> ================
> Comment at: lib/CodeGen/IfConversion.cpp:646-647
>    // Now, in preparation for counting duplicate instructions at the ends of the
> -  // blocks, move the end iterators up past any branch instructions.
> -  --TIE;
> -  --FIE;
> -
> -  // After this point TIB and TIE define an inclusive range, which means that
> -  // TIB == TIE is true when there is one more instruction to consider, not at
> -  // the end. Because we may not be able to go before TIB, we need a flag to
> -  // indicate a completely empty range.
> -  bool TEmpty = false, FEmpty = false;
> -
> -  // Upon exit TIE and FIE will both point at the last non-shared instruction.
> -  // They need to be moved forward to point past the last non-shared
> -  // instruction if the range they delimit is non-empty.
> -  auto IncrementEndIteratorsOnExit = make_scope_exit([&]() {
> -    if (!TEmpty)
> -      ++TIE;
> -    if (!FEmpty)
> -      ++FIE;
> -  });
> +  // blocks, switch to reverse_iterators. Note that these are NOT std
> +  // reverse_iterators, so we have to manually do the off by one accounting.
> +  MachineBasicBlock::reverse_iterator RTIE = ++(TIE.getReverse());
> ----------------
> dblaikie wrote:
> > Is this something we should be relying on? Does the spec say how reverse iterators can/should be constructed from non-reverse iterators in general? (and is MBB violating that contract?)
> >
> > Should we be fixing MBB's reverse_iterators to do this accounting if it's the usual/expected/precedential (which is totally a word) thing?
> See the comment in include/llvm/ADT/ilist_iterator.h:
> 
>   /// Convert from an iterator to its reverse.
>   ///
>   /// TODO: Roll this into the implicit constructor once we're sure that no one
>   /// is relying on the std::reverse_iterator off-by-one semantics.
> 
> I take that to mean that we are intentionally not supplying the std::reverse_iterator semantics.
> 
> The comment is aimed at a reader familiar with those semantics.
> 
> 
> https://reviews.llvm.org/D27792
> 
> 
> 



More information about the llvm-commits mailing list