From b26e10d12dd467e2fdc716daea76b07d235aa1a2 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Sun, 11 Oct 2026 04:44:40 +0000 Subject: [PATCH] PPC64: Align backend selection and ABI feature guards The PPC64 ABI checker registered kernels whenever the target was PPC64LE, while the kernels require POWER8 vector support. Removing the checker's forced assembly flags would leave checks referring to kernels omitted by the build's CPU flags. Add `MLK_SYS_PPC64LE_POWER8_VECTOR`, requiring `__ALTIVEC__`, `__VSX__`, and `__POWER8_VECTOR__` on PPC64LE. Use it to select the default PPC64 backend in `native/meta.h`, as for the NEON and AVX2 backends. Unsupported targets then use portable C without selecting the native wrappers. Remove the per-kernel and constant-table `__POWER8_VECTOR__` guards and the wrappers' compile-time fallback branches. Explicitly selecting the PPC64 backend now requires a target with its documented features, matching the other backends. The PPC64 wrappers previously checked only `__POWER8_VECTOR__` at compile time, so a custom capability function could not disable them at runtime. Append `MLK_SYS_CAP_PPC64LE_POWER8_VECTOR` and have all four wrappers consult the capability hook before calling assembly. Return `MLK_NATIVE_FUNC_FALLBACK` without modifying the input if it rejects POWER8 vector support. Use the same feature macro for the generated ABI checks, registry, call stub and self-test. Name the ABI feature `POWER8_VECTOR` and consult the capability hook before calling assembly from ABI checks or the self-test. Correct the backend READMEs from POWER9 to POWER8 and state the AltiVec and VSX requirement. The default capability hook assumes compile-time features are supported; runtime detection requires a custom function. Signed-off-by: Hanno Becker --- dev/ppc64le/README.md | 5 ++- dev/ppc64le/meta.h | 36 +++++++++---------- dev/ppc64le/src/consts.c | 4 +-- dev/ppc64le/src/mlkem_intt_ppc_asm.S | 7 ++-- dev/ppc64le/src/mlkem_ntt_ppc_asm.S | 6 ++-- dev/ppc64le/src/mlkem_poly_tomont_ppc_asm.S | 6 ++-- dev/ppc64le/src/mlkem_reduce_ppc_asm.S | 6 ++-- mlkem/mlkem_native.c | 1 + mlkem/mlkem_native_asm.S | 1 + mlkem/src/native/meta.h | 4 +-- mlkem/src/native/ppc64le/README.md | 4 +-- mlkem/src/native/ppc64le/meta.h | 36 +++++++++---------- mlkem/src/native/ppc64le/src/consts.c | 4 +-- .../native/ppc64le/src/mlkem_intt_ppc_asm.S | 7 ++-- .../native/ppc64le/src/mlkem_ntt_ppc_asm.S | 6 ++-- .../ppc64le/src/mlkem_poly_tomont_ppc_asm.S | 6 ++-- .../native/ppc64le/src/mlkem_reduce_ppc_asm.S | 6 ++-- mlkem/src/sys.h | 13 ++++++- scripts/autogen | 21 +++++------ test/abicheck/README.md | 6 ++-- test/abicheck/ppc64le/abicheck_ppc64le.mk | 10 +++--- test/abicheck/ppc64le/callstub_ppc64le.S | 6 ++++ .../ppc64le/checks/check_intt_ppc_asm.c | 12 +++++-- .../ppc64le/checks/check_ntt_ppc_asm.c | 12 +++++-- .../checks/check_poly_tomont_ppc_asm.c | 12 +++++-- .../ppc64le/checks/check_reduce_ppc_asm.c | 12 +++++-- test/abicheck/ppc64le/checks_ppc64le_all.h | 4 +++ test/abicheck/ppc64le/selftest_ppc64le.S | 6 ++++ test/abicheck/selftest.c | 23 +++++++----- 29 files changed, 170 insertions(+), 112 deletions(-) diff --git a/dev/ppc64le/README.md b/dev/ppc64le/README.md index def9e7e7ef..de50aeaaca 100644 --- a/dev/ppc64le/README.md +++ b/dev/ppc64le/README.md @@ -2,6 +2,5 @@ # ppc64le backend (little endian) -This directory contains a native backend for little endian POWER 9 (ppc64le) and above systems. -Or, Power systems supporting ISA 2.07 and above. - +This directory contains a native backend for little endian PPC64. +It requires POWER8 or above as well as the AltiVec and VSX extensions. diff --git a/dev/ppc64le/meta.h b/dev/ppc64le/meta.h index e10ecd6907..882f9aeef4 100644 --- a/dev/ppc64le/meta.h +++ b/dev/ppc64le/meta.h @@ -28,52 +28,48 @@ MLK_MUST_CHECK_RETURN_VALUE static MLK_INLINE int mlk_ntt_native(int16_t data[MLKEM_N]) { -#if defined(__POWER8_VECTOR__) + if (!mlk_sys_check_capability(MLK_SYS_CAP_PPC64LE_POWER8_VECTOR)) + { + return MLK_NATIVE_FUNC_FALLBACK; + } mlk_ntt_ppc_asm(data, mlk_ppc_qdata); return MLK_NATIVE_FUNC_SUCCESS; -#else - (void)data; - return MLK_NATIVE_FUNC_FALLBACK; -#endif } #if !defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API) MLK_MUST_CHECK_RETURN_VALUE static MLK_INLINE int mlk_intt_native(int16_t data[MLKEM_N]) { -#if defined(__POWER8_VECTOR__) + if (!mlk_sys_check_capability(MLK_SYS_CAP_PPC64LE_POWER8_VECTOR)) + { + return MLK_NATIVE_FUNC_FALLBACK; + } mlk_intt_ppc_asm(data, mlk_ppc_qdata); return MLK_NATIVE_FUNC_SUCCESS; -#else - (void)data; - return MLK_NATIVE_FUNC_FALLBACK; -#endif } #endif /* !MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API */ MLK_MUST_CHECK_RETURN_VALUE static MLK_INLINE int mlk_poly_reduce_native(int16_t data[MLKEM_N]) { -#if defined(__POWER8_VECTOR__) + if (!mlk_sys_check_capability(MLK_SYS_CAP_PPC64LE_POWER8_VECTOR)) + { + return MLK_NATIVE_FUNC_FALLBACK; + } mlk_reduce_ppc_asm(data, mlk_ppc_qdata); return MLK_NATIVE_FUNC_SUCCESS; -#else - (void)data; - return MLK_NATIVE_FUNC_FALLBACK; -#endif } #if !defined(MLK_CONFIG_NO_KEYPAIR_API) MLK_MUST_CHECK_RETURN_VALUE static MLK_INLINE int mlk_poly_tomont_native(int16_t data[MLKEM_N]) { -#if defined(__POWER8_VECTOR__) + if (!mlk_sys_check_capability(MLK_SYS_CAP_PPC64LE_POWER8_VECTOR)) + { + return MLK_NATIVE_FUNC_FALLBACK; + } mlk_poly_tomont_ppc_asm(data, mlk_ppc_qdata); return MLK_NATIVE_FUNC_SUCCESS; -#else - (void)data; - return MLK_NATIVE_FUNC_FALLBACK; -#endif } #endif /* !MLK_CONFIG_NO_KEYPAIR_API */ #endif /* !__ASSEMBLER__ */ diff --git a/dev/ppc64le/src/consts.c b/dev/ppc64le/src/consts.c index f6e1abd5b9..ec700ac6f0 100644 --- a/dev/ppc64le/src/consts.c +++ b/dev/ppc64le/src/consts.c @@ -12,7 +12,7 @@ #include "../../../common.h" #if defined(MLK_ARITH_BACKEND_PPC64LE_DEFAULT) && \ - !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && defined(__POWER8_VECTOR__) + !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) #include "consts.h" @@ -296,4 +296,4 @@ MLK_ALIGN MLK_INTERNAL_DATA_DEFINITION const int16_t mlk_ppc_qdata[2072] = { /* clang-format on */ #endif /* MLK_ARITH_BACKEND_PPC64LE_DEFAULT && \ - !MLK_CONFIG_MULTILEVEL_NO_SHARED && __POWER8_VECTOR__ */ + !MLK_CONFIG_MULTILEVEL_NO_SHARED */ diff --git a/dev/ppc64le/src/mlkem_intt_ppc_asm.S b/dev/ppc64le/src/mlkem_intt_ppc_asm.S index 3a67ee8e6b..c702a281dd 100644 --- a/dev/ppc64le/src/mlkem_intt_ppc_asm.S +++ b/dev/ppc64le/src/mlkem_intt_ppc_asm.S @@ -8,7 +8,7 @@ #include "../../../common.h" #if defined(MLK_ARITH_BACKEND_PPC64LE_DEFAULT) && \ - !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && defined(__POWER8_VECTOR__) && \ + !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && \ (!defined(MLK_CONFIG_NO_ENCAPS_API) || \ !defined(MLK_CONFIG_NO_DECAPS_API)) /*yaml @@ -18,7 +18,7 @@ ABI: Architecture: powerpc64le CallingConvention: ELFv2 - Features: [VSX] + Features: [POWER8_VECTOR] r3: type: buffer size_bytes: 512 @@ -1004,5 +1004,4 @@ mlk_intt_ppc_asm_Loopf: /* simpasm: footer-start */ #endif /* MLK_ARITH_BACKEND_PPC64LE_DEFAULT && !MLK_CONFIG_MULTILEVEL_NO_SHARED \ - && __POWER8_VECTOR__ && (!MLK_CONFIG_NO_ENCAPS_API || \ - !MLK_CONFIG_NO_DECAPS_API) */ + && (!MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API) */ diff --git a/dev/ppc64le/src/mlkem_ntt_ppc_asm.S b/dev/ppc64le/src/mlkem_ntt_ppc_asm.S index d88738a792..0319d96bea 100644 --- a/dev/ppc64le/src/mlkem_ntt_ppc_asm.S +++ b/dev/ppc64le/src/mlkem_ntt_ppc_asm.S @@ -8,7 +8,7 @@ #include "../../../common.h" #if defined(MLK_ARITH_BACKEND_PPC64LE_DEFAULT) && \ - !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && defined(__POWER8_VECTOR__) + !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) /*yaml Name: ntt_ppc_asm Description: PowerPC64 VSX forward NTT @@ -16,7 +16,7 @@ ABI: Architecture: powerpc64le CallingConvention: ELFv2 - Features: [VSX] + Features: [POWER8_VECTOR] r3: type: buffer size_bytes: 512 @@ -767,4 +767,4 @@ MLK_ASM_FN_SYMBOL(ntt_ppc_asm) /* simpasm: footer-start */ #endif /* MLK_ARITH_BACKEND_PPC64LE_DEFAULT && !MLK_CONFIG_MULTILEVEL_NO_SHARED \ - && __POWER8_VECTOR__ */ + */ diff --git a/dev/ppc64le/src/mlkem_poly_tomont_ppc_asm.S b/dev/ppc64le/src/mlkem_poly_tomont_ppc_asm.S index 52f93d3cb3..13e427b4b1 100644 --- a/dev/ppc64le/src/mlkem_poly_tomont_ppc_asm.S +++ b/dev/ppc64le/src/mlkem_poly_tomont_ppc_asm.S @@ -15,7 +15,7 @@ #include "../../../common.h" #if defined(MLK_ARITH_BACKEND_PPC64LE_DEFAULT) && \ - !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && defined(__POWER8_VECTOR__) && \ + !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && \ !defined(MLK_CONFIG_NO_KEYPAIR_API) /*yaml Name: poly_tomont_ppc_asm @@ -24,7 +24,7 @@ ABI: Architecture: powerpc64le CallingConvention: ELFv2 - Features: [VSX] + Features: [POWER8_VECTOR] r3: type: buffer size_bytes: 512 @@ -242,4 +242,4 @@ MLK_ASM_FN_SYMBOL(poly_tomont_ppc_asm) /* simpasm: footer-start */ #endif /* MLK_ARITH_BACKEND_PPC64LE_DEFAULT && !MLK_CONFIG_MULTILEVEL_NO_SHARED \ - && __POWER8_VECTOR__ && !MLK_CONFIG_NO_KEYPAIR_API */ + && !MLK_CONFIG_NO_KEYPAIR_API */ diff --git a/dev/ppc64le/src/mlkem_reduce_ppc_asm.S b/dev/ppc64le/src/mlkem_reduce_ppc_asm.S index 9795d70bb4..1b4e43fabb 100644 --- a/dev/ppc64le/src/mlkem_reduce_ppc_asm.S +++ b/dev/ppc64le/src/mlkem_reduce_ppc_asm.S @@ -7,7 +7,7 @@ */ #include "../../../common.h" #if defined(MLK_ARITH_BACKEND_PPC64LE_DEFAULT) && \ - !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && defined(__POWER8_VECTOR__) + !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) /*yaml Name: reduce_ppc_asm Description: PowerPC64 VSX modular reduction @@ -15,7 +15,7 @@ ABI: Architecture: powerpc64le CallingConvention: ELFv2 - Features: [VSX] + Features: [POWER8_VECTOR] r3: type: buffer size_bytes: 512 @@ -463,4 +463,4 @@ MLK_ASM_FN_SYMBOL(reduce_ppc_asm) /* simpasm: footer-start */ #endif /* MLK_ARITH_BACKEND_PPC64LE_DEFAULT && !MLK_CONFIG_MULTILEVEL_NO_SHARED \ - && __POWER8_VECTOR__ */ + */ diff --git a/mlkem/mlkem_native.c b/mlkem/mlkem_native.c index 84adf0806c..840734539e 100644 --- a/mlkem/mlkem_native.c +++ b/mlkem/mlkem_native.c @@ -684,6 +684,7 @@ #undef MLK_SYS_LINUX #undef MLK_SYS_LITTLE_ENDIAN #undef MLK_SYS_PPC64LE +#undef MLK_SYS_PPC64LE_POWER8_VECTOR #undef MLK_SYS_RISCV32 #undef MLK_SYS_RISCV64 #undef MLK_SYS_RISCV64_RVV diff --git a/mlkem/mlkem_native_asm.S b/mlkem/mlkem_native_asm.S index e0a0213c57..f393c22dfa 100644 --- a/mlkem/mlkem_native_asm.S +++ b/mlkem/mlkem_native_asm.S @@ -715,6 +715,7 @@ #undef MLK_SYS_LINUX #undef MLK_SYS_LITTLE_ENDIAN #undef MLK_SYS_PPC64LE +#undef MLK_SYS_PPC64LE_POWER8_VECTOR #undef MLK_SYS_RISCV32 #undef MLK_SYS_RISCV64 #undef MLK_SYS_RISCV64_RVV diff --git a/mlkem/src/native/meta.h b/mlkem/src/native/meta.h index dbd07a5bda..d12726db2a 100644 --- a/mlkem/src/native/meta.h +++ b/mlkem/src/native/meta.h @@ -10,7 +10,7 @@ */ #include "../sys.h" -#ifdef MLK_SYS_AARCH64_NEON +#if defined(MLK_SYS_AARCH64_NEON) #include "aarch64/meta.h" #endif @@ -23,7 +23,7 @@ #include "riscv64/meta.h" #endif -#ifdef MLK_SYS_PPC64LE +#if defined(MLK_SYS_PPC64LE_POWER8_VECTOR) #include "ppc64le/meta.h" #endif diff --git a/mlkem/src/native/ppc64le/README.md b/mlkem/src/native/ppc64le/README.md index 733e32e113..de50aeaaca 100644 --- a/mlkem/src/native/ppc64le/README.md +++ b/mlkem/src/native/ppc64le/README.md @@ -2,5 +2,5 @@ # ppc64le backend (little endian) -This directory contains a native backend for little endian POWER 9 (ppc64le) and above systems. -Or, Power systems supporting ISA 2.07 and above. +This directory contains a native backend for little endian PPC64. +It requires POWER8 or above as well as the AltiVec and VSX extensions. diff --git a/mlkem/src/native/ppc64le/meta.h b/mlkem/src/native/ppc64le/meta.h index 2f292432df..94923174af 100644 --- a/mlkem/src/native/ppc64le/meta.h +++ b/mlkem/src/native/ppc64le/meta.h @@ -28,52 +28,48 @@ MLK_MUST_CHECK_RETURN_VALUE static MLK_INLINE int mlk_ntt_native(int16_t data[MLKEM_N]) { -#if defined(__POWER8_VECTOR__) + if (!mlk_sys_check_capability(MLK_SYS_CAP_PPC64LE_POWER8_VECTOR)) + { + return MLK_NATIVE_FUNC_FALLBACK; + } mlk_ntt_ppc_asm(data, mlk_ppc_qdata); return MLK_NATIVE_FUNC_SUCCESS; -#else - (void)data; - return MLK_NATIVE_FUNC_FALLBACK; -#endif } #if !defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API) MLK_MUST_CHECK_RETURN_VALUE static MLK_INLINE int mlk_intt_native(int16_t data[MLKEM_N]) { -#if defined(__POWER8_VECTOR__) + if (!mlk_sys_check_capability(MLK_SYS_CAP_PPC64LE_POWER8_VECTOR)) + { + return MLK_NATIVE_FUNC_FALLBACK; + } mlk_intt_ppc_asm(data, mlk_ppc_qdata); return MLK_NATIVE_FUNC_SUCCESS; -#else - (void)data; - return MLK_NATIVE_FUNC_FALLBACK; -#endif } #endif /* !MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API */ MLK_MUST_CHECK_RETURN_VALUE static MLK_INLINE int mlk_poly_reduce_native(int16_t data[MLKEM_N]) { -#if defined(__POWER8_VECTOR__) + if (!mlk_sys_check_capability(MLK_SYS_CAP_PPC64LE_POWER8_VECTOR)) + { + return MLK_NATIVE_FUNC_FALLBACK; + } mlk_reduce_ppc_asm(data, mlk_ppc_qdata); return MLK_NATIVE_FUNC_SUCCESS; -#else - (void)data; - return MLK_NATIVE_FUNC_FALLBACK; -#endif } #if !defined(MLK_CONFIG_NO_KEYPAIR_API) MLK_MUST_CHECK_RETURN_VALUE static MLK_INLINE int mlk_poly_tomont_native(int16_t data[MLKEM_N]) { -#if defined(__POWER8_VECTOR__) + if (!mlk_sys_check_capability(MLK_SYS_CAP_PPC64LE_POWER8_VECTOR)) + { + return MLK_NATIVE_FUNC_FALLBACK; + } mlk_poly_tomont_ppc_asm(data, mlk_ppc_qdata); return MLK_NATIVE_FUNC_SUCCESS; -#else - (void)data; - return MLK_NATIVE_FUNC_FALLBACK; -#endif } #endif /* !MLK_CONFIG_NO_KEYPAIR_API */ #endif /* !__ASSEMBLER__ */ diff --git a/mlkem/src/native/ppc64le/src/consts.c b/mlkem/src/native/ppc64le/src/consts.c index f6e1abd5b9..ec700ac6f0 100644 --- a/mlkem/src/native/ppc64le/src/consts.c +++ b/mlkem/src/native/ppc64le/src/consts.c @@ -12,7 +12,7 @@ #include "../../../common.h" #if defined(MLK_ARITH_BACKEND_PPC64LE_DEFAULT) && \ - !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && defined(__POWER8_VECTOR__) + !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) #include "consts.h" @@ -296,4 +296,4 @@ MLK_ALIGN MLK_INTERNAL_DATA_DEFINITION const int16_t mlk_ppc_qdata[2072] = { /* clang-format on */ #endif /* MLK_ARITH_BACKEND_PPC64LE_DEFAULT && \ - !MLK_CONFIG_MULTILEVEL_NO_SHARED && __POWER8_VECTOR__ */ + !MLK_CONFIG_MULTILEVEL_NO_SHARED */ diff --git a/mlkem/src/native/ppc64le/src/mlkem_intt_ppc_asm.S b/mlkem/src/native/ppc64le/src/mlkem_intt_ppc_asm.S index cd6929f6ac..e665bc0da2 100644 --- a/mlkem/src/native/ppc64le/src/mlkem_intt_ppc_asm.S +++ b/mlkem/src/native/ppc64le/src/mlkem_intt_ppc_asm.S @@ -8,7 +8,7 @@ #include "../../../common.h" #if defined(MLK_ARITH_BACKEND_PPC64LE_DEFAULT) && \ - !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && defined(__POWER8_VECTOR__) && \ + !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && \ (!defined(MLK_CONFIG_NO_ENCAPS_API) || \ !defined(MLK_CONFIG_NO_DECAPS_API)) /*yaml @@ -18,7 +18,7 @@ ABI: Architecture: powerpc64le CallingConvention: ELFv2 - Features: [VSX] + Features: [POWER8_VECTOR] r3: type: buffer size_bytes: 512 @@ -3238,8 +3238,7 @@ mlk_intt_ppc_asm_Loopf: MLK_ASM_FN_SIZE(intt_ppc_asm) #endif /* MLK_ARITH_BACKEND_PPC64LE_DEFAULT && !MLK_CONFIG_MULTILEVEL_NO_SHARED \ - && __POWER8_VECTOR__ && (!MLK_CONFIG_NO_ENCAPS_API || \ - !MLK_CONFIG_NO_DECAPS_API) */ + && (!MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API) */ #if defined(__ELF__) .section .note.GNU-stack,"",%progbits diff --git a/mlkem/src/native/ppc64le/src/mlkem_ntt_ppc_asm.S b/mlkem/src/native/ppc64le/src/mlkem_ntt_ppc_asm.S index 09ec84a966..cd9c7b810a 100644 --- a/mlkem/src/native/ppc64le/src/mlkem_ntt_ppc_asm.S +++ b/mlkem/src/native/ppc64le/src/mlkem_ntt_ppc_asm.S @@ -8,7 +8,7 @@ #include "../../../common.h" #if defined(MLK_ARITH_BACKEND_PPC64LE_DEFAULT) && \ - !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && defined(__POWER8_VECTOR__) + !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) /*yaml Name: ntt_ppc_asm Description: PowerPC64 VSX forward NTT @@ -16,7 +16,7 @@ ABI: Architecture: powerpc64le CallingConvention: ELFv2 - Features: [VSX] + Features: [POWER8_VECTOR] r3: type: buffer size_bytes: 512 @@ -1665,7 +1665,7 @@ MLK_ASM_FN_SYMBOL(ntt_ppc_asm) MLK_ASM_FN_SIZE(ntt_ppc_asm) #endif /* MLK_ARITH_BACKEND_PPC64LE_DEFAULT && !MLK_CONFIG_MULTILEVEL_NO_SHARED \ - && __POWER8_VECTOR__ */ + */ #if defined(__ELF__) .section .note.GNU-stack,"",%progbits diff --git a/mlkem/src/native/ppc64le/src/mlkem_poly_tomont_ppc_asm.S b/mlkem/src/native/ppc64le/src/mlkem_poly_tomont_ppc_asm.S index 3e430638d3..7a9be58fa3 100644 --- a/mlkem/src/native/ppc64le/src/mlkem_poly_tomont_ppc_asm.S +++ b/mlkem/src/native/ppc64le/src/mlkem_poly_tomont_ppc_asm.S @@ -15,7 +15,7 @@ #include "../../../common.h" #if defined(MLK_ARITH_BACKEND_PPC64LE_DEFAULT) && \ - !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && defined(__POWER8_VECTOR__) && \ + !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && \ !defined(MLK_CONFIG_NO_KEYPAIR_API) /*yaml Name: poly_tomont_ppc_asm @@ -24,7 +24,7 @@ ABI: Architecture: powerpc64le CallingConvention: ELFv2 - Features: [VSX] + Features: [POWER8_VECTOR] r3: type: buffer size_bytes: 512 @@ -309,7 +309,7 @@ MLK_ASM_FN_SYMBOL(poly_tomont_ppc_asm) MLK_ASM_FN_SIZE(poly_tomont_ppc_asm) #endif /* MLK_ARITH_BACKEND_PPC64LE_DEFAULT && !MLK_CONFIG_MULTILEVEL_NO_SHARED \ - && __POWER8_VECTOR__ && !MLK_CONFIG_NO_KEYPAIR_API */ + && !MLK_CONFIG_NO_KEYPAIR_API */ #if defined(__ELF__) .section .note.GNU-stack,"",%progbits diff --git a/mlkem/src/native/ppc64le/src/mlkem_reduce_ppc_asm.S b/mlkem/src/native/ppc64le/src/mlkem_reduce_ppc_asm.S index e82376c74b..c3fffcf3f4 100644 --- a/mlkem/src/native/ppc64le/src/mlkem_reduce_ppc_asm.S +++ b/mlkem/src/native/ppc64le/src/mlkem_reduce_ppc_asm.S @@ -7,7 +7,7 @@ */ #include "../../../common.h" #if defined(MLK_ARITH_BACKEND_PPC64LE_DEFAULT) && \ - !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && defined(__POWER8_VECTOR__) + !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) /*yaml Name: reduce_ppc_asm Description: PowerPC64 VSX modular reduction @@ -15,7 +15,7 @@ ABI: Architecture: powerpc64le CallingConvention: ELFv2 - Features: [VSX] + Features: [POWER8_VECTOR] r3: type: buffer size_bytes: 512 @@ -724,7 +724,7 @@ MLK_ASM_FN_SYMBOL(reduce_ppc_asm) MLK_ASM_FN_SIZE(reduce_ppc_asm) #endif /* MLK_ARITH_BACKEND_PPC64LE_DEFAULT && !MLK_CONFIG_MULTILEVEL_NO_SHARED \ - && __POWER8_VECTOR__ */ + */ #if defined(__ELF__) .section .note.GNU-stack,"",%progbits diff --git a/mlkem/src/sys.h b/mlkem/src/sys.h index b93882257e..5b65630106 100644 --- a/mlkem/src/sys.h +++ b/mlkem/src/sys.h @@ -74,6 +74,14 @@ #define MLK_SYS_PPC64LE #endif +/* Check if the PPC64LE compilation target supports the vector instructions + * used by the POWER8 backend: AltiVec/VMX, VSX, and POWER8 vector extensions + * (Power ISA 2.07). AltiVec predates POWER8; VSX was introduced in POWER7. */ +#if defined(MLK_SYS_PPC64LE) && defined(__ALTIVEC__) && defined(__VSX__) && \ + defined(__POWER8_VECTOR__) +#define MLK_SYS_PPC64LE_POWER8_VECTOR +#endif + #if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 64 #define MLK_SYS_RISCV64 #endif @@ -281,7 +289,10 @@ typedef enum MLK_SYS_CAP_AARCH64_NEON, MLK_SYS_CAP_AARCH64_SHA3, /* Armv8.1-M */ - MLK_SYS_CAP_ARMV81M_MVE + MLK_SYS_CAP_ARMV81M_MVE, + /* PowerPC64 */ + /* AltiVec/VMX, VSX, and POWER8 vector extensions (Power ISA 2.07). */ + MLK_SYS_CAP_PPC64LE_POWER8_VECTOR } mlk_sys_cap; #endif /* !__ASSEMBLER__ */ diff --git a/scripts/autogen b/scripts/autogen index 2b1ab95284..cf47c21a8e 100755 --- a/scripts/autogen +++ b/scripts/autogen @@ -2276,7 +2276,7 @@ def gen_ppc64le_zeta_files(): yield '#include "../../../common.h"' yield "" yield "#if defined(MLK_ARITH_BACKEND_PPC64LE_DEFAULT) && \\" - yield " !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && defined(__POWER8_VECTOR__)" + yield " !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED)" yield "" yield '#include "consts.h"' yield "" @@ -2288,7 +2288,7 @@ def gen_ppc64le_zeta_files(): def gen_c_epilogue(): yield "" yield "#endif /* MLK_ARITH_BACKEND_PPC64LE_DEFAULT && \\" - yield " !MLK_CONFIG_MULTILEVEL_NO_SHARED && __POWER8_VECTOR__ */" + yield " !MLK_CONFIG_MULTILEVEL_NO_SHARED */" yield "" # dev copy: one array, annotated per region, LANES values per line. @@ -2954,6 +2954,7 @@ def get_syscaps(): "MLK_SYS_CAP_AARCH64_NEON", "MLK_SYS_CAP_AARCH64_SHA3", "MLK_SYS_CAP_ARMV81M_MVE", + "MLK_SYS_CAP_PPC64LE_POWER8_VECTOR", ] @@ -4916,14 +4917,14 @@ ABI_CAPS = { "mlkem/src/fips202/native/armv81m/src/keccak_f1600_x4_state_xor_bytes_mve.S", ], }, - # VSX is build-time only: every ppc64le kernel requires it, the call - # stub saves vr20-vr31 unconditionally, and we never run the binary on - # a non-VSX host. No #if guard, no syscap. - "VSX": { + # NTT/INTT use the POWER8 vector merges vmrgew/vmrgow (ISA 2.07). + # AltiVec predates POWER8, and VSX was introduced in POWER7. + # All current PPC64 kernels and ABI stubs share the backend's guard. + "POWER8_VECTOR": { "asm_subdir": "ppc64le", - "guard": None, - "syscap": None, - "description": "PPC64 VSX/Altivec (POWER8)", + "guard": "MLK_SYS_PPC64LE_POWER8_VECTOR", + "syscap": "MLK_SYS_CAP_PPC64LE_POWER8_VECTOR", + "description": "AltiVec/VSX and POWER8 vector extensions (Power ISA 2.07)", "cflags": ["-mcpu=power8", "-maltivec", "-mvsx"], "aux_files": [ "test/abicheck/ppc64le/callstub_ppc64le.S", @@ -5228,7 +5229,7 @@ def gen_abicheck(): # Emit a runtime mlk_sys_check_capability() skip (returning # MLK_ABICHECK_SKIPPED) per Features cap that has a syscap; caps - # without a syscap (build-time-only, e.g. PPC64 VSX) are no-ops here. + # without a syscap are no-ops here. # Emitted after the buffer decls to keep C90 mixed-decl-and-code happy. for cap in features: cap_enum = ABI_CAPS[cap]["syscap"] diff --git a/test/abicheck/README.md b/test/abicheck/README.md index ba6cd7c81f..c83e1a13f7 100644 --- a/test/abicheck/README.md +++ b/test/abicheck/README.md @@ -31,8 +31,10 @@ Before trusting any verdict, `abicheck.c` runs a self-test: hand-written corrupters (`/selftest_.S`) that each clobber one callee-saved register, confirming the checker fires. -The `mlkem/src/.../*.S` sources are assembled directly. On unsupported -architectures the registry is empty and the driver exits cleanly. +The `mlkem/src/.../*.S` sources are assembled directly. Compile-time feature +guards select which checks are registered; a check is skipped if +`mlk_sys_check_capability()` reports a required feature as unavailable. +On unsupported architectures the registry is empty and the driver exits cleanly. ## Code generation diff --git a/test/abicheck/ppc64le/abicheck_ppc64le.mk b/test/abicheck/ppc64le/abicheck_ppc64le.mk index 7e32c0bc57..acc89c0360 100644 --- a/test/abicheck/ppc64le/abicheck_ppc64le.mk +++ b/test/abicheck/ppc64le/abicheck_ppc64le.mk @@ -14,15 +14,15 @@ # Default each cap's file list to empty so the unconditional appends # below are safe even when a cap has no kernels on this arch. -ABICHECK_REQ_VSX_FILES := +ABICHECK_REQ_POWER8_VECTOR_FILES := -# VSX: PPC64 VSX/Altivec (POWER8) -ABICHECK_REQ_VSX_FILES := \ +# POWER8_VECTOR: AltiVec/VSX and POWER8 vector extensions (Power ISA 2.07) +ABICHECK_REQ_POWER8_VECTOR_FILES := \ mlkem/src/native/ppc64le/src/mlkem_intt_ppc_asm.S \ mlkem/src/native/ppc64le/src/mlkem_ntt_ppc_asm.S \ mlkem/src/native/ppc64le/src/mlkem_poly_tomont_ppc_asm.S \ mlkem/src/native/ppc64le/src/mlkem_reduce_ppc_asm.S \ test/abicheck/ppc64le/callstub_ppc64le.S \ test/abicheck/ppc64le/selftest_ppc64le.S -ABICHECK_REQ_VSX_OBJS := $(call MAKE_OBJS,$(ABICHECK_DIR),$(ABICHECK_REQ_VSX_FILES)) -$(ABICHECK_REQ_VSX_OBJS): CFLAGS += -mcpu=power8 -maltivec -mvsx +ABICHECK_REQ_POWER8_VECTOR_OBJS := $(call MAKE_OBJS,$(ABICHECK_DIR),$(ABICHECK_REQ_POWER8_VECTOR_FILES)) +$(ABICHECK_REQ_POWER8_VECTOR_OBJS): CFLAGS += -mcpu=power8 -maltivec -mvsx diff --git a/test/abicheck/ppc64le/callstub_ppc64le.S b/test/abicheck/ppc64le/callstub_ppc64le.S index 31c14fcd42..caa373d6f2 100644 --- a/test/abicheck/ppc64le/callstub_ppc64le.S +++ b/test/abicheck/ppc64le/callstub_ppc64le.S @@ -29,6 +29,10 @@ * CR2-CR4, and LR. */ +#include "../../../mlkem/src/sys.h" + +#if defined(MLK_SYS_PPC64LE_POWER8_VECTOR) + #define ST_GPR_ARG 0 /* r3-r10 */ #define ST_GPR_NV 64 /* r14-r31 */ #define ST_FPR 208 /* f14-f31 */ @@ -456,6 +460,8 @@ asm_call_stub_ppc64le: blr .cfi_endproc +#endif /* MLK_SYS_PPC64LE_POWER8_VECTOR */ + #if defined(__ELF__) .section .note.GNU-stack, "", @progbits #endif diff --git a/test/abicheck/ppc64le/checks/check_intt_ppc_asm.c b/test/abicheck/ppc64le/checks/check_intt_ppc_asm.c index 995f83a677..3f75fe2a2c 100644 --- a/test/abicheck/ppc64le/checks/check_intt_ppc_asm.c +++ b/test/abicheck/ppc64le/checks/check_intt_ppc_asm.c @@ -14,7 +14,7 @@ #include "../abicheck_ppc64le.h" #include "../checks_ppc64le_all.h" -#if defined(MLK_SYS_PPC64LE) +#if defined(MLK_SYS_PPC64LE) && defined(MLK_SYS_PPC64LE_POWER8_VECTOR) #include "../../../notrandombytes/notrandombytes.h" @@ -30,6 +30,14 @@ int check_intt_ppc_asm(void) MLK_ALIGN uint8_t buf_r3[512]; /* Input/output polynomial (256 x int16_t) */ MLK_ALIGN uint8_t buf_r4[4144]; /* Precomputed constants (2072 x int16_t) */ + if (!mlk_sys_check_capability(MLK_SYS_CAP_PPC64LE_POWER8_VECTOR)) + { + fprintf(stderr, + "ABI check intt_ppc_asm: host lacks AltiVec/VSX and POWER8 vector " + "extensions (Power ISA 2.07), skipping\n"); + return MLK_ABICHECK_SKIPPED; + } + for (test_iter = 0; test_iter < MLK_ABICHECK_NUM_TESTS; test_iter++) { /* Initialize random register state */ @@ -62,4 +70,4 @@ int check_intt_ppc_asm(void) return MLK_ABICHECK_PASSED; } -#endif /* MLK_SYS_PPC64LE */ +#endif /* MLK_SYS_PPC64LE && MLK_SYS_PPC64LE_POWER8_VECTOR */ diff --git a/test/abicheck/ppc64le/checks/check_ntt_ppc_asm.c b/test/abicheck/ppc64le/checks/check_ntt_ppc_asm.c index 40dab3e356..5a2565fe82 100644 --- a/test/abicheck/ppc64le/checks/check_ntt_ppc_asm.c +++ b/test/abicheck/ppc64le/checks/check_ntt_ppc_asm.c @@ -14,7 +14,7 @@ #include "../abicheck_ppc64le.h" #include "../checks_ppc64le_all.h" -#if defined(MLK_SYS_PPC64LE) +#if defined(MLK_SYS_PPC64LE) && defined(MLK_SYS_PPC64LE_POWER8_VECTOR) #include "../../../notrandombytes/notrandombytes.h" @@ -30,6 +30,14 @@ int check_ntt_ppc_asm(void) MLK_ALIGN uint8_t buf_r3[512]; /* Input/output polynomial (256 x int16_t) */ MLK_ALIGN uint8_t buf_r4[4144]; /* Precomputed constants (2072 x int16_t) */ + if (!mlk_sys_check_capability(MLK_SYS_CAP_PPC64LE_POWER8_VECTOR)) + { + fprintf(stderr, + "ABI check ntt_ppc_asm: host lacks AltiVec/VSX and POWER8 vector " + "extensions (Power ISA 2.07), skipping\n"); + return MLK_ABICHECK_SKIPPED; + } + for (test_iter = 0; test_iter < MLK_ABICHECK_NUM_TESTS; test_iter++) { /* Initialize random register state */ @@ -61,4 +69,4 @@ int check_ntt_ppc_asm(void) return MLK_ABICHECK_PASSED; } -#endif /* MLK_SYS_PPC64LE */ +#endif /* MLK_SYS_PPC64LE && MLK_SYS_PPC64LE_POWER8_VECTOR */ diff --git a/test/abicheck/ppc64le/checks/check_poly_tomont_ppc_asm.c b/test/abicheck/ppc64le/checks/check_poly_tomont_ppc_asm.c index 69d43e2b3c..cb6c2caf44 100644 --- a/test/abicheck/ppc64le/checks/check_poly_tomont_ppc_asm.c +++ b/test/abicheck/ppc64le/checks/check_poly_tomont_ppc_asm.c @@ -14,7 +14,7 @@ #include "../abicheck_ppc64le.h" #include "../checks_ppc64le_all.h" -#if defined(MLK_SYS_PPC64LE) +#if defined(MLK_SYS_PPC64LE) && defined(MLK_SYS_PPC64LE_POWER8_VECTOR) #include "../../../notrandombytes/notrandombytes.h" @@ -30,6 +30,14 @@ int check_poly_tomont_ppc_asm(void) MLK_ALIGN uint8_t buf_r3[512]; /* Input/output polynomial (256 x int16_t) */ MLK_ALIGN uint8_t buf_r4[4144]; /* Precomputed constants (2072 x int16_t) */ + if (!mlk_sys_check_capability(MLK_SYS_CAP_PPC64LE_POWER8_VECTOR)) + { + fprintf(stderr, + "ABI check poly_tomont_ppc_asm: host lacks AltiVec/VSX and POWER8 " + "vector extensions (Power ISA 2.07), skipping\n"); + return MLK_ABICHECK_SKIPPED; + } + for (test_iter = 0; test_iter < MLK_ABICHECK_NUM_TESTS; test_iter++) { /* Initialize random register state */ @@ -62,4 +70,4 @@ int check_poly_tomont_ppc_asm(void) return MLK_ABICHECK_PASSED; } -#endif /* MLK_SYS_PPC64LE */ +#endif /* MLK_SYS_PPC64LE && MLK_SYS_PPC64LE_POWER8_VECTOR */ diff --git a/test/abicheck/ppc64le/checks/check_reduce_ppc_asm.c b/test/abicheck/ppc64le/checks/check_reduce_ppc_asm.c index c5bbafed9b..f4583760ba 100644 --- a/test/abicheck/ppc64le/checks/check_reduce_ppc_asm.c +++ b/test/abicheck/ppc64le/checks/check_reduce_ppc_asm.c @@ -14,7 +14,7 @@ #include "../abicheck_ppc64le.h" #include "../checks_ppc64le_all.h" -#if defined(MLK_SYS_PPC64LE) +#if defined(MLK_SYS_PPC64LE) && defined(MLK_SYS_PPC64LE_POWER8_VECTOR) #include "../../../notrandombytes/notrandombytes.h" @@ -30,6 +30,14 @@ int check_reduce_ppc_asm(void) MLK_ALIGN uint8_t buf_r3[512]; /* Input/output polynomial (256 x int16_t) */ MLK_ALIGN uint8_t buf_r4[4144]; /* Precomputed constants (2072 x int16_t) */ + if (!mlk_sys_check_capability(MLK_SYS_CAP_PPC64LE_POWER8_VECTOR)) + { + fprintf(stderr, + "ABI check reduce_ppc_asm: host lacks AltiVec/VSX and POWER8 " + "vector extensions (Power ISA 2.07), skipping\n"); + return MLK_ABICHECK_SKIPPED; + } + for (test_iter = 0; test_iter < MLK_ABICHECK_NUM_TESTS; test_iter++) { /* Initialize random register state */ @@ -62,4 +70,4 @@ int check_reduce_ppc_asm(void) return MLK_ABICHECK_PASSED; } -#endif /* MLK_SYS_PPC64LE */ +#endif /* MLK_SYS_PPC64LE && MLK_SYS_PPC64LE_POWER8_VECTOR */ diff --git a/test/abicheck/ppc64le/checks_ppc64le_all.h b/test/abicheck/ppc64le/checks_ppc64le_all.h index de497c488d..0c23aaf539 100644 --- a/test/abicheck/ppc64le/checks_ppc64le_all.h +++ b/test/abicheck/ppc64le/checks_ppc64le_all.h @@ -18,16 +18,20 @@ #if defined(MLK_SYS_PPC64LE) +#if defined(MLK_SYS_PPC64LE_POWER8_VECTOR) int check_intt_ppc_asm(void); int check_ntt_ppc_asm(void); int check_poly_tomont_ppc_asm(void); int check_reduce_ppc_asm(void); +#endif /* MLK_SYS_PPC64LE_POWER8_VECTOR */ static const abicheck_entry_t all_checks[] = { +#if defined(MLK_SYS_PPC64LE_POWER8_VECTOR) {"intt_ppc_asm", check_intt_ppc_asm}, {"ntt_ppc_asm", check_ntt_ppc_asm}, {"poly_tomont_ppc_asm", check_poly_tomont_ppc_asm}, {"reduce_ppc_asm", check_reduce_ppc_asm}, +#endif /* MLK_SYS_PPC64LE_POWER8_VECTOR */ {NULL, NULL} /* Sentinel */ }; diff --git a/test/abicheck/ppc64le/selftest_ppc64le.S b/test/abicheck/ppc64le/selftest_ppc64le.S index b68ecfefb8..633871cff3 100644 --- a/test/abicheck/ppc64le/selftest_ppc64le.S +++ b/test/abicheck/ppc64le/selftest_ppc64le.S @@ -12,10 +12,14 @@ * input. */ +#include "../../../mlkem/src/sys.h" + #if defined(__ELF__) .section .note.GNU-stack,"",@progbits #endif +#if defined(MLK_SYS_PPC64LE_POWER8_VECTOR) + .text .machine power8 .abiversion 2 @@ -118,3 +122,5 @@ define_local \name corrupt_cr selftest_ppc64le_corrupt_cr2, 8 corrupt_cr selftest_ppc64le_corrupt_cr3, 12 corrupt_cr selftest_ppc64le_corrupt_cr4, 16 + +#endif /* MLK_SYS_PPC64LE_POWER8_VECTOR */ diff --git a/test/abicheck/selftest.c b/test/abicheck/selftest.c index ce4a05e869..d631a4e7d9 100644 --- a/test/abicheck/selftest.c +++ b/test/abicheck/selftest.c @@ -175,7 +175,7 @@ static const selftest_entry_t x86_64_entries[] = { {NULL, NULL, 0}, }; -#elif defined(MLK_SYS_PPC64LE) +#elif defined(MLK_SYS_PPC64LE_POWER8_VECTOR) extern void selftest_ppc64le_noop(void); /* GPRs r14..r31 (18) */ @@ -325,7 +325,7 @@ static const selftest_entry_t armv81m_entries[] = { }; #endif /* !MLK_SYS_AARCH64 && !(MLK_SYS_X86_64 && MLK_SYSV_ABI_SUPPORTED) && \ - !MLK_SYS_PPC64LE && MLK_SYS_ARMV81M_MVE */ + !MLK_SYS_PPC64LE_POWER8_VECTOR && MLK_SYS_ARMV81M_MVE */ int abicheck_selftest(void) { @@ -354,21 +354,26 @@ int abicheck_selftest(void) asm_call_stub_x86_64_sysv, check_x86_64_sysv_compliance, x86_64_entries, (MLK_SYSV_ABI void (*)(void))); -#elif defined(MLK_SYS_PPC64LE) - SELFTEST_RUN_ARCH("ppc64le", struct ppc64le_register_state, - init_ppc64le_register_state, asm_call_stub_ppc64le, - check_ppc64le_elfv2_compliance, ppc64le_entries, - (void (*)(void))); +#elif defined(MLK_SYS_PPC64LE_POWER8_VECTOR) + /* The call stub saves vector registers. Keep the self-test's capability + * check aligned with the current backend's POWER8 minimum. */ + if (mlk_sys_check_capability(MLK_SYS_CAP_PPC64LE_POWER8_VECTOR)) + { + SELFTEST_RUN_ARCH("ppc64le", struct ppc64le_register_state, + init_ppc64le_register_state, asm_call_stub_ppc64le, + check_ppc64le_elfv2_compliance, ppc64le_entries, + (void (*)(void))); + } #elif defined(MLK_SYS_ARMV81M_MVE) SELFTEST_RUN_ARCH("armv81m", struct armv81m_register_state, init_armv81m_register_state, asm_call_stub_armv81m, check_armv81m_aapcs32_compliance, armv81m_entries, (void (*)(void))); #else /* !MLK_SYS_AARCH64 && !(MLK_SYS_X86_64 && MLK_SYSV_ABI_SUPPORTED) && \ - !MLK_SYS_PPC64LE && MLK_SYS_ARMV81M_MVE */ + !MLK_SYS_PPC64LE_POWER8_VECTOR && MLK_SYS_ARMV81M_MVE */ /* No abicheck support on this architecture. */ #endif /* !MLK_SYS_AARCH64 && !(MLK_SYS_X86_64 && MLK_SYSV_ABI_SUPPORTED) && \ - !MLK_SYS_PPC64LE && !MLK_SYS_ARMV81M_MVE */ + !MLK_SYS_PPC64LE_POWER8_VECTOR && !MLK_SYS_ARMV81M_MVE */ return failures; }