Skip to content

Commit 51d641a

Browse files
authored
Merge pull request #1146 from pq-code-package/arch_specs
Makefile: Add compile-time compiler+host platform feature detection
2 parents a48d98e + 9da1ccd commit 51d641a

File tree

7 files changed

+214
-32
lines changed

7 files changed

+214
-32
lines changed

.github/actions/ct-test/action.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,5 @@ runs:
3939
- shell: ${{ env.SHELL }}
4040
run: |
4141
make clean
42-
tests func --exec-wrapper="valgrind --error-exitcode=1 --track-origins=yes ${{ inputs.valgrind_flags }}" --cflags="-DMLK_CONFIG_CT_TESTING_ENABLED -DNTESTS=50 ${{ inputs.cflags }}"
42+
# Disable the AArch64 SHA3 extension as it's not yet supported by valgrind
43+
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 }}"

Makefile

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
build test all \
1717
clean quickcheck check-defined-CYCLES \
1818
size_512 size_768 size_1024 size \
19-
run_size_512 run_size_768 run_size_1024 run_size
19+
run_size_512 run_size_768 run_size_1024 run_size \
20+
host_info
2021

2122
SHELL := /bin/bash
2223
.DEFAULT_GOAL := build
@@ -26,6 +27,8 @@ all: build
2627
W := $(EXEC_WRAPPER)
2728

2829
include test/mk/config.mk
30+
include test/mk/compiler.mk
31+
include test/mk/auto.mk
2932
include test/mk/components.mk
3033
include test/mk/rules.mk
3134

@@ -86,6 +89,15 @@ acvp_1024: $(MLKEM1024_DIR)/bin/acvp_mlkem1024
8689
$(Q)echo " ACVP ML-KEM-1024: $^"
8790
acvp: acvp_512 acvp_768 acvp_1024
8891

92+
ifeq ($(HOST_PLATFORM),Linux-aarch64)
93+
# valgrind does not work with the AArch64 SHA3 extension
94+
# Use armv8-a as the target architecture, overwriting a
95+
# potential earlier addition of armv8.4-a+sha3.
96+
$(MLKEM512_DIR)/bin/test_stack512: CFLAGS += -march=armv8-a
97+
$(MLKEM768_DIR)/bin/test_stack768: CFLAGS += -march=armv8-a
98+
$(MLKEM1024_DIR)/bin/test_stack1024: CFLAGS += -march=armv8-a
99+
endif
100+
89101
stack_512: $(MLKEM512_DIR)/bin/test_stack512
90102
$(Q)echo " STACK ML-KEM-512: $^"
91103
stack_768: $(MLKEM768_DIR)/bin/test_stack768
@@ -176,6 +188,30 @@ run_size: \
176188
run_size_768 \
177189
run_size_1024
178190

191+
# Display host and compiler feature detection information
192+
# Shows which architectural features are supported by both the compiler and host CPU
193+
# Usage: make host_info [AUTO=0|1] [CROSS_PREFIX=...]
194+
host_info:
195+
@echo "=== Host and Compiler Feature Detection ==="
196+
@echo "Host Platform: $(HOST_PLATFORM)"
197+
@echo "Target Architecture: $(ARCH)"
198+
@echo "Compiler: $(CC)"
199+
@echo "Cross Prefix: $(if $(CROSS_PREFIX),$(CROSS_PREFIX),<none>)"
200+
@echo "AUTO: $(AUTO)"
201+
@echo ""
202+
ifeq ($(ARCH),x86_64)
203+
@echo "=== x86_64 Feature Support ==="
204+
@echo "AVX2: Host $(if $(filter 1,$(MK_HOST_SUPPORTS_AVX2)),✅,❌) Compiler $(if $(filter 1,$(MK_COMPILER_SUPPORTS_AVX2)),✅,❌)"
205+
@echo "SSE2: Host $(if $(filter 1,$(MK_HOST_SUPPORTS_SSE2)),✅,❌) Compiler $(if $(filter 1,$(MK_COMPILER_SUPPORTS_SSE2)),✅,❌)"
206+
@echo "BMI2: Host $(if $(filter 1,$(MK_HOST_SUPPORTS_BMI2)),✅,❌) Compiler $(if $(filter 1,$(MK_COMPILER_SUPPORTS_BMI2)),✅,❌)"
207+
else ifeq ($(ARCH),aarch64)
208+
@echo "=== AArch64 Feature Support ==="
209+
@echo "SHA3: Host $(if $(filter 1,$(MK_HOST_SUPPORTS_SHA3)),✅,❌) Compiler $(if $(filter 1,$(MK_COMPILER_SUPPORTS_SHA3)),✅,❌)"
210+
else
211+
@echo "=== Architecture Not Supported ==="
212+
@echo "No specific feature detection available for $(ARCH)"
213+
endif
214+
179215
clean:
180216
-$(RM) -rf *.gcno *.gcda *.lcov *.o *.so
181217
-$(RM) -rf $(BUILD_DIR)

examples/monolithic_build_multilevel_native/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ endif
6161
# Native compilation
6262
ifeq ($(CROSS_PREFIX),)
6363
ifeq ($(HOST_PLATFORM),Linux-x86_64)
64-
CFLAGS += -mavx2 -mbmi2 -mpopcnt -maes
64+
CFLAGS += -mavx2 -mbmi2
6565
CFLAGS += -DMLK_FORCE_X86_64
6666
else ifeq ($(HOST_PLATFORM),Linux-aarch64)
6767
CFLAGS += -DMLK_FORCE_AARCH64
@@ -70,7 +70,7 @@ else ifeq ($(HOST_PLATFORM),Darwin-arm64)
7070
endif
7171
# Cross compilation
7272
else ifneq ($(findstring x86_64, $(CROSS_PREFIX)),)
73-
CFLAGS += -mavx2 -mbmi2 -mpopcnt -maes
73+
CFLAGS += -mavx2 -mbmi2
7474
CFLAGS += -DMLK_FORCE_X86_64
7575
else ifneq ($(findstring aarch64_be, $(CROSS_PREFIX)),)
7676
CFLAGS += -DMLK_FORCE_AARCH64_EB

examples/multilevel_build_native/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ endif
2828
# Native compilation
2929
ifeq ($(CROSS_PREFIX),)
3030
ifeq ($(HOST_PLATFORM),Linux-x86_64)
31-
CFLAGS += -mavx2 -mbmi2 -mpopcnt -maes
31+
CFLAGS += -mavx2 -mbmi2
3232
CFLAGS += -DMLK_FORCE_X86_64
3333
else ifeq ($(HOST_PLATFORM),Linux-aarch64)
3434
CFLAGS += -DMLK_FORCE_AARCH64
@@ -37,7 +37,7 @@ else ifeq ($(HOST_PLATFORM),Darwin-arm64)
3737
endif
3838
# Cross compilation
3939
else ifneq ($(findstring x86_64, $(CROSS_PREFIX)),)
40-
CFLAGS += -mavx2 -mbmi2 -mpopcnt -maes
40+
CFLAGS += -mavx2 -mbmi2
4141
CFLAGS += -DMLK_FORCE_X86_64
4242
else ifneq ($(findstring aarch64_be, $(CROSS_PREFIX)),)
4343
CFLAGS += -DMLK_FORCE_AARCH64_EB

test/mk/auto.mk

Lines changed: 106 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,113 @@
11
# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
22
#
3-
# Automatically detect system architecture and set preprocessor etc accordingly
3+
# Automatically detect system architecture and set preprocessor flags accordingly
4+
# This file detects host CPU capabilities and combines them with compiler support
5+
# to enable optimal compilation flags.
46

