Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .github/workflows/clang-cl.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Clang-CL

permissions:
contents: read

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

env:
BUILD_TYPE: Release

jobs:
build:
runs-on: windows-latest

steps:
- uses: actions/checkout@v4

- uses: ilammy/msvc-dev-cmd@v1

- name: Environment
run: clang-cl -E -Xclang -dM nul

- name: Configure CMake
env:
CC: clang-cl
CMAKE_GENERATOR: Ninja
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}

- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}

- name: Test
working-directory: ${{github.workspace}}/build
run: ctest -C ${{env.BUILD_TYPE}} --output-on-failure -LE performance
7 changes: 4 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@ IMPL_SOURCES += src/hiaex4/HiAEx4_vaes_avx512.c
ALL_SOURCES = $(MAIN_SOURCE) $(IMPL_SOURCES)

# Header dependencies
HIAE_HEADERS = include/HiAE.h src/hiae/HiAE_internal.h src/hiae/softaes.h
HIAEX2_HEADERS = include/HiAEx2.h src/hiaex2/HiAEx2_internal.h src/hiaex2/softaes.h
HIAEX4_HEADERS = include/HiAEx4.h src/hiaex4/HiAEx4_internal.h src/hiaex4/softaes.h
COMMON_HEADERS = src/common/common.h src/common/cpu.h
HIAE_HEADERS = include/HiAE.h src/hiae/HiAE_internal.h src/hiae/softaes.h $(COMMON_HEADERS)
HIAEX2_HEADERS = include/HiAEx2.h src/hiaex2/HiAEx2_internal.h src/hiaex2/softaes.h $(COMMON_HEADERS)
HIAEX4_HEADERS = include/HiAEx4.h src/hiaex4/HiAEx4_internal.h src/hiaex4/softaes.h $(COMMON_HEADERS)
CLI_HEADERS = hiae-cli/src/platform.h hiae-cli/src/key_utils.h hiae-cli/src/file_ops.h
TEST_HEADERS = test/timing.h

Expand Down
18 changes: 18 additions & 0 deletions scripts/amalgamate.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ def remove_includes(content, implementation_file=None):
# Keep system includes, remove local includes
if ('"HiAE.h"' in include_file or
'"HiAE_internal.h"' in include_file or
'"../common/common.h"' in include_file or
'"../common/cpu.h"' in include_file or
'"softaes.h"' in include_file):
continue
# Keep all other includes (system headers, intrinsics, etc.)
Expand Down Expand Up @@ -307,6 +309,21 @@ def create_amalgamation():
header_body = re.sub(r'#ifdef __cplusplus.*?#endif', '', header_body, flags=re.DOTALL)
amalgamated_content += header_body

# Add shared capability-detection headers (src/common)
for common_name, guard in (("common.h", "hiae_common_H"), ("cpu.h", "hiae_cpu_H")):
common_header = read_file(repo_root / "src" / "common" / common_name)
if not common_header:
print(f"Failed to read src/common/{common_name}")
return False
common_content = re.search(r'#define ' + guard + r'\s*\n(.*?)#endif /\* ' + guard + r' \*/',
common_header, re.DOTALL)
if not common_content:
print(f"Failed to parse src/common/{common_name}")
return False
common_body = common_content.group(1)
common_body = re.sub(r'#include\s+"[^"]+"', '', common_body)
amalgamated_content += f"\n/* Shared definitions from src/common/{common_name} */\n{common_body}\n"

# Add internal header content
internal_header = read_file(source_path / "HiAE_internal.h")
if not internal_header:
Expand All @@ -320,6 +337,7 @@ def create_amalgamation():
internal_body = internal_content.group(1)
# Remove includes we've already handled
internal_body = re.sub(r'#include\s+"HiAE\.h"', '', internal_body)
internal_body = re.sub(r'#include\s+"\.\./common/[^"]+"', '', internal_body)
internal_body = re.sub(r'#include\s+<[^>]+>', '', internal_body)
amalgamated_content += f"\n/* Internal definitions from HiAE_internal.h */\n{internal_body}\n"

Expand Down
82 changes: 82 additions & 0 deletions src/common/common.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#ifndef hiae_common_H
#define hiae_common_H

/*
* Compiler / target capability detection shared by every translation unit.
*
* This header must be included by all implementation files and by the
* dispatchers, so that all of them agree on which implementations exist.
* Keeping this block in a single place is what prevents two translation
* units from disagreeing about the availability of an implementation.
*/

