CRC32.c (4093B)
1 /* 2 * CRC32 Implementation with Hardware Acceleration 3 * Uses CRC32 instruction (SSE 4.2) when available 4 */ 5 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <string.h> 9 #include <stdint.h> 10 #include <immintrin.h> 11 12 #ifdef __GNUC__ 13 #include <cpuid.h> 14 #endif 15 16 // CPU feature detection 17 static int has_crc32_inst = 0; 18 static int features_detected = 0; 19 20 static void detect_cpu_features(void) { 21 if (features_detected) return; 22 #ifdef __GNUC__ 23 unsigned int eax, ebx, ecx, edx; 24 if (__get_cpuid(1, &eax, &ebx, &ecx, &edx)) { 25 has_crc32_inst = (ecx & bit_SSE4_2) != 0; 26 } 27 #endif 28 features_detected = 1; 29 } 30 31 // CRC32 lookup table (for software fallback) 32 static uint32_t crc32_table[256]; 33 static int table_initialized = 0; 34 35 static void crc32_init_table(void) { 36 if (table_initialized) return; 37 38 for (uint32_t i = 0; i < 256; i++) { 39 uint32_t crc = i; 40 for (int j = 0; j < 8; j++) { 41 if (crc & 1) { 42 crc = (crc >> 1) ^ 0xEDB88320; 43 } else { 44 crc >>= 1; 45 } 46 } 47 crc32_table[i] = crc; 48 } 49 table_initialized = 1; 50 } 51 52 // Software CRC32 implementation 53 static uint32_t crc32_software(const uint8_t *data, size_t len, uint32_t crc) { 54 if (!table_initialized) { 55 crc32_init_table(); 56 } 57 58 crc = ~crc; 59 for (size_t i = 0; i < len; i++) { 60 crc = crc32_table[(crc ^ data[i]) & 0xFF] ^ (crc >> 8); 61 } 62 return ~crc; 63 } 64 65 // Hardware CRC32 implementation (SSE 4.2) 66 #ifdef __SSE4_2__ 67 static uint32_t crc32_hardware(const uint8_t *data, size_t len, uint32_t crc) { 68 size_t i; 69 70 // Process 8 bytes at a time on 64-bit 71 #if defined(__x86_64__) || defined(_M_X64) 72 for (i = 0; i + 7 < len; i += 8) { 73 uint64_t val; 74 memcpy(&val, data + i, 8); 75 crc = _mm_crc32_u64(crc, val); 76 } 77 #else 78 // Process 4 bytes at a time on 32-bit 79 for (i = 0; i + 3 < len; i += 4) { 80 uint32_t val; 81 memcpy(&val, data + i, 4); 82 crc = _mm_crc32_u32(crc, val); 83 } 84 #endif 85 86 // Process remaining bytes 87 for (; i < len; i++) { 88 crc = _mm_crc32_u8(crc, data[i]); 89 } 90 91 return crc; 92 } 93 #endif 94 95 // Public CRC32 function 96 uint32_t crc32(const uint8_t *data, size_t len) { 97 if (!features_detected) { 98 detect_cpu_features(); 99 } 100 101 #ifdef __SSE4_2__ 102 if (has_crc32_inst) { 103 return crc32_hardware(data, len, 0); 104 } 105 #endif 106 107 return crc32_software(data, len, 0); 108 } 109 110 // CRC32 with initial value 111 uint32_t crc32_continue(const uint8_t *data, size_t len, uint32_t initial_crc) { 112 if (!features_detected) { 113 detect_cpu_features(); 114 } 115 116 #ifdef __SSE4_2__ 117 if (has_crc32_inst) { 118 return crc32_hardware(data, len, initial_crc); 119 } 120 #endif 121 122 return crc32_software(data, len, initial_crc); 123 } 124 125 // Test program 126 #ifndef LIB_MODE 127 int main(void) { 128 detect_cpu_features(); 129 130 printf("CRC32 Implementation\n"); 131 printf("====================\n"); 132 printf("Hardware acceleration (CRC32 instruction): %s\n\n", has_crc32_inst ? "Yes" : "No"); 133 134 // Test vectors 135 const char *test1 = ""; 136 const char *test2 = "The quick brown fox jumps over the lazy dog"; 137 const char *test3 = "123456789"; 138 139 uint32_t crc; 140 141 // Test 1 142 printf("Test 1: \"%s\"\n", test1); 143 crc = crc32((uint8_t*)test1, strlen(test1)); 144 printf("CRC32: 0x%08x\n", crc); 145 printf("Expected: 0x00000000\n\n"); 146 147 // Test 2 148 printf("Test 2: \"%s\"\n", test2); 149 crc = crc32((uint8_t*)test2, strlen(test2)); 150 printf("CRC32: 0x%08x\n", crc); 151 printf("Expected: 0x414fa339\n\n"); 152 153 // Test 3 154 printf("Test 3: \"%s\"\n", test3); 155 crc = crc32((uint8_t*)test3, strlen(test3)); 156 printf("CRC32: 0x%08x\n", crc); 157 printf("Expected: 0xcbf43926\n\n"); 158 159 // Test incremental CRC 160 printf("Test 4: Incremental CRC of \"123\" + \"456789\"\n"); 161 uint32_t crc1 = crc32((uint8_t*)"123", 3); 162 uint32_t crc2 = crc32_continue((uint8_t*)"456789", 6, crc1); 163 printf("CRC32: 0x%08x\n", crc2); 164 printf("Expected: 0xcbf43926 (same as Test 3)\n\n"); 165 166 return 0; 167 } 168 #endif