/* 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 | |
#define longest_match_686 _longest_match_686 | |
#define cpudetect32 _cpudetect32 | |
#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_686( | |
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==1) | |
return longest_match_686(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 */ |