Commit c690101d for xz
commit c690101dddd784b75224a8935f56cd163d3e90a3
Author: Lasse Collin <lasse.collin@tukaani.org>
Date: Wed Dec 10 16:49:55 2025 +0200
tuklib_integer: Autodetect when -mstrict-align is used with GCC on ARM64
On ARM64, support for fast unaligned memory access was autodetected by
checking if __ARM_FEATURE_UNALIGNED is defined. However, at least GCC
versions up to 15.2.0 define the macro even when -mstrict-align has
been specified. Thus, autodetection with GCC doesn't work correctly,
and binaries built using -mstrict-align can be much slower than they
need to be, unless the user also passes --disable-unaligned-access
to configure or -DTUKLIB_FAST_UNALIGNED_ACCESS=OFF to cmake.
See the GCC bug:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111555
Workaround the issue by using heuristics with GCC on ARM64.
With Clang, the detection using __ARM_FEATURE_UNALIGNED works.
It also works with GCC on 32-bit ARM.
Fixes: e5f13a66567b ("tuklib_integer: Autodetect support for unaligned access on ARM.")
diff --git a/cmake/tuklib_integer.cmake b/cmake/tuklib_integer.cmake
index e2d6c71d..c2cd04e4 100644
--- a/cmake/tuklib_integer.cmake
+++ b/cmake/tuklib_integer.cmake
@@ -159,24 +159,16 @@ function(tuklib_integer TARGET_OR_ALL)
set(FAST_UNALIGNED_GUESS ON)
endif()
- elseif(PROCESSOR MATCHES "^arm|^aarch64|^riscv")
- # On 32-bit and 64-bit ARM, GCC and Clang
- # #define __ARM_FEATURE_UNALIGNED if
- # unaligned access is supported.
- #
- # Exception: GCC at least up to 13.2.0
- # defines it even when using -mstrict-align
- # so in that case this autodetection goes wrong.
- # Most of the time -mstrict-align isn't used so it
- # shouldn't be a common problem in practice. See:
- # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111555
+ elseif(PROCESSOR MATCHES "^arm|^riscv" AND NOT PROCESSOR MATCHES "^arm64")
+ # On 32-bit ARM, GCC and Clang # #define __ARM_FEATURE_UNALIGNED
+ # if and only if unaligned access is supported.
#
# RISC-V C API Specification says that if
# __riscv_misaligned_fast is defined then
# unaligned access is known to be fast.
#
# MSVC is handled as a special case: We assume that
- # 32/64-bit ARM supports fast unaligned access.
+ # 32-bit ARM supports fast unaligned access.
# If MSVC gets RISC-V support then this will assume
# fast unaligned access on RISC-V too.
check_c_source_compiles("
@@ -192,6 +184,53 @@ function(tuklib_integer TARGET_OR_ALL)
set(FAST_UNALIGNED_GUESS ON)
endif()
+ elseif(PROCESSOR MATCHES "^aarch64|^arm64")
+ # On ARM64, Clang defines __ARM_FEATURE_UNALIGNED if and only if
+ # unaligned access is supported. However, GCC (at least up to 15.2.0)
+ # defines it even when using -mstrict-align, so autodetection with
+ # this macro doesn't work with GCC on ARM64. (It does work on
+ # 32-bit ARM.) See:
+ #
+ # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111555
+ #
+ # We need three checks:
+ #
+ # 1. If __ARM_FEATURE_UNALIGNED is defined and the
+ # compiler isn't GCC, unaligned access is enabled.
+ # If the compiler is MSVC, unaligned access is
+ # enabled even without __ARM_FEATURE_UNALIGNED.
+ check_c_source_compiles("
+ #if defined(__ARM_FEATURE_UNALIGNED) \
+ && (!defined(__GNUC__) || defined(__clang__))
+ #elif defined(_MSC_VER)
+ #else
+ compile error
+ #endif
+ int main(void) { return 0; }
+ "
+ TUKLIB_FAST_UNALIGNED_DEFINED_BY_PREPROCESSOR)
+ if(TUKLIB_FAST_UNALIGNED_DEFINED_BY_PREPROCESSOR)
+ set(FAST_UNALIGNED_GUESS ON)
+ else()
+ # 2. If __ARM_FEATURE_UNALIGNED is not defined,
+ # unaligned access is disabled.
+ check_c_source_compiles("
+ #ifdef __ARM_FEATURE_UNALIGNED
+ compile error
+ #endif
+ int main(void) { return 0; }
+ "
+ TUKLIB_FAST_UNALIGNED_NOT_DEFINED_BY_PREPROCESSOR)
+ if(NOT TUKLIB_FAST_UNALIGNED_NOT_DEFINED_BY_PREPROCESSOR)
+ # 3. Use heuristics to detect if -mstrict-align is
+ # in effect when building with GCC.
+ tuklib_integer_internal_strict_align("[ \t]ldrb[ \t]")
+ if(NOT TUKLIB_INTEGER_STRICT_ALIGN)
+ set(FAST_UNALIGNED_GUESS ON)
+ endif()
+ endif()
+ endif()
+
elseif(PROCESSOR MATCHES "^loongarch")
tuklib_integer_internal_strict_align("[ \t]ld\\.bu[ \t]")
if(NOT TUKLIB_INTEGER_STRICT_ALIGN)
diff --git a/m4/tuklib_integer.m4 b/m4/tuklib_integer.m4
index a3128a20..29f2c95f 100644
--- a/m4/tuklib_integer.m4
+++ b/m4/tuklib_integer.m4
@@ -130,34 +130,74 @@ if test "x$enable_unaligned_access" = xauto ; then
i?86|x86_64|powerpc|powerpc64|powerpc64le)
enable_unaligned_access=yes
;;
- arm*|aarch64*|riscv*)
- # On 32-bit and 64-bit ARM, GCC and Clang
- # #define __ARM_FEATURE_UNALIGNED if
- # unaligned access is supported.
- #
- # Exception: GCC at least up to 13.2.0
- # defines it even when using -mstrict-align
- # so in that case this autodetection goes wrong.
- # Most of the time -mstrict-align isn't used so it
- # shouldn't be a common problem in practice. See:
- # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111555
+ arm*|riscv*)
+ # On 32-bit ARM, GCC and Clang
+ # #define __ARM_FEATURE_UNALIGNED
+ # if and only if unaligned access is supported.
#
# RISC-V C API Specification says that if
# __riscv_misaligned_fast is defined then
# unaligned access is known to be fast.
#
# MSVC is handled as a special case: We assume that
- # 32/64-bit ARM supports fast unaligned access.
+ # 32-bit ARM supports fast unaligned access.
# If MSVC gets RISC-V support then this will assume
# fast unaligned access on RISC-V too.
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
-#if !defined(__ARM_FEATURE_UNALIGNED) \
- && !defined(__riscv_misaligned_fast) \
- && !defined(_MSC_VER)
-compile error
-#endif
-int main(void) { return 0; }
-])], [enable_unaligned_access=yes], [enable_unaligned_access=no])
+ #if !defined(__ARM_FEATURE_UNALIGNED) \
+ && !defined(__riscv_misaligned_fast) \
+ && !defined(_MSC_VER)
+ compile error
+ #endif
+ int main(void) { return 0; }
+ ])],
+ [enable_unaligned_access=yes],
+ [enable_unaligned_access=no])
+ ;;
+ aarch64*)
+ # On ARM64, Clang defines __ARM_FEATURE_UNALIGNED
+ # if and only if unaligned access is supported.
+ # However, GCC (at least up to 15.2.0) defines it
+ # even when using -mstrict-align, so autodetection
+ # with this macro doesn't work with GCC on ARM64.
+ # (It does work on 32-bit ARM.) See:
+ #
+ # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111555
+ #
+ # We need three checks:
+ #
+ # 1. If __ARM_FEATURE_UNALIGNED is defined and the
+ # compiler isn't GCC, unaligned access is enabled.
+ # If the compiler is MSVC, unaligned access is
+ # enabled even without __ARM_FEATURE_UNALIGNED.
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([
+ #if defined(__ARM_FEATURE_UNALIGNED) \
+ && (!defined(__GNUC__) \
+ || defined(__clang__))
+ #elif defined(_MSC_VER)
+ #else
+ compile error
+ #endif
+ int main(void) { return 0; }
+ ])], [enable_unaligned_access=yes])
+
+ # 2. If __ARM_FEATURE_UNALIGNED is not defined,
+ # unaligned access is disabled.
+ if test "x$enable_unaligned_access" = xauto ; then
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([
+ #ifdef __ARM_FEATURE_UNALIGNED
+ compile error
+ #endif
+ int main(void) { return 0; }
+ ])], [enable_unaligned_access=no])
+ fi
+
+ # 3. Use heuristics to detect if -mstrict-align is
+ # in effect when building with GCC.
+ if test "x$enable_unaligned_access" = xauto ; then
+ [tuklib_integer_strict_align \
+ '[[:blank:]]ldrb[[:blank:]]']
+ fi
;;
loongarch*)
# See sections 7.4, 8.1, and 8.2: