]> git.ipfire.org Git - thirdparty/zlib-ng.git/commitdiff
Combine extra_lbits/base_length and extra_dbits/base_dist lookup tables
authorNathan Moinvaziri <nathan@nathanm.com>
Thu, 19 Feb 2026 22:54:19 +0000 (14:54 -0800)
committerHans Kristian Rosbach <hk-github@circlestorm.org>
Tue, 10 Mar 2026 15:08:22 +0000 (16:08 +0100)
Pack base values and extra bit counts into combined tables (lbase_extra,
dbase_extra) to reduce memory loads in the deflate hot path.

Each match emission now requires 2 loads instead of 4 for the extra
bits handling.

Assisted-by: Claude Code
tools/maketrees.c
trees_emit.h
trees_tbl.h

index 54c1d929eeb884c76b329ac0ecb68a880de48ca4..aa68c35603952ff94cdb69438adf049896a4ff6f 100644 (file)
@@ -127,14 +127,21 @@ static void gen_trees_header(void) {
         printf("%2u%s", length_code[i], SEPARATOR(i, STD_MAX_MATCH-STD_MIN_MATCH, 20));
     }
 
-    printf("Z_INTERNAL const int base_length[LENGTH_CODES] = {\n");
+    printf("/* Combined base + extra_bits tables for single-lookup optimization.\n");
+    printf(" * Length table: bits 0-7 = base_length, bits 8-11 = extra_lbits\n");
+    printf(" * Distance table: bits 0-15 = base_dist, bits 16-19 = extra_dbits\n");
+    printf(" */\n");
+    printf("#define LBASE_EXTRA(base, extra) ((extra) << 8 | (base))\n");
+    printf("#define DBASE_EXTRA(base, extra) ((extra) << 16 | (base))\n\n");
+
+    printf("Z_INTERNAL const uint16_t lbase_extra[LENGTH_CODES] = {\n");
     for (i = 0; i < LENGTH_CODES; i++) {
-        printf("%d%s", base_length[i], SEPARATOR(i, LENGTH_CODES-1, 20));
+        printf("LBASE_EXTRA(%3d, %d)%s", base_length[i], extra_lbits[i], SEPARATOR(i, LENGTH_CODES-1, 4));
     }
 
-    printf("Z_INTERNAL const int base_dist[D_CODES] = {\n");
+    printf("Z_INTERNAL const uint32_t dbase_extra[D_CODES] = {\n");
     for (i = 0; i < D_CODES; i++) {
-        printf("%5d%s", base_dist[i], SEPARATOR(i, D_CODES-1, 10));
+        printf("DBASE_EXTRA(%5d, %2d)%s", base_dist[i], extra_dbits[i], SEPARATOR(i, D_CODES-1, 4));
     }
 
     printf("#endif /* TREES_TBL_H_ */\n");
index 2a18fe28d3d70d2b50430de50c8d55a2592e3d0e..365aac0768bbfcd2b7d995bc67c1c00fee727b55 100644 (file)
@@ -17,8 +17,9 @@ extern Z_INTERNAL const ct_data static_dtree[D_CODES];
 extern const unsigned char Z_INTERNAL zng_dist_code[DIST_CODE_LEN];
 extern const unsigned char Z_INTERNAL zng_length_code[STD_MAX_MATCH-STD_MIN_MATCH+1];
 
-extern Z_INTERNAL const int base_length[LENGTH_CODES];
-extern Z_INTERNAL const int base_dist[D_CODES];
+/* Combined base + extra_bits tables for single-lookup optimization */
+extern Z_INTERNAL const uint16_t lbase_extra[LENGTH_CODES];
+extern Z_INTERNAL const uint32_t dbase_extra[D_CODES];
 
 /* Bit buffer and deflate code stderr tracing */
 #ifdef ZLIB_DEBUG
