jpayne@68: # host-cpu-c-abi.m4 serial 17 jpayne@68: dnl Copyright (C) 2002-2024 Free Software Foundation, Inc. jpayne@68: dnl This file is free software; the Free Software Foundation jpayne@68: dnl gives unlimited permission to copy and/or distribute it, jpayne@68: dnl with or without modifications, as long as this notice is preserved. jpayne@68: jpayne@68: dnl From Bruno Haible and Sam Steingold. jpayne@68: jpayne@68: dnl Sets the HOST_CPU variable to the canonical name of the CPU. jpayne@68: dnl Sets the HOST_CPU_C_ABI variable to the canonical name of the CPU with its jpayne@68: dnl C language ABI (application binary interface). jpayne@68: dnl Also defines __${HOST_CPU}__ and __${HOST_CPU_C_ABI}__ as C macros in jpayne@68: dnl config.h. jpayne@68: dnl jpayne@68: dnl This canonical name can be used to select a particular assembly language jpayne@68: dnl source file that will interoperate with C code on the given host. jpayne@68: dnl jpayne@68: dnl For example: jpayne@68: dnl * 'i386' and 'sparc' are different canonical names, because code for i386 jpayne@68: dnl will not run on SPARC CPUs and vice versa. They have different jpayne@68: dnl instruction sets. jpayne@68: dnl * 'sparc' and 'sparc64' are different canonical names, because code for jpayne@68: dnl 'sparc' and code for 'sparc64' cannot be linked together: 'sparc' code jpayne@68: dnl contains 32-bit instructions, whereas 'sparc64' code contains 64-bit jpayne@68: dnl instructions. A process on a SPARC CPU can be in 32-bit mode or in 64-bit jpayne@68: dnl mode, but not both. jpayne@68: dnl * 'mips' and 'mipsn32' are different canonical names, because they use jpayne@68: dnl different argument passing and return conventions for C functions, and jpayne@68: dnl although the instruction set of 'mips' is a large subset of the jpayne@68: dnl instruction set of 'mipsn32'. jpayne@68: dnl * 'mipsn32' and 'mips64' are different canonical names, because they use jpayne@68: dnl different sizes for the C types like 'int' and 'void *', and although jpayne@68: dnl the instruction sets of 'mipsn32' and 'mips64' are the same. jpayne@68: dnl * The same canonical name is used for different endiannesses. You can jpayne@68: dnl determine the endianness through preprocessor symbols: jpayne@68: dnl - 'arm': test __ARMEL__. jpayne@68: dnl - 'mips', 'mipsn32', 'mips64': test _MIPSEB vs. _MIPSEL. jpayne@68: dnl - 'powerpc64': test _BIG_ENDIAN vs. _LITTLE_ENDIAN. jpayne@68: dnl * The same name 'i386' is used for CPUs of type i386, i486, i586 jpayne@68: dnl (Pentium), AMD K7, Pentium II, Pentium IV, etc., because jpayne@68: dnl - Instructions that do not exist on all of these CPUs (cmpxchg, jpayne@68: dnl MMX, SSE, SSE2, 3DNow! etc.) are not frequently used. If your jpayne@68: dnl assembly language source files use such instructions, you will jpayne@68: dnl need to make the distinction. jpayne@68: dnl - Speed of execution of the common instruction set is reasonable across jpayne@68: dnl the entire family of CPUs. If you have assembly language source files jpayne@68: dnl that are optimized for particular CPU types (like GNU gmp has), you jpayne@68: dnl will need to make the distinction. jpayne@68: dnl See . jpayne@68: AC_DEFUN([gl_HOST_CPU_C_ABI], jpayne@68: [ jpayne@68: AC_REQUIRE([AC_CANONICAL_HOST]) jpayne@68: AC_REQUIRE([gl_C_ASM]) jpayne@68: AC_CACHE_CHECK([host CPU and C ABI], [gl_cv_host_cpu_c_abi], jpayne@68: [case "$host_cpu" in jpayne@68: jpayne@68: changequote(,)dnl jpayne@68: i[34567]86 ) jpayne@68: changequote([,])dnl jpayne@68: gl_cv_host_cpu_c_abi=i386 jpayne@68: ;; jpayne@68: jpayne@68: x86_64 ) jpayne@68: # On x86_64 systems, the C compiler may be generating code in one of jpayne@68: # these ABIs: jpayne@68: # - 64-bit instruction set, 64-bit pointers, 64-bit 'long': x86_64. jpayne@68: # - 64-bit instruction set, 64-bit pointers, 32-bit 'long': x86_64 jpayne@68: # with native Windows (mingw, MSVC). jpayne@68: # - 64-bit instruction set, 32-bit pointers, 32-bit 'long': x86_64-x32. jpayne@68: # - 32-bit instruction set, 32-bit pointers, 32-bit 'long': i386. jpayne@68: AC_COMPILE_IFELSE( jpayne@68: [AC_LANG_SOURCE( jpayne@68: [[#if (defined __x86_64__ || defined __amd64__ \ jpayne@68: || defined _M_X64 || defined _M_AMD64) jpayne@68: int ok; jpayne@68: #else jpayne@68: error fail jpayne@68: #endif jpayne@68: ]])], jpayne@68: [AC_COMPILE_IFELSE( jpayne@68: [AC_LANG_SOURCE( jpayne@68: [[#if defined __ILP32__ || defined _ILP32 jpayne@68: int ok; jpayne@68: #else jpayne@68: error fail jpayne@68: #endif jpayne@68: ]])], jpayne@68: [gl_cv_host_cpu_c_abi=x86_64-x32], jpayne@68: [gl_cv_host_cpu_c_abi=x86_64])], jpayne@68: [gl_cv_host_cpu_c_abi=i386]) jpayne@68: ;; jpayne@68: jpayne@68: changequote(,)dnl jpayne@68: alphaev[4-8] | alphaev56 | alphapca5[67] | alphaev6[78] ) jpayne@68: changequote([,])dnl jpayne@68: gl_cv_host_cpu_c_abi=alpha jpayne@68: ;; jpayne@68: jpayne@68: arm* | aarch64 ) jpayne@68: # Assume arm with EABI. jpayne@68: # On arm64 systems, the C compiler may be generating code in one of jpayne@68: # these ABIs: jpayne@68: # - aarch64 instruction set, 64-bit pointers, 64-bit 'long': arm64. jpayne@68: # - aarch64 instruction set, 32-bit pointers, 32-bit 'long': arm64-ilp32. jpayne@68: # - 32-bit instruction set, 32-bit pointers, 32-bit 'long': arm or armhf. jpayne@68: AC_COMPILE_IFELSE( jpayne@68: [AC_LANG_SOURCE( jpayne@68: [[#ifdef __aarch64__ jpayne@68: int ok; jpayne@68: #else jpayne@68: error fail jpayne@68: #endif jpayne@68: ]])], jpayne@68: [AC_COMPILE_IFELSE( jpayne@68: [AC_LANG_SOURCE( jpayne@68: [[#if defined __ILP32__ || defined _ILP32 jpayne@68: int ok; jpayne@68: #else jpayne@68: error fail jpayne@68: #endif jpayne@68: ]])], jpayne@68: [gl_cv_host_cpu_c_abi=arm64-ilp32], jpayne@68: [gl_cv_host_cpu_c_abi=arm64])], jpayne@68: [# Don't distinguish little-endian and big-endian arm, since they jpayne@68: # don't require different machine code for simple operations and jpayne@68: # since the user can distinguish them through the preprocessor jpayne@68: # defines __ARMEL__ vs. __ARMEB__. jpayne@68: # But distinguish arm which passes floating-point arguments and jpayne@68: # return values in integer registers (r0, r1, ...) - this is jpayne@68: # gcc -mfloat-abi=soft or gcc -mfloat-abi=softfp - from arm which jpayne@68: # passes them in float registers (s0, s1, ...) and double registers jpayne@68: # (d0, d1, ...) - this is gcc -mfloat-abi=hard. GCC 4.6 or newer jpayne@68: # sets the preprocessor defines __ARM_PCS (for the first case) and jpayne@68: # __ARM_PCS_VFP (for the second case), but older GCC does not. jpayne@68: echo 'double ddd; void func (double dd) { ddd = dd; }' > conftest.c jpayne@68: # Look for a reference to the register d0 in the .s file. jpayne@68: AC_TRY_COMMAND(${CC-cc} $CFLAGS $CPPFLAGS $gl_c_asm_opt conftest.c) >/dev/null 2>&1 jpayne@68: if LC_ALL=C grep 'd0,' conftest.$gl_asmext >/dev/null; then jpayne@68: gl_cv_host_cpu_c_abi=armhf jpayne@68: else jpayne@68: gl_cv_host_cpu_c_abi=arm jpayne@68: fi jpayne@68: rm -f conftest* jpayne@68: ]) jpayne@68: ;; jpayne@68: jpayne@68: hppa1.0 | hppa1.1 | hppa2.0* | hppa64 ) jpayne@68: # On hppa, the C compiler may be generating 32-bit code or 64-bit jpayne@68: # code. In the latter case, it defines _LP64 and __LP64__. jpayne@68: AC_COMPILE_IFELSE( jpayne@68: [AC_LANG_SOURCE( jpayne@68: [[#ifdef __LP64__ jpayne@68: int ok; jpayne@68: #else jpayne@68: error fail jpayne@68: #endif jpayne@68: ]])], jpayne@68: [gl_cv_host_cpu_c_abi=hppa64], jpayne@68: [gl_cv_host_cpu_c_abi=hppa]) jpayne@68: ;; jpayne@68: jpayne@68: ia64* ) jpayne@68: # On ia64 on HP-UX, the C compiler may be generating 64-bit code or jpayne@68: # 32-bit code. In the latter case, it defines _ILP32. jpayne@68: AC_COMPILE_IFELSE( jpayne@68: [AC_LANG_SOURCE( jpayne@68: [[#ifdef _ILP32 jpayne@68: int ok; jpayne@68: #else jpayne@68: error fail jpayne@68: #endif jpayne@68: ]])], jpayne@68: [gl_cv_host_cpu_c_abi=ia64-ilp32], jpayne@68: [gl_cv_host_cpu_c_abi=ia64]) jpayne@68: ;; jpayne@68: jpayne@68: mips* ) jpayne@68: # We should also check for (_MIPS_SZPTR == 64), but gcc keeps this jpayne@68: # at 32. jpayne@68: AC_COMPILE_IFELSE( jpayne@68: [AC_LANG_SOURCE( jpayne@68: [[#if defined _MIPS_SZLONG && (_MIPS_SZLONG == 64) jpayne@68: int ok; jpayne@68: #else jpayne@68: error fail jpayne@68: #endif jpayne@68: ]])], jpayne@68: [gl_cv_host_cpu_c_abi=mips64], jpayne@68: [# In the n32 ABI, _ABIN32 is defined, _ABIO32 is not defined (but jpayne@68: # may later get defined by ), and _MIPS_SIM == _ABIN32. jpayne@68: # In the 32 ABI, _ABIO32 is defined, _ABIN32 is not defined (but jpayne@68: # may later get defined by ), and _MIPS_SIM == _ABIO32. jpayne@68: AC_COMPILE_IFELSE( jpayne@68: [AC_LANG_SOURCE( jpayne@68: [[#if (_MIPS_SIM == _ABIN32) jpayne@68: int ok; jpayne@68: #else jpayne@68: error fail jpayne@68: #endif jpayne@68: ]])], jpayne@68: [gl_cv_host_cpu_c_abi=mipsn32], jpayne@68: [gl_cv_host_cpu_c_abi=mips])]) jpayne@68: ;; jpayne@68: jpayne@68: powerpc* ) jpayne@68: # Different ABIs are in use on AIX vs. Mac OS X vs. Linux,*BSD. jpayne@68: # No need to distinguish them here; the caller may distinguish jpayne@68: # them based on the OS. jpayne@68: # On powerpc64 systems, the C compiler may still be generating jpayne@68: # 32-bit code. And on powerpc-ibm-aix systems, the C compiler may jpayne@68: # be generating 64-bit code. jpayne@68: AC_COMPILE_IFELSE( jpayne@68: [AC_LANG_SOURCE( jpayne@68: [[#if defined __powerpc64__ || defined __LP64__ jpayne@68: int ok; jpayne@68: #else jpayne@68: error fail jpayne@68: #endif jpayne@68: ]])], jpayne@68: [# On powerpc64, there are two ABIs on Linux: The AIX compatible jpayne@68: # one and the ELFv2 one. The latter defines _CALL_ELF=2. jpayne@68: AC_COMPILE_IFELSE( jpayne@68: [AC_LANG_SOURCE( jpayne@68: [[#if defined _CALL_ELF && _CALL_ELF == 2 jpayne@68: int ok; jpayne@68: #else jpayne@68: error fail jpayne@68: #endif jpayne@68: ]])], jpayne@68: [gl_cv_host_cpu_c_abi=powerpc64-elfv2], jpayne@68: [gl_cv_host_cpu_c_abi=powerpc64]) jpayne@68: ], jpayne@68: [gl_cv_host_cpu_c_abi=powerpc]) jpayne@68: ;; jpayne@68: jpayne@68: rs6000 ) jpayne@68: gl_cv_host_cpu_c_abi=powerpc jpayne@68: ;; jpayne@68: jpayne@68: riscv32 | riscv64 ) jpayne@68: # There are 2 architectures (with variants): rv32* and rv64*. jpayne@68: AC_COMPILE_IFELSE( jpayne@68: [AC_LANG_SOURCE( jpayne@68: [[#if __riscv_xlen == 64 jpayne@68: int ok; jpayne@68: #else jpayne@68: error fail jpayne@68: #endif jpayne@68: ]])], jpayne@68: [cpu=riscv64], jpayne@68: [cpu=riscv32]) jpayne@68: # There are 6 ABIs: ilp32, ilp32f, ilp32d, lp64, lp64f, lp64d. jpayne@68: # Size of 'long' and 'void *': jpayne@68: AC_COMPILE_IFELSE( jpayne@68: [AC_LANG_SOURCE( jpayne@68: [[#if defined __LP64__ jpayne@68: int ok; jpayne@68: #else jpayne@68: error fail jpayne@68: #endif jpayne@68: ]])], jpayne@68: [main_abi=lp64], jpayne@68: [main_abi=ilp32]) jpayne@68: # Float ABIs: jpayne@68: # __riscv_float_abi_double: jpayne@68: # 'float' and 'double' are passed in floating-point registers. jpayne@68: # __riscv_float_abi_single: jpayne@68: # 'float' are passed in floating-point registers. jpayne@68: # __riscv_float_abi_soft: jpayne@68: # No values are passed in floating-point registers. jpayne@68: AC_COMPILE_IFELSE( jpayne@68: [AC_LANG_SOURCE( jpayne@68: [[#if defined __riscv_float_abi_double jpayne@68: int ok; jpayne@68: #else jpayne@68: error fail jpayne@68: #endif jpayne@68: ]])], jpayne@68: [float_abi=d], jpayne@68: [AC_COMPILE_IFELSE( jpayne@68: [AC_LANG_SOURCE( jpayne@68: [[#if defined __riscv_float_abi_single jpayne@68: int ok; jpayne@68: #else jpayne@68: error fail jpayne@68: #endif jpayne@68: ]])], jpayne@68: [float_abi=f], jpayne@68: [float_abi='']) jpayne@68: ]) jpayne@68: gl_cv_host_cpu_c_abi="${cpu}-${main_abi}${float_abi}" jpayne@68: ;; jpayne@68: jpayne@68: s390* ) jpayne@68: # On s390x, the C compiler may be generating 64-bit (= s390x) code jpayne@68: # or 31-bit (= s390) code. jpayne@68: AC_COMPILE_IFELSE( jpayne@68: [AC_LANG_SOURCE( jpayne@68: [[#if defined __LP64__ || defined __s390x__ jpayne@68: int ok; jpayne@68: #else jpayne@68: error fail jpayne@68: #endif jpayne@68: ]])], jpayne@68: [gl_cv_host_cpu_c_abi=s390x], jpayne@68: [gl_cv_host_cpu_c_abi=s390]) jpayne@68: ;; jpayne@68: jpayne@68: sparc | sparc64 ) jpayne@68: # UltraSPARCs running Linux have `uname -m` = "sparc64", but the jpayne@68: # C compiler still generates 32-bit code. jpayne@68: AC_COMPILE_IFELSE( jpayne@68: [AC_LANG_SOURCE( jpayne@68: [[#if defined __sparcv9 || defined __arch64__ jpayne@68: int ok; jpayne@68: #else jpayne@68: error fail jpayne@68: #endif jpayne@68: ]])], jpayne@68: [gl_cv_host_cpu_c_abi=sparc64], jpayne@68: [gl_cv_host_cpu_c_abi=sparc]) jpayne@68: ;; jpayne@68: jpayne@68: *) jpayne@68: gl_cv_host_cpu_c_abi="$host_cpu" jpayne@68: ;; jpayne@68: esac jpayne@68: ]) jpayne@68: jpayne@68: dnl In most cases, $HOST_CPU and $HOST_CPU_C_ABI are the same. jpayne@68: HOST_CPU=`echo "$gl_cv_host_cpu_c_abi" | sed -e 's/-.*//'` jpayne@68: HOST_CPU_C_ABI="$gl_cv_host_cpu_c_abi" jpayne@68: AC_SUBST([HOST_CPU]) jpayne@68: AC_SUBST([HOST_CPU_C_ABI]) jpayne@68: jpayne@68: # This was jpayne@68: # AC_DEFINE_UNQUOTED([__${HOST_CPU}__]) jpayne@68: # AC_DEFINE_UNQUOTED([__${HOST_CPU_C_ABI}__]) jpayne@68: # earlier, but KAI C++ 3.2d doesn't like this. jpayne@68: sed -e 's/-/_/g' >> confdefs.h <