在ARM架构上指令集加速CRC32计算的c语言实现

0. 概要

CRC32(循环冗余校验)是一种常用的校验算法,用于检测数据传输或存储中的错误。本文介绍了在ARM架构上利用硬件加速指令集实现CRC32计算的方法,并提供了相应的代码示例。

1. 实现

实现方法: 在ARM架构上,可以利用指令集中的特殊指令来加速CRC32的计算过程。具体而言,我们可以使用crc32cx、crc32cw、crc32ch和crc32cb等指令来分别处理64位、32位、16位和8位的数据块。以下是实现的基本思路:

  • 初始化CRC32值:首先,使用crc32_start函数初始化CRC32值,设置为0xffffffff。
  • 执行CRC32计算:然后,使用crc32_do函数对输入数据执行CRC32计算。在+ ARM架构上,利用硬件加速指令集来高效地处理数据,尽可能地利用SIMD(单指令多数据)并行计算。
  • 结束CRC32计算:最后,使用crc32_end函数对计算结果进行处理,返回最终的CRC32值。

头文件

// crc32_utils.h
#ifndef UTILS_CRC32_UTILS_H
#define UTILS_CRC32_UTILS_H

#include <stddef.h>
#include <stdint.h>

#define kCrc32TableSize 256
uint32_t crc32_start(void);
uint32_t crc32_end(uint32_t crc);
uint32_t crc32_do(const void *const in_buf, uint32_t crc, const uint64_t in_buf_len);

#endif  // UTILS_CRC32_UTILS_H

实现方法

// crc32_utils.c
#include "Utils/crc32_utils.h"

uint32_t crc32_start(void) {
  return 0xffffffffU;
}

uint32_t crc32_end(uint32_t crc) {
  return crc ^ 0xffffffffU;
}

#if defined(__aarch64__) || defined(__arm__)

uint32_t crc32_do(const void *const in_buf, uint32_t crc, const uint64_t in_buf_len) {
  int64_t bytes = in_buf_len;
  const uint8_t *data = (const uint8_t *)(in_buf);
  while (bytes >= sizeof(uint64_t)) {
    __asm__("crc32cx %w[c], %w[c], %x[v]" : [ c ] "+r"(crc) : [ v ] "r"(*((uint64_t *)data)));
    data += sizeof(uint64_t);
    bytes -= sizeof(uint64_t);
  }
  if (bytes & sizeof(uint32_t)) {
    __asm__("crc32cw %w[c], %w[c], %w[v]" : [ c ] "+r"(crc) : [ v ] "r"(*((uint32_t *)data)));
    data += sizeof(uint32_t);
    bytes -= sizeof(uint32_t);
  }
  if (bytes & sizeof(uint16_t)) {
    __asm__("crc32ch %w[c], %w[c], %w[v]" : [ c ] "+r"(crc) : [ v ] "r"(*((uint16_t *)data)));
    data += sizeof(uint16_t);
    bytes -= sizeof(uint16_t);
  }
  if (bytes & sizeof(uint8_t)) {
    __asm__("crc32cb %w[c], %w[c], %w[v]" : [ c ] "+r"(crc) : [ v ] "r"(*((uint8_t *)data)));
  }
  return crc;
}

#else