5-
# Native compilation
6-
ifeq ($(CROSS_PREFIX),)
7+
ifndef _AUTO_MK
8+
_AUTO_MK :=
9+
10+
# Helper function to check if host CPU supports a feature
11+
# Usage: $(call check_host_feature,feature_pattern,source_command)
12+
define check_host_feature
13+
$(shell $(2) 2>/dev/null | grep -q "$(1)" && echo 1 || echo 0)
14+
endef
15+
16+
# x86_64 architecture detection
17+
ifeq ($(ARCH),x86_64)
18+
19+
# Host CPU feature detection for x86_64
720
ifeq ($(HOST_PLATFORM),Linux-x86_64)
8-
CFLAGS += -mavx2 -mbmi2 -mpopcnt -maes
9-
CFLAGS += -DMLK_FORCE_X86_64
10-
else ifeq ($(HOST_PLATFORM),Linux-aarch64)
11-
CFLAGS += -DMLK_FORCE_AARCH64
21+
# Linux: Use /proc/cpuinfo
22+
MK_HOST_SUPPORTS_AVX2 := $(call check_host_feature,avx2,cat /proc/cpuinfo)
23+
MK_HOST_SUPPORTS_SSE2 := $(call check_host_feature,sse2,cat /proc/cpuinfo)
24+
MK_HOST_SUPPORTS_BMI2 := $(call check_host_feature,bmi2,cat /proc/cpuinfo)
25+
else ifeq ($(HOST_PLATFORM),Darwin-x86_64)
26+
# macOS: Use sysctl
27+
MK_HOST_SUPPORTS_AVX2 := $(call check_host_feature,AVX2,sysctl -n machdep.cpu.leaf7_features)
28+
MK_HOST_SUPPORTS_SSE2 := $(call check_host_feature,SSE2,sysctl -n machdep.cpu.features)
29+
MK_HOST_SUPPORTS_BMI2 := $(call check_host_feature,BMI2,sysctl -n machdep.cpu.leaf7_features)
30+
else ifneq ($(CROSS_PREFIX),)
31+
# Cross-compilation: assume all features are supported
32+
MK_HOST_SUPPORTS_AVX2 := 1
33+
MK_HOST_SUPPORTS_SSE2 := 1
34+
MK_HOST_SUPPORTS_BMI2 := 1
35+
else
36+
# Other platforms: assume no support
37+
MK_HOST_SUPPORTS_AVX2 := 0
38+
MK_HOST_SUPPORTS_SSE2 := 0
39+
MK_HOST_SUPPORTS_BMI2 := 0
40+
endif # HOST_PLATFORM x86_64
41+
42+
endif # x86_64
43+
44+
# AArch64 architecture detection
45+
ifeq ($(ARCH),aarch64)
46+
47+
# Host CPU feature detection for AArch64
48+
ifeq ($(HOST_PLATFORM),Linux-aarch64)
49+
# Linux: Use /proc/cpuinfo (look for sha3 in Features line)
50+
MK_HOST_SUPPORTS_SHA3 := $(call check_host_feature,sha3,cat /proc/cpuinfo)
1251
else ifeq ($(HOST_PLATFORM),Darwin-arm64)
13-
CFLAGS += -DMLK_FORCE_AARCH64
52+
# macOS: Use sysctl to check for SHA3 support
53+
MK_HOST_SUPPORTS_SHA3 := $(call check_host_feature,1,sysctl -n hw.optional.armv8_2_sha3)
54+
else ifneq ($(CROSS_PREFIX),)
55+
# Cross-compilation: assume all features are supported
56+
MK_HOST_SUPPORTS_SHA3 := 1
57+
else
58+
# Other platforms: assume no support
59+
MK_HOST_SUPPORTS_SHA3 := 0
60+
endif # HOST_PLATFORM aarch64
61+
62+
endif # aarch64
63+
64+
# Only apply CFLAGS modifications if AUTO=1
65+
ifeq ($(AUTO),1)
66+
67+
# x86_64 CFLAGS configuration
68+
ifeq ($(ARCH),x86_64)
69+
CFLAGS += -DMLK_FORCE_X86_64
70+
71+
# Add flags only if both compiler and host support the feature
72+
ifeq ($(MK_COMPILER_SUPPORTS_AVX2)$(MK_HOST_SUPPORTS_AVX2),11)
73+
CFLAGS += -mavx2
1474
endif
15-
# Cross compilation
16-
else ifneq ($(findstring x86_64, $(CROSS_PREFIX)),)
17-
CFLAGS += -mavx2 -mbmi2 -mpopcnt -maes
18-
CFLAGS += -DMLK_FORCE_X86_64
19-
else ifneq ($(findstring aarch64_be, $(CROSS_PREFIX)),)
20-
CFLAGS += -DMLK_FORCE_AARCH64_EB
21-
else ifneq ($(findstring aarch64, $(CROSS_PREFIX)),)
22-
CFLAGS += -DMLK_FORCE_AARCH64
23-
else ifneq ($(findstring riscv64, $(CROSS_PREFIX)),)
24-
CFLAGS += -DMLK_FORCE_RISCV64
25-
else ifneq ($(findstring riscv32, $(CROSS_PREFIX)),)
26-
CFLAGS += -DMLK_FORCE_RISCV32
27-
else ifneq ($(findstring powerpc64le, $(CROSS_PREFIX)),)
28-
CFLAGS += -DMLK_FORCE_PPC64LE
75+
76+
ifeq ($(MK_COMPILER_SUPPORTS_BMI2)$(MK_HOST_SUPPORTS_BMI2),11)
77+
CFLAGS += -mbmi2
2978
endif
79+
endif # x86_64
80+
81+
# AArch64 CFLAGS configuration
82+
ifeq ($(ARCH),aarch64)
83+
CFLAGS += -DMLK_FORCE_AARCH64
84+
85+
# Add SHA3 flags only if both compiler and host support it
86+
ifeq ($(MK_COMPILER_SUPPORTS_SHA3)$(MK_HOST_SUPPORTS_SHA3),11)
87+
CFLAGS += -march=armv8.4-a+sha3
88+
endif
89+
endif # aarch64
90+
91+
# AArch64 Big Endian CFLAGS configuration
92+
ifeq ($(ARCH),aarch64_be)
93+
CFLAGS += -DMLK_FORCE_AARCH64_EB
94+
endif # aarch64_be
95+
96+
# RISC-V 64-bit CFLAGS configuration
97+
ifeq ($(ARCH),riscv64)
98+
CFLAGS += -DMLK_FORCE_RISCV64
99+
endif # riscv64
100+
101+
# RISC-V 32-bit CFLAGS configuration
102+
ifeq ($(ARCH),riscv32)
103+
CFLAGS += -DMLK_FORCE_RISCV32
104+
endif # riscv32
105+
106+
# PowerPC 64-bit Little Endian CFLAGS configuration
107+
ifeq ($(ARCH),powerpc64le)
108+
CFLAGS += -DMLK_FORCE_PPC64LE
109+
endif # powerpc64le
110+
111+
endif # AUTO=1
112+
113+
endif # _AUTO_MK

