Fixture 52
hash functions
C · 3 functions · 4 lanes · 12 of 12 function-lanes behave identically
All 4 lanes recompile and return the same results as the original.
FNV-1a, a djb2 variant, and the MurmurHash3 finalizer. These are pure multiply/xor/shift chains: with no control flow to anchor on, an incorrect constant or shift width is immediately visible in the differential.
#include <stdint.h>
/* FNV-1a, a djb2 variant, and the MurmurHash3 finalizer. These are pure
* multiply/xor/shift chains: with no control flow to anchor on, an incorrect
* constant or shift width is immediately visible in the differential. */
#define HASH_MAX 16
__attribute__((noinline)) uint32_t
fnv1a_32(const uint8_t *data, int32_t length) {
uint32_t hash = 2166136261u;
int32_t index;
if (data == 0 || length < 0 || length > HASH_MAX) {
return 0;
}
for (index = 0; index < length; ++index) {
hash ^= (uint32_t)data[index];
hash *= 16777619u;
}
return hash;
}
__attribute__((noinline)) uint32_t
djb2_xor(const uint8_t *data, int32_t length) {
uint32_t hash = 5381u;
int32_t index;
if (data == 0 || length < 0 || length > HASH_MAX) {
return 0;
}
for (index = 0; index < length; ++index) {
hash = ((hash << 5) + hash) ^ (uint32_t)data[index];
}
return hash;
}
__attribute__((noinline)) uint32_t murmur3_finalize(uint32_t value) {
value ^= value >> 16;
value *= 0x85EBCA6Bu;
value ^= value >> 13;
value *= 0xC2B2AE35u;
value ^= value >> 16;
return value;
} Recovered C
Generated by glaurung decompile --style decbench at b47f6b43.
baseline.json records the result after recompiling the C and calling it beside the
original with seeded inputs.
clang -O0
3/3djb2_xor pass 26 lines
// glaurung: djb2_xor @ 0x1190
uint32_t djb2_xor(const uint8_t * arg0, int32_t arg1) {
unsigned int hash;
int index;
int local_4;
// x86-64 prologue: save rbp
hash = 0x1505;
if ((arg0 == 0)) {
// x86-64 epilogue: restore rbp
return 0;
}
if (((long)(arg1) < 0)) {
// x86-64 epilogue: restore rbp
return 0;
}
if (((((unsigned long)((unsigned int)(arg1)) == 16) | ((long)(arg1) < 16)) == 0)) {
// x86-64 epilogue: restore rbp
return 0;
}
for (index = 0; (index < arg1); index++) {
hash = ((unsigned int)(((unsigned long)((unsigned int)((hash << 5))) + hash)) ^ (unsigned int)((unsigned char)(arg0[index])));
}
local_4 = hash;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
} fnv1a_32 pass 27 lines
// glaurung: fnv1a_32 @ 0x1100
uint32_t fnv1a_32(const uint8_t * arg0, int32_t arg1) {
unsigned int hash;
int index;
int local_4;
// x86-64 prologue: save rbp
hash = -0x7ee3623bLL;
if ((arg0 == 0)) {
// x86-64 epilogue: restore rbp
return 0;
}
if (((long)(arg1) < 0)) {
// x86-64 epilogue: restore rbp
return 0;
}
if (((((unsigned long)((unsigned int)(arg1)) == 16) | ((long)(arg1) < 16)) == 0)) {
// x86-64 epilogue: restore rbp
return 0;
}
for (index = 0; (index < arg1); index++) {
hash = ((unsigned int)((unsigned char)(arg0[index])) ^ hash);
hash = (hash * 0x1000193);
}
local_4 = hash;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
} murmur3_finalize pass 11 lines
// glaurung: murmur3_finalize @ 0x1220
uint32_t murmur3_finalize(uint32_t arg0) {
// x86-64 prologue: save rbp
arg0 = ((unsigned int)(((unsigned int)(arg0) >> 16)) ^ arg0);
arg0 = (arg0 * -0x7a143595LL);
arg0 = ((unsigned int)(((unsigned int)(arg0) >> 13)) ^ arg0);
arg0 = (arg0 * -0x3d4d51cbLL);
arg0 = ((unsigned int)(((unsigned int)(arg0) >> 16)) ^ arg0);
// x86-64 epilogue: restore rbp
return arg0;
} clang -O2
3/3djb2_xor pass 58 lines
// glaurung: djb2_xor @ 0x11c0
uint32_t djb2_xor(const uint8_t * arg0, int32_t arg1) {
int index;
unsigned int hash;
long ret;
long var12;
long var2;
long var20;
long var28;
long var36;
long var44;
long var48;
long var50;
long var51;
long var6;
long var8;
ret = 0;
if ((arg0 != 0)) {
ret = 0;
if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
return ret;
}
if (((unsigned long)((unsigned int)(arg1)) == 0)) {
return 0x1505;
}
var2 = (unsigned long)((unsigned int)(arg1));
var6 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) & 3)));
if (((unsigned long)(3) <= (unsigned long)(((unsigned long)((unsigned int)(arg1)) - 1)))) {
var8 = (unsigned long)((unsigned int)((var2 & -4)));
index = 0;
var12 = 0x1505;
do {
var20 = (unsigned long)((unsigned int)(((unsigned int)((unsigned char)(*(char *)(((long)arg0 + index)))) ^ (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var12)) << 5))) + var12))))));
var28 = (unsigned long)((unsigned int)(((unsigned int)((unsigned char)(*(char *)(((long)arg0 + index + 0x1)))) ^ (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var20)) << 5))) + var20))))));
var36 = (unsigned long)((unsigned int)(((unsigned int)((unsigned char)(*(char *)(((long)arg0 + index + 0x2)))) ^ (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var28)) << 5))) + var28))))));
ret = (unsigned long)((unsigned int)(((unsigned int)((unsigned char)(*(char *)(((long)arg0 + index + 0x3)))) ^ (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var36)) << 5))) + var36))))));
index = (index + 4);
var12 = ret;
var44 = (unsigned long)((unsigned int)(index));
} while ((var8 != index));
} else {
ret = 0x1505;
var44 = 0;
}
if ((var6 == 0)) {
return ret;
}
var48 = (long)(((long)arg0 + var44));
var50 = 0;
var51 = ret;
do {
ret = (unsigned long)((unsigned int)(((unsigned int)((unsigned char)(*(char *)((var48 + var50)))) ^ (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var51)) << 5))) + var51))))));
var50 = (var50 + 1);
var51 = ret;
} while ((var6 != var50));
}
return ret;
} fnv1a_32 pass 56 lines
// glaurung: fnv1a_32 @ 0x1100
uint32_t fnv1a_32(const uint8_t * arg0, int32_t arg1) {
int index;
unsigned int hash;
long ret;
long var12;
long var2;
long var28;
long var29;
long var33;
long var35;
long var36;
long var40;
long var6;
long var8;
ret = 0;
if ((arg0 != 0)) {
ret = 0;
if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
return ret;
}
if (((unsigned long)((unsigned int)(arg1)) == 0)) {
return 0x811c9dc5;
}
var2 = (unsigned long)((unsigned int)(arg1));
var6 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) & 3)));
if (((unsigned long)(3) <= (unsigned long)(((unsigned long)((unsigned int)(arg1)) - 1)))) {
var8 = (unsigned long)((unsigned int)((var2 & -4)));
index = 0;
var12 = 0x811c9dc5;
do {
var28 = ((unsigned long)((unsigned int)(((unsigned int)((unsigned char)(*(char *)(((long)arg0 + index + 0x3)))) ^ ((unsigned long)((unsigned int)(((unsigned int)((unsigned char)(*(char *)(((long)arg0 + index + 0x2)))) ^ ((unsigned long)((unsigned int)(((unsigned int)((unsigned char)(*(char *)(((long)arg0 + index + 0x1)))) ^ ((unsigned long)((unsigned int)(((unsigned int)((unsigned char)(*(char *)(((long)arg0 + index)))) ^ var12))) * 0x1000193)))) * 0x1000193)))) * 0x1000193)))) * 0x1000193);
index = (index + 4);
var12 = var28;
var29 = (unsigned long)((unsigned int)(index));
} while ((var8 != index));
} else {
var28 = 0x811c9dc5;
var29 = 0;
}
ret = var28;
if ((var6 == 0)) {
return ret;
}
var33 = (long)(((long)arg0 + var29));
var35 = 0;
var36 = var28;
do {
var40 = ((unsigned long)((unsigned int)(((unsigned int)((unsigned char)(*(char *)((var33 + var35)))) ^ var36))) * 0x1000193);
var35 = (var35 + 1);
var36 = var40;
ret = var40;
} while ((var6 != var35));
}
return ret;
} murmur3_finalize pass 8 lines
// glaurung: murmur3_finalize @ 0x1280
uint32_t murmur3_finalize(uint32_t arg0) {
int var13;
int var6;
var6 = ((unsigned int)(((unsigned long)((unsigned int)(((unsigned int)(arg0) >> 16))) ^ arg0)) * -0x7a143595LL);
var13 = ((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var6)) >> 13))) ^ var6)) * -0x3d4d51cbLL);
return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var13)) >> 16))) ^ var13));
} gcc -O0
3/3djb2_xor pass 24 lines
// glaurung: djb2_xor @ 0x1165
uint32_t djb2_xor(const uint8_t * arg0, int32_t arg1) {
unsigned int hash;
int index;
// x86-64 prologue: save rbp
hash = 0x1505;
if ((arg0 == 0)) {
// x86-64 epilogue: restore rbp
return 0;
}
if (((long)(arg1) < 0)) {
// x86-64 epilogue: restore rbp
return 0;
}
if (((((unsigned long)((unsigned int)(arg1)) == 16) | ((long)(arg1) < 16)) == 0)) {
// x86-64 epilogue: restore rbp
return 0;
}
for (index = 0; (index < arg1); index++) {
hash = ((unsigned int)((unsigned char)(((unsigned int)((unsigned char)(arg0[index])) & 255))) ^ (unsigned int)(((unsigned long)((unsigned int)((hash << 5))) + hash)));
}
// x86-64 epilogue: restore rbp
return hash;
} fnv1a_32 pass 25 lines
// glaurung: fnv1a_32 @ 0x10f9
uint32_t fnv1a_32(const uint8_t * arg0, int32_t arg1) {
unsigned int hash;
int index;
// x86-64 prologue: save rbp
hash = -0x7ee3623bLL;
if ((arg0 == 0)) {
// x86-64 epilogue: restore rbp
return 0;
}
if (((long)(arg1) < 0)) {
// x86-64 epilogue: restore rbp
return 0;
}
if (((((unsigned long)((unsigned int)(arg1)) == 16) | ((long)(arg1) < 16)) == 0)) {
// x86-64 epilogue: restore rbp
return 0;
}
for (index = 0; (index < arg1); index++) {
hash = (hash ^ (unsigned int)((unsigned char)(((unsigned int)((unsigned char)(arg0[index])) & 255))));
hash = (hash * 0x1000193);
}
// x86-64 epilogue: restore rbp
return hash;
} murmur3_finalize pass 11 lines
// glaurung: murmur3_finalize @ 0x11d5
uint32_t murmur3_finalize(uint32_t arg0) {
// x86-64 prologue: save rbp
arg0 = (arg0 ^ (unsigned int)(((unsigned int)(arg0) >> 16)));
arg0 = (arg0 * -0x7a143595LL);
arg0 = (arg0 ^ (unsigned int)(((unsigned int)(arg0) >> 13)));
arg0 = (arg0 * -0x3d4d51cbLL);
arg0 = (arg0 ^ (unsigned int)(((unsigned int)(arg0) >> 16)));
// x86-64 epilogue: restore rbp
return arg0;
} gcc -O2
3/3djb2_xor pass 27 lines
// glaurung: djb2_xor @ 0x1150
uint32_t djb2_xor(const uint8_t * arg0, int32_t arg1) {
unsigned int hash;
int index;
long ret;
long var2;
long var4;
long var5;
if ((arg0 == 0)) {
return 0;
}
if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
return 0;
}
if (((unsigned long)((unsigned int)(arg1)) == 0)) {
return 0x1505;
}
var2 = (long)((((long)arg0 + (unsigned long)((unsigned int)((arg1 - 1)))) + 1));
var4 = 0x1505;
var5 = (long)arg0;
do {
var5 = (var5 + 1);
ret = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)((var4 + (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var4)) << 5)))))) ^ (unsigned int)((unsigned char)(*(char *)((var5 - 0x1)))))));
var4 = ret;
} while ((var5 != var2));
return ret;
} fnv1a_32 pass 27 lines
// glaurung: fnv1a_32 @ 0x1100
uint32_t fnv1a_32(const uint8_t * arg0, int32_t arg1) {
unsigned int hash;
int index;
long ret;
long var2;
long var4;
int var5;
if ((arg0 == 0)) {
return 0;
}
if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
return 0;
}
if (((unsigned long)((unsigned int)(arg1)) == 0)) {
return 0x811c9dc5;
}
var2 = (long)((((long)arg0 + (unsigned long)((unsigned int)((arg1 - 1)))) + 1));
ret = 0x811c9dc5;
var4 = (long)arg0;
do {
var5 = (unsigned int)((unsigned char)(*(char *)((var4))));
var4 = (var4 + 1);
ret = ((unsigned long)((unsigned int)((ret ^ var5))) * 0x1000193);
} while ((var4 != var2));
return ret;
} murmur3_finalize pass 8 lines
// glaurung: murmur3_finalize @ 0x11a0
uint32_t murmur3_finalize(uint32_t arg0) {
int var13;
int var6;
var6 = ((unsigned int)(((unsigned long)((unsigned int)(((unsigned int)(arg0) >> 16))) ^ arg0)) * -0x7a143595LL);
var13 = ((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var6)) >> 13))) ^ var6)) * -0x3d4d51cbLL);
return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var13)) >> 16))) ^ var13));
}