Browse Source

lib/uzlib/defl_static: Implement some code size improvements.

This commit makes the following changes:
- Replace 256-byte reverse-bits-in-byte lookup table with computation.
- Replace length and distance code lookup tables with computation.
- Remove comp_disabled check (it's unused).
- Make the dest_write_cb take the data pointer directly, rather than the
  Outbuf.

Saves 500 bytes on PYBV11.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
pull/11905/head
Jim Mussared 1 year ago
committed by Damien George
parent
commit
0900976384
  1. 218
      lib/uzlib/defl_static.c
  2. 3
      lib/uzlib/defl_static.h

218
lib/uzlib/defl_static.c

@ -10,6 +10,9 @@ Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry,
Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus
Kuhn, Colin Watson, and CORE SDI S.A. Kuhn, Colin Watson, and CORE SDI S.A.
Optimised for MicroPython:
Copyright (c) 2023 by Jim Mussared
Permission is hereby granted, free of charge, to any person Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction, (the "Software"), to deal in the Software without restriction,
@ -55,152 +58,44 @@ static void outbits(struct Outbuf *out, unsigned long bits, int nbits)
out->outbits |= bits << out->noutbits; out->outbits |= bits << out->noutbits;
out->noutbits += nbits; out->noutbits += nbits;
while (out->noutbits >= 8) { while (out->noutbits >= 8) {
out->dest_write_cb(out, out->outbits & 0xFF); out->dest_write_cb(out->dest_write_data, out->outbits & 0xFF);
out->outbits >>= 8; out->outbits >>= 8;
out->noutbits -= 8; out->noutbits -= 8;
} }
} }
static const unsigned char mirrorbytes[256] = { static const unsigned char mirrornibbles[16] = {
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf,
0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
}; };
typedef struct { static unsigned int mirrorbyte(unsigned int b) {
uint8_t extrabits; return mirrornibbles[b & 0xf] << 4 | mirrornibbles[b >> 4];
uint8_t min, max; }
} len_coderecord;
typedef struct {
uint8_t code, extrabits;
uint16_t min, max;
} dist_coderecord;
#define TO_LCODE(x, y) x - 3, y - 3
#define FROM_LCODE(x) (x + 3)
static const len_coderecord lencodes[] = {
{0, TO_LCODE(3, 3)},
{0, TO_LCODE(4, 4)},
{0, TO_LCODE(5, 5)},
{0, TO_LCODE(6, 6)},
{0, TO_LCODE(7, 7)},
{0, TO_LCODE(8, 8)},
{0, TO_LCODE(9, 9)},
{0, TO_LCODE(10, 10)},
{1, TO_LCODE(11, 12)},
{1, TO_LCODE(13, 14)},
{1, TO_LCODE(15, 16)},
{1, TO_LCODE(17, 18)},
{2, TO_LCODE(19, 22)},
{2, TO_LCODE(23, 26)},
{2, TO_LCODE(27, 30)},
{2, TO_LCODE(31, 34)},
{3, TO_LCODE(35, 42)},
{3, TO_LCODE(43, 50)},
{3, TO_LCODE(51, 58)},
{3, TO_LCODE(59, 66)},
{4, TO_LCODE(67, 82)},
{4, TO_LCODE(83, 98)},
{4, TO_LCODE(99, 114)},
{4, TO_LCODE(115, 130)},
{5, TO_LCODE(131, 162)},
{5, TO_LCODE(163, 194)},
{5, TO_LCODE(195, 226)},
{5, TO_LCODE(227, 257)},
{0, TO_LCODE(258, 258)},
};
static const dist_coderecord distcodes[] = { static int int_log2(int x) {
{0, 0, 1, 1}, int r = 0;
{1, 0, 2, 2}, while (x >>= 1) {
{2, 0, 3, 3}, ++r;
{3, 0, 4, 4}, }
{4, 1, 5, 6}, return r;
{5, 1, 7, 8}, }
{6, 2, 9, 12},
{7, 2, 13, 16},
{8, 3, 17, 24},
{9, 3, 25, 32},
{10, 4, 33, 48},
{11, 4, 49, 64},
{12, 5, 65, 96},
{13, 5, 97, 128},
{14, 6, 129, 192},
{15, 6, 193, 256},
{16, 7, 257, 384},
{17, 7, 385, 512},
{18, 8, 513, 768},
{19, 8, 769, 1024},
{20, 9, 1025, 1536},
{21, 9, 1537, 2048},
{22, 10, 2049, 3072},
{23, 10, 3073, 4096},
{24, 11, 4097, 6144},
{25, 11, 6145, 8192},
{26, 12, 8193, 12288},
{27, 12, 12289, 16384},
{28, 13, 16385, 24576},
{29, 13, 24577, 32768},
};
void zlib_literal(struct Outbuf *out, unsigned char c) void zlib_literal(struct Outbuf *out, unsigned char c)
{ {
if (out->comp_disabled) {
/*
* We're in an uncompressed block, so just output the byte.
*/
outbits(out, c, 8);
return;
}
if (c <= 143) { if (c <= 143) {
/* 0 through 143 are 8 bits long starting at 00110000. */ /* 0 through 143 are 8 bits long starting at 00110000. */
outbits(out, mirrorbytes[0x30 + c], 8); outbits(out, mirrorbyte(0x30 + c), 8);
} else { } else {
/* 144 through 255 are 9 bits long starting at 110010000. */ /* 144 through 255 are 9 bits long starting at 110010000. */
outbits(out, 1 + 2 * mirrorbytes[0x90 - 144 + c], 9); outbits(out, 1 + 2 * mirrorbyte(0x90 - 144 + c), 9);
} }
} }
void zlib_match(struct Outbuf *out, int distance, int len) void zlib_match(struct Outbuf *out, int distance, int len)
{ {
const dist_coderecord *d; assert(distance >= 1 && distance <= 32768);
const len_coderecord *l; distance -= 1;
int i, j, k;
int lcode;
assert(!out->comp_disabled);
while (len > 0) { while (len > 0) {
int thislen; int thislen;
@ -218,73 +113,56 @@ void zlib_match(struct Outbuf *out, int distance, int len)
thislen = (len > 260 ? 258 : len <= 258 ? len : len - 3); thislen = (len > 260 ? 258 : len <= 258 ? len : len - 3);
len -= thislen; len -= thislen;
/* assert(thislen >= 3 && thislen <= 258);
* Binary-search to find which length code we're
* transmitting. thislen -= 3;
*/ int lcode = 28;
i = -1; int x = int_log2(thislen);
j = sizeof(lencodes) / sizeof(*lencodes); int y;
while (1) { if (thislen < 255) {
assert(j - i >= 2); if (x) {
k = (j + i) / 2; --x;
if (thislen < FROM_LCODE(lencodes[k].min))
j = k;
else if (thislen > FROM_LCODE(lencodes[k].max))
i = k;
else {
l = &lencodes[k];
break; /* found it! */
} }
y = (thislen >> (x ? x - 1 : 0)) & 3;
lcode = x * 4 + y;
} }
lcode = l - lencodes + 257;
/* /*
* Transmit the length code. 256-279 are seven bits * Transmit the length code. 256-279 are seven bits
* starting at 0000000; 280-287 are eight bits starting at * starting at 0000000; 280-287 are eight bits starting at
* 11000000. * 11000000.
*/ */
if (lcode <= 279) { if (lcode <= 22) {
outbits(out, mirrorbytes[(lcode - 256) * 2], 7); outbits(out, mirrorbyte((lcode + 1) * 2), 7);
} else { } else {
outbits(out, mirrorbytes[0xc0 - 280 + lcode], 8); outbits(out, mirrorbyte(lcode + 169), 8);
} }
/* /*
* Transmit the extra bits. * Transmit the extra bits.
*/ */
if (l->extrabits) if (thislen < 255 && x > 1) {
outbits(out, thislen - FROM_LCODE(l->min), l->extrabits); int extrabits = x - 1;
int lmin = (thislen >> extrabits) << extrabits;
/* outbits(out, thislen - lmin, extrabits);
* Binary-search to find which distance code we're
* transmitting.
*/
i = -1;
j = sizeof(distcodes) / sizeof(*distcodes);
while (1) {
assert(j - i >= 2);
k = (j + i) / 2;
if (distance < distcodes[k].min)
j = k;
else if (distance > distcodes[k].max)
i = k;
else {
d = &distcodes[k];
break; /* found it! */
}
} }
x = int_log2(distance);
y = (distance >> (x ? x - 1 : 0)) & 1;
/* /*
* Transmit the distance code. Five bits starting at 00000. * Transmit the distance code. Five bits starting at 00000.
*/ */
outbits(out, mirrorbytes[d->code * 8], 5); outbits(out, mirrorbyte((x * 2 + y) * 8), 5);
/* /*
* Transmit the extra bits. * Transmit the extra bits.
*/ */
if (d->extrabits) if (x > 1) {
outbits(out, distance - d->min, d->extrabits); int dextrabits = x - 1;
int dmin = (distance >> dextrabits) << dextrabits;
outbits(out, distance - dmin, dextrabits);
}
} }
} }

3
lib/uzlib/defl_static.h

@ -32,10 +32,9 @@
struct Outbuf { struct Outbuf {
void *dest_write_data; void *dest_write_data;
void (*dest_write_cb)(struct Outbuf *outbuf, uint8_t byte); void (*dest_write_cb)(void *data, uint8_t byte);
unsigned long outbits; unsigned long outbits;
int noutbits; int noutbits;
int comp_disabled;
}; };
void zlib_start_block(struct Outbuf *ctx); void zlib_start_block(struct Outbuf *ctx);

Loading…
Cancel
Save