diff options
-rw-r--r-- | llvm/include/llvm/ADT/STLExtras.h | 33 | ||||
-rw-r--r-- | llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 2 | ||||
-rw-r--r-- | llvm/lib/Transforms/Scalar/NewGVN.cpp | 8 | ||||
-rw-r--r-- | llvm/unittests/ADT/STLExtrasTest.cpp | 15 |
4 files changed, 39 insertions, 19 deletions
diff --git a/llvm/include/llvm/ADT/STLExtras.h b/llvm/include/llvm/ADT/STLExtras.h index 03109a078ed..3d6d7a6d2a8 100644 --- a/llvm/include/llvm/ADT/STLExtras.h +++ b/llvm/include/llvm/ADT/STLExtras.h @@ -1005,6 +1005,18 @@ void DeleteContainerSeconds(Container &C) { C.clear(); } +/// Get the size of a range. This is a wrapper function around std::distance +/// which is only enabled when the operation is O(1). +template <typename R> +auto size(R &&Range, typename std::enable_if< + std::is_same<typename std::iterator_traits<decltype( + Range.begin())>::iterator_category, + std::random_access_iterator_tag>::value, + void>::type * = nullptr) + -> decltype(std::distance(Range.begin(), Range.end())) { + return std::distance(Range.begin(), Range.end()); +} + /// Provide wrappers to std::for_each which take ranges instead of having to /// pass begin/end explicitly. template <typename R, typename UnaryPredicate> @@ -1115,6 +1127,15 @@ auto lower_bound(R &&Range, ForwardIt I) -> decltype(adl_begin(Range)) { return std::lower_bound(adl_begin(Range), adl_end(Range), I); } +/// Wrapper function around std::equal to detect if all elements +/// in a container are same. +template <typename R> +bool is_splat(R &&Range) { + size_t range_size = size(Range); + return range_size != 0 && (range_size == 1 || + std::equal(adl_begin(Range) + 1, adl_end(Range), adl_begin(Range))); +} + /// Given a range of type R, iterate the entire range and return a /// SmallVector with elements of the vector. This is useful, for example, /// when you want to iterate a range and then sort the results. @@ -1136,18 +1157,6 @@ void erase_if(Container &C, UnaryPredicate P) { C.erase(remove_if(C, P), C.end()); } -/// Get the size of a range. This is a wrapper function around std::distance -/// which is only enabled when the operation is O(1). -template <typename R> -auto size(R &&Range, typename std::enable_if< - std::is_same<typename std::iterator_traits<decltype( - Range.begin())>::iterator_category, - std::random_access_iterator_tag>::value, - void>::type * = nullptr) - -> decltype(std::distance(Range.begin(), Range.end())) { - return std::distance(Range.begin(), Range.end()); -} - //===----------------------------------------------------------------------===// // Extra additions to <memory> //===----------------------------------------------------------------------===// diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index f0efe4da6e6..9ae5b3c6590 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -2931,7 +2931,7 @@ void SelectionDAGBuilder::visitSelect(const User &I) { ISD::VSELECT : ISD::SELECT; // Min/max matching is only viable if all output VTs are the same. - if (std::equal(ValueVTs.begin(), ValueVTs.end(), ValueVTs.begin())) { + if (is_splat(ValueVTs)) { EVT VT = ValueVTs[0]; LLVMContext &Ctx = *DAG.getContext(); auto &TLI = DAG.getTargetLoweringInfo(); diff --git a/llvm/lib/Transforms/Scalar/NewGVN.cpp b/llvm/lib/Transforms/Scalar/NewGVN.cpp index 4dfde3a22a0..bfb7d3dd8ad 100644 --- a/llvm/lib/Transforms/Scalar/NewGVN.cpp +++ b/llvm/lib/Transforms/Scalar/NewGVN.cpp @@ -3174,10 +3174,7 @@ bool NewGVN::singleReachablePHIPath( SmallVector<const Value *, 32> OperandList; std::copy(FilteredPhiArgs.begin(), FilteredPhiArgs.end(), std::back_inserter(OperandList)); - bool Okay = OperandList.size() == 1; - if (!Okay) - Okay = - std::equal(OperandList.begin(), OperandList.end(), OperandList.begin()); + bool Okay = is_splat(OperandList); if (Okay) return singleReachablePHIPath(Visited, cast<MemoryAccess>(OperandList[0]), Second); @@ -3272,8 +3269,7 @@ void NewGVN::verifyMemoryCongruency() const { const MemoryDef *MD = cast<MemoryDef>(U); return ValueToClass.lookup(MD->getMemoryInst()); }); - assert(std::equal(PhiOpClasses.begin(), PhiOpClasses.end(), - PhiOpClasses.begin()) && + assert(is_splat(PhiOpClasses) && "All MemoryPhi arguments should be in the same class"); } } diff --git a/llvm/unittests/ADT/STLExtrasTest.cpp b/llvm/unittests/ADT/STLExtrasTest.cpp index 1e1e9c3d5f0..427d470b61d 100644 --- a/llvm/unittests/ADT/STLExtrasTest.cpp +++ b/llvm/unittests/ADT/STLExtrasTest.cpp @@ -415,4 +415,19 @@ TEST(STLExtrasTest, EarlyIncrementTest) { EXPECT_EQ(EIR.end(), I); } +TEST(STLExtrasTest, splat) { + std::vector<int> V; + EXPECT_FALSE(is_splat(V)); + + V.push_back(1); + EXPECT_TRUE(is_splat(V)); + + V.push_back(1); + V.push_back(1); + EXPECT_TRUE(is_splat(V)); + + V.push_back(2); + EXPECT_FALSE(is_splat(V)); +} + } // namespace |