diff options
author | Alon Zakai <azakai@google.com> | 2024-11-04 12:56:46 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-11-04 12:56:46 -0800 |
commit | c35e9871697b0b103228a96e9e79066e762d5e22 (patch) | |
tree | bcd8ae8f24e0b7e62ca309f35513553b727ee112 /src | |
parent | 9f496abc5cf1ddbca8c8a4f4e740c412588708ef (diff) | |
download | binaryen-c35e9871697b0b103228a96e9e79066e762d5e22.tar.gz binaryen-c35e9871697b0b103228a96e9e79066e762d5e22.tar.bz2 binaryen-c35e9871697b0b103228a96e9e79066e762d5e22.zip |
Make 32-bit hashing identical to 64-bit in TypeSSA (#7048)
This is NFC on 64-bit systems but noticeable on 32.
Also remove the 32-bit path in hash_combine. That isn't necessary for this fix,
but it makes the code simpler and also makes debugging between systems
simpler. It might also avoid problems in future cases, if we are lucky. The only
cost is perhaps a slight slowdown on 32-bit systems, which seems worth it.
Fixes #7046
Diffstat (limited to 'src')
-rw-r--r-- | src/passes/TypeSSA.cpp | 10 | ||||
-rw-r--r-- | src/support/hash.h | 22 |
2 files changed, 19 insertions, 13 deletions
diff --git a/src/passes/TypeSSA.cpp b/src/passes/TypeSSA.cpp index 8ba6c10c4..cda78474b 100644 --- a/src/passes/TypeSSA.cpp +++ b/src/passes/TypeSSA.cpp @@ -92,8 +92,12 @@ std::vector<HeapType> ensureTypesAreInNewRecGroup(RecGroup recGroup, // "random" extra item in the rec group that is so outlandish it will // surely (?) never collide with anything. We must loop while doing so, // until we find a hash that does not collide. - auto hashSize = num + 10; - size_t random = num; + // + // Note that we use uint64_t here, and deterministic_hash_combine below, to + // ensure our output is fully deterministic - the types we add here are + // observable in the output. + uint64_t hashSize = num + 10; + uint64_t random = num; while (1) { // Make a builder and add a slot for the hash. TypeBuilder builder(num + 1); @@ -106,7 +110,7 @@ std::vector<HeapType> ensureTypesAreInNewRecGroup(RecGroup recGroup, for (Index i = 0; i < hashSize; i++) { // TODO: a denser encoding? auto type = (random & 1) ? Type::i32 : Type::f64; - hash_combine(random, hashSize + i); + deterministic_hash_combine(random, hashSize + i); hashStruct.fields.push_back(Field(type, Mutable)); } builder[num] = hashStruct; diff --git a/src/support/hash.h b/src/support/hash.h index b99902616..ba1001d66 100644 --- a/src/support/hash.h +++ b/src/support/hash.h @@ -28,29 +28,31 @@ template<typename T> inline std::size_t hash(const T& value) { } // Combines two digests into the first digest. Use instead of `rehash` if -// `otherDigest` is another digest and not a `size_t` value. This is also useful -// when you want deterministic behavior across systems, as this method does not -// call std::hash, so it does not depend on the behavior of the local machine's -// C++ standard library implementation. +// `otherDigest` is another digest. This is also deterministic, aside from +// possible differences in size_t (see deterministic_hash_combine, below). inline void hash_combine(std::size_t& digest, const std::size_t otherDigest) { // see: boost/container_hash/hash.hpp // The constant is the N-bits reciprocal of the golden ratio: // phi = (1 + sqrt(5)) / 2 -#if SIZE_MAX == UINT64_MAX // trunc(2^64 / phi) = 0x9e3779b97f4a7c15 digest ^= otherDigest + 0x9e3779b97f4a7c15 + (digest << 12) + (digest >> 4); -#else - // trunc(2^32 / phi) = 0x9e3779b9 - digest ^= otherDigest + 0x9e3779b9 + (digest << 6) + (digest >> 2); -#endif } // Hashes `value` and combines the resulting digest into the existing digest. -// Use instead of `hash_combine` if `value` is not another digest. +// Use instead of `hash_combine` if `value` is not another digest (i.e., it +// needs to be hashed first). template<typename T> inline void rehash(std::size_t& digest, const T& value) { hash_combine(digest, hash(value)); } +// Similar to hash_combine, but guaranteed to produce the exact same results on +// all machines, even ones where size_t differs. This is essentially identical +// to hash_combine, but the types are all uint64_t. +inline void deterministic_hash_combine(uint64_t& digest, + const uint64_t otherDigest) { + digest ^= otherDigest + 0x9e3779b97f4a7c15 + (digest << 12) + (digest >> 4); +} + } // namespace wasm namespace std { |