// from:
// https://github.com/andry81/
// tacklelib/blob/34ae9f73f5fb209ad8a5d7e9817e90979680efc6/
// include/tacklelib/utility/crc_tables.hpp
// Table of g_crc32_1EDC6F41
static uint32_t crctable[kCrc32TableSize] = {
    0x00000000U, 0xf26b8303U, 0xe13b70f7U, 0x1350f3f4U, 0xc79a971fU, 0x35f1141cU,
    0x26a1e7e8U, 0xd4ca64ebU, 0x8ad958cfU, 0x78b2dbccU, 0x6be22838U, 0x9989ab3bU,
    0x4d43cfd0U, 0xbf284cd3U, 0xac78bf27U, 0x5e133c24U, 0x105ec76fU, 0xe235446cU,
    0xf165b798U, 0x030e349bU, 0xd7c45070U, 0x25afd373U, 0x36ff2087U, 0xc494a384U,
    0x9a879fa0U, 0x68ec1ca3U, 0x7bbcef57U, 0x89d76c54U, 0x5d1d08bfU, 0xaf768bbcU,
    0xbc267848U, 0x4e4dfb4bU, 0x20bd8edeU, 0xd2d60dddU, 0xc186fe29U, 0x33ed7d2aU,
    0xe72719c1U, 0x154c9ac2U, 0x061c6936U, 0xf477ea35U, 0xaa64d611U, 0x580f5512U,
    0x4b5fa6e6U, 0xb93425e5U, 0x6dfe410eU, 0x9f95c20dU, 0x8cc531f9U, 0x7eaeb2faU,
    0x30e349b1U, 0xc288cab2U, 0xd1d83946U, 0x23b3ba45U, 0xf779deaeU, 0x05125dadU,
    0x1642ae59U, 0xe4292d5aU, 0xba3a117eU, 0x4851927dU, 0x5b016189U, 0xa96ae28aU,
    0x7da08661U, 0x8fcb0562U, 0x9c9bf696U, 0x6ef07595U, 0x417b1dbcU, 0xb3109ebfU,
    0xa0406d4bU, 0x522bee48U, 0x86e18aa3U, 0x748a09a0U, 0x67dafa54U, 0x95b17957U,
    0xcba24573U, 0x39c9c670U, 0x2a993584U, 0xd8f2b687U, 0x0c38d26cU, 0xfe53516fU,
    0xed03a29bU, 0x1f682198U, 0x5125dad3U, 0xa34e59d0U, 0xb01eaa24U, 0x42752927U,
    0x96bf4dccU, 0x64d4cecfU, 0x77843d3bU, 0x85efbe38U, 0xdbfc821cU, 0x2997011fU,
    0x3ac7f2ebU, 0xc8ac71e8U, 0x1c661503U, 0xee0d9600U, 0xfd5d65f4U, 0x0f36e6f7U,
    0x61c69362U, 0x93ad1061U, 0x80fde395U, 0x72966096U, 0xa65c047dU, 0x5437877eU,
    0x4767748aU, 0xb50cf789U, 0xeb1fcbadU, 0x197448aeU, 0x0a24bb5aU, 0xf84f3859U,
    0x2c855cb2U, 0xdeeedfb1U, 0xcdbe2c45U, 0x3fd5af46U, 0x7198540dU, 0x83f3d70eU,
    0x90a324faU, 0x62c8a7f9U, 0xb602c312U, 0x44694011U, 0x5739b3e5U, 0xa55230e6U,
    0xfb410cc2U, 0x092a8fc1U, 0x1a7a7c35U, 0xe811ff36U, 0x3cdb9bddU, 0xceb018deU,
    0xdde0eb2aU, 0x2f8b6829U, 0x82f63b78U, 0x709db87bU, 0x63cd4b8fU, 0x91a6c88cU,
    0x456cac67U, 0xb7072f64U, 0xa457dc90U, 0x563c5f93U, 0x082f63b7U, 0xfa44e0b4U,
    0xe9141340U, 0x1b7f9043U, 0xcfb5f4a8U, 0x3dde77abU, 0x2e8e845fU, 0xdce5075cU,
    0x92a8fc17U, 0x60c37f14U, 0x73938ce0U, 0x81f80fe3U, 0x55326b08U, 0xa759e80bU,
    0xb4091bffU, 0x466298fcU, 0x1871a4d8U, 0xea1a27dbU, 0xf94ad42fU, 0x0b21572cU,
    0xdfeb33c7U, 0x2d80b0c4U, 0x3ed04330U, 0xccbbc033U, 0xa24bb5a6U, 0x502036a5U,
    0x4370c551U, 0xb11b4652U, 0x65d122b9U, 0x97baa1baU, 0x84ea524eU, 0x7681d14dU,
    0x2892ed69U, 0xdaf96e6aU, 0xc9a99d9eU, 0x3bc21e9dU, 0xef087a76U, 0x1d63f975U,
    0x0e330a81U, 0xfc588982U, 0xb21572c9U, 0x407ef1caU, 0x532e023eU, 0xa145813dU,
    0x758fe5d6U, 0x87e466d5U, 0x94b49521U, 0x66df1622U, 0x38cc2a06U, 0xcaa7a905U,
    0xd9f75af1U, 0x2b9cd9f2U, 0xff56bd19U, 0x0d3d3e1aU, 0x1e6dcdeeU, 0xec064eedU,
    0xc38d26c4U, 0x31e6a5c7U, 0x22b65633U, 0xd0ddd530U, 0x0417b1dbU, 0xf67c32d8U,
    0xe52cc12cU, 0x1747422fU, 0x49547e0bU, 0xbb3ffd08U, 0xa86f0efcU, 0x5a048dffU,
    0x8ecee914U, 0x7ca56a17U, 0x6ff599e3U, 0x9d9e1ae0U, 0xd3d3e1abU, 0x21b862a8U,
    0x32e8915cU, 0xc083125fU, 0x144976b4U, 0xe622f5b7U, 0xf5720643U, 0x07198540U,
    0x590ab964U, 0xab613a67U, 0xb831c993U, 0x4a5a4a90U, 0x9e902e7bU, 0x6cfbad78U,
    0x7fab5e8cU, 0x8dc0dd8fU, 0xe330a81aU, 0x115b2b19U, 0x020bd8edU, 0xf0605beeU,
    0x24aa3f05U, 0xd6c1bc06U, 0xc5914ff2U, 0x37faccf1U, 0x69e9f0d5U, 0x9b8273d6U,
    0x88d28022U, 0x7ab90321U, 0xae7367caU, 0x5c18e4c9U, 0x4f48173dU, 0xbd23943eU,
    0xf36e6f75U, 0x0105ec76U, 0x12551f82U, 0xe03e9c81U, 0x34f4f86aU, 0xc69f7b69U,
    0xd5cf889dU, 0x27a40b9eU, 0x79b737baU, 0x8bdcb4b9U, 0x988c474dU, 0x6ae7c44eU,
    0xbe2da0a5U, 0x4c4623a6U, 0x5f16d052U, 0xad7d5351U};

