如何利用英特尔特定指令实现CRC32?

时间:2015-07-02 12:05:06

标签: c crc32

英特尔在SSE4.2指令集中提供了特定的CRC32 instruction。如何利用此指令加速CRC32计算?

2 个答案:

答案 0 :(得分:11)

首先,英特尔的CRC32指令用于计算CRC-32C(即使用与常规CRC32不同的多项式。查看Wikipedia CRC32条目)

要使用gcc使用英特尔的CRC32C硬件加速,您可以:

  1. 通过asm语句
  2. 在C代码中使用内联汇编语言
  3. 使用内在函数_mm_crc32_u8_mm_crc32_u16_mm_crc32_u32_mm_crc32_u64。有关英特尔编译器icc的说明,请参见Intel Intrinsics Guide,但gcc也会实现它们。
  4. 这是使用__mm_crc32_u8执行此操作的方法,一次占用一个字节,使用__mm_crc32_u64可以进一步提高性能,因为它一次需要8个字节。

    uint32_t sse42_crc32(const uint8_t *bytes, size_t len)
    {
      uint32_t hash = 0;
      size_t i = 0;
      for (i=0;i<len;i++) {
        hash = _mm_crc32_u8(hash, bytes[i]);
      }
    
      return hash;
    }
    

    要编译此内容,您需要在-msse4.2中传递CFLAGS。与gcc -g -msse4.2 test.c一样,否则会抱怨undefined reference to _mm_crc32_u8

    如果要在可执行文件运行的平台中没有该指令,则要恢复到普通的C实现,可以使用GCC的ifunc属性。像

    uint32_t sse42_crc32(const uint8_t *bytes, size_t len)
    {
      /* use _mm_crc32_u* here */
    }
    
    uint32_t default_crc32(const uint8_t *bytes, size_t len)
    {
      /* pure C implementation */
    }
    
    /* this will be called at load time to decide which function really use */
    /* sse42_crc32 if SSE 4.2 is supported */
    /* default_crc32 if not */
    static void * resolve_crc32(void) {
      __builtin_cpu_init();
      if (__builtin_cpu_supports("sse4.2")) return sse42_crc32;
    
      return default_crc32;
    }
    
    /* crc32() implementation will be resolved at load time to either */
    /* sse42_crc32() or default_crc32() */
    uint32_t crc32(const uint8_t *bytes, size_t len) __attribute__ ((ifunc ("resolve_crc32")));
    

答案 1 :(得分:3)

有关CRC-32C的快速硬件和软件实现,请参阅this answer。硬件实现有效地并行运行三条crc32指令以提高速度。