diff --git a/llvm/include/llvm/ADT/UniqueRange.h b/llvm/include/llvm/ADT/UniqueRange.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/ADT/UniqueRange.h @@ -0,0 +1,97 @@ +//===- llvm/ADT/UniqueIterator.h - Iterate over unique elements -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// An iterator adaptor that uniques the elements of given inner iterators. +// +// \code +// int A[] = { 1, 2, 3, 2 }; +// auto R = make_unique_range(A); +// // R contains { 1, 2, 3 }. +// \endcode +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_UNIQUEITERATOR_H +#define LLVM_ADT_UNIQUEITERATOR_H + +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/iterator.h" +#include "llvm/ADT/iterator_range.h" +#include +#include +#include + +namespace llvm { + +namespace detail { + +template +using IterOfRange = decltype(std::begin(std::declval())); + +template +using ValueOfIterOfRange = + typename std::remove_cv()))>::type>::type; + +} // end namespace detail + +template +class unique_iterator + : public iterator_adaptor_base, + WrappedIteratorT, + std::forward_iterator_tag> { + using BaseT = + iterator_adaptor_base, + WrappedIteratorT, std::forward_iterator_tag>; + + WrappedIteratorT End; + SetT Set; + + void findNextUnique() { + while (this->I != End && !Set.insert(*this->I).second) + BaseT::operator++(); + } + +public: + // Construct the iterator. The begin iterator needs to know where the end + // is, so that it can properly stop when it gets there. + unique_iterator(WrappedIteratorT Begin, WrappedIteratorT End) + : BaseT(Begin), End(End) { + findNextUnique(); + } + + using BaseT::operator++; + + unique_iterator &operator++() { + BaseT::operator++(); + findNextUnique(); + return *this; + } +}; + +/// Convenience function that takes a range of elements, +/// and return a new unique_iterator range. +/// +/// FIXME: Currently if RangeT && is a rvalue reference to a temporary, the +/// lifetime of that temporary is not kept by the returned range object, and the +/// temporary is going to be dropped on the floor after the make_iterator_range +/// full expression that contains this function call. +template , 8>> +iterator_range, SetT>> +make_unique_range(RangeT &&Range) { + using UniqueIteratorT = unique_iterator, SetT>; + return make_range(UniqueIteratorT(std::begin(std::forward(Range)), + std::end(std::forward(Range))), + UniqueIteratorT(std::end(std::forward(Range)), + std::end(std::forward(Range)))); +} + +} // end namespace llvm + +#endif // LLVM_ADT_UNIQUEITERATOR_H diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -22,6 +22,7 @@ #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/UniqueRange.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/AssumeBundleQueries.h" @@ -2583,11 +2584,8 @@ if (PN1->getParent() != PN2->getParent()) return false; - SmallPtrSet VisitedBBs; bool UsedFullRecursion = false; - for (const BasicBlock *IncomBB : PN1->blocks()) { - if (!VisitedBBs.insert(IncomBB).second) - continue; // Don't reprocess blocks that we have dealt with already. + for (const BasicBlock *IncomBB : make_unique_range(PN1->blocks())) { const Value *IV1 = PN1->getIncomingValueForBlock(IncomBB); const Value *IV2 = PN2->getIncomingValueForBlock(IncomBB); const APInt *C1, *C2; diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -24,6 +24,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/UniqueRange.h" #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/ConstantFolding.h" #include "llvm/Analysis/EHPersonalities.h" @@ -304,17 +305,18 @@ SmallPtrSet SI1Succs(succ_begin(SI1BB), succ_end(SI1BB)); bool Fail = false; - for (BasicBlock *Succ : successors(SI2BB)) - if (SI1Succs.count(Succ)) - for (BasicBlock::iterator BBI = Succ->begin(); isa(BBI); ++BBI) { - PHINode *PN = cast(BBI); - if (PN->getIncomingValueForBlock(SI1BB) != - PN->getIncomingValueForBlock(SI2BB)) { - if (FailBlocks) - FailBlocks->insert(Succ); - Fail = true; - } + for (BasicBlock *Succ : make_unique_range(successors(SI2BB))) { + if (!SI1Succs.count(Succ)) + continue; + for (PHINode &PN : Succ->phis()) { + if (PN.getIncomingValueForBlock(SI1BB) != + PN.getIncomingValueForBlock(SI2BB)) { + if (FailBlocks) + FailBlocks->insert(Succ); + Fail = true; } + } + } return !Fail; } diff --git a/llvm/unittests/ADT/IteratorTest.cpp b/llvm/unittests/ADT/IteratorTest.cpp --- a/llvm/unittests/ADT/IteratorTest.cpp +++ b/llvm/unittests/ADT/IteratorTest.cpp @@ -6,11 +6,12 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/ilist.h" #include "llvm/ADT/iterator.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/UniqueRange.h" +#include "llvm/ADT/ilist.h" #include "gtest/gtest.h" using namespace llvm; @@ -266,6 +267,63 @@ EXPECT_EQ((SmallVector{6, 4, 2, 0}), Actual4); } +TEST(UniqueIteratorTest, BasicInt) { + int A[] = {0, 4, 4, 1, 2, 1, 3, 4, 3}; + auto Range = make_unique_range(A); + SmallVector Actual(Range.begin(), Range.end()); + EXPECT_EQ((SmallVector{0, 4, 1, 2, 3}), Actual); +} + +TEST(UniqueIteratorTest, BasicPtr) { + void *A = nullptr, *B = nullptr, *C = nullptr, *D = nullptr; + void **Arr[] = {&A, &D, &C, &B, &A, &B, &B}; + auto Range = make_unique_range(Arr); + SmallVector Actual(Range.begin(), Range.end()); + EXPECT_EQ((SmallVector{&A, &D, &C, &B}), Actual); +} + +TEST(UniqueIteratorTest, Lazy) { + SmallSet Referenced; + struct Vindictive { + int i; + SmallSet *Referenced; + bool operator<(const Vindictive &Other) const { + Referenced->insert(i); + Referenced->insert(Other.i); + return i < Other.i; + } + bool operator==(const Vindictive &Other) const { + Referenced->insert(i); + Referenced->insert(Other.i); + return i == Other.i; + } + }; + Vindictive A[] = { + {0, &Referenced}, {2, &Referenced}, {3, &Referenced}, {5, &Referenced}}; + auto Range = make_unique_range(A); + auto Begin = Range.begin(); + auto End = Range.begin(); + { + SmallVector ReferencedActual(Referenced.begin(), Referenced.end()); + EXPECT_EQ((SmallVector{}), ReferencedActual); + } + ++Begin; + { + SmallVector ReferencedActual(Referenced.begin(), Referenced.end()); + EXPECT_EQ((SmallVector{0, 2}), ReferencedActual); + } + ++Begin; + { + SmallVector ReferencedActual(Referenced.begin(), Referenced.end()); + EXPECT_EQ((SmallVector{0, 2, 3}), ReferencedActual); + } + ++Begin; + { + SmallVector ReferencedActual(Referenced.begin(), Referenced.end()); + EXPECT_EQ((SmallVector{0, 2, 3, 5}), ReferencedActual); + } +} + TEST(PointerIterator, Basic) { int A[] = {1, 2, 3, 4}; pointer_iterator Begin(std::begin(A)), End(std::end(A));