Index: llvm/include/llvm/ADT/ilist_iterator.h =================================================================== --- llvm/include/llvm/ADT/ilist_iterator.h +++ llvm/include/llvm/ADT/ilist_iterator.h @@ -102,10 +102,23 @@ return *this; } - /// Convert from an iterator to its reverse. + /// Explicit conversion between forward/reverse iterators. /// - /// 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. + /// Translate between forward and reverse iterators without changing range + /// boundaries. The resulting iterator will dereference (and have a handle) + /// to the previous node, which is somewhat unexpected; but converting the + /// two endpoints in a range will give the same range in reverse. + /// + /// This matches std::reverse_iterator conversions. + explicit ilist_iterator( + const ilist_iterator &RHS) + : ilist_iterator(++RHS.getReverse()) {} + + /// Get a reverse iterator to the same node. + /// + /// Gives a reverse iterator that will dereference (and have a handle) to the + /// same node. Converting the endpoint iterators in a range will give a + /// different range; for range operations, use the explicit conversions. ilist_iterator getReverse() const { if (NodePtr) return ilist_iterator(*NodePtr); Index: llvm/include/llvm/CodeGen/MachineInstrBundleIterator.h =================================================================== --- llvm/include/llvm/CodeGen/MachineInstrBundleIterator.h +++ llvm/include/llvm/CodeGen/MachineInstrBundleIterator.h @@ -153,6 +153,18 @@ : MII(I.getInstrIterator()) {} MachineInstrBundleIterator() : MII(nullptr) {} + /// Explicit conversion between forward/reverse iterators. + /// + /// Translate between forward and reverse iterators without changing range + /// boundaries. The resulting iterator will dereference (and have a handle) + /// to the previous node, which is somewhat unexpected; but converting the + /// two endpoints in a range will give the same range in reverse. + /// + /// This matches std::reverse_iterator conversions. + explicit MachineInstrBundleIterator( + const MachineInstrBundleIterator &I) + : MachineInstrBundleIterator(++I.getReverse()) {} + /// Get the bundle iterator for the given instruction's bundle. static MachineInstrBundleIterator getAtBundleBegin(instr_iterator MI) { return MachineInstrBundleIteratorHelper::getBundleBegin(MI); @@ -258,6 +270,11 @@ nonconst_iterator getNonConstIterator() const { return MII.getNonConst(); } + /// Get a reverse iterator to the same node. + /// + /// Gives a reverse iterator that will dereference (and have a handle) to the + /// same node. Converting the endpoint iterators in a range will give a + /// different range; for range operations, use the explicit conversions. reverse_iterator getReverse() const { return MII.getReverse(); } }; Index: llvm/unittests/ADT/IListIteratorTest.cpp =================================================================== --- llvm/unittests/ADT/IListIteratorTest.cpp +++ llvm/unittests/ADT/IListIteratorTest.cpp @@ -131,4 +131,46 @@ EXPECT_EQ(L.rend(), RI); } +TEST(IListIteratorTest, ReverseConstructor) { + simple_ilist L; + const simple_ilist &CL = L; + Node A, B; + L.insert(L.end(), A); + L.insert(L.end(), B); + + // Save typing. + typedef simple_ilist::iterator iterator; + typedef simple_ilist::reverse_iterator reverse_iterator; + typedef simple_ilist::const_iterator const_iterator; + typedef simple_ilist::const_reverse_iterator const_reverse_iterator; + + // Check explicit conversions. + EXPECT_EQ(++CL.begin(), const_iterator(++CL.rbegin())); + EXPECT_EQ(++CL.begin(), const_iterator(++L.rbegin())); + EXPECT_EQ(++CL.rbegin(), const_reverse_iterator(++CL.begin())); + EXPECT_EQ(++CL.rbegin(), const_reverse_iterator(++L.begin())); + EXPECT_EQ(++L.begin(), iterator(++L.rbegin())); + EXPECT_EQ(++L.rbegin(), reverse_iterator(++L.begin())); + EXPECT_EQ(CL.begin(), const_iterator(CL.rend())); + EXPECT_EQ(CL.begin(), const_iterator(L.rend())); + EXPECT_EQ(CL.end(), const_iterator(CL.rbegin())); + EXPECT_EQ(CL.end(), const_iterator(L.rbegin())); + EXPECT_EQ(CL.rbegin(), const_reverse_iterator(CL.end())); + EXPECT_EQ(CL.rbegin(), const_reverse_iterator(L.end())); + EXPECT_EQ(CL.rend(), const_reverse_iterator(CL.begin())); + EXPECT_EQ(CL.rend(), const_reverse_iterator(L.begin())); + EXPECT_EQ(L.begin(), iterator(L.rend())); + EXPECT_EQ(L.end(), iterator(L.rbegin())); + EXPECT_EQ(L.rbegin(), reverse_iterator(L.end())); + EXPECT_EQ(L.rend(), reverse_iterator(L.begin())); + + // Confirm lack of implicit conversions. + EXPECT_FALSE((std::is_convertible::value)); + EXPECT_FALSE((std::is_convertible::value)); + EXPECT_FALSE( + (std::is_convertible::value)); + EXPECT_FALSE( + (std::is_convertible::value)); +} + } // end namespace Index: llvm/unittests/CodeGen/MachineInstrBundleIteratorTest.cpp =================================================================== --- llvm/unittests/CodeGen/MachineInstrBundleIteratorTest.cpp +++ llvm/unittests/CodeGen/MachineInstrBundleIteratorTest.cpp @@ -130,4 +130,70 @@ ASSERT_TRUE(CI != CMBI.getIterator()); } +struct MyUnbundledInstr + : ilist_node> { + bool isBundledWithPred() const { return false; } + bool isBundledWithSucc() const { return false; } +}; +typedef MachineInstrBundleIterator unbundled_iterator; +typedef MachineInstrBundleIterator + const_unbundled_iterator; +typedef MachineInstrBundleIterator + reverse_unbundled_iterator; +typedef MachineInstrBundleIterator + const_reverse_unbundled_iterator; + +TEST(MachineInstrBundleIteratorTest, ReverseConstructor) { + simple_ilist> L; + const auto &CL = L; + MyUnbundledInstr A, B; + L.insert(L.end(), A); + L.insert(L.end(), B); + + // Save typing. + typedef MachineInstrBundleIterator iterator; + typedef MachineInstrBundleIterator reverse_iterator; + typedef MachineInstrBundleIterator const_iterator; + typedef MachineInstrBundleIterator + const_reverse_iterator; + + // Convert to bundle iterators. + auto begin = [&]() -> iterator { return L.begin(); }; + auto end = [&]() -> iterator { return L.end(); }; + auto rbegin = [&]() -> reverse_iterator { return L.rbegin(); }; + auto rend = [&]() -> reverse_iterator { return L.rend(); }; + auto cbegin = [&]() -> const_iterator { return CL.begin(); }; + auto cend = [&]() -> const_iterator { return CL.end(); }; + auto crbegin = [&]() -> const_reverse_iterator { return CL.rbegin(); }; + auto crend = [&]() -> const_reverse_iterator { return CL.rend(); }; + + // Check explicit conversions. + EXPECT_EQ(++cbegin(), const_iterator(++crbegin())); + EXPECT_EQ(++cbegin(), const_iterator(++rbegin())); + EXPECT_EQ(++crbegin(), const_reverse_iterator(++cbegin())); + EXPECT_EQ(++crbegin(), const_reverse_iterator(++begin())); + EXPECT_EQ(++begin(), iterator(++rbegin())); + EXPECT_EQ(++rbegin(), reverse_iterator(++begin())); + EXPECT_EQ(cbegin(), const_iterator(crend())); + EXPECT_EQ(cbegin(), const_iterator(rend())); + EXPECT_EQ(cend(), const_iterator(crbegin())); + EXPECT_EQ(cend(), const_iterator(rbegin())); + EXPECT_EQ(crbegin(), const_reverse_iterator(cend())); + EXPECT_EQ(crbegin(), const_reverse_iterator(end())); + EXPECT_EQ(crend(), const_reverse_iterator(cbegin())); + EXPECT_EQ(crend(), const_reverse_iterator(begin())); + EXPECT_EQ(begin(), iterator(rend())); + EXPECT_EQ(end(), iterator(rbegin())); + EXPECT_EQ(rbegin(), reverse_iterator(end())); + EXPECT_EQ(rend(), reverse_iterator(begin())); + + // Confirm lack of implicit conversions. + EXPECT_FALSE((std::is_convertible::value)); + EXPECT_FALSE((std::is_convertible::value)); + EXPECT_FALSE( + (std::is_convertible::value)); + EXPECT_FALSE( + (std::is_convertible::value)); +} + } // end namespace