https://github.com/numpy/numpy/commit/de0b2d5c6dee9303c4a055e7591978ed5a06e403 From de0b2d5c6dee9303c4a055e7591978ed5a06e403 Mon Sep 17 00:00:00 2001 From: matoro Date: Sun, 18 Jun 2023 19:39:06 -0400 Subject: [PATCH] BLD: Port long double identification to C for meson This ports the old Python code for identifying the long double representation to C, so that it can be easily invoked by meson. The original implementation is at https://github.com/numpy/numpy/blob/eead09a3d02c09374942cdc787c0b5e4fe9e7472/numpy/core/setup_common.py#L264-L434 The C portion of the code has been tested and confirmed to work on systems with the following formats, either natively or via an alternative ABI: INTEL_EXTENDED_16_BYTES_LE, IEEE_QUAD_BE, IEEE_QUAD_LE, IBM_DOUBLE_DOUBLE_BE, IBM_DOUBLE_DOUBLE_LE, IEEE_DOUBLE_BE, INTEL_EXTENDED_12_BYTES_LE. The original meson port includes an error condition with the comment "This should not be possible, 12 bits of "content" should still result in sizeof() being 16." As far as I can tell this is incorrect, as compiling on an x86_64 system with 32-bit ABI (gcc -m32) does indeed have sizeof(long double)==12. This is reflected in the C code. Closes gh-23972, closes https://github.com/mesonbuild/meson/issues/11068. --- numpy/core/meson.build | 110 ++++++++++++++++++++++++++++++++--------- 1 file changed, 87 insertions(+), 23 deletions(-) diff --git a/numpy/core/meson.build b/numpy/core/meson.build index 3427de408f1..92b393e4bc1 100644 --- a/numpy/core/meson.build +++ b/numpy/core/meson.build @@ -361,29 +361,93 @@ foreach intrin: optional_intrinsics endif endforeach -# long double representation detection (see setup_common.py) -# TODO: this is still incomplete, and different from how it's done in the -# numpy.distutils based build, see https://github.com/mesonbuild/meson/issues/11068 -longdouble_size = cc.sizeof('long double') -if longdouble_size == 8 - if host_machine.endian() == 'little' - longdouble_format = 'IEEE_DOUBLE_LE' - else - longdouble_format = 'IEEE_DOUBLE_BE' - endif -elif longdouble_size == 12 - error('This should not be possible, 12 bits of "content" should still result in sizeof() being 16. Please report this error!' - ) -elif longdouble_size == 16 - if host_machine.endian() == 'little' - # FIXME: this varies, there's multiple formats here! Not yet implemented. - # TBD how we deal with the mess of old long double formats. - longdouble_format = 'INTEL_EXTENDED_16_BYTES_LE' - else - error('No idea what this is ....') - endif -else - error('Unknown long double size: ' + londouble_size) +# This is a port of the old python code for identifying the long double +# representation to C. The old Python code is in this range: +# https://github.com/numpy/numpy/blob/eead09a3d02c09374942cdc787c0b5e4fe9e7472/numpy/core/setup_common.py#L264-L434 +# This port is in service of solving gh-23972 +# as well as https://github.com/mesonbuild/meson/issues/11068 +longdouble_format = meson.get_compiler('c').run( +''' +#include +#include + +#define repcmp(z) (memcmp((const char *)&foo.x, z, sizeof(foo.x)) == 0) + +const struct { + char before[16]; + long double x; + char after[8]; +} foo = {{'\0'}, -123456789.0, {'\0'}}; + +int main(void) { + switch (sizeof(foo.x)) { + case 8: { + if (repcmp( + ((const char[]){0000, 0000, 0000, 0124, 0064, 0157, 0235, 0301}))) { + fprintf(stdout, "IEEE_DOUBLE_LE"); + return 0; + } + if (repcmp( + ((const char[]){0301, 0235, 0157, 0064, 0124, 0000, 0000, 0000}))) { + fprintf(stdout, "IEEE_DOUBLE_BE"); + return 0; + } + fprintf(stdout, "UNKNOWN"); + return 1; + } + case 12: { + if (repcmp(((const char[]){0000, 0000, 0000, 0000, 0240, 0242, 0171, 0353, + 0031, 0300, 0000, 0000}))) { + fprintf(stdout, "INTEL_EXTENDED_12_BYTES_LE"); + return 0; + } + if (repcmp(((const char[]){0300, 0031, 0000, 0000, 0353, 0171, 0242, 0240, + 0000, 0000, 0000, 0000}))) { + fprintf(stdout, "MOTOROLA_EXTENDED_12_BYTES_BE"); + return 0; + } + fprintf(stdout, "UNKNOWN"); + return 1; + } + case 16: { + if (repcmp( + ((const char[]){0000, 0000, 0000, 0000, 0240, 0242, 0171, 0353, + 0031, 0300, 0000, 0000, 0000, 0000, 0000, 0000}))) { + fprintf(stdout, "INTEL_EXTENDED_16_BYTES_LE"); + return 0; + } + if (repcmp( + ((const char[]){0300, 0031, 0326, 0363, 0105, 0100, 0000, 0000, + 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000}))) { + fprintf(stdout, "IEEE_QUAD_BE"); + return 0; + } + if (repcmp( + ((const char[]){0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, + 0000, 0000, 0100, 0105, 0363, 0326, 0031, 0300}))) { + fprintf(stdout, "IEEE_QUAD_LE"); + return 0; + } + if (repcmp( + ((const char[]){0000, 0000, 0000, 0124, 0064, 0157, 0235, 0301, + 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000}))) { + fprintf(stdout, "IBM_DOUBLE_DOUBLE_LE"); + return 0; + } + if (repcmp( + ((const char[]){0301, 0235, 0157, 0064, 0124, 0000, 0000, 0000, + 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000}))) { + fprintf(stdout, "IBM_DOUBLE_DOUBLE_BE"); + return 0; + } + fprintf(stdout, "UNKNOWN"); + return 1; + } + } +} +''').stdout() +if longdouble_format == 'UNKNOWN' or longdouble_format == 'UNDEFINED' + error('Unknown long double format of size: ' + cc.sizeof('long double').to_string()) endif cdata.set10('HAVE_LDOUBLE_' + longdouble_format, true)