Index: include/llvm/ADT/SmallPtrSet.h =================================================================== --- include/llvm/ADT/SmallPtrSet.h +++ include/llvm/ADT/SmallPtrSet.h @@ -25,6 +25,13 @@ #include #include +#if LLVM_ENABLE_ABI_BREAKING_CHECKS +namespace llvm { +template struct ReverseIterate { static bool value; }; +template bool ReverseIterate::value = false; +} +#endif + namespace llvm { /// SmallPtrSetImplBase - This is the common code shared among all the @@ -206,7 +213,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::value) + RetreatIfNotValid(); + else +#endif + AdvanceIfNotValid(); } bool operator==(const SmallPtrSetIteratorImpl &RHS) const { @@ -227,6 +239,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. @@ -252,13 +275,29 @@ } inline SmallPtrSetIterator& operator++() { // Preincrement +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + if (ReverseIterate::value) + 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::value) + --*this; + else +#endif + ++*this; + return tmp; } }; @@ -343,9 +382,22 @@ } inline iterator begin() const { +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + if (ReverseIterate::value) + return endPtr(); +#endif return iterator(CurArray, EndPointer()); } inline iterator end() const { +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + if (ReverseIterate::value) + 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,19 @@ #define DEBUG_TYPE "commandline" +#if LLVM_ENABLE_ABI_BREAKING_CHECKS +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. +template struct ReverseIterate { static bool value; }; +template bool ReverseIterate::value = false; +static cl::opt ReverseIteration("reverse-iterate", + cl::location(ReverseIterate::value), cl::init(true)); +} +#endif + //===----------------------------------------------------------------------===// // Template instantiations and anchors. // Index: unittests/ADT/CMakeLists.txt =================================================================== --- unittests/ADT/CMakeLists.txt +++ unittests/ADT/CMakeLists.txt @@ -63,6 +63,11 @@ VariadicFunctionTest.cpp ) +if(DEFINED LLVM_ENABLE_ABI_BREAKING_CHECKS) + add_definitions(-DLLVM_ENABLE_ABI_BREAKING_CHECKS) + list(APPEND ADTSources ReverseIterationTest.cpp) +endif() + add_llvm_unittest(ADTTests ${ADTSources} ) Index: unittests/ADT/ReverseIterationTest.cpp =================================================================== --- /dev/null +++ unittests/ADT/ReverseIterationTest.cpp @@ -0,0 +1,37 @@ +//===- 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; + +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::value = false; + for (const auto &Tuple : zip(Set, Ptrs)) + ASSERT_EQ(std::get<0>(Tuple), std::get<1>(Tuple)); + + // Check reverse iteration. + ReverseIterate::value = true; + for (const auto &Tuple : zip(Set, ReversePtrs)) + ASSERT_EQ(std::get<0>(Tuple), std::get<1>(Tuple)); +}