@@ -114,7 +115,7 @@ static inline void zng_emit_lit(deflate_state *s, const ct_data *ltree, unsigned
  */
 static inline uint32_t zng_emit_dist(deflate_state *s, const ct_data *ltree, const ct_data *dtree,
                                      uint32_t lc, uint32_t dist, uint64_t *bi_buf, uint32_t *bi_valid) {
-    uint32_t c, extra;
+    uint32_t c, extra, lext;
     uint8_t code;
     uint64_t match_bits;
     uint32_t match_bits_len;
@@ -127,12 +128,12 @@ static inline uint32_t zng_emit_dist(deflate_state *s, const ct_data *ltree, con
 
     match_bits = ltree[c].Code;
     match_bits_len = ltree[c].Len;
-    extra = extra_lbits[code];
-    if (extra != 0) {
-        lc -= base_length[code];
-        match_bits |= ((uint64_t)lc << match_bits_len);
-        match_bits_len += extra;
-    }
+    /* Get extra bits count and subtract base length from match length */
+    lext = lbase_extra[code];
+    extra = lext >> 8;
+    lc -= lext & 0xff;
+    match_bits |= ((uint64_t)(lc & ((1U << extra) - 1)) << match_bits_len);
+    match_bits_len += extra;
 
     dist--; /* dist is now the match distance - 1 */
     code = d_code(dist);
@@ -142,12 +143,12 @@ static inline uint32_t zng_emit_dist(deflate_state *s, const ct_data *ltree, con
     /* Send the distance code */
     match_bits |= ((uint64_t)dtree[code].Code << match_bits_len);
     match_bits_len += dtree[code].Len;
-    extra = extra_dbits[code];
-    if (extra != 0) {
-        dist -= base_dist[code];
-        match_bits |= ((uint64_t)dist << match_bits_len);
-        match_bits_len += extra;
-    }
+    /* Get extra bits count and subtract base distance */
+    lext = dbase_extra[code];
+    extra = lext >> 16;
+    dist -= lext & 0xffff;
+    match_bits |= ((uint64_t)(dist & ((1U << extra) - 1)) << match_bits_len);
+    match_bits_len += extra;
 
     send_bits(s, match_bits, match_bits_len, *bi_buf, *bi_valid);
 
index a3912b7fd7677e2e9b53f667997d98c1e22099df..16a47450b77001df6be8de17ae320eaac1444c5b 100644 (file)
@@ -118,15 +118,33 @@ const unsigned char Z_INTERNAL zng_length_code[STD_MAX_MATCH-STD_MIN_MATCH+1] =
 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
 };
 
-Z_INTERNAL const int base_length[LENGTH_CODES] = {
-0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
-64, 80, 96, 112, 128, 160, 192, 224, 0
+/* Combined base + extra_bits tables for single-lookup optimization.
+ * Length table: bits 0-7 = base_length, bits 8-11 = extra_lbits
+ * Distance table: bits 0-15 = base_dist, bits 16-19 = extra_dbits
+ */
+#define LBASE_EXTRA(base, extra) ((extra) << 8 | (base))
+#define DBASE_EXTRA(base, extra) ((extra) << 16 | (base))
+
+Z_INTERNAL const uint16_t lbase_extra[LENGTH_CODES] = {
+LBASE_EXTRA(  0, 0), LBASE_EXTRA(  1, 0), LBASE_EXTRA(  2, 0), LBASE_EXTRA(  3, 0),
+LBASE_EXTRA(  4, 0), LBASE_EXTRA(  5, 0), LBASE_EXTRA(  6, 0), LBASE_EXTRA(  7, 0),
+LBASE_EXTRA(  8, 1), LBASE_EXTRA( 10, 1), LBASE_EXTRA( 12, 1), LBASE_EXTRA( 14, 1),
+LBASE_EXTRA( 16, 2), LBASE_EXTRA( 20, 2), LBASE_EXTRA( 24, 2), LBASE_EXTRA( 28, 2),
+LBASE_EXTRA( 32, 3), LBASE_EXTRA( 40, 3), LBASE_EXTRA( 48, 3), LBASE_EXTRA( 56, 3),
+LBASE_EXTRA( 64, 4), LBASE_EXTRA( 80, 4), LBASE_EXTRA( 96, 4), LBASE_EXTRA(112, 4),
+LBASE_EXTRA(128, 5), LBASE_EXTRA(160, 5), LBASE_EXTRA(192, 5), LBASE_EXTRA(224, 5),
+LBASE_EXTRA(  0, 0)
 };
 
-Z_INTERNAL const int base_dist[D_CODES] = {
-    0,     1,     2,     3,     4,     6,     8,    12,    16,    24,
-   32,    48,    64,    96,   128,   192,   256,   384,   512,   768,
- 1024,  1536,  2048,  3072,  4096,  6144,  8192, 12288, 16384, 24576
+Z_INTERNAL const uint32_t dbase_extra[D_CODES] = {
+DBASE_EXTRA(    0,  0), DBASE_EXTRA(    1,  0), DBASE_EXTRA(    2,  0), DBASE_EXTRA(    3,  0),
+DBASE_EXTRA(    4,  1), DBASE_EXTRA(    6,  1), DBASE_EXTRA(    8,  2), DBASE_EXTRA(   12,  2),
+DBASE_EXTRA(   16,  3), DBASE_EXTRA(   24,  3), DBASE_EXTRA(   32,  4), DBASE_EXTRA(   48,  4),
+DBASE_EXTRA(   64,  5), DBASE_EXTRA(   96,  5), DBASE_EXTRA(  128,  6), DBASE_EXTRA(  192,  6),
+DBASE_EXTRA(  256,  7), DBASE_EXTRA(  384,  7), DBASE_EXTRA(  512,  8), DBASE_EXTRA(  768,  8),
+DBASE_EXTRA( 1024,  9), DBASE_EXTRA( 1536,  9), DBASE_EXTRA( 2048, 10), DBASE_EXTRA( 3072, 10),
+DBASE_EXTRA( 4096, 11), DBASE_EXTRA( 6144, 11), DBASE_EXTRA( 8192, 12), DBASE_EXTRA(12288, 12),
+DBASE_EXTRA(16384, 13), DBASE_EXTRA(24576, 13)
 };
 
 #endif /* TREES_TBL_H_ */