Files
Aaru.Checksums.Native/simd.c

393 lines
12 KiB
C
Raw Normal View History

2021-10-13 03:25:16 +01:00
/*
2021-10-13 03:46:47 +01:00
* This file is part of the Aaru Data Preservation Suite.
2022-12-01 23:06:20 +00:00
* Copyright (c) 2019-2023 Natalia Portillo.
2021-10-13 03:46:47 +01:00
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
2021-10-13 03:25:16 +01:00
2021-10-13 05:16:52 +01:00
#include <stddef.h>
#include <stdint.h>
2021-10-05 02:21:51 +01:00
#include "library.h"
2021-09-29 01:27:02 +01:00
#include "simd.h"
2023-09-23 18:55:52 +01:00
#if defined(__x86_64__) || defined(__amd64) || defined(_M_AMD64) || defined(_M_X64) || defined(__I386__) || \
defined(__i386__) || defined(__THW_INTEL) || defined(_M_IX86)
#ifdef _MSC_VER
#include <intrin.h>
#else
/*
* Newer versions of GCC and clang come with cpuid.h
* (ftr GCC 4.7 in Debian Wheezy has this)
*/
#include <cpuid.h>
#endif
2023-09-23 18:10:44 +01:00
/**
* @brief Gets the CPUID information for the given info value.
*
* This function retrieves the CPUID information for the specified info argument
* and stores the results in the provided pointers: eax, ebx, ecx, and edx.
* Each register represents a 32-bit value returned by the CPUID instruction.
*
* @param info The CPUID info value specifying the desired information to retrieve.
* @param eax Pointer to store the value of the EAX register.
* @param ebx Pointer to store the value of the EBX register.
* @param ecx Pointer to store the value of the ECX register.
* @param edx Pointer to store the value of the EDX register.
*
* @note It is important to ensure that the provided pointers are valid and point
* to a memory location that can be modified by this function.
*
* @see https://en.wikipedia.org/wiki/CPUID
*
* @return None.
*/
2024-04-30 15:12:48 +01:00
static void cpuid(int info, unsigned *eax, unsigned *ebx, unsigned *ecx, unsigned *edx)
{
#ifdef _MSC_VER
unsigned int registers[4];
__cpuid(registers, info);
*eax = registers[0];
*ebx = registers[1];
*ecx = registers[2];
*edx = registers[3];
#else
/* GCC, clang */
unsigned int _eax;
unsigned int _ebx;
unsigned int _ecx;
unsigned int _edx;
__cpuid(info, _eax, _ebx, _ecx, _edx);
*eax = _eax;
*ebx = _ebx;
*ecx = _ecx;
*edx = _edx;
#endif
}
2023-09-23 18:10:44 +01:00
/**
* @brief Get the CPU extended information using CPUID instruction.
*
* This function retrieves the extended information from the CPU by using the CPUID instruction.
* It reads the result into the output parameters eax, ebx, ecx, and edx based on the input parameters info and count.
*
* @param info The CPUID function number to be executed.
* @param count The sub-leaf index for certain CPUID functions.
* @param eax Pointer to store the value of the EAX register.
* @param ebx Pointer to store the value of the EBX register.
* @param ecx Pointer to store the value of the ECX register.
* @param edx Pointer to store the value of the EDX register.
*
* @note It is important to ensure that the provided pointers are valid and point
* to a memory location that can be modified by this function.
*
* @see https://en.wikipedia.org/wiki/CPUID
*
* @return None.
*/
2024-04-30 15:12:48 +01:00
static void cpuidex(int info, int count, unsigned *eax, unsigned *ebx, unsigned *ecx, unsigned *edx)
2021-09-28 22:30:57 +01:00
{
#ifdef _MSC_VER
unsigned int registers[4];
__cpuidex(registers, info, count);
*eax = registers[0];
*ebx = registers[1];
*ecx = registers[2];
*edx = registers[3];
#else
/* GCC, clang */
unsigned int _eax;
unsigned int _ebx;
unsigned int _ecx;
unsigned int _edx;
__cpuid_count(info, count, _eax, _ebx, _ecx, _edx);
*eax = _eax;
*ebx = _ebx;
*ecx = _ecx;
*edx = _edx;
#endif
}
2023-09-23 18:10:44 +01:00
/**
2023-09-23 19:51:50 +01:00
* @brief Checks if the hardware supports the CLMUL instruction set.
2023-09-23 18:10:44 +01:00
*
2023-09-23 19:51:50 +01:00
* The function checks if the system's CPU supports the CLMUL (Carry-Less Multiplication) instruction set.
* CLMUL is an extension to the x86 instruction set architecture and provides hardware acceleration for
2023-09-23 18:10:44 +01:00
* carry-less multiplication operations.
*
2023-09-23 19:51:50 +01:00
* @return True if CLMUL instruction set is supported, False otherwise.
2023-09-23 18:10:44 +01:00
*
2023-09-23 19:51:50 +01:00
* @see https://software.intel.com/sites/landingpage/IntrinsicsGuide/#techs=CLMUL
2023-09-23 18:10:44 +01:00
* @see https://en.wikipedia.org/wiki/Carry-less_multiplication
*/
int have_clmul(void)
{
unsigned eax, ebx, ecx, edx;
int has_pclmulqdq;
int has_sse41;
cpuid(1 /* feature bits */, &eax, &ebx, &ecx, &edx);
has_pclmulqdq = ecx & 0x2; /* bit 1 */
has_sse41 = ecx & 0x80000; /* bit 19 */
return has_pclmulqdq && has_sse41;
}
2023-09-23 18:10:44 +01:00
/**
2023-09-23 19:51:50 +01:00
* @brief Checks if the current processor supports SSSE3 instructions.
2023-09-23 18:10:44 +01:00
*
2023-09-23 19:51:50 +01:00
* The function detects whether the current processor supports SSSE3 instructions by
* checking the CPU feature flags. SSSE3 (Supplemental Streaming SIMD Extensions 3)
2023-09-23 18:10:44 +01:00
* is an extension to the x86 instruction set architecture that introduces
* additional SIMD instructions useful for multimedia and signal processing tasks.
*
2023-09-23 19:51:50 +01:00
* @return true if the current processor supports SSSE3 instructions, false otherwise.
2023-09-23 18:10:44 +01:00
*
2023-09-23 19:51:50 +01:00
* @see https://software.intel.com/sites/landingpage/IntrinsicsGuide/#techs=SSSE3
* @see https://en.wikipedia.org/wiki/SSSE3
2023-09-23 18:10:44 +01:00
*/
2021-09-28 20:16:40 +01:00
int have_ssse3(void)
{
unsigned eax, ebx, ecx, edx;
cpuid(1 /* feature bits */, &eax, &ebx, &ecx, &edx);
return ecx & 0x200;
}
2023-09-23 18:10:44 +01:00
/**
2023-09-23 19:51:50 +01:00
* @brief Checks if the current processor supports AVX2 instructions.
2023-09-23 18:10:44 +01:00
*
2023-09-23 19:51:50 +01:00
* The function detects whether the current processor supports AVX2 instructions by
* checking the CPU feature flags. AVX2 (Advanced Vector Extensions 2) is an extension
2023-09-23 18:10:44 +01:00
* to the x86 instruction set architecture that introduces additional SIMD instructions
* useful for multimedia and signal processing tasks.
*
2023-09-23 19:51:50 +01:00
* @return true if the current processor supports AVX2 instructions, false otherwise.
2023-09-23 18:10:44 +01:00
*
2023-09-23 19:51:50 +01:00
* @see https://software.intel.com/sites/landingpage/IntrinsicsGuide/#techs=AVX2
2023-09-23 18:10:44 +01:00
* @see https://en.wikipedia.org/wiki/Advanced_Vector_Extensions
*/
2021-09-28 22:30:57 +01:00
int have_avx2(void)
{
unsigned eax, ebx, ecx, edx;
cpuidex(7 /* extended feature bits */, 0, &eax, &ebx, &ecx, &edx);
return ebx & 0x20;
}
2021-09-29 01:27:02 +01:00
#endif
#if defined(__aarch64__) || defined(_M_ARM64) || defined(__arm__) || defined(_M_ARM)
#if defined(_WIN32)
2023-09-23 18:55:52 +01:00
#include <windows.h>
2021-10-13 03:46:47 +01:00
#include <processthreadsapi.h>
2023-09-23 18:55:52 +01:00
#elif defined(__APPLE__)
2023-09-23 18:55:52 +01:00
#include <sys/sysctl.h>
2023-09-23 18:55:52 +01:00
#else
2023-09-23 18:55:52 +01:00
2021-09-29 01:27:02 +01:00
#include <sys/auxv.h>
2023-09-23 18:55:52 +01:00
2021-09-29 01:27:02 +01:00
#endif
#endif
2021-09-29 01:27:02 +01:00
2021-10-13 03:46:47 +01:00
#if(defined(__aarch64__) || defined(_M_ARM64) || defined(__arm__) || defined(_M_ARM)) && defined(__APPLE__)
2023-09-23 18:55:52 +01:00
2023-09-23 18:10:44 +01:00
/**
* @brief Checks if the current processor supports NEON instructions.
*
* The function detects whether the current processor supports NEON instructions by
* checking the CPU feature flags. NEON is an extension to the ARM instruction set
* architecture that introduces additional SIMD instructions useful for multimedia
* and signal processing tasks.
*
* @return true if the current processor supports NEON instructions, false otherwise.
*
* @see https://developer.arm.com/architectures/instruction-sets/simd-isas/neon
* @see https://en.wikipedia.org/wiki/ARM_architecture#Advanced_SIMD_(NEON)
*/
int have_neon_apple()
{
2021-10-13 03:46:47 +01:00
int value;
size_t len = sizeof(int);
2021-10-13 03:46:47 +01:00
int ret = sysctlbyname("hw.optional.neon", &value, &len, NULL, 0);
2021-10-13 03:46:47 +01:00
if(ret != 0) return 0;
return value == 1;
}
2023-09-23 18:10:44 +01:00
/**
* @brief Checks if the current processor supports CRC32 instructions.
*
* The function detects whether the current processor supports CRC32 instructions by
* checking the CPU feature flags. CRC32 is an extension to the ARM instruction set
* architecture that introduces additional instructions for calculating CRC32 checksums.
*
* @return true if the current processor supports CRC32 instructions, false otherwise.
*/
int have_crc32_apple()
{
2021-10-13 03:46:47 +01:00
int value;
size_t len = sizeof(int);
int ret = sysctlbyname("hw.optional.armv8_crc32", &value, &len, NULL, 0);
2021-10-13 03:46:47 +01:00
if(ret != 0) return 0;
return value == 1;
}
2023-09-23 18:10:44 +01:00
/**
* @brief Checks if the current processor supports cryptographic instructions.
*
* The function detects whether the current processor supports cryptographic instructions by
* checking the CPU feature flags. Cryptographic instructions are an extension to the ARM instruction set
* architecture that introduces additional instructions for cryptographic operations.
*
* @return true if the current processor supports cryptographic instructions, false otherwise.
*/
2024-04-30 15:12:48 +01:00
int have_crypto_apple() { return 0; }
2023-09-23 18:55:52 +01:00
#endif
2021-09-29 01:27:02 +01:00
#if defined(__aarch64__) || defined(_M_ARM64)
2023-09-23 18:55:52 +01:00
2021-09-29 01:27:02 +01:00
int have_neon(void)
{
2024-04-30 15:12:48 +01:00
return 1; // ARMv8-A made it mandatory
2021-09-29 01:27:02 +01:00
}
2023-09-23 18:10:44 +01:00
/**
* @brief Checks if the current processor supports CRC32 instructions.
*
* The function detects whether the current processor supports CRC32 instructions by
* checking the CPU feature flags. CRC32 is an extension to the ARM instruction set
* architecture that introduces additional instructions for calculating CRC32 checksums.
*
* @return true if the current processor supports CRC32 instructions, false otherwise.
*/
int have_arm_crc32(void)
{
#if defined(_WIN32)
return IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE) != 0;
#elif defined(__APPLE__)
return have_crc32_apple();
#else
return getauxval(AT_HWCAP) & HWCAP_CRC32;
#endif
}
2021-10-05 00:31:37 +01:00
2023-09-23 18:10:44 +01:00
/**
* @brief Checks if the current processor supports cryptographic instructions.
*
* The function detects whether the current processor supports cryptographic instructions by
* checking the CPU feature flags. Cryptographic instructions are an extension to the ARM instruction set
* architecture that introduces additional instructions for cryptographic operations.
*
* @return true if the current processor supports cryptographic instructions, false otherwise.
*/
int have_arm_crypto(void)
{
#if defined(_WIN32)
return IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) != 0;
#elif defined(__APPLE__)
return have_crypto_apple();
#else
return getauxval(AT_HWCAP) & HWCAP_AES;
#endif
}
2023-09-23 18:55:52 +01:00
2021-09-29 01:27:02 +01:00
#endif
#if defined(__arm__) || defined(_M_ARM)
2023-09-23 18:55:52 +01:00
2023-09-23 18:10:44 +01:00
/**
* @brief Checks if the current processor supports NEON instructions.
*
* The function detects whether the current processor supports NEON instructions by
* checking the CPU feature flags. NEON is an extension to the ARM instruction set
* architecture that introduces additional SIMD instructions useful for multimedia
* and signal processing tasks.
*
* @return true if the current processor supports NEON instructions, false otherwise.
*
* @see https://developer.arm.com/architectures/instruction-sets/simd-isas/neon
* @see https://en.wikipedia.org/wiki/ARM_architecture#Advanced_SIMD_(NEON)
*/
int have_neon(void)
{
#if defined(_WIN32)
return IsProcessorFeaturePresent(PF_ARM_VFP_32_REGISTERS_AVAILABLE) != 0;
#elif defined(__APPLE__)
return have_neon_apple();
#else
return getauxval(AT_HWCAP) & HWCAP_NEON;
#endif
}
2023-09-23 18:10:44 +01:00
/**
* @brief Checks if the current processor supports CRC32 instructions.
*
* The function detects whether the current processor supports CRC32 instructions by
* checking the CPU feature flags. CRC32 is an extension to the ARM instruction set
* architecture that introduces additional instructions for calculating CRC32 checksums.
*
* @return true if the current processor supports CRC32 instructions, false otherwise.
*/
int have_arm_crc32(void)
{
#if defined(_WIN32)
return IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE) != 0;
#elif defined(__APPLE__)
return have_crc32_apple();
#else
// Not defined in ARMv7 compilers, even if the CPU has the capability
#ifndef HWCAP2_CRC32
#define HWCAP2_CRC32 (1 << 4)
#endif
return getauxval(AT_HWCAP2) & HWCAP2_CRC32;
#endif
}
2021-10-05 00:31:37 +01:00
2023-09-23 18:10:44 +01:00
/**
* @brief Checks if the current processor supports cryptographic instructions.
*
* The function detects whether the current processor supports cryptographic instructions by
* checking the CPU feature flags. Cryptographic instructions are an extension to the ARM instruction set
* architecture that introduces additional instructions for cryptographic operations.
*
* @return true if the current processor supports cryptographic instructions, false otherwise.
*/
int have_arm_crypto(void)
{
#if defined(_WIN32)
return IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) != 0;
#elif defined(__APPLE__)
return have_crypto_apple();
#else
return getauxval(AT_HWCAP2) & HWCAP2_AES;
#endif
}
2023-09-23 18:55:52 +01:00
2021-10-13 05:16:52 +01:00
#endif