Index: include/llvm/ADT/SmallPtrSet.h =================================================================== --- include/llvm/ADT/SmallPtrSet.h +++ include/llvm/ADT/SmallPtrSet.h @@ -27,6 +27,12 @@ #include namespace llvm { +#if LLVM_ENABLE_ABI_BREAKING_CHECKS +extern bool ReverseIterate; +#endif +} + +namespace llvm { class SmallPtrSetIteratorImpl; @@ -205,7 +211,12 @@ public: explicit SmallPtrSetIteratorImpl(const void *const *BP, const void*const *E) : Bucket(BP), End(E) { - AdvanceIfNotValid(); +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + if (ReverseIterate) + RetreatIfNotValid(); + else +#endif + AdvanceIfNotValid(); } bool operator==(const SmallPtrSetIteratorImpl &RHS) const { @@ -226,6 +237,17 @@ *Bucket == SmallPtrSetImplBase::getTombstoneMarker())) ++Bucket; } +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + void RetreatIfNotValid() { + --Bucket; + assert(Bucket <= End); + while (Bucket != End && + (*Bucket == SmallPtrSetImplBase::getEmptyMarker() || + *Bucket == SmallPtrSetImplBase::getTombstoneMarker())) { + --Bucket; + } + } +#endif }; /// SmallPtrSetIterator - This implements a const_iterator for SmallPtrSet. @@ -251,13 +273,29 @@ } inline SmallPtrSetIterator& operator++() { // Preincrement +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + if (ReverseIterate) + RetreatIfNotValid(); + else { + ++Bucket; + AdvanceIfNotValid(); + } +#else ++Bucket; AdvanceIfNotValid(); +#endif return *this; } SmallPtrSetIterator operator++(int) { // Postincrement - SmallPtrSetIterator tmp = *this; ++*this; return tmp; + SmallPtrSetIterator tmp = *this; +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + if (ReverseIterate) + --*this; + else +#endif + ++*this; + return tmp; } }; @@ -342,9 +380,23 @@ } inline iterator begin() const { +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + if (ReverseIterate) + return endPtr(); +#endif return iterator(CurArray, EndPointer()); } + inline iterator end() const { +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + if (ReverseIterate) + return iterator(CurArray, CurArray); +#endif + return endPtr(); + } + +private: + inline iterator endPtr() const { const void *const *End = EndPointer(); return iterator(End, End); } Index: lib/Support/CommandLine.cpp =================================================================== --- lib/Support/CommandLine.cpp +++ lib/Support/CommandLine.cpp @@ -45,6 +45,18 @@ #define DEBUG_TYPE "commandline" +namespace llvm { +// If LLVM_ENABLE_ABI_BREAKING_CHECKS is set the flag -mllvm -reverse-iterate +// can be used to toggle forward/reverse iteration of unordered containers. +// This will help uncover differences in codegen caused due to undefined +// iteration order. +#if LLVM_ENABLE_ABI_BREAKING_CHECKS +bool ReverseIterate; +static cl::opt ReverseIteration("reverse-iterate", + cl::location(ReverseIterate), cl::init(true)); +#endif +} + //===----------------------------------------------------------------------===// // Template instantiations and anchors. // Index: unittests/ADT/CMakeLists.txt =================================================================== --- unittests/ADT/CMakeLists.txt +++ unittests/ADT/CMakeLists.txt @@ -41,6 +41,7 @@ PostOrderIteratorTest.cpp PriorityWorklistTest.cpp RangeAdapterTest.cpp + ReverseIterationTest.cpp SCCIteratorTest.cpp STLExtrasTest.cpp ScopeExitTest.cpp Index: unittests/ADT/ReverseIterationTest.cpp =================================================================== --- /dev/null +++ unittests/ADT/ReverseIterationTest.cpp @@ -0,0 +1,41 @@ +//===- llvm/unittest/ADT/ReverseIterationTest.cpp ------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// ReverseIteration unit tests. +// +//===----------------------------------------------------------------------===// + +#include "gtest/gtest.h" +#include "llvm/ADT/SmallPtrSet.h" + +using namespace llvm; + +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + +TEST(ReverseIterationTest, SmallPtrSetTest) { + + SmallPtrSet Set; + void *Ptrs[] = { (void*)0x1, (void*)0x2, (void*)0x3, (void*)0x4 }; + void *ReversePtrs[] = { (void*)0x4, (void*)0x3, (void*)0x2, (void*)0x1 }; + + for (auto *Ptr: Ptrs) + Set.insert(Ptr); + + // Check forward iteration. + ReverseIterate = false; + for (const auto &Tuple : zip(Set, Ptrs)) + ASSERT_EQ(std::get<0>(Tuple), std::get<1>(Tuple)); + + // Check reverse iteration. + ReverseIterate = true; + for (const auto &Tuple : zip(Set, ReversePtrs)) + ASSERT_EQ(std::get<0>(Tuple), std::get<1>(Tuple)); +} + +#endif // LLVM_ENABLE_ABI_BREAKING_CHECKS