uint32_t crc32_do(const void *const in_buf, uint32_t crc, const uint64_t in_buf_len) {
  const uint8_t *data = (const uint8_t *)(in_buf);
  uint64_t bytes = in_buf_len;
  const uint64_t loop_limit_count = 4;
  // Calculate the crc for the data
  while (bytes >= loop_limit_count) {
    // Calculate the crc for 4 bytes
    crc ^= (uint32_t)(*data++) & 0xFFU;
    crc ^= ((uint32_t)(*data++) & 0xFFU) << 8;
    crc ^= ((uint32_t)(*data++) & 0xFFU) << 16;
    crc ^= ((uint32_t)(*data++) & 0xFFU) << 24;

    // Update the crc
    crc = crctable[crc & 0xFFU] ^ (crc >> 8);
    crc = crctable[crc & 0xFFU] ^ (crc >> 8);
    crc = crctable[crc & 0xFFU] ^ (crc >> 8);
    crc = crctable[crc & 0xFFU] ^ (crc >> 8);

    bytes -= 4;
  }

  // Handle any remaining bytes
  while (bytes != 0) {
    bytes--;
    crc = crctable[(crc ^ (uint32_t)(*data++)) & 0xFFU] ^ (crc >> 8);
  }

  return crc;
}

#endif  // ARCH_ARM64

2. 使用实例代码

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "crc32_utils.h"

int main() {
    // 要计算CRC32的字符串
    const char *str = "Hello, world!";
    // 获取字符串长度(不包括空字符)
    uint64_t str_len = strlen(str);
    // 初始化CRC32值
    uint32_t crc = crc32_start();
    // 执行CRC32计算
    crc = crc32_do(str, crc, str_len);
    // 结束CRC32计算,获取最终CRC值
    crc = crc32_end(crc);

    // 打印计算结果
    printf("CRC32: 0x%08x\n", crc);

    return 0;
}

3. CMake编译设置

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=generic+crc")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mcpu=generic+crc")

  • 8
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

橘色的喵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值