diff --git a/.github/actions/ct-test/action.yml b/.github/actions/ct-test/action.yml index ddf543522..c60276505 100644 --- a/.github/actions/ct-test/action.yml +++ b/.github/actions/ct-test/action.yml @@ -39,4 +39,5 @@ runs: - shell: ${{ env.SHELL }} run: | make clean - tests func --exec-wrapper="valgrind --error-exitcode=1 --track-origins=yes ${{ inputs.valgrind_flags }}" --cflags="-DMLK_CONFIG_CT_TESTING_ENABLED -DNTESTS=50 ${{ inputs.cflags }}" + # Disable the AArch64 SHA3 extension as it's not yet supported by valgrind + MK_COMPILER_SUPPORTS_SHA3=0 tests func --exec-wrapper="valgrind --error-exitcode=1 --track-origins=yes ${{ inputs.valgrind_flags }}" --cflags="-DMLK_CONFIG_CT_TESTING_ENABLED -DNTESTS=50 ${{ inputs.cflags }}" diff --git a/Makefile b/Makefile index 56f05bba2..058f0a7f4 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,8 @@ build test all \ clean quickcheck check-defined-CYCLES \ size_512 size_768 size_1024 size \ - run_size_512 run_size_768 run_size_1024 run_size + run_size_512 run_size_768 run_size_1024 run_size \ + host_info SHELL := /bin/bash .DEFAULT_GOAL := build @@ -26,6 +27,8 @@ all: build W := $(EXEC_WRAPPER) include test/mk/config.mk +include test/mk/compiler.mk +include test/mk/auto.mk include test/mk/components.mk include test/mk/rules.mk @@ -86,6 +89,15 @@ acvp_1024: $(MLKEM1024_DIR)/bin/acvp_mlkem1024 $(Q)echo " ACVP ML-KEM-1024: $^" acvp: acvp_512 acvp_768 acvp_1024 +ifeq ($(HOST_PLATFORM),Linux-aarch64) +# valgrind does not work with the AArch64 SHA3 extension +# Use armv8-a as the target architecture, overwriting a +# potential earlier addition of armv8.4-a+sha3. +$(MLKEM512_DIR)/bin/test_stack512: CFLAGS += -march=armv8-a +$(MLKEM768_DIR)/bin/test_stack768: CFLAGS += -march=armv8-a +$(MLKEM1024_DIR)/bin/test_stack1024: CFLAGS += -march=armv8-a +endif + stack_512: $(MLKEM512_DIR)/bin/test_stack512 $(Q)echo " STACK ML-KEM-512: $^" stack_768: $(MLKEM768_DIR)/bin/test_stack768 @@ -176,6 +188,30 @@ run_size: \ run_size_768 \ run_size_1024 +# Display host and compiler feature detection information +# Shows which architectural features are supported by both the compiler and host CPU +# Usage: make host_info [AUTO=0|1] [CROSS_PREFIX=...] +host_info: + @echo "=== Host and Compiler Feature Detection ===" + @echo "Host Platform: $(HOST_PLATFORM)" + @echo "Target Architecture: $(ARCH)" + @echo "Compiler: $(CC)" + @echo "Cross Prefix: $(if $(CROSS_PREFIX),$(CROSS_PREFIX),)" + @echo "AUTO: $(AUTO)" + @echo "" +ifeq ($(ARCH),x86_64) + @echo "=== x86_64 Feature Support ===" + @echo "AVX2: Host $(if $(filter 1,$(MK_HOST_SUPPORTS_AVX2)),✅,❌) Compiler $(if $(filter 1,$(MK_COMPILER_SUPPORTS_AVX2)),✅,❌)" + @echo "SSE2: Host $(if $(filter 1,$(MK_HOST_SUPPORTS_SSE2)),✅,❌) Compiler $(if $(filter 1,$(MK_COMPILER_SUPPORTS_SSE2)),✅,❌)" + @echo "BMI2: Host $(if $(filter 1,$(MK_HOST_SUPPORTS_BMI2)),✅,❌) Compiler $(if $(filter 1,$(MK_COMPILER_SUPPORTS_BMI2)),✅,❌)" +else ifeq ($(ARCH),aarch64) + @echo "=== AArch64 Feature Support ===" + @echo "SHA3: Host $(if $(filter 1,$(MK_HOST_SUPPORTS_SHA3)),✅,❌) Compiler $(if $(filter 1,$(MK_COMPILER_SUPPORTS_SHA3)),✅,❌)" +else + @echo "=== Architecture Not Supported ===" + @echo "No specific feature detection available for $(ARCH)" +endif + clean: -$(RM) -rf *.gcno *.gcda *.lcov *.o *.so -$(RM) -rf $(BUILD_DIR) diff --git a/examples/monolithic_build_multilevel_native/Makefile b/examples/monolithic_build_multilevel_native/Makefile index 908311de1..34f4abb30 100644 --- a/examples/monolithic_build_multilevel_native/Makefile +++ b/examples/monolithic_build_multilevel_native/Makefile @@ -61,7 +61,7 @@ endif # Native compilation ifeq ($(CROSS_PREFIX),) ifeq ($(HOST_PLATFORM),Linux-x86_64) - CFLAGS += -mavx2 -mbmi2 -mpopcnt -maes + CFLAGS += -mavx2 -mbmi2 CFLAGS += -DMLK_FORCE_X86_64 else ifeq ($(HOST_PLATFORM),Linux-aarch64) CFLAGS += -DMLK_FORCE_AARCH64 @@ -70,7 +70,7 @@ else ifeq ($(HOST_PLATFORM),Darwin-arm64) endif # Cross compilation else ifneq ($(findstring x86_64, $(CROSS_PREFIX)),) - CFLAGS += -mavx2 -mbmi2 -mpopcnt -maes + CFLAGS += -mavx2 -mbmi2 CFLAGS += -DMLK_FORCE_X86_64 else ifneq ($(findstring aarch64_be, $(CROSS_PREFIX)),) CFLAGS += -DMLK_FORCE_AARCH64_EB diff --git a/examples/multilevel_build_native/Makefile b/examples/multilevel_build_native/Makefile index 7d0645551..2217a2193 100644 --- a/examples/multilevel_build_native/Makefile +++ b/examples/multilevel_build_native/Makefile @@ -28,7 +28,7 @@ endif # Native compilation ifeq ($(CROSS_PREFIX),) ifeq ($(HOST_PLATFORM),Linux-x86_64) - CFLAGS += -mavx2 -mbmi2 -mpopcnt -maes + CFLAGS += -mavx2 -mbmi2 CFLAGS += -DMLK_FORCE_X86_64 else ifeq ($(HOST_PLATFORM),Linux-aarch64) CFLAGS += -DMLK_FORCE_AARCH64 @@ -37,7 +37,7 @@ else ifeq ($(HOST_PLATFORM),Darwin-arm64) endif # Cross compilation else ifneq ($(findstring x86_64, $(CROSS_PREFIX)),) - CFLAGS += -mavx2 -mbmi2 -mpopcnt -maes + CFLAGS += -mavx2 -mbmi2 CFLAGS += -DMLK_FORCE_X86_64 else ifneq ($(findstring aarch64_be, $(CROSS_PREFIX)),) CFLAGS += -DMLK_FORCE_AARCH64_EB diff --git a/test/mk/auto.mk b/test/mk/auto.mk index b09c4dae9..bcbf3ac1c 100644 --- a/test/mk/auto.mk +++ b/test/mk/auto.mk @@ -1,29 +1,113 @@ # SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT # -# Automatically detect system architecture and set preprocessor etc accordingly +# Automatically detect system architecture and set preprocessor flags accordingly +# This file detects host CPU capabilities and combines them with compiler support +# to enable optimal compilation flags. -# Native compilation -ifeq ($(CROSS_PREFIX),) +ifndef _AUTO_MK +_AUTO_MK := + +# Helper function to check if host CPU supports a feature +# Usage: $(call check_host_feature,feature_pattern,source_command) +define check_host_feature +$(shell $(2) 2>/dev/null | grep -q "$(1)" && echo 1 || echo 0) +endef + +# x86_64 architecture detection +ifeq ($(ARCH),x86_64) + +# Host CPU feature detection for x86_64 ifeq ($(HOST_PLATFORM),Linux-x86_64) - CFLAGS += -mavx2 -mbmi2 -mpopcnt -maes - CFLAGS += -DMLK_FORCE_X86_64 -else ifeq ($(HOST_PLATFORM),Linux-aarch64) - CFLAGS += -DMLK_FORCE_AARCH64 +# Linux: Use /proc/cpuinfo +MK_HOST_SUPPORTS_AVX2 := $(call check_host_feature,avx2,cat /proc/cpuinfo) +MK_HOST_SUPPORTS_SSE2 := $(call check_host_feature,sse2,cat /proc/cpuinfo) +MK_HOST_SUPPORTS_BMI2 := $(call check_host_feature,bmi2,cat /proc/cpuinfo) +else ifeq ($(HOST_PLATFORM),Darwin-x86_64) +# macOS: Use sysctl +MK_HOST_SUPPORTS_AVX2 := $(call check_host_feature,AVX2,sysctl -n machdep.cpu.leaf7_features) +MK_HOST_SUPPORTS_SSE2 := $(call check_host_feature,SSE2,sysctl -n machdep.cpu.features) +MK_HOST_SUPPORTS_BMI2 := $(call check_host_feature,BMI2,sysctl -n machdep.cpu.leaf7_features) +else ifneq ($(CROSS_PREFIX),) +# Cross-compilation: assume all features are supported +MK_HOST_SUPPORTS_AVX2 := 1 +MK_HOST_SUPPORTS_SSE2 := 1 +MK_HOST_SUPPORTS_BMI2 := 1 +else +# Other platforms: assume no support +MK_HOST_SUPPORTS_AVX2 := 0 +MK_HOST_SUPPORTS_SSE2 := 0 +MK_HOST_SUPPORTS_BMI2 := 0 +endif # HOST_PLATFORM x86_64 + +endif # x86_64 + +# AArch64 architecture detection +ifeq ($(ARCH),aarch64) + +# Host CPU feature detection for AArch64 +ifeq ($(HOST_PLATFORM),Linux-aarch64) +# Linux: Use /proc/cpuinfo (look for sha3 in Features line) +MK_HOST_SUPPORTS_SHA3 := $(call check_host_feature,sha3,cat /proc/cpuinfo) else ifeq ($(HOST_PLATFORM),Darwin-arm64) - CFLAGS += -DMLK_FORCE_AARCH64 +# macOS: Use sysctl to check for SHA3 support +MK_HOST_SUPPORTS_SHA3 := $(call check_host_feature,1,sysctl -n hw.optional.armv8_2_sha3) +else ifneq ($(CROSS_PREFIX),) +# Cross-compilation: assume all features are supported +MK_HOST_SUPPORTS_SHA3 := 1 +else +# Other platforms: assume no support +MK_HOST_SUPPORTS_SHA3 := 0 +endif # HOST_PLATFORM aarch64 + +endif # aarch64 + +# Only apply CFLAGS modifications if AUTO=1 +ifeq ($(AUTO),1) + +# x86_64 CFLAGS configuration +ifeq ($(ARCH),x86_64) +CFLAGS += -DMLK_FORCE_X86_64 + +# Add flags only if both compiler and host support the feature +ifeq ($(MK_COMPILER_SUPPORTS_AVX2)$(MK_HOST_SUPPORTS_AVX2),11) +CFLAGS += -mavx2 endif -# Cross compilation -else ifneq ($(findstring x86_64, $(CROSS_PREFIX)),) - CFLAGS += -mavx2 -mbmi2 -mpopcnt -maes - CFLAGS += -DMLK_FORCE_X86_64 -else ifneq ($(findstring aarch64_be, $(CROSS_PREFIX)),) - CFLAGS += -DMLK_FORCE_AARCH64_EB -else ifneq ($(findstring aarch64, $(CROSS_PREFIX)),) - CFLAGS += -DMLK_FORCE_AARCH64 -else ifneq ($(findstring riscv64, $(CROSS_PREFIX)),) - CFLAGS += -DMLK_FORCE_RISCV64 -else ifneq ($(findstring riscv32, $(CROSS_PREFIX)),) - CFLAGS += -DMLK_FORCE_RISCV32 -else ifneq ($(findstring powerpc64le, $(CROSS_PREFIX)),) - CFLAGS += -DMLK_FORCE_PPC64LE + +ifeq ($(MK_COMPILER_SUPPORTS_BMI2)$(MK_HOST_SUPPORTS_BMI2),11) +CFLAGS += -mbmi2 endif +endif # x86_64 + +# AArch64 CFLAGS configuration +ifeq ($(ARCH),aarch64) +CFLAGS += -DMLK_FORCE_AARCH64 + +# Add SHA3 flags only if both compiler and host support it +ifeq ($(MK_COMPILER_SUPPORTS_SHA3)$(MK_HOST_SUPPORTS_SHA3),11) +CFLAGS += -march=armv8.4-a+sha3 +endif +endif # aarch64 + +# AArch64 Big Endian CFLAGS configuration +ifeq ($(ARCH),aarch64_be) +CFLAGS += -DMLK_FORCE_AARCH64_EB +endif # aarch64_be + +# RISC-V 64-bit CFLAGS configuration +ifeq ($(ARCH),riscv64) +CFLAGS += -DMLK_FORCE_RISCV64 +endif # riscv64 + +# RISC-V 32-bit CFLAGS configuration +ifeq ($(ARCH),riscv32) +CFLAGS += -DMLK_FORCE_RISCV32 +endif # riscv32 + +# PowerPC 64-bit Little Endian CFLAGS configuration +ifeq ($(ARCH),powerpc64le) +CFLAGS += -DMLK_FORCE_PPC64LE +endif # powerpc64le + +endif # AUTO=1 + +endif # _AUTO_MK diff --git a/test/mk/compiler.mk b/test/mk/compiler.mk new file mode 100644 index 000000000..0e0461bbf --- /dev/null +++ b/test/mk/compiler.mk @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT +# +# Compiler feature detection for mlkem-native +# This file detects whether the compiler supports various architectural features +# used by mlkem-native through compile-time tests with C code containing inline assembly. +# +# Feature detection can be overridden by setting the corresponding variable on the command line: +# make MK_COMPILER_SUPPORTS_SHA3=0 # Disable SHA3 detection +# make MK_COMPILER_SUPPORTS_AVX2=0 # Disable AVX2 detection +# make MK_COMPILER_SUPPORTS_BMI2=0 # Disable BMI2 detection +# make MK_COMPILER_SUPPORTS_SSE2=0 # Disable SSE2 detection + +ifndef _COMPILER_MK +_COMPILER_MK := + +# Normalize architecture names +ARCH := $(shell uname -m) +ifeq ($(ARCH),arm64) +ARCH := aarch64 +endif + +# Override ARCH for cross-compilation based on CROSS_PREFIX +ifneq ($(CROSS_PREFIX),) +ifneq ($(findstring x86_64, $(CROSS_PREFIX)),) +ARCH := x86_64 +else ifneq ($(findstring aarch64_be, $(CROSS_PREFIX)),) +ARCH := aarch64_be +else ifneq ($(findstring aarch64, $(CROSS_PREFIX)),) +ARCH := aarch64 +else ifneq ($(findstring riscv64, $(CROSS_PREFIX)),) +ARCH := riscv64 +else ifneq ($(findstring riscv32, $(CROSS_PREFIX)),) +ARCH := riscv32 +else ifneq ($(findstring powerpc64le, $(CROSS_PREFIX)),) +ARCH := powerpc64le +endif +endif # CROSS_PREFIX + +# x86_64 feature detection +ifeq ($(ARCH),x86_64) + +# Test AVX2 support using C with inline assembly +# Can be overridden by setting MK_COMPILER_SUPPORTS_AVX2=0/1 on command line +MK_COMPILER_SUPPORTS_AVX2 ?= $(shell echo 'int main() { __asm__("vpxor %%ymm0, %%ymm1, %%ymm2" ::: "ymm0", "ymm1", "ymm2"); return 0; }' | $(CC) -mavx2 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +# Test SSE2 support using C with inline assembly +# Can be overridden by setting MK_COMPILER_SUPPORTS_SSE2=0/1 on command line +MK_COMPILER_SUPPORTS_SSE2 ?= $(shell echo 'int main() { __asm__("pxor %%xmm0, %%xmm1" ::: "xmm0", "xmm1"); return 0; }' | $(CC) -msse2 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +# Test BMI2 support using C with inline assembly +# Can be overridden by setting MK_COMPILER_SUPPORTS_BMI2=0/1 on command line +MK_COMPILER_SUPPORTS_BMI2 ?= $(shell echo 'int main() { __asm__("pdep %%eax, %%ebx, %%ecx" ::: "eax", "ebx", "ecx"); return 0; }' | $(CC) -mbmi2 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +endif # x86_64 + +# AArch64 feature detection +ifeq ($(ARCH),aarch64) + +# Test SHA3 support (Armv8.4-a+SHA3) using C with inline assembly +# Can be overridden by setting MK_COMPILER_SUPPORTS_SHA3=0/1 on command line +MK_COMPILER_SUPPORTS_SHA3 ?= $(shell echo 'int main() { __asm__("eor3 v0.16b, v1.16b, v2.16b, v3.16b" ::: "v0", "v1", "v2", "v3"); return 0; }' | $(CC) -march=armv8.4-a+sha3 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +endif # aarch64 + +endif # _COMPILER_MK diff --git a/test/mk/config.mk b/test/mk/config.mk index 43e0be02e..832e89608 100644 --- a/test/mk/config.mk +++ b/test/mk/config.mk @@ -81,10 +81,6 @@ CYCLES ?= OPT ?= 1 RETAINED_VARS := CROSS_PREFIX CYCLES OPT AUTO -ifeq ($(AUTO),1) -include test/mk/auto.mk -endif - BUILD_DIR ?= test/build MAKE_OBJS = $(2:%=$(1)/%.o)