1
0
mirror of https://git.tukaani.org/xz.git synced 2025-12-17 10:58:45 +00:00

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.")
This commit is contained in:
Lasse Collin 2025-12-10 16:49:55 +02:00
parent d9b318f5b8
commit c690101ddd
No known key found for this signature in database
GPG Key ID: 38EE757D69184620
2 changed files with 110 additions and 31 deletions

View File

@ -159,24 +159,16 @@ function(tuklib_integer TARGET_OR_ALL)
set(FAST_UNALIGNED_GUESS ON) set(FAST_UNALIGNED_GUESS ON)
endif() endif()
elseif(PROCESSOR MATCHES "^arm|^aarch64|^riscv") elseif(PROCESSOR MATCHES "^arm|^riscv" AND NOT PROCESSOR MATCHES "^arm64")
# On 32-bit and 64-bit ARM, GCC and Clang # On 32-bit ARM, GCC and Clang # #define __ARM_FEATURE_UNALIGNED
# #define __ARM_FEATURE_UNALIGNED if # if and only if unaligned access is supported.
# 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
# #
# RISC-V C API Specification says that if # RISC-V C API Specification says that if
# __riscv_misaligned_fast is defined then # __riscv_misaligned_fast is defined then
# unaligned access is known to be fast. # unaligned access is known to be fast.
# #
# MSVC is handled as a special case: We assume that # 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 # If MSVC gets RISC-V support then this will assume
# fast unaligned access on RISC-V too. # fast unaligned access on RISC-V too.
check_c_source_compiles(" check_c_source_compiles("
@ -192,6 +184,53 @@ function(tuklib_integer TARGET_OR_ALL)
set(FAST_UNALIGNED_GUESS ON) set(FAST_UNALIGNED_GUESS ON)
endif() 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") elseif(PROCESSOR MATCHES "^loongarch")
tuklib_integer_internal_strict_align("[ \t]ld\\.bu[ \t]") tuklib_integer_internal_strict_align("[ \t]ld\\.bu[ \t]")
if(NOT TUKLIB_INTEGER_STRICT_ALIGN) if(NOT TUKLIB_INTEGER_STRICT_ALIGN)

View File

@ -130,24 +130,17 @@ if test "x$enable_unaligned_access" = xauto ; then
i?86|x86_64|powerpc|powerpc64|powerpc64le) i?86|x86_64|powerpc|powerpc64|powerpc64le)
enable_unaligned_access=yes enable_unaligned_access=yes
;; ;;
arm*|aarch64*|riscv*) arm*|riscv*)
# On 32-bit and 64-bit ARM, GCC and Clang # On 32-bit ARM, GCC and Clang
# #define __ARM_FEATURE_UNALIGNED if # #define __ARM_FEATURE_UNALIGNED
# unaligned access is supported. # if and only 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
# #
# RISC-V C API Specification says that if # RISC-V C API Specification says that if
# __riscv_misaligned_fast is defined then # __riscv_misaligned_fast is defined then
# unaligned access is known to be fast. # unaligned access is known to be fast.
# #
# MSVC is handled as a special case: We assume that # 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 # If MSVC gets RISC-V support then this will assume
# fast unaligned access on RISC-V too. # fast unaligned access on RISC-V too.
AC_COMPILE_IFELSE([AC_LANG_SOURCE([ AC_COMPILE_IFELSE([AC_LANG_SOURCE([
@ -157,7 +150,54 @@ if test "x$enable_unaligned_access" = xauto ; then
compile error compile error
#endif #endif
int main(void) { return 0; } int main(void) { return 0; }
])], [enable_unaligned_access=yes], [enable_unaligned_access=no]) ])],
[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*) loongarch*)
# See sections 7.4, 8.1, and 8.2: # See sections 7.4, 8.1, and 8.2: