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

ece*_*ulm 11 c crc32

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

ece*_*ulm 12

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

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

  1. 通过asm语句在C代码中内联汇编语言
  2. 使用内部函数_mm_crc32_u8,_mm_crc32_u16,_mm_crc32_u32_mm_crc32_u64.有关英特尔编译器的说明,请参阅" 英特尔内部指南",iccgcc也可以实现它们.

这就是你如何做到这一点__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;
}
Run Code Online (Sandbox Code Playgroud)

为了编译这一点,你需要通过-msse4.2CFLAGS.就像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")));
Run Code Online (Sandbox Code Playgroud)