]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/cxgbe/cudbg/fastlz.c
MFV r331712:
[FreeBSD/FreeBSD.git] / sys / dev / cxgbe / cudbg / fastlz.c
1 /*
2    FastLZ - lightning-fast lossless compression library
3
4    Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)
5    Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
6    Copyright (C) 2005 Ariya Hidayat (ariya@kde.org)
7
8    Permission is hereby granted, free of charge, to any person obtaining a copy
9    of this software and associated documentation files (the "Software"), to deal
10    in the Software without restriction, including without limitation the rights
11    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12    copies of the Software, and to permit persons to whom the Software is
13    furnished to do so, subject to the following conditions:
14
15    The above copyright notice and this permission notice shall be included in
16    all copies or substantial portions of the Software.
17
18    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24    THE SOFTWARE.
25    */
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28
29 #include "osdep.h"
30 #include "fastlz.h"
31
32 #if !defined(FASTLZ__COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR)
33
34 /*
35  * Always check for bound when decompressing.
36  * Generally it is best to leave it defined.
37  */
38 #define FASTLZ_SAFE
39
40 #if defined(WIN32) || defined(__NT__) || defined(_WIN32) || defined(__WIN32__)
41 #if defined(_MSC_VER) || defined(__GNUC__)
42 /* #include <windows.h> */
43 #pragma warning(disable : 4242)
44 #pragma warning(disable : 4244)
45 #endif
46 #endif
47
48 /*
49  * Give hints to the compiler for branch prediction optimization.
50  */
51 #if defined(__GNUC__) && (__GNUC__ > 2)
52 #define FASTLZ_EXPECT_CONDITIONAL(c)    (__builtin_expect((c), 1))
53 #define FASTLZ_UNEXPECT_CONDITIONAL(c)  (__builtin_expect((c), 0))
54 #else
55 #define FASTLZ_EXPECT_CONDITIONAL(c)    (c)
56 #define FASTLZ_UNEXPECT_CONDITIONAL(c)  (c)
57 #endif
58
59 /*
60  * Use inlined functions for supported systems.
61  */
62 #if defined(__GNUC__) || defined(__DMC__) || defined(__POCC__) ||\
63         defined(__WATCOMC__) || defined(__SUNPRO_C)
64 #define FASTLZ_INLINE inline
65 #elif defined(__BORLANDC__) || defined(_MSC_VER) || defined(__LCC__)
66 #define FASTLZ_INLINE __inline
67 #else
68 #define FASTLZ_INLINE
69 #endif
70
71 /*
72  * Prevent accessing more than 8-bit at once, except on x86 architectures.
73  */
74 #if !defined(FASTLZ_STRICT_ALIGN)
75 #define FASTLZ_STRICT_ALIGN
76 #if defined(__i386__) || defined(__386)  /* GNU C, Sun Studio */
77 #undef FASTLZ_STRICT_ALIGN
78 #elif defined(__i486__) || defined(__i586__) || defined(__i686__) /* GNU C */
79 #undef FASTLZ_STRICT_ALIGN
80 #elif defined(_M_IX86) /* Intel, MSVC */
81 #undef FASTLZ_STRICT_ALIGN
82 #elif defined(__386)
83 #undef FASTLZ_STRICT_ALIGN
84 #elif defined(_X86_) /* MinGW */
85 #undef FASTLZ_STRICT_ALIGN
86 #elif defined(__I86__) /* Digital Mars */
87 #undef FASTLZ_STRICT_ALIGN
88 #endif
89 #endif
90
91 /*
92  * FIXME: use preprocessor magic to set this on different platforms!
93  */
94
95 #define MAX_COPY       32
96 #define MAX_LEN       264  /* 256 + 8 */
97 #define MAX_DISTANCE 8192
98
99 #if !defined(FASTLZ_STRICT_ALIGN)
100 #define FASTLZ_READU16(p) (*((const unsigned short *)(p)))
101 #else
102 #define FASTLZ_READU16(p) ((p)[0] | (p)[1]<<8)
103 #endif
104
105 #define HASH_LOG  13
106 #define HASH_SIZE (1 << HASH_LOG)
107 #define HASH_MASK  (HASH_SIZE - 1)
108 #define HASH_FUNCTION(v, p) {\
109                                 v = FASTLZ_READU16(p);\
110                                 v ^= FASTLZ_READU16(p + 1)^\
111                                      (v>>(16 - HASH_LOG));\
112                                 v &= HASH_MASK;\
113                             }
114
115 #undef FASTLZ_LEVEL
116 #define FASTLZ_LEVEL 1
117
118 #undef FASTLZ_COMPRESSOR
119 #undef FASTLZ_DECOMPRESSOR
120 #define FASTLZ_COMPRESSOR fastlz1_compress
121 #define FASTLZ_DECOMPRESSOR fastlz1_decompress
122 static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void *input, int length,
123                                            void *output);
124 static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void *input, int length,
125                                              void *output, int maxout);
126 #include "fastlz.c"
127
128 #undef FASTLZ_LEVEL
129 #define FASTLZ_LEVEL 2
130
131 #undef MAX_DISTANCE
132 #define MAX_DISTANCE 8191
133 #define MAX_FARDISTANCE (65535 + MAX_DISTANCE - 1)
134
135 #undef FASTLZ_COMPRESSOR
136 #undef FASTLZ_DECOMPRESSOR
137 #define FASTLZ_COMPRESSOR fastlz2_compress
138 #define FASTLZ_DECOMPRESSOR fastlz2_decompress
139 static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void *input, int length,
140                                            void *output);
141 static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void *input, int length,
142                                              void *output, int maxout);
143 #include "fastlz.c"
144
145 int fastlz_compress(const void *input, int length, void *output)
146 {
147         /* for short block, choose fastlz1 */
148         if (length < 65536)
149                 return fastlz1_compress(input, length, output);
150
151         /* else... */
152         return fastlz2_compress(input, length, output);
153 }
154
155 int fastlz_decompress(const void *input, int length, void *output, int maxout)
156 {
157         /* magic identifier for compression level */
158         int level = ((*(const unsigned char *)input) >> 5) + 1;
159
160         if (level == 1)
161                 return fastlz1_decompress(input, length, output, maxout);
162         if (level == 2)
163                 return fastlz2_decompress(input, length, output, maxout);
164
165         /* unknown level, trigger error */
166         return 0;
167 }
168
169 int fastlz_compress_level(int level, const void *input, int length,
170                           void *output)
171 {
172         if (level == 1)
173                 return fastlz1_compress(input, length, output);
174         if (level == 2)
175                 return fastlz2_compress(input, length, output);
176
177         return 0;
178 }
179
180 #else /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */
181
182
183 static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void *input, int length,
184                                            void *output)
185 {
186         const unsigned char *ip = (const unsigned char *) input;
187         const unsigned char *ip_bound = ip + length - 2;
188         const unsigned char *ip_limit = ip + length - 12;
189         unsigned char *op = (unsigned char *) output;
190         static const unsigned char *g_htab[HASH_SIZE];
191
192         const unsigned char **htab = g_htab;
193         const unsigned char **hslot;
194         unsigned int hval;
195
196         unsigned int copy;
197
198         /* sanity check */
199         if (FASTLZ_UNEXPECT_CONDITIONAL(length < 4)) {
200                 if (length) {
201                         /* create literal copy only */
202                         *op++ = length - 1;
203                         ip_bound++;
204                         while (ip <= ip_bound)
205                                 *op++ = *ip++;
206                         return length + 1;
207                 } else
208                         return 0;
209         }
210
211         /* initializes hash table */
212         for (hslot = htab; hslot < htab + HASH_SIZE; hslot++)
213                 *hslot = ip;
214
215         /* we start with literal copy */
216         copy = 2;
217         *op++ = MAX_COPY - 1;
218         *op++ = *ip++;
219         *op++ = *ip++;
220
221         /* main loop */
222         while (FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit)) {
223                 const unsigned char *ref;
224                 unsigned int distance;
225
226                 /* minimum match length */
227                 unsigned int len = 3;
228
229                 /* comparison starting-point */
230                 const unsigned char *anchor = ip;
231
232                 /* check for a run */
233 #if FASTLZ_LEVEL == 2
234                 if (ip[0] == ip[-1] &&
235                     FASTLZ_READU16(ip - 1) == FASTLZ_READU16(ip + 1)) {
236                         distance = 1;
237                         ip += 3;
238                         ref = anchor - 1 + 3;
239                         goto match;
240                 }
241 #endif
242
243                 /* find potential match */
244                 HASH_FUNCTION(hval, ip);
245                 hslot = htab + hval;
246                 ref = htab[hval];
247
248                 /* calculate distance to the match */
249                 distance = anchor - ref;
250
251                 /* update hash table */
252                 *hslot = anchor;
253
254                 if (!ref)
255                         goto literal;
256                 /* is this a match? check the first 3 bytes */
257                 if (distance == 0 ||
258 #if FASTLZ_LEVEL == 1
259                                 (distance >= MAX_DISTANCE) ||
260 #else
261                                 (distance >= MAX_FARDISTANCE) ||
262 #endif
263                                 *ref++ != *ip++ || *ref++ != *ip++ ||
264                                 *ref++ != *ip++)
265                         goto literal;
266
267 #if FASTLZ_LEVEL == 2
268                 /* far, needs at least 5-byte match */
269                 if (distance >= MAX_DISTANCE) {
270                         if (*ip++ != *ref++ || *ip++ != *ref++)
271                                 goto literal;
272                         len += 2;
273                 }
274
275 match:
276 #endif
277
278                 /* last matched byte */
279                 ip = anchor + len;
280
281                 /* distance is biased */
282                 distance--;
283
284                 if (!distance) {
285                         /* zero distance means a run */
286                         unsigned char x = ip[-1];
287                         while (ip < ip_bound)
288                                 if (*ref++ != x)
289                                         break;
290                                 else
291                                         ip++;
292                 } else
293                         for (;;) {
294                                 /* safe because the outer check
295                                  * against ip limit */
296                                 if (*ref++ != *ip++)
297                                         break;
298                                 if (*ref++ != *ip++)
299                                         break;
300                                 if (*ref++ != *ip++)
301                                         break;
302                                 if (*ref++ != *ip++)
303                                         break;
304                                 if (*ref++ != *ip++)
305                                         break;
306                                 if (*ref++ != *ip++)
307                                         break;
308                                 if (*ref++ != *ip++)
309                                         break;
310                                 if (*ref++ != *ip++)
311                                         break;
312                                 while (ip < ip_bound)
313                                         if (*ref++ != *ip++)
314                                                 break;
315                                 break;
316                         }
317
318                 /* if we have copied something, adjust the copy count */
319                 if (copy)
320                         /* copy is biased, '0' means 1 byte copy */
321                         *(op - copy - 1) = copy - 1;
322                 else
323                         /* back, to overwrite the copy count */
324                         op--;
325
326                 /* reset literal counter */
327                 copy = 0;
328
329                 /* length is biased, '1' means a match of 3 bytes */
330                 ip -= 3;
331                 len = ip - anchor;
332
333                 /* encode the match */
334 #if FASTLZ_LEVEL == 2
335                 if (distance < MAX_DISTANCE) {
336                         if (len < 7) {
337                                 *op++ = (len << 5) + (distance >> 8);
338                                 *op++ = (distance & 255);
339                         } else {
340                                 *op++ = (7 << 5) + (distance >> 8);
341                                 for (len -= 7; len >= 255; len -= 255)
342                                         *op++ = 255;
343                                 *op++ = len;
344                                 *op++ = (distance & 255);
345                         }
346                 } else {
347                         /* far away, but not yet in the another galaxy... */
348                         if (len < 7) {
349                                 distance -= MAX_DISTANCE;
350                                 *op++ = (len << 5) + 31;
351                                 *op++ = 255;
352                                 *op++ = distance >> 8;
353                                 *op++ = distance & 255;
354                         } else {
355                                 distance -= MAX_DISTANCE;
356                                 *op++ = (7 << 5) + 31;
357                                 for (len -= 7; len >= 255; len -= 255)
358                                         *op++ = 255;
359                                 *op++ = len;
360                                 *op++ = 255;
361                                 *op++ = distance >> 8;
362                                 *op++ = distance & 255;
363                         }
364                 }
365 #else
366
367                 if (FASTLZ_UNEXPECT_CONDITIONAL(len > MAX_LEN - 2))
368                         while (len > MAX_LEN - 2) {
369                                 *op++ = (7 << 5) + (distance >> 8);
370                                 *op++ = MAX_LEN - 2 - 7 - 2;
371                                 *op++ = (distance & 255);
372                                 len -= MAX_LEN - 2;
373                         }
374
375                 if (len < 7) {
376                         *op++ = (len << 5) + (distance >> 8);
377                         *op++ = (distance & 255);
378                 } else {
379                         *op++ = (7 << 5) + (distance >> 8);
380                         *op++ = len - 7;
381                         *op++ = (distance & 255);
382                 }
383 #endif
384
385                 /* update the hash at match boundary */
386                 HASH_FUNCTION(hval, ip);
387                 htab[hval] = ip++;
388                 HASH_FUNCTION(hval, ip);
389                 htab[hval] = ip++;
390
391                 /* assuming literal copy */
392                 *op++ = MAX_COPY - 1;
393
394                 continue;
395
396 literal:
397                 *op++ = *anchor++;
398                 ip = anchor;
399                 copy++;
400                 if (FASTLZ_UNEXPECT_CONDITIONAL(copy == MAX_COPY)) {
401                         copy = 0;
402                         *op++ = MAX_COPY - 1;
403                 }
404         }
405
406         /* left-over as literal copy */
407         ip_bound++;
408         while (ip <= ip_bound) {
409                 *op++ = *ip++;
410                 copy++;
411                 if (copy == MAX_COPY) {
412                         copy = 0;
413                         *op++ = MAX_COPY - 1;
414                 }
415         }
416
417         /* if we have copied something, adjust the copy length */
418         if (copy)
419                 *(op - copy - 1) = copy - 1;
420         else
421                 op--;
422
423 #if FASTLZ_LEVEL == 2
424         /* marker for fastlz2 */
425         *(unsigned char *)output |= (1 << 5);
426 #endif
427
428         return op - (unsigned char *)output;
429 }
430
431 static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void *input, int length,
432                                              void *output, int maxout)
433 {
434         const unsigned char *ip = (const unsigned char *) input;
435         const unsigned char *ip_limit  = ip + length;
436         unsigned char *op = (unsigned char *) output;
437         unsigned char *op_limit = op + maxout;
438         unsigned int ctrl = (*ip++) & 31;
439         int loop = 1;
440
441         do {
442                 const unsigned char *ref = op;
443                 unsigned int len = ctrl >> 5;
444                 unsigned int ofs = (ctrl & 31) << 8;
445
446                 if (ctrl >= 32) {
447 #if FASTLZ_LEVEL == 2
448                         unsigned char code;
449 #endif
450                         len--;
451                         ref -= ofs;
452                         if (len == 7 - 1)
453 #if FASTLZ_LEVEL == 1
454                                 len += *ip++;
455                         ref -= *ip++;
456 #else
457                         do {
458                                 code = *ip++;
459                                 len += code;
460                         } while (code == 255);
461                         code = *ip++;
462                         ref -= code;
463
464                         /* match from 16-bit distance */
465                         if (FASTLZ_UNEXPECT_CONDITIONAL(code == 255))
466                                 if (FASTLZ_EXPECT_CONDITIONAL(ofs ==
467                                                               (31 << 8))) {
468                                         ofs = (*ip++) << 8;
469                                         ofs += *ip++;
470                                         ref = op - ofs - MAX_DISTANCE;
471                                 }
472 #endif
473
474 #ifdef FASTLZ_SAFE
475                         if (FASTLZ_UNEXPECT_CONDITIONAL(op + len + 3 >
476                                                         op_limit))
477                                 return 0;
478
479                         if (FASTLZ_UNEXPECT_CONDITIONAL(ref - 1 <
480                                                         (unsigned char *)output)
481                                                        )
482                                 return 0;
483 #endif
484
485                         if (FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit))
486                                 ctrl = *ip++;
487                         else
488                                 loop = 0;
489
490                         if (ref == op) {
491                                 /* optimize copy for a run */
492                                 unsigned char b = ref[-1];
493                                 *op++ = b;
494                                 *op++ = b;
495                                 *op++ = b;
496                                 for (; len; --len)
497                                         *op++ = b;
498                         } else {
499 #if !defined(FASTLZ_STRICT_ALIGN)
500                                 const unsigned short *p;
501                                 unsigned short *q;
502 #endif
503                                 /* copy from reference */
504                                 ref--;
505                                 *op++ = *ref++;
506                                 *op++ = *ref++;
507                                 *op++ = *ref++;
508
509 #if !defined(FASTLZ_STRICT_ALIGN)
510                                 /* copy a byte, so that now it's word aligned */
511                                 if (len & 1) {
512                                         *op++ = *ref++;
513                                         len--;
514                                 }
515
516                                 /* copy 16-bit at once */
517                                 q = (unsigned short *) op;
518                                 op += len;
519                                 p = (const unsigned short *) ref;
520                                 for (len >>= 1; len > 4; len -= 4) {
521                                         *q++ = *p++;
522                                         *q++ = *p++;
523                                         *q++ = *p++;
524                                         *q++ = *p++;
525                                 }
526                                 for (; len; --len)
527                                         *q++ = *p++;
528 #else
529                                 for (; len; --len)
530                                         *op++ = *ref++;
531 #endif
532                         }
533                 } else {
534                         ctrl++;
535 #ifdef FASTLZ_SAFE
536                         if (FASTLZ_UNEXPECT_CONDITIONAL(op + ctrl > op_limit))
537                                 return 0;
538                         if (FASTLZ_UNEXPECT_CONDITIONAL(ip + ctrl > ip_limit))
539                                 return 0;
540 #endif
541
542                         *op++ = *ip++;
543                         for (--ctrl; ctrl; ctrl--)
544                                 *op++ = *ip++;
545
546                         loop = FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit);
547                         if (loop)
548                                 ctrl = *ip++;
549                 }
550         } while (FASTLZ_EXPECT_CONDITIONAL(loop));
551
552         return op - (unsigned char *)output;
553 }
554
555 #endif /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */