Skip to content

Commit 5a427e7

Browse files
committed
Intel x64 ASM: intrinsic output
Add another implementation of the assembly code for Intel x64 that uses intrinsics and C code.
1 parent c5c63c0 commit 5a427e7

23 files changed

Lines changed: 349982 additions & 31 deletions

CMakeLists.txt

Lines changed: 145 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2177,8 +2177,7 @@ else()
21772177
endif()
21782178
endif()
21792179

2180-
# TODO: - AES-XTS
2181-
# - Web server
2180+
# TODO: - Web server
21822181
# - Web client
21832182
add_option("WOLFSSL_CMAC"
21842183
"Enable CMAC (default: disabled)"
@@ -2763,10 +2762,128 @@ if("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "x86_64|AMD64")
27632762
set(WOLFSSL_X86_64_BUILD ON)
27642763
add_option("WOLFSSL_X86_64_BUILD_ASM" "Build ASM files" "yes" "yes;no")
27652764
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_X86_64_BUILD")
2765+
elseif("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "^(i[3-6]86|x86)$")
2766+
# 32-bit x86. The distinction matters beyond the define: the AES-GCM
2767+
# speedup has its OWN assembly there (aes_gcm_x86_asm.S) rather than a
2768+
# 32-bit build of the x86-64 one, which is what BUILD_X86_ASM selects
2769+
# below - the same split autotools makes with ENABLED_X86_ASM.
2770+
set(WOLFSSL_X86_BUILD ON)
2771+
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_X86_BUILD")
27662772
elseif("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "aarch64|arm64")
27672773
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_AARCH64_BUILD")
27682774
endif()
27692775

2776+
# Intel assembly speedups. cmake/functions.cmake already selects the asm
2777+
# sources from this variable; declaring it makes it discoverable and gives it
2778+
# a default. USE_INTEL_SPEEDUP is what makes the C dispatch to those sources -
2779+
# without it they compile but nothing ever calls them.
2780+
add_option("WOLFSSL_INTEL_ASM"
2781+
"Enable Intel assembly speedups (default: disabled)"
2782+
"no" "yes;no")
2783+
2784+
if(WOLFSSL_INTEL_ASM)
2785+
list(APPEND WOLFSSL_DEFINITIONS "-DUSE_INTEL_SPEEDUP")
2786+
endif()
2787+
2788+
# AES-NI. Same shape: functions.cmake already reads WOLFSSL_AESNI to select
2789+
# the AES assembly, but WOLFSSL_AESNI has to reach the compiler as well or
2790+
# aes.c leaves every AES-NI path out and the assembly it does build is never
2791+
# called. --enable-intelasm implies it in the autotools build; match that.
2792+
add_option("WOLFSSL_AESNI"
2793+
"Enable AES-NI (default: disabled)"
2794+
"no" "yes;no")
2795+
2796+
if(WOLFSSL_AESNI OR WOLFSSL_INTEL_ASM)
2797+
# x86 only. Both the define and the -maes below are meaningless
2798+
# elsewhere, and -maes lands on CMAKE_C_FLAGS for the library AND every
2799+
# example and test target, so a cross compiler rejects the whole build.
2800+
# Fail with a clear message instead, as WOLFSSL_INTELASM_INTRINSICS and
2801+
# WOLFSSL_FALCON_ASM do below.
2802+
if(NOT WOLFSSL_X86_64_BUILD AND NOT WOLFSSL_X86_BUILD)
2803+
message(FATAL_ERROR
2804+
"WOLFSSL_AESNI / WOLFSSL_INTEL_ASM are x86 only")
2805+
endif()
2806+
set(WOLFSSL_AESNI "yes")
2807+
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_AESNI")
2808+
# aes.c uses AES-NI intrinsics directly in the key schedule, so the
2809+
# instructions have to be available to the compiler, not just to the
2810+
# assembler. A flag, not a define, so it goes on CMAKE_C_FLAGS rather
2811+
# than WOLFSSL_DEFINITIONS. This is an ISA the runtime dispatch already
2812+
# requires before calling in, so it does not widen what any dispatched
2813+
# routine may use.
2814+
if(NOT CMAKE_C_COMPILER_ID STREQUAL "MSVC")
2815+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maes")
2816+
endif()
2817+
endif()
2818+
2819+
# AES-XTS. The XTS assembly is wrapped in WOLFSSL_AES_XTS, so without this
2820+
# option the file is an empty translation unit.
2821+
add_option("WOLFSSL_AESXTS"
2822+
"Enable AES-XTS (default: disabled)"
2823+
"no" "yes;no")
2824+
2825+
if(WOLFSSL_AESXTS)
2826+
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_AES_XTS")
2827+
# --enable-aesxts also turns the streaming API on by default for
2828+
# non-ARMASM builds (configure.ac defaults ENABLED_AESXTS_STREAM from
2829+
# ENABLED_AESXTS). Without this, cmake -DWOLFSSL_AESXTS=yes silently
2830+
# gives a smaller API than the autotools equivalent - no
2831+
# wc_AesXtsEncryptInit/Update/Final - which breaks the documented
2832+
# --enable-foo == -DWOLFSSL_FOO=yes mapping.
2833+
if(NOT WOLFSSL_ARM_ASM)
2834+
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_AESXTS_STREAM")
2835+
endif()
2836+
endif()
2837+
2838+
# Build the Intel speedups from the generated C intrinsics rather than from
2839+
# the generated assembly. Both come out of one generator, so the two forms
2840+
# compute the same thing; the C form is visible to the optimiser, to LTO and
2841+
# to the sanitisers. Coverage is per algorithm - anything without an
2842+
# intrinsics translation keeps building from assembly.
2843+
# Falcon's floating-point backend. Falcon needs binary64 arithmetic that is
2844+
# bit-exact everywhere it runs, so the fpr layer is written in SSE2 rather
2845+
# than left to the compiler; this is autotools' --enable-falcon=asm. It is
2846+
# x86-64 only, and it selects a different fpr representation from the
2847+
# native-double backends, which is why those are mutually exclusive there.
2848+
add_option("WOLFSSL_FALCON_ASM"
2849+
"Build Falcon's fpr layer from the generated x86-64 assembly (default: disabled)"
2850+
"no" "yes;no")
2851+
2852+
if (WOLFSSL_FALCON_ASM)
2853+
if (NOT WOLFSSL_FALCON)
2854+
message(FATAL_ERROR "WOLFSSL_FALCON_ASM requires WOLFSSL_FALCON")
2855+
endif()
2856+
if (NOT WOLFSSL_X86_64_BUILD)
2857+
message(FATAL_ERROR "WOLFSSL_FALCON_ASM is x86-64 only")
2858+
endif()
2859+
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_FALCON_FPR_ASM")
2860+
set_wolfssl_definitions("WOLFSSL_FALCON_FPR_ASM" RESULT)
2861+
endif()
2862+
2863+
add_option("WOLFSSL_INTELASM_INTRINSICS"
2864+
"Build the x86-64 speedups from generated C intrinsics rather than assembly (default: disabled)"
2865+
"no" "yes;no")
2866+
2867+
if(WOLFSSL_INTELASM_INTRINSICS)
2868+
if(NOT WOLFSSL_INTEL_ASM)
2869+
message(FATAL_ERROR
2870+
"WOLFSSL_INTELASM_INTRINSICS requires WOLFSSL_INTEL_ASM")
2871+
endif()
2872+
if(NOT WOLFSSL_X86_64_BUILD)
2873+
message(FATAL_ERROR "WOLFSSL_INTELASM_INTRINSICS is x86-64 only")
2874+
endif()
2875+
# Unlike the assembly it replaces, this code is compiled, and CMake adds
2876+
# no -O of its own unless a build type asks for one. At -O0 the generated
2877+
# SHA-256 runs several times slower than the assembly rather than at
2878+
# parity, which reads as the intrinsics being slow instead of unoptimised.
2879+
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_C_FLAGS MATCHES "-O")
2880+
message(WARNING
2881+
"WOLFSSL_INTELASM_INTRINSICS with no CMAKE_BUILD_TYPE: the "
2882+
"generated C compiles unoptimised and will be far slower than "
2883+
"the assembly. Use -DCMAKE_BUILD_TYPE=Release.")
2884+
endif()
2885+
endif()
2886+
27702887
# SP math all
27712888
add_option("WOLFSSL_SP_MATH_ALL"
27722889
"Enable Single Precision math implementation for full algorithm suite (default: enabled)"
@@ -4223,6 +4340,32 @@ endif()
42234340

42244341
add_library(wolfssl::wolfssl ALIAS wolfssl)
42254342

4343+
# The generated x86-64 intrinsics are a literal transliteration of the assembly
4344+
# - one C statement per instruction - so their functions are enormous.
4345+
# Unoptimised, the compiler gives every intermediate its own stack slot and
4346+
# never reuses one: mlkem_encapsulate_avx512 gets a 718KB frame on gcc and
4347+
# 1.9MB on clang, enough to overflow a thread stack. At -O1 and above the slots
4348+
# are shared and the frame drops to about 2KB. CMake emits no -O at all when
4349+
# CMAKE_BUILD_TYPE is unset, which is the default, so force the level on just
4350+
# these sources - not on the rest of the library, whose flags stay the user's.
4351+
# Override with -DWOLFSSL_INTRIN_OPT=-O2 if you want a different level.
4352+
set(WOLFSSL_INTRIN_OPT "" CACHE STRING
4353+
"Optimisation flag for the generated *_intrin.c files (default -O1, /O1 on MSVC)")
4354+
if(NOT WOLFSSL_INTRIN_OPT)
4355+
if(MSVC)
4356+
set(WOLFSSL_INTRIN_OPT "/O1")
4357+
else()
4358+
set(WOLFSSL_INTRIN_OPT "-O1")
4359+
endif()
4360+
endif()
4361+
foreach(_intrin_src ${LIB_SOURCES})
4362+
if(_intrin_src MATCHES "_intrin\\.c$")
4363+
set_source_files_properties("${_intrin_src}" PROPERTIES
4364+
COMPILE_OPTIONS "${WOLFSSL_INTRIN_OPT}")
4365+
endif()
4366+
endforeach()
4367+
unset(_intrin_src)
4368+
42264369
if (NOT "$ENV{ARIA_DIR}" STREQUAL "")
42274370
message(STATUS "Found Environment variable ARIA_DIR=$ENV{ARIA_DIR}")
42284371
if(WOLFSSL_ARIA)

0 commit comments

Comments
 (0)