Commit 10507a61 authored by Andrew Morton's avatar Andrew Morton Committed by Jens Axboe

[PATCH] crc32 improvements

Patch from Joakim Tjernlund <joakim.tjernlund@lumentis.se>

I did the optimizations in the crc32 patch Brian Murphy submitted a while ago.
Now I have cleaned it up a little and made some more optimizations.

gcc is quite bad at loop optimizations (at least for PPC) so I have
rewritten them to make gcc to generate better code. Even recent gcc's(3.2.x) produces
better code.

Also reduced the unrolling since it did not make a noticeable difference.
parent 81eb6906
...@@ -87,55 +87,51 @@ u32 attribute((pure)) crc32_le(u32 crc, unsigned char const *p, size_t len) ...@@ -87,55 +87,51 @@ u32 attribute((pure)) crc32_le(u32 crc, unsigned char const *p, size_t len)
{ {
# if CRC_LE_BITS == 8 # if CRC_LE_BITS == 8
const u32 *b =(u32 *)p; const u32 *b =(u32 *)p;
const u32 *e; const u32 *tab = crc32table_le;
/* load data 32 bits wide, xor data 32 bits wide. */
crc = __cpu_to_le32(crc);
/* Align it */
for ( ; ((long)b)&3 && len ; len--){
# ifdef __LITTLE_ENDIAN # ifdef __LITTLE_ENDIAN
crc = (crc>>8) ^ crc32table_le[ (crc ^ *((u8 *)b)++) & 0xff ]; # define DO_CRC crc = (crc>>8) ^ tab[ crc & 255 ]
# define ENDIAN_SHIFT 0
# else # else
crc = (crc<<8) ^ crc32table_le[ crc>>24 ^ *((u8 *)b)++ ]; # define DO_CRC crc = (crc<<8) ^ tab[ crc >> 24 ]
# define ENDIAN_SHIFT 24
# endif # endif
crc = __cpu_to_le32(crc);
/* Align it */
if(unlikely(((long)b)&3 && len)){
do {
crc ^= *((u8 *)b)++ << ENDIAN_SHIFT;
DO_CRC;
} while ((--len) && ((long)b)&3 );
} }
e = (u32 *) ( (u8 *)b + (len & ~7)); if(likely(len >= 4)){
while (b < e) { /* load data 32 bits wide, xor data 32 bits wide. */
crc ^= *b++; size_t save_len = len & 3;
# ifdef __LITTLE_ENDIAN len = len >> 2;
crc = (crc>>8) ^ crc32table_le[ crc & 0xff ]; --b; /* use pre increment below(*++b) for speed */
crc = (crc>>8) ^ crc32table_le[ crc & 0xff ]; do {
crc = (crc>>8) ^ crc32table_le[ crc & 0xff ]; crc ^= *++b;
crc = (crc>>8) ^ crc32table_le[ crc & 0xff ]; DO_CRC;
# else DO_CRC;
crc = (crc<<8) ^ crc32table_le[ crc >> 24 ]; DO_CRC;
crc = (crc<<8) ^ crc32table_le[ crc >> 24 ]; DO_CRC;
crc = (crc<<8) ^ crc32table_le[ crc >> 24 ]; } while (--len);
crc = (crc<<8) ^ crc32table_le[ crc >> 24 ]; b++; /* point to next byte(s) */
# endif len = save_len;
crc ^= *b++;
# ifdef __LITTLE_ENDIAN
crc = (crc>>8) ^ crc32table_le[ crc & 0xff ];
crc = (crc>>8) ^ crc32table_le[ crc & 0xff ];
crc = (crc>>8) ^ crc32table_le[ crc & 0xff ];
crc = (crc>>8) ^ crc32table_le[ crc & 0xff ];
# else
crc = (crc<<8) ^ crc32table_le[ crc >> 24 ];
crc = (crc<<8) ^ crc32table_le[ crc >> 24 ];
crc = (crc<<8) ^ crc32table_le[ crc >> 24 ];
crc = (crc<<8) ^ crc32table_le[ crc >> 24 ];
# endif
} }
/* And the last few bytes */ /* And the last few bytes */
e = (u32 *)((u8 *)b + (len & 7)); if(len){
while (b < e){ do {
# ifdef __LITTLE_ENDIAN crc ^= *((u8 *)b)++ << ENDIAN_SHIFT;
crc = (crc>>8) ^ crc32table_le[ (crc ^ *((u8 *)b)++) & 0xff ]; DO_CRC;
# else } while (--len);
crc = (crc<<8) ^ crc32table_le[ crc>>24 ^ *((u8 *)b)++ ];
# endif
} }
return __le32_to_cpu(crc) ;
return __le32_to_cpu(crc);
#undef ENDIAN_SHIFT
#undef DO_CRC
# elif CRC_LE_BITS == 4 # elif CRC_LE_BITS == 4
while (len--) { while (len--) {
crc ^= *p++; crc ^= *p++;
...@@ -196,55 +192,50 @@ u32 attribute((pure)) crc32_be(u32 crc, unsigned char const *p, size_t len) ...@@ -196,55 +192,50 @@ u32 attribute((pure)) crc32_be(u32 crc, unsigned char const *p, size_t len)
{ {
# if CRC_BE_BITS == 8 # if CRC_BE_BITS == 8
const u32 *b =(u32 *)p; const u32 *b =(u32 *)p;
const u32 *e; const u32 *tab = crc32table_be;
/* load data 32 bits wide, xor data 32 bits wide. */
crc = __cpu_to_be32(crc);
/* Align it */
for ( ; ((long)b)&3 && len ; len--){
# ifdef __LITTLE_ENDIAN # ifdef __LITTLE_ENDIAN
crc = (crc>>8) ^ crc32table_be[ (crc ^ *((u8 *)b)++) & 0xff ]; # define DO_CRC crc = (crc>>8) ^ tab[ crc & 255 ]
# define ENDIAN_SHIFT 24
# else # else
crc = (crc<<8) ^ crc32table_be[ crc>>24 ^ *((u8 *)b)++ ]; # define DO_CRC crc = (crc<<8) ^ tab[ crc >> 24 ]
# define ENDIAN_SHIFT 0
# endif # endif
crc = __cpu_to_be32(crc);
/* Align it */
if(unlikely(((long)b)&3 && len)){
do {
crc ^= *((u8 *)b)++ << ENDIAN_SHIFT;
DO_CRC;
} while ((--len) && ((long)b)&3 );
} }
e = (u32 *) ( (u8 *)b + (len & ~7)); if(likely(len >= 4)){
while (b < e) { /* load data 32 bits wide, xor data 32 bits wide. */
crc ^= *b++; size_t save_len = len & 3;
# ifdef __LITTLE_ENDIAN len = len >> 2;
crc = (crc>>8) ^ crc32table_be[ crc & 0xff ]; --b; /* use pre increment below(*++b) for speed */
crc = (crc>>8) ^ crc32table_be[ crc & 0xff ]; do {
crc = (crc>>8) ^ crc32table_be[ crc & 0xff ]; crc ^= *++b;
crc = (crc>>8) ^ crc32table_be[ crc & 0xff ]; DO_CRC;
# else DO_CRC;
crc = (crc<<8) ^ crc32table_be[ crc >> 24 ]; DO_CRC;
crc = (crc<<8) ^ crc32table_be[ crc >> 24 ]; DO_CRC;
crc = (crc<<8) ^ crc32table_be[ crc >> 24 ]; } while (--len);
crc = (crc<<8) ^ crc32table_be[ crc >> 24 ]; b++; /* point to next byte(s) */
# endif len = save_len;
crc ^= *b++;
# ifdef __LITTLE_ENDIAN
crc = (crc>>8) ^ crc32table_be[ crc & 0xff ];
crc = (crc>>8) ^ crc32table_be[ crc & 0xff ];
crc = (crc>>8) ^ crc32table_be[ crc & 0xff ];
crc = (crc>>8) ^ crc32table_be[ crc & 0xff ];
# else
crc = (crc<<8) ^ crc32table_be[ crc >> 24 ];
crc = (crc<<8) ^ crc32table_be[ crc >> 24 ];
crc = (crc<<8) ^ crc32table_be[ crc >> 24 ];
crc = (crc<<8) ^ crc32table_be[ crc >> 24 ];
# endif
} }
/* And the last few bytes */ /* And the last few bytes */
e = (u32 *)((u8 *)b + (len & 7)); if(len){
while (b < e){ do {
# ifdef __LITTLE_ENDIAN crc ^= *((u8 *)b)++ << ENDIAN_SHIFT;
crc = (crc>>8) ^ crc32table_be[ (crc ^ *((u8 *)b)++) & 0xff ]; DO_CRC;
# else } while (--len);
crc = (crc<<8) ^ crc32table_be[ crc>>24 ^ *((u8 *)b)++ ];
# endif
} }
return __be32_to_cpu(crc) ; return __be32_to_cpu(crc);
#undef ENDIAN_SHIFT
#undef DO_CRC
# elif CRC_BE_BITS == 4 # elif CRC_BE_BITS == 4
while (len--) { while (len--) {
crc ^= *p++ << 24; crc ^= *p++ << 24;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment