home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / zip22.zip / crc_i386.S < prev    next >
Text File  |  1997-10-11  |  9KB  |  231 lines

  1. /*
  2.  * crc_i386.S, optimized CRC calculation function for Zip and UnZip, not
  3.  * copyrighted by Paul Kienitz and Christian Spieler.  Last revised 12 Oct 97.
  4.  *
  5.  * GRR 961110:  incorporated Scott Field optimizations from win32/crc_i386.asm
  6.  *              => overall 6% speedup in "unzip -tq" on 9MB zipfile (486-66)
  7.  *
  8.  * SPC 970402:  revised for Rodney Brown's optimizations (32-bit-wide
  9.  *              aligned reads for most of the data from buffer), can be
  10.  *              disabled by defining the macro NO_32_BIT_LOADS
  11.  *
  12.  * SPC 971012:  added Rodney Brown's additional tweaks for 32-bit-optimized
  13.  *              CPUs (like the Pentium Pro, Pentium II, and probably some
  14.  *              Pentium clones). This optimization is controlled by the
  15.  *              preprocessor switch "__686" and is disabled by default.
  16.  *              (This default is based on the assumption that most users
  17.  *              do not yet work on a Pentium Pro or Pentium II machine ...)
  18.  *
  19.  * FLAT memory model assumed.  Calling interface:
  20.  *   - args are pushed onto the stack from right to left,
  21.  *   - return value is given in the EAX register,
  22.  *   - all other registers (with exception of EFLAGS) are preserved. (With
  23.  *     GNU C 2.7.x, %edx and %ecx are `scratch' registers, but preserving
  24.  *     them nevertheless adds only 4 single byte instructions.)
  25.  *
  26.  * This source generates the function
  27.  * ulg crc32(ulg crc, ZCONST uch *buf, ulg len).
  28.  *
  29.  * The loop unrolling can be disabled by defining the macro NO_UNROLLED_LOOPS.
  30.  * This results in shorter code at the expense of reduced performance.
  31.  */
  32.  
  33. /* This file is NOT used in conjunction with zlib. */
  34. #ifndef USE_ZLIB
  35.  
  36. /* Preprocess with -DNO_UNDERLINE if your C compiler does not prefix
  37.  * external symbols with an underline character '_'.
  38.  */
  39. #if defined(NO_UNDERLINE) || defined(__ELF__)
  40. #  define _crc32            crc32
  41. #  define _get_crc_table    get_crc_table
  42. #endif
  43. /* Use 16-byte alignment if your assembler supports it. Warning: gas
  44.  * uses a log(x) parameter (.align 4 means 16-byte alignment). On SVR4
  45.  * the parameter is a number of bytes.
  46.  */
  47. #ifndef ALIGNMENT
  48. #  define ALIGNMENT .align 4,0x90
  49. #endif
  50.  
  51. #if defined(i386) || defined(_i386) || defined(_I386) || defined(__i386)
  52.  
  53. /* This version is for 386 Unix, OS/2, MSDOS in 32 bit mode (gcc & gas).
  54.  * Warning: it uses the AT&T syntax: mov source,dest
  55.  * This file is only optional. If you want to use the C version,
  56.  * remove -DASM_CRC from CFLAGS in Makefile and set OBJA to an empty string.
  57.  */
  58.  
  59.                 .file   "crc_i386.S"
  60.  
  61. #if defined(NO_STD_STACKFRAME) && defined(USE_STD_STACKFRAME)
  62. #  undef USE_STACKFRAME
  63. #else
  64.    /* The default is to use standard stack frame entry, because it
  65.     * results in smaller code!
  66.     */
  67. #  ifndef USE_STD_STACKFRAME
  68. #    define USE_STD_STACKFRAME
  69. #  endif
  70. #endif
  71.  
  72. #ifdef USE_STD_STACKFRAME
  73. #  define _STD_ENTRY    pushl   %ebp ; movl   %esp,%ebp
  74. #  define arg1  8(%ebp)
  75. #  define arg2  12(%ebp)
  76. #  define arg3  16(%ebp)
  77. #  define _STD_LEAVE    popl    %ebp
  78. #else /* !USE_STD_STACKFRAME */
  79. #  define _STD_ENTRY
  80. #  define arg1  24(%esp)
  81. #  define arg2  28(%esp)
  82. #  define arg3  32(%esp)
  83. #  define _STD_LEAVE
  84. #endif /* ?USE_STD_STACKFRAME */
  85.  
  86. /*
  87.  * These two (three) macros make up the loop body of the CRC32 cruncher.
  88.  * registers modified:
  89.  *   eax  : crc value "c"
  90.  *   esi  : pointer to next data byte (or lword) "buf++"
  91.  * registers read:
  92.  *   edi  : pointer to base of crc_table array
  93.  * scratch registers:
  94.  *   ebx  : index into crc_table array
  95.  *          (requires upper three bytes = 0 when __686 is undefined)
  96.  */
  97. #ifndef __686   /* optimize for 386, 486, Pentium */
  98. #define Do_CRC          /* c = (c >> 8) ^ table[c & 0xFF] */\
  99.                 movb    %al, %bl                ;/* tmp = c & 0xFF  */\
  100.                 shrl    $8, %eax                ;/* c = (c >> 8)    */\
  101.                 xorl    (%edi, %ebx, 4), %eax   ;/* c ^= table[tmp] */
  102. #else   /* __686 : optimize for Pentium Pro and compatible CPUs */
  103. #define Do_CRC          /* c = (c >> 8) ^ table[c & 0xFF] */\
  104.                 movzbl  %al, %ebx               ;/* tmp = c & 0xFF  */\
  105.                 shrl    $8, %eax                ;/* c = (c >> 8)    */\
  106.                 xorl    (%edi, %ebx, 4), %eax   ;/* c ^=table[tmp]  */
  107. #endif  /* ?__686 */
  108.  
  109. #define Do_CRC_byte     /* c = (c >> 8) ^ table[(c^*buf++)&0xFF] */\
  110.                 xorb    (%esi), %al     ;/* c ^= *buf  */\
  111.                 incl    %esi            ;/* buf++      */\
  112.                 Do_CRC
  113.  
  114. #ifndef  NO_32_BIT_LOADS
  115. #define Do_CRC_lword \
  116.                 xorl    (%esi), %eax    ;/* c ^= *(ulg *)buf */\
  117.                 addl    $4, %esi        ;/* ((ulg *)buf)++   */\
  118.                 Do_CRC \
  119.                 Do_CRC \
  120.                 Do_CRC \
  121.                 Do_CRC
  122. #endif  /* !NO_32_BIT_LOADS */
  123.  
  124.  
  125.                 .text
  126.  
  127.                 .globl  _crc32
  128.  
  129. _crc32:                         /* ulg crc32(ulg crc, uch *buf, extent len) */
  130.                 _STD_ENTRY
  131.                 pushl   %edi
  132.                 pushl   %esi
  133.                 pushl   %ebx
  134.                 pushl   %edx
  135.                 pushl   %ecx
  136.  
  137.                 movl    arg2, %esi           /* 2nd arg: uch *buf            */
  138.                 subl    %eax, %eax           /* > if (!buf)                  */
  139.                 testl   %esi, %esi           /* >   return 0;                */
  140.                 jz      .L_fine              /* > else {                     */
  141.                 call    _get_crc_table
  142.                 movl    %eax, %edi
  143.                 movl    arg1, %eax           /* 1st arg: ulg crc             */
  144. #ifndef __686
  145.                 subl    %ebx, %ebx           /* ebx=0; bl usable as dword    */
  146. #endif
  147.                 movl    arg3, %ecx           /* 3rd arg: extent len          */
  148.                 notl    %eax                 /* >   c = ~crc;                */
  149.  
  150. #ifndef  NO_UNROLLED_LOOPS
  151. #  ifndef  NO_32_BIT_LOADS
  152.                 testl   %ecx, %ecx
  153.                 jz      .L_bail
  154.                 /* Assert now have positive length */
  155. .L_align_loop:
  156.                 testl   $3, %esi        /* Align buf on lword boundary */
  157.                 jz      .L_aligned_now
  158.                 Do_CRC_byte
  159.                 decl    %ecx
  160.                 jnz     .L_align_loop
  161. .L_aligned_now:
  162. #  endif  /* !NO_32_BIT_LOADS */
  163.                 movl    %ecx, %edx           /* save len in edx          */
  164.                 andl    $7, %edx             /* edx = len % 8            */
  165.                 shrl    $3, %ecx             /* ecx = len / 8            */
  166.                 jz      .L_No_Eights
  167. /*  align loop head at start of 486 internal cache line !! */
  168.                 ALIGNMENT
  169. .L_Next_Eight:
  170. #  ifndef NO_32_BIT_LOADS
  171.                  /* Do_CRC_lword */
  172.                  xorl    (%esi), %eax    ;/* c ^= *(ulg *)buf */
  173.                  addl    $4, %esi        ;/* ((ulg *)buf)++   */
  174.                  Do_CRC
  175.                  Do_CRC
  176.                  Do_CRC
  177.                  Do_CRC
  178.                  /* Do_CRC_lword */
  179.                  xorl    (%esi), %eax    ;/* c ^= *(ulg *)buf */
  180.                  addl    $4, %esi        ;/* ((ulg *)buf)++   */
  181.                  Do_CRC
  182.                  Do_CRC
  183.                  Do_CRC
  184.                  Do_CRC
  185. #  else   /* NO_32_BIT_LOADS */
  186.                  Do_CRC_byte
  187.                  Do_CRC_byte
  188.                  Do_CRC_byte
  189.                  Do_CRC_byte
  190.                  Do_CRC_byte
  191.                  Do_CRC_byte
  192.                  Do_CRC_byte
  193.                  Do_CRC_byte
  194. #  endif  /* ?NO_32_BIT_LOADS */
  195.                 decl    %ecx
  196.                 jnz     .L_Next_Eight
  197.  
  198. .L_No_Eights:
  199.                 movl    %edx, %ecx
  200. #endif /* NO_UNROLLED_LOOPS */
  201.  
  202. #ifndef NO_JECXZ_SUPPORT
  203.                 jecxz   .L_bail              /* > if (len)                   */
  204. #else
  205.                 testl   %ecx, %ecx           /* > if (len)                   */
  206.                 jz      .L_bail
  207. #endif
  208. /* align loop head at start of 486 internal cache line !! */
  209.                 ALIGNMENT
  210. .L_loupe:                                    /* >   do {                     */
  211.                  Do_CRC_byte                 /*       c = CRC32(c, *buf++);  */
  212.                 decl    %ecx                 /* >   } while (--len);         */
  213.                 jnz     .L_loupe
  214.  
  215. .L_bail:                                     /* > }                          */
  216.                 notl    %eax                 /* > return ~c;                 */
  217. .L_fine:
  218.                 popl    %ecx
  219.                 popl    %edx
  220.                 popl    %ebx
  221.                 popl    %esi
  222.                 popl    %edi
  223.                 _STD_LEAVE
  224.                 ret
  225.  
  226. #else
  227.  error: this asm version is for 386 only
  228. #endif /* i386 || _i386 || _I386 || __i386 */
  229.  
  230. #endif /* !USE_ZLIB */
  231.