| /* gvmat32.c -- C portion of the optimized longest_match for 32 bits x86 |
| * Copyright (C) 1995-1996 Jean-loup Gailly and Gilles Vollant. |
| * File written by Gilles Vollant, by modifiying the longest_match |
| * from Jean-loup Gailly in deflate.c |
| * it prepare all parameters and call the assembly longest_match_gvasm |
| * longest_match execute standard C code is wmask != 0x7fff |
| * (assembly code is faster with a fixed wmask) |
| * |
| */ |
| |
| #include "deflate.h" |
| |
| #undef FAR |
| #include <windows.h> |
| |
| #ifdef ASMV |
| #define NIL 0 |
| |
| #define UNALIGNED_OK |
| |
| |
| /* if your C compiler don't add underline before function name, |
| define ADD_UNDERLINE_ASMFUNC */ |
| #ifdef ADD_UNDERLINE_ASMFUNC |
| #define longest_match_7fff _longest_match_7fff |
| #endif |
| |
| |
| |
| void match_init() |
| { |
| } |
| |
| unsigned long cpudetect32(); |
| |
| uInt longest_match_c( |
| deflate_state *s, |
| IPos cur_match); /* current match */ |
| |
| |
| uInt longest_match_7fff( |
| deflate_state *s, |
| IPos cur_match); /* current match */ |
| |
| uInt longest_match( |
| deflate_state *s, |
| IPos cur_match) /* current match */ |
| { |
| static uInt iIsPPro=2; |
| |
| if ((s->w_mask == 0x7fff) && (iIsPPro==0)) |
| return longest_match_7fff(s,cur_match); |
| |
| if (iIsPPro==2) |
| iIsPPro = (((cpudetect32()/0x100)&0xf)>=6) ? 1 : 0; |
| |
| return longest_match_c(s,cur_match); |
| } |
| |
| |
| |
| uInt longest_match_c(s, cur_match) |
| deflate_state *s; |
| IPos cur_match; /* current match */ |
| { |
| unsigned chain_length = s->max_chain_length;/* max hash chain length */ |
| register Bytef *scan = s->window + s->strstart; /* current string */ |
| register Bytef *match; /* matched string */ |
| register int len; /* length of current match */ |
| int best_len = s->prev_length; /* best match length so far */ |
| int nice_match = s->nice_match; /* stop if match long enough */ |
| IPos limit = s->strstart > (IPos)MAX_DIST(s) ? |
| s->strstart - (IPos)MAX_DIST(s) : NIL; |
| /* Stop when cur_match becomes <= limit. To simplify the code, |
| * we prevent matches with the string of window index 0. |
| */ |
| Posf *prev = s->prev; |
| uInt wmask = s->w_mask; |
| |
| #ifdef UNALIGNED_OK |
| /* Compare two bytes at a time. Note: this is not always beneficial. |
| * Try with and without -DUNALIGNED_OK to check. |
| */ |
| register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; |
| register ush scan_start = *(ushf*)scan; |
| register ush scan_end = *(ushf*)(scan+best_len-1); |
| #else |
| register Bytef *strend = s->window + s->strstart + MAX_MATCH; |
| register Byte scan_end1 = scan[best_len-1]; |
| register Byte scan_end = scan[best_len]; |
| #endif |
| |
| /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. |
| * It is easy to get rid of this optimization if necessary. |
| */ |
| Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); |
| |
| /* Do not waste too much time if we already have a good match: */ |
| if (s->prev_length >= s->good_match) { |
| chain_length >>= 2; |
| } |
| /* Do not look for matches beyond the end of the input. This is necessary |
| * to make deflate deterministic. |
| */ |
| if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; |
| |
| Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); |
| |
| do { |
| Assert(cur_match < s->strstart, "no future"); |
| match = s->window + cur_match; |
| |
| /* Skip to next match if the match length cannot increase |
| * or if the match length is less than 2: |
| */ |
| #if (defined(UNALIGNED_OK) && MAX_MATCH == 258) |
| /* This code assumes sizeof(unsigned short) == 2. Do not use |
| * UNALIGNED_OK if your compiler uses a different size. |
| */ |
| if (*(ushf*)(match+best_len-1) != scan_end || |
| *(ushf*)match != scan_start) continue; |
| |
| /* It is not necessary to compare scan[2] and match[2] since they are |
| * always equal when the other bytes match, given that the hash keys |
| * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at |
| * strstart+3, +5, ... up to strstart+257. We check for insufficient |
| * lookahead only every 4th comparison; the 128th check will be made |
| * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is |
| * necessary to put more guard bytes at the end of the window, or |
| * to check more often for insufficient lookahead. |
| */ |
| Assert(scan[2] == match[2], "scan[2]?"); |
| scan++, match++; |
| do { |
| } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && |
| *(ushf*)(scan+=2) == *(ushf*)(match+=2) && |
| *(ushf*)(scan+=2) == *(ushf*)(match+=2) && |
| *(ushf*)(scan+=2) == *(ushf*)(match+=2) && |
| scan < strend); |
| /* The funny "do {}" generates better code on most compilers */ |
| |
| /* Here, scan <= window+strstart+257 */ |
| Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); |
| if (*scan == *match) scan++; |
| |
| len = (MAX_MATCH - 1) - (int)(strend-scan); |
| scan = strend - (MAX_MATCH-1); |
| |
| #else /* UNALIGNED_OK */ |
| |
| if (match[best_len] != scan_end || |
| match[best_len-1] != scan_end1 || |
| *match != *scan || |
| *++match != scan[1]) continue; |
| |
| /* The check at best_len-1 can be removed because it will be made |
| * again later. (This heuristic is not always a win.) |
| * It is not necessary to compare scan[2] and match[2] since they |
| * are always equal when the other bytes match, given that |
| * the hash keys are equal and that HASH_BITS >= 8. |
| */ |
| scan += 2, match++; |
| Assert(*scan == *match, "match[2]?"); |
| |
| /* We check for insufficient lookahead only every 8th comparison; |
| * the 256th check will be made at strstart+258. |
| */ |
| do { |
| } while (*++scan == *++match && *++scan == *++match && |
| *++scan == *++match && *++scan == *++match && |
| *++scan == *++match && *++scan == *++match && |
| *++scan == *++match && *++scan == *++match && |
| scan < strend); |
| |
| Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); |
| |
| len = MAX_MATCH - (int)(strend - scan); |
| scan = strend - MAX_MATCH; |
| |
| #endif /* UNALIGNED_OK */ |
| |
| if (len > best_len) { |
| s->match_start = cur_match; |
| best_len = len; |
| if (len >= nice_match) break; |
| #ifdef UNALIGNED_OK |
| scan_end = *(ushf*)(scan+best_len-1); |
| #else |
| scan_end1 = scan[best_len-1]; |
| scan_end = scan[best_len]; |
| #endif |
| } |
| } while ((cur_match = prev[cur_match & wmask]) > limit |
| && --chain_length != 0); |
| |
| if ((uInt)best_len <= s->lookahead) return (uInt)best_len; |
| return s->lookahead; |
| } |
| |
| #endif /* ASMV */ |