This is an archive of the discontinued LLVM Phabricator instance.

[ADT] Make filter_iterator support bidirectional iteration
ClosedPublic

Authored by vsk on Apr 19 2018, 6:01 PM.

Details

Summary

This makes it possible to reverse a filtered range. For example, here's
a way to visit memory accesses in a BasicBlock in reverse order:

auto MemInsts = reverse(make_filter_range(BB, [](Instruction &I) {
  return isa<StoreInst>(&I) || isa<LoadInst>(&I);
}));

for (auto &MI : MemInsts)
  ...

To implement this functionality, I factored out forward iteration
functionality into filter_iterator_base, and added a specialization of
filter_iterator_impl which supports bidirectional iteration. Thanks to
Tim Shen, Zachary Turner, and others for suggesting this design and
providing feedback! This version of the patch supersedes the original
(https://reviews.llvm.org/D45792).

This was motivated by a problem we encountered in D45657: we'd like to
visit the non-debug-info instructions in a BasicBlock in reverse order.

Testing: check-llvm, check-clang

Diff Detail

Repository
rL LLVM

Event Timeline

vsk created this revision.Apr 19 2018, 6:01 PM
mattd added a subscriber: mattd.Apr 20 2018, 12:16 AM
timshen added inline comments.Apr 20 2018, 12:54 PM
include/llvm/ADT/STLExtras.h
298 ↗(On Diff #143206)

Would std::bidirectional_iterator_tag simply work?

309 ↗(On Diff #143206)

If WrappedIteratorT is not bidirectional, we don't need this data member. Maybe add a comment about this optimization opportunity?

timshen added inline comments.Apr 20 2018, 1:58 PM
include/llvm/ADT/STLExtras.h
324 ↗(On Diff #143206)

I think it's better to have:

while (!Payload->Pred(*this->I))

Notice that as it is described in http://en.cppreference.com/w/cpp/concept/BidirectionalIterator, the precondition is "a is decrementable (there exists such b that a == ++b)". Therefore, there must be an iterator value that satisfies Payload->Pred(*this->I). If users wrote a bug by decrementing on begin, I'd rather keep looping and let sanitizers catch it.

timshen added inline comments.Apr 20 2018, 2:07 PM
include/llvm/ADT/STLExtras.h
344 ↗(On Diff #143206)

SFINAE wouldn't work here unless you make operator--() a function template, which is an overkill.

I suggest to specialize the class on bidirectional iterator. It might require some boilerplate. For example:

template <typename Iter,
                  typename Predicate,
                  typename iter_tag = typename iterator_traits<Iter>::iterator_category>
class filter_iterator_impl { ... };

template <typename Iter, typename Predicate>
class filter_iterator_impl<Iter, Predicate, std::bidrectional_iterator_tag> { ... };

template <typename Iter, typename Predicate>
using filter_iterator = filter_iterator_impl<Iter, Predicate>;  // to hide template parameter "iter_tag".
vsk updated this revision to Diff 143398.Apr 20 2018, 3:07 PM
vsk marked 4 inline comments as done.
vsk retitled this revision from (WIP) Alternate approach to reversing filtered iterators to [ADT] Teach reverse() about filter_iterator ranges.
vsk edited the summary of this revision. (Show Details)
  • Adopt design suggestions from Tim.
  • Remove the Optional<PayloadType> wrapper, because the end iterator requires a predicate functor in the common case.
vsk added inline comments.Apr 20 2018, 3:07 PM
include/llvm/ADT/STLExtras.h
298 ↗(On Diff #143206)

Neat, it would've worked.

However, I did still need detail::fwd_or_bidi_tag to implement the specialized version of filter_iterator_impl you described. That's because you'd need to check if the wrapped iterator's category is derived from bidirectional_iterator_tag to make the specialization work.

309 ↗(On Diff #143206)

As you pointed out, the Begin member isn't needed in the bidirectional case either, so I've removed it.

324 ↗(On Diff #143206)

I see, sounds good! That makes it possible to get rid of the Begin member.

344 ↗(On Diff #143206)

Thanks, this worked out.

vsk retitled this revision from [ADT] Teach reverse() about filter_iterator ranges to [ADT] Make filter_iterator support bidirectional iteration.Apr 20 2018, 3:11 PM
fhahn added a subscriber: fhahn.Apr 22 2018, 4:38 AM
fhahn added a comment.Apr 24 2018, 9:24 AM

Thank you very much for tackling this :)

timshen accepted this revision.Apr 25 2018, 2:37 PM

Looks good. The filter_iterator_base + filter_iterator_impl + filter_iterator hierarchy is unfortunately complicated, but I don't have any immediate ideas on simplifying it.

This revision is now accepted and ready to land.Apr 25 2018, 2:37 PM
This revision was automatically updated to reflect the committed changes.