test/mk/compiler.mk

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
2+
#
3+
# Compiler feature detection for mlkem-native
4+
# This file detects whether the compiler supports various architectural features
5+
# used by mlkem-native through compile-time tests with C code containing inline assembly.
6+
#
7+
# Feature detection can be overridden by setting the corresponding variable on the command line:
8+
# make MK_COMPILER_SUPPORTS_SHA3=0 # Disable SHA3 detection
9+
# make MK_COMPILER_SUPPORTS_AVX2=0 # Disable AVX2 detection
10+
# make MK_COMPILER_SUPPORTS_BMI2=0 # Disable BMI2 detection
11+
# make MK_COMPILER_SUPPORTS_SSE2=0 # Disable SSE2 detection
12+
13+
ifndef _COMPILER_MK
14+
_COMPILER_MK :=
15+
16+
# Normalize architecture names
17+
ARCH := $(shell uname -m)
18+
ifeq ($(ARCH),arm64)
19+
ARCH := aarch64
20+
endif
21+
22+
# Override ARCH for cross-compilation based on CROSS_PREFIX
23+
ifneq ($(CROSS_PREFIX),)
24+
ifneq ($(findstring x86_64, $(CROSS_PREFIX)),)
25+
ARCH := x86_64
26+
else ifneq ($(findstring aarch64_be, $(CROSS_PREFIX)),)
27+
ARCH := aarch64_be
28+
else ifneq ($(findstring aarch64, $(CROSS_PREFIX)),)
29+
ARCH := aarch64
30+
else ifneq ($(findstring riscv64, $(CROSS_PREFIX)),)
31+
ARCH := riscv64
32+
else ifneq ($(findstring riscv32, $(CROSS_PREFIX)),)
33+
ARCH := riscv32
34+
else ifneq ($(findstring powerpc64le, $(CROSS_PREFIX)),)
35+
ARCH := powerpc64le
36+
endif
37+
endif # CROSS_PREFIX
38+
39+
# x86_64 feature detection
40+
ifeq ($(ARCH),x86_64)
41+
42+
# Test AVX2 support using C with inline assembly
43+
# Can be overridden by setting MK_COMPILER_SUPPORTS_AVX2=0/1 on command line
44+
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)
45+
46+
# Test SSE2 support using C with inline assembly
47+
# Can be overridden by setting MK_COMPILER_SUPPORTS_SSE2=0/1 on command line
48+
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)
49+
50+
# Test BMI2 support using C with inline assembly
51+
# Can be overridden by setting MK_COMPILER_SUPPORTS_BMI2=0/1 on command line
52+
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)
53+
54+
endif # x86_64
55+
56+
# AArch64 feature detection
57+
ifeq ($(ARCH),aarch64)
58+
59+
# Test SHA3 support (Armv8.4-a+SHA3) using C with inline assembly
60+
# Can be overridden by setting MK_COMPILER_SUPPORTS_SHA3=0/1 on command line
61+
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)
62+
63+
endif # aarch64
64+
65+
endif # _COMPILER_MK

test/mk/config.mk

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,6 @@ CYCLES ?=
8181
OPT ?= 1
8282
RETAINED_VARS := CROSS_PREFIX CYCLES OPT AUTO
8383

84-
ifeq ($(AUTO),1)
85-
include test/mk/auto.mk
86-
endif
87-
8884
BUILD_DIR ?= test/build
8985

9086
MAKE_OBJS = $(2:%=$(1)/%.o)

0 commit comments

Comments
 (0)