view crc32.c @ 3:6483683ac857 default tip

*: add profiling code too; expand x86 to use all eight XMM registers basically ported verbatim from the assembly
author Paper <paper@tflc.us>
date Mon, 09 Feb 2026 21:30:30 -0500
parents 422835bc1aca
children
line wrap: on
line source

#include "crc32.h"
#include "crc32i.h"
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <assert.h>
#include <stdlib.h>
#include <time.h>

/* Align to a byte offset using the given crc function. */
static void crc32_align(uint32_t *crc, crc32_r_spec crcfunc, size_t align, const unsigned char **message, size_t *sz)
{
	size_t sz8, szs;

	/* Alignment check */
	if (ALIGNED(*message, align))
		return;

	/* Calculate size needed to align */
	sz8 = align - ((uintptr_t)*message % align);
	szs = MIN(*sz, sz8);

	*crc = crcfunc(*crc, *message, sz8);
	*message += sz8;
	*sz -= sz8;
}

CRC32_API
uint32_t crc32(const unsigned char *message, size_t sz)
{
	uint32_t crc;
	size_t i;

	if (!sz)
		return 0;

	crc = 0xFFFFFFFF;
	crc32_align(&crc, crc32c_r, ALIGNOF(uint32_t), &message, &sz);
	if (!sz) return ~crc;

#if defined(__x86_64__) && defined(__GNUC__)
	/* Check at runtime if we can use vpclmulqdq */
	if (__builtin_cpu_supports("vpclmulqdq")) {
		/* Align and do the rest with vpclmulqdq */
		crc32_align(&crc, crc32qw_r, 16, &message, &sz);
		if (!sz) return ~crc;

		return ~crc32x86_vpclmulqdq_r(crc, message, sz);
	} /* Otherwise just use 32-bit impl */
#endif

	return ~crc32qw_r(crc, message, sz);
}