#ifdef __linux__
# define HAVE_SYS_AUXV_H
# define HAVE_GETAUXVAL
#endif
#ifdef __ANDROID_API__
# if __ANDROID_API__ < 18
# undef HAVE_GETAUXVAL
# endif
# define HAVE_ANDROID_GETCPUFEATURES
#endif
#if defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_AMD64)
# define HAVE_CPUID
# define NATIVE_LITTLE_ENDIAN
# if defined(__clang__) || defined(__GNUC__)
# define HAVE_AVX_ASM
# endif
# define HAVE_AVXINTRIN_H
# define HAVE_AVX2INTRIN_H
# define HAVE_AVX512FINTRIN_H
# define HAVE_TMMINTRIN_H
# define HAVE_WMMINTRIN_H
# define HAVE_VAESINTRIN_H
# ifdef __GNUC__
# if !__has_include(<vaesintrin.h>)
# undef HAVE_VAESINTRIN_H
# endif
# endif
/* target pragmas don't define these flags on clang-cl (an alternative clang driver for Windows) */
# if defined(__clang__) && defined(_MSC_BUILD) && defined(_MSC_VER) && \
(defined(_M_IX86) || defined(_M_AMD64)) && !defined(__SSE3__)
# undef __SSE3__
# undef __SSSE3__
# undef __SSE4_1__
# undef __AVX__
# undef __AVX2__
# undef __AVX512F__
# undef __AES__
# undef __VAES__

# define __SSE3__ 1
# define __SSSE3__ 1
# define __SSE4_1__ 1
# define __AVX__ 1
# define __AVX2__ 1
# define __AVX512F__ 1
# define __AES__ 1
# define __VAES__ 1

/*
* The macros above were synthesized so that the intrinsics headers expose
* everything the target pragmas can emit. They describe the compiler, not
* the CPU the code will run on, and must therefore never be used to decide
* which implementations get compiled in. See cpu.h.
*/
# define HIAE_ISA_MACROS_SYNTHESIZED 1
# endif

#endif

#ifdef DISABLE_AVX2
# undef HAVE_AVXINTRIN_H
# undef HAVE_AVX2INTRIN_H
# undef HAVE_AVX512FINTRIN_H
# undef HAVE_VAESINTRIN_H
#endif
#ifdef DISABLE_AVX512
# undef HAVE_AVX512FINTRIN_H
#endif

#endif /* hiae_common_H */
32 changes: 32 additions & 0 deletions src/common/cpu.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#ifndef hiae_cpu_H
#define hiae_cpu_H

#include "common.h"

/*
* HIAE*_HAS_HW_AES is set when the compilation baseline itself guarantees that
* a hardware implementation of the corresponding variant is present. In that
* case the software implementation is not compiled in at all.
*
* Every translation unit that needs to know whether the software
* implementation exists must test these macros, and only these macros.
* Testing __AES__ & friends directly is not equivalent: on clang-cl they are
* synthesized in common.h so that the intrinsics headers work, and they then
* describe the compiler rather than the target CPU.
*/

#if defined(__ARM_FEATURE_CRYPTO)
# define HIAE_HAS_HW_AES
# define HIAEX2_HAS_HW_AES
# define HIAEX4_HAS_HW_AES
#elif !defined(HIAE_ISA_MACROS_SYNTHESIZED)
# if defined(__AES__) && defined(__VAES__) && defined(__AVX512F__)
# define HIAE_HAS_HW_AES
# define HIAEX4_HAS_HW_AES
# endif
# if defined(__AES__) && defined(__VAES__) && defined(__AVX2__)
# define HIAEX2_HAS_HW_AES
# endif
#endif

#endif /* hiae_cpu_H */
94 changes: 9 additions & 85 deletions src/hiae/HiAE.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,67 +11,6 @@
#include <stddef.h>
#include <stdint.h>

#ifdef __linux__
# define HAVE_SYS_AUXV_H
# define HAVE_GETAUXVAL
#endif
#ifdef __ANDROID_API__
# if __ANDROID_API__ < 18
# undef HAVE_GETAUXVAL
# endif
# define HAVE_ANDROID_GETCPUFEATURES
#endif
#if defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_AMD64)
# define HAVE_CPUID
# define NATIVE_LITTLE_ENDIAN
# if defined(__clang__) || defined(__GNUC__)
# define HAVE_AVX_ASM
# endif
# define HAVE_AVXINTRIN_H
# define HAVE_AVX2INTRIN_H
# define HAVE_AVX512FINTRIN_H
# define HAVE_TMMINTRIN_H
# define HAVE_WMMINTRIN_H
# define HAVE_VAESINTRIN_H
# ifdef __GNUC__
# if !__has_include(<vaesintrin.h>)
# undef HAVE_VAESINTRIN_H
# endif
# endif
/* target pragmas don't define these flags on clang-cl (an alternative clang driver for Windows) */
# if defined(__clang__) && defined(_MSC_BUILD) && defined(_MSC_VER) && \
(defined(_M_IX86) || defined(_M_AMD64)) && !defined(__SSE3__)
# undef __SSE3__
# undef __SSSE3__
# undef __SSE4_1__
# undef __AVX__
# undef __AVX2__
# undef __AVX512F__
# undef __AES__
# undef __VAES__

# define __SSE3__ 1
# define __SSSE3__ 1
# define __SSE4_1__ 1
# define __AVX__ 1
# define __AVX2__ 1
# define __AVX512F__ 1
# define __AES__ 1
# define __VAES__ 1
# endif

