10b57cec5SDimitry Andric //===-- checksum.h ----------------------------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #ifndef SCUDO_CHECKSUM_H_
100b57cec5SDimitry Andric #define SCUDO_CHECKSUM_H_
110b57cec5SDimitry Andric
120b57cec5SDimitry Andric #include "internal_defs.h"
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric // Hardware CRC32 is supported at compilation via the following:
153a9a9c0cSDimitry Andric // - for i386 & x86_64: -mcrc32 (earlier: -msse4.2)
160b57cec5SDimitry Andric // - for ARM & AArch64: -march=armv8-a+crc or -mcrc
170b57cec5SDimitry Andric // An additional check must be performed at runtime as well to make sure the
180b57cec5SDimitry Andric // emitted instructions are valid on the target host.
190b57cec5SDimitry Andric
203a9a9c0cSDimitry Andric #if defined(__CRC32__)
213a9a9c0cSDimitry Andric // NB: clang has <crc32intrin.h> but GCC does not
223a9a9c0cSDimitry Andric #include <smmintrin.h>
2381ad6265SDimitry Andric #define CRC32_INTRINSIC \
2481ad6265SDimitry Andric FIRST_32_SECOND_64(__builtin_ia32_crc32si, __builtin_ia32_crc32di)
253a9a9c0cSDimitry Andric #elif defined(__SSE4_2__)
260b57cec5SDimitry Andric #include <smmintrin.h>
270b57cec5SDimitry Andric #define CRC32_INTRINSIC FIRST_32_SECOND_64(_mm_crc32_u32, _mm_crc32_u64)
280b57cec5SDimitry Andric #endif
290b57cec5SDimitry Andric #ifdef __ARM_FEATURE_CRC32
300b57cec5SDimitry Andric #include <arm_acle.h>
310b57cec5SDimitry Andric #define CRC32_INTRINSIC FIRST_32_SECOND_64(__crc32cw, __crc32cd)
320b57cec5SDimitry Andric #endif
33*0fca6ea1SDimitry Andric #ifdef __loongarch__
34*0fca6ea1SDimitry Andric #include <larchintrin.h>
35*0fca6ea1SDimitry Andric #define CRC32_INTRINSIC FIRST_32_SECOND_64(__crcc_w_w_w, __crcc_w_d_w)
36*0fca6ea1SDimitry Andric #endif
370b57cec5SDimitry Andric
380b57cec5SDimitry Andric namespace scudo {
390b57cec5SDimitry Andric
400b57cec5SDimitry Andric enum class Checksum : u8 {
410b57cec5SDimitry Andric BSD = 0,
420b57cec5SDimitry Andric HardwareCRC32 = 1,
430b57cec5SDimitry Andric };
440b57cec5SDimitry Andric
450b57cec5SDimitry Andric // BSD checksum, unlike a software CRC32, doesn't use any array lookup. We save
460b57cec5SDimitry Andric // significantly on memory accesses, as well as 1K of CRC32 table, on platforms
470b57cec5SDimitry Andric // that do no support hardware CRC32. The checksum itself is 16-bit, which is at
480b57cec5SDimitry Andric // odds with CRC32, but enough for our needs.
computeBSDChecksum(u16 Sum,uptr Data)49480093f4SDimitry Andric inline u16 computeBSDChecksum(u16 Sum, uptr Data) {
500b57cec5SDimitry Andric for (u8 I = 0; I < sizeof(Data); I++) {
510b57cec5SDimitry Andric Sum = static_cast<u16>((Sum >> 1) | ((Sum & 1) << 15));
520b57cec5SDimitry Andric Sum = static_cast<u16>(Sum + (Data & 0xff));
530b57cec5SDimitry Andric Data >>= 8;
540b57cec5SDimitry Andric }
550b57cec5SDimitry Andric return Sum;
560b57cec5SDimitry Andric }
570b57cec5SDimitry Andric
580b57cec5SDimitry Andric bool hasHardwareCRC32();
590b57cec5SDimitry Andric WEAK u32 computeHardwareCRC32(u32 Crc, uptr Data);
600b57cec5SDimitry Andric
610b57cec5SDimitry Andric } // namespace scudo
620b57cec5SDimitry Andric
630b57cec5SDimitry Andric #endif // SCUDO_CHECKSUM_H_
64