diff options
author | Jay Foad <jay.foad@gmail.com> | 2012-02-23 09:16:04 +0000 |
---|---|---|
committer | Jay Foad <jay.foad@gmail.com> | 2012-02-23 09:16:04 +0000 |
commit | 6592eacf9006d046e8bc4999600e2973a3b56eac (patch) | |
tree | a8f2920a38d80052600147c30fb16f49e3307f1d /include | |
parent | 9d91c5d31c6758124559c0916d852295f47a2bec (diff) | |
download | llvm-6592eacf9006d046e8bc4999600e2973a3b56eac.tar.gz llvm-6592eacf9006d046e8bc4999600e2973a3b56eac.tar.bz2 llvm-6592eacf9006d046e8bc4999600e2973a3b56eac.tar.xz |
The implementation of GeneralHash::addBits broke C++ aliasing rules; fix
it with memcpy. This also fixes a problem on big-endian hosts, where
addUnaligned would return different results depending on the alignment
of the data.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@151247 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'include')
-rw-r--r-- | include/llvm/ADT/Hashing.h | 46 |
1 files changed, 20 insertions, 26 deletions
diff --git a/include/llvm/ADT/Hashing.h b/include/llvm/ADT/Hashing.h index 07c62efe77..27c411e322 100644 --- a/include/llvm/ADT/Hashing.h +++ b/include/llvm/ADT/Hashing.h @@ -19,6 +19,7 @@ #include "llvm/Support/AlignOf.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/DataTypes.h" +#include <cstring> namespace llvm { @@ -140,39 +141,32 @@ private: mix(uint32_t(Val)); } - template<typename T, bool isAligned> - struct addBitsImpl { - static void add(GeneralHash &Hash, const T *I, const T *E) { - Hash.addUnaligned( - reinterpret_cast<const uint8_t *>(I), - reinterpret_cast<const uint8_t *>(E)); + // Add a range of bytes from I to E. + void addBytes(const char *I, const char *E) { + uint32_t Data; + // Note that aliasing rules forbid us from dereferencing + // reinterpret_cast<uint32_t *>(I) even if I happens to be suitably + // aligned, so we use memcpy instead. + for (; E - I >= ptrdiff_t(sizeof Data); I += sizeof Data) { + // A clever compiler should be able to turn this memcpy into a single + // aligned or unaligned load (depending on the alignment of the type T + // that was used in the call to addBits). + std::memcpy(&Data, I, sizeof Data); + mix(Data); } - }; - - template<typename T> - struct addBitsImpl<T, true> { - static void add(GeneralHash &Hash, const T *I, const T *E) { - Hash.addAligned( - reinterpret_cast<const uint32_t *>(I), - reinterpret_cast<const uint32_t *>(E)); + if (I != E) { + Data = 0; + std::memcpy(&Data, I, E - I); + mix(Data); } - }; + } // Add a range of bits from I to E. template<typename T> void addBits(const T *I, const T *E) { - addBitsImpl<T, AlignOf<T>::Alignment_GreaterEqual_4Bytes>::add(*this, I, E); + addBytes(reinterpret_cast<const char *>(I), + reinterpret_cast<const char *>(E)); } - - // Add a range of uint32s - void addAligned(const uint32_t *I, const uint32_t *E) { - while (I < E) { - mix(*I++); - } - } - - // Add a possibly unaligned sequence of bytes. - void addUnaligned(const uint8_t *I, const uint8_t *E); }; } // end namespace llvm |