#endif

#ifdef DISABLE_AVX2
# undef HAVE_AVXINTRIN_H
# undef HAVE_AVX2INTRIN_H
# undef HAVE_AVX512FINTRIN_H
# undef HAVE_VAESINTRIN_H
#endif
#ifdef DISABLE_AVX512
# undef HAVE_AVX512FINTRIN_H
#endif

#ifdef HAVE_ANDROID_GETCPUFEATURES
# include <cpu-features.h>
#endif
Expand Down Expand Up @@ -374,8 +313,7 @@ hiae_runtime_get_cpu_features(void)
}

// External declarations for implementation tables
#if !((defined(__AES__) && defined(__VAES__) && defined(__AVX512F__)) || \
defined(__ARM_FEATURE_CRYPTO))
#ifndef HIAE_HAS_HW_AES
extern const HiAE_impl_t hiae_software_impl;
#endif
#if defined(__x86_64__) || defined(_M_X64)
Expand All @@ -395,8 +333,7 @@ hiae_get_impl_by_name(const char *name)
return NULL;
}

#if !((defined(__AES__) && defined(__VAES__) && defined(__AVX512F__)) || \
defined(__ARM_FEATURE_CRYPTO))
#ifndef HIAE_HAS_HW_AES
if (strcmp(name, "Software") == 0) {
return (HiAE_impl_t *) &hiae_software_impl;
}
Expand Down Expand Up @@ -450,10 +387,14 @@ hiae_init_dispatch(void)
hiae_runtime_get_cpu_features();
}

#if !((defined(__AES__) && defined(__VAES__) && defined(__AVX512F__)) || \
defined(__ARM_FEATURE_CRYPTO))
// Default to software implementation when hardware AES+VAES+AVX512 is not available
// Start from the implementation the compilation baseline guarantees, then
// upgrade it below if the CPU actually supports something faster.
#ifndef HIAE_HAS_HW_AES
hiae_impl = (HiAE_impl_t *) &hiae_software_impl;
#elif defined(__x86_64__) || defined(_M_X64)
hiae_impl = (HiAE_impl_t *) &hiae_aesni_impl;
#elif defined(__aarch64__) || defined(_M_ARM64) || defined(__arm64__)
hiae_impl = (HiAE_impl_t *) &hiae_arm_impl;
#endif

// Select best available implementation based on CPU features
Expand All @@ -471,23 +412,6 @@ hiae_init_dispatch(void)
}
#endif

#if (defined(__AES__) && defined(__VAES__) && defined(__AVX512F__)) || defined(__ARM_FEATURE_CRYPTO)
// When hardware AES+VAES+AVX512 is available, ensure we have a valid implementation
if (hiae_impl == NULL) {
# if defined(__x86_64__) || defined(_M_X64)
// Fallback to AES-NI on x86-64 if available
if (hiae_aesni_impl.init != NULL) {
hiae_impl = (HiAE_impl_t *) &hiae_aesni_impl;
}
# elif defined(__aarch64__) || defined(_M_ARM64) || defined(__arm64__)
// Fallback to ARM NEON on ARM64 if available
if (hiae_arm_impl.init != NULL) {
hiae_impl = (HiAE_impl_t *) &hiae_arm_impl;
}
# endif
}
#endif

#ifdef SOFTAES_ENABLED
(void) softaes_block_zero;
(void) softaes_block_load;
Expand Down
2 changes: 2 additions & 0 deletions src/hiae/HiAE_internal.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef HIAE_INTERNAL_H
#define HIAE_INTERNAL_H

#include "../common/common.h"
#include "../common/cpu.h"
#include "HiAE.h"
#include <string.h>

Expand Down
5 changes: 2 additions & 3 deletions src/hiae/HiAE_software.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
#include "HiAE_internal.h"

// Only compile software implementation if hardware AES+VAES+AVX512 is not available
#if !((defined(__AES__) && defined(__VAES__) && defined(__AVX512F__)) || \
defined(__ARM_FEATURE_CRYPTO))
#ifndef HIAE_HAS_HW_AES

# define FAVOR_PERFORMANCE
# include "softaes.h"
Expand Down Expand Up @@ -720,4 +719,4 @@ const HiAE_impl_t hiae_software_impl = { .name = "Software",
.decrypt = HiAE_decrypt_software,
.mac = HiAE_mac_software };

#endif // !defined(__AES__) && !defined(__ARM_FEATURE_CRYPTO)
#endif /* !HIAE_HAS_HW_AES */
3 changes: 2 additions & 1 deletion src/hiae/HiAE_vaes_avx512.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
#include "HiAE.h"
#include "HiAE_internal.h"

/* clang-cl can build this implementation; MSVC proper cannot (no target pragmas) */
#if (defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_AMD64)) && \
!defined(_MSC_VER)
(!defined(_MSC_VER) || defined(__clang__))

# ifdef __clang__
# if __clang_major__ >= 18
Expand Down
Loading
Loading