summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorJay Foad <jay.foad@gmail.com>2012-02-23 09:16:04 +0000
committerJay Foad <jay.foad@gmail.com>2012-02-23 09:16:04 +0000
commit6592eacf9006d046e8bc4999600e2973a3b56eac (patch)
treea8f2920a38d80052600147c30fb16f49e3307f1d /include
parent9d91c5d31c6758124559c0916d852295f47a2bec (diff)
downloadllvm-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.h46
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