From 1d3df9f7dd82fe49001e714a4c31962387b526f6 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Wed, 13 Mar 2024 19:57:53 +0300 Subject: [PATCH] Switch folding engine to semi-perfect hash function --- gen_ir_fold_hash.c | 53 ++++++++++++++++++++++++++++++++++++++++------ ir.c | 6 +++++- 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/gen_ir_fold_hash.c b/gen_ir_fold_hash.c index 52205297..efd656f5 100644 --- a/gen_ir_fold_hash.c +++ b/gen_ir_fold_hash.c @@ -15,6 +15,10 @@ #define MAX_RULES 2048 #define MAX_SLOTS (MAX_RULES * 4) +#define USE_SEMI_PERFECT_HASH 1 +#define USE_SHL_HASH 1 +#define USE_ROL_HASH 0 + static ir_strtab strtab; void print_hash(uint32_t *mask, uint32_t count) @@ -28,12 +32,14 @@ void print_hash(uint32_t *mask, uint32_t count) printf("};\n\n"); } -#if 0 +#if USE_SHL_HASH static uint32_t hash_shl2(uint32_t mask, uint32_t r1, uint32_t r2) { return ((mask << r1) - mask) << r2; } -#else +#endif + +#if USE_ROL_HASH #define ir_rol(x, n) (((x)<<(n)) | ((x)>>(-(int)(n)&(8*sizeof(x)-1)))) #define ir_ror(x, n) (((x)<<(-(int)(n)&(8*sizeof(x)-1))) | ((x)>>(n))) @@ -50,29 +56,64 @@ int find_hash(uint32_t *mask, uint32_t count) uint32_t n, r1, r2, i, h; for (n = (count | 1); n < MAX_SLOTS; n += 2) { +#if USE_SEMI_PERFECT_HASH + int semi_perfect = 0; +#endif + for (r1 = 0; r1 < 31; r1++) { for (r2 = 0; r2 < 32; r2++) { -#if 0 +#if USE_SHL_HASH memset(hash, 0, n * sizeof(uint32_t)); for (i = 0; i < count; i++) { h = hash_shl2(mask[i] & 0x1fffff, r1, r2) % n; - if (hash[h]) break; /* collision */ + if (hash[h]) { +#if USE_SEMI_PERFECT_HASH + h++; + if (!hash[h]) { + hash[h] = mask[i]; + semi_perfect = 1; + continue; + } +#endif + break; /* collision */ + } hash[h] = mask[i]; } if (i == count) { print_hash(hash, n); +#if USE_SEMI_PERFECT_HASH + if (semi_perfect) { + printf("#define IR_FOLD_SEMI_PERFECT_HASH\n\n"); + } +#endif printf("static uint32_t _ir_fold_hashkey(uint32_t h)\n{\n\treturn (((h << %d) - h) << %d) %% %d;\n}\n", r1, r2, n); return 1; } -#else +#endif +#if USE_ROL_HASH memset(hash, 0, n * sizeof(uint32_t)); for (i = 0; i < count; i++) { h = hash_rol2(mask[i] & 0x1fffff, r1, r2) % n; - if (hash[h]) break; /* collision */ + if (hash[h]) { +#if USE_SEMI_PERFECT_HASH + h++; + if (!hash[h]) { + hash[h] = mask[i]; + semi_perfect = 1; + continue; + } +#endif + break; /* collision */ + } hash[h] = mask[i]; } if (i == count) { print_hash(hash, n); +#if USE_SEMI_PERFECT_HASH + if (semi_perfect) { + printf("#define IR_FOLD_SEMI_PERFECT_HASH\n\n"); + } +#endif printf("static uint32_t _ir_fold_hashkey(uint32_t h)\n{\nreturn ir_rol32((ir_rol32(h, %d) - h), %d) %% %d;\n}\n", r1, r2, n); return 1; } diff --git a/ir.c b/ir.c index 32527e45..d4e3314f 100644 --- a/ir.c +++ b/ir.c @@ -926,7 +926,11 @@ ir_ref ir_folding(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3, uint32_t k = key & any; uint32_t h = _ir_fold_hashkey(k); uint32_t fh = _ir_fold_hash[h]; - if (IR_FOLD_KEY(fh) == k /*|| (fh = _ir_fold_hash[h+1], (fh & 0x1fffff) == k)*/) { + if (IR_FOLD_KEY(fh) == k +#ifdef IR_FOLD_SEMI_PERFECT_HASH + || (fh = _ir_fold_hash[h+1], (fh & 0x1fffff) == k) +#endif + ) { switch (IR_FOLD_RULE(fh)) { #include "ir_fold.h" default: