Introduce a test that exercises various ABI aspects of C23 float types. This is based on existing tests such as `float16-basic.c`.
2025-08-31 Trevor Gross <tmgr...@umich.edu> gcc/testsuite/ * gcc.dg/torture/float128-abi.c: New test. * gcc.dg/torture/float128x-abi.c: New test. * gcc.dg/torture/float16-abi.c: New test. * gcc.dg/torture/float32-abi.c: New test. * gcc.dg/torture/float32x-abi.c: New test. * gcc.dg/torture/float64-abi.c: New test. * gcc.dg/torture/float64x-abi.c: New test. * gcc.dg/torture/floatn-abi.h: New test. Signed-off-by: Trevor Gross <tmgr...@umich.edu> --- This can't catch ABI bugs against anything other than GCC of course, but it is intended to sanity check against things like stack misalignments and libcall mismatches that have shown up here and there. Tested on x86-64. Testsuite maintainers are copied. gcc/testsuite/gcc.dg/torture/float128-abi.c | 9 + gcc/testsuite/gcc.dg/torture/float128x-abi.c | 9 + gcc/testsuite/gcc.dg/torture/float16-abi.c | 9 + gcc/testsuite/gcc.dg/torture/float32-abi.c | 9 + gcc/testsuite/gcc.dg/torture/float32x-abi.c | 9 + gcc/testsuite/gcc.dg/torture/float64-abi.c | 9 + gcc/testsuite/gcc.dg/torture/float64x-abi.c | 10 + gcc/testsuite/gcc.dg/torture/floatn-abi.h | 189 +++++++++++++++++++ 8 files changed, 253 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/torture/float128-abi.c create mode 100644 gcc/testsuite/gcc.dg/torture/float128x-abi.c create mode 100644 gcc/testsuite/gcc.dg/torture/float16-abi.c create mode 100644 gcc/testsuite/gcc.dg/torture/float32-abi.c create mode 100644 gcc/testsuite/gcc.dg/torture/float32x-abi.c create mode 100644 gcc/testsuite/gcc.dg/torture/float64-abi.c create mode 100644 gcc/testsuite/gcc.dg/torture/float64x-abi.c create mode 100644 gcc/testsuite/gcc.dg/torture/floatn-abi.h diff --git a/gcc/testsuite/gcc.dg/torture/float128-abi.c b/gcc/testsuite/gcc.dg/torture/float128-abi.c new file mode 100644 index 00000000000..f985b6d83f0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/float128-abi.c @@ -0,0 +1,9 @@ +/* Test _Float128. */ +/* { dg-do run } */ +/* { dg-options "-Wno-old-style-definition" } */ +/* { dg-add-options float128 } */ +/* { dg-require-effective-target float128_runtime } */ + +#define WIDTH 128 +#define EXT 0 +#include "floatn-abi.h" diff --git a/gcc/testsuite/gcc.dg/torture/float128x-abi.c b/gcc/testsuite/gcc.dg/torture/float128x-abi.c new file mode 100644 index 00000000000..f841cd12945 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/float128x-abi.c @@ -0,0 +1,9 @@ +/* Test _Float128x. */ +/* { dg-do run } */ +/* { dg-options "-Wno-old-style-definition" } */ +/* { dg-add-options float128x } */ +/* { dg-require-effective-target float128x_runtime } */ + +#define WIDTH 128 +#define EXT 1 +#include "floatn-abi.h" diff --git a/gcc/testsuite/gcc.dg/torture/float16-abi.c b/gcc/testsuite/gcc.dg/torture/float16-abi.c new file mode 100644 index 00000000000..523480169bf --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/float16-abi.c @@ -0,0 +1,9 @@ +/* Test _Float16. */ +/* { dg-do run } */ +/* { dg-options "-Wno-old-style-definition" } */ +/* { dg-add-options float16 } */ +/* { dg-require-effective-target float16_runtime } */ + +#define WIDTH 16 +#define EXT 0 +#include "floatn-abi.h" diff --git a/gcc/testsuite/gcc.dg/torture/float32-abi.c b/gcc/testsuite/gcc.dg/torture/float32-abi.c new file mode 100644 index 00000000000..61abee5d81b --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/float32-abi.c @@ -0,0 +1,9 @@ +/* Test _Float32. */ +/* { dg-do run } */ +/* { dg-options "-Wno-old-style-definition" } */ +/* { dg-add-options float32 } */ +/* { dg-require-effective-target float32_runtime } */ + +#define WIDTH 32 +#define EXT 0 +#include "floatn-abi.h" diff --git a/gcc/testsuite/gcc.dg/torture/float32x-abi.c b/gcc/testsuite/gcc.dg/torture/float32x-abi.c new file mode 100644 index 00000000000..fd8d1f515d8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/float32x-abi.c @@ -0,0 +1,9 @@ +/* Test _Float32x. */ +/* { dg-do run } */ +/* { dg-options "-Wno-old-style-definition" } */ +/* { dg-add-options float32x } */ +/* { dg-require-effective-target float32x_runtime } */ + +#define WIDTH 32 +#define EXT 1 +#include "floatn-abi.h" diff --git a/gcc/testsuite/gcc.dg/torture/float64-abi.c b/gcc/testsuite/gcc.dg/torture/float64-abi.c new file mode 100644 index 00000000000..365f90546cf --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/float64-abi.c @@ -0,0 +1,9 @@ +/* Test _Float64. */ +/* { dg-do run } */ +/* { dg-options "-Wno-old-style-definition" } */ +/* { dg-add-options float64 } */ +/* { dg-require-effective-target float64_runtime } */ + +#define WIDTH 64 +#define EXT 0 +#include "floatn-abi.h" diff --git a/gcc/testsuite/gcc.dg/torture/float64x-abi.c b/gcc/testsuite/gcc.dg/torture/float64x-abi.c new file mode 100644 index 00000000000..439e0c639ce --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/float64x-abi.c @@ -0,0 +1,10 @@ +/* Test _Float64x. */ +/* { dg-do run } */ +/* { dg-options "-Wno-old-style-definition" } */ +/* { dg-add-options float64x } */ +/* { dg-require-effective-target float64x_runtime } */ + +#define WIDTH 64 +#define TYPE_BITS 80 +#define EXT 1 +#include "floatn-abi.h" diff --git a/gcc/testsuite/gcc.dg/torture/floatn-abi.h b/gcc/testsuite/gcc.dg/torture/floatn-abi.h new file mode 100644 index 00000000000..a56c6e59ce9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/floatn-abi.h @@ -0,0 +1,189 @@ +/* Smoke tests for parameter passing and returning, including varargs. Define + WIDTH to the float width and EXT to 1 for _FloatNx or 0 for _FloatN. For + types where the data representation is smaller than the type's width (x86 + _Float64x), TYPE_BITS should also be defined. */ + +#define __STDC_WANT_IEC_60559_TYPES_EXT__ + +#include <float.h> +#include <stdarg.h> +#include <stddef.h> + +#define _CONCAT(X, Y) X##Y +#define CONCAT(X, Y) _CONCAT (X, Y) +#define FLT_MAC(S) CONCAT (CONCAT (CONCAT (FLT, SUFFIX_UPPER), _), S) + +#if EXT +#define SUFFIX CONCAT (WIDTH, x) +#define SUFFIX_UPPER CONCAT (WIDTH, X) +#else +#define SUFFIX WIDTH +#define SUFFIX_UPPER WIDTH +#endif + +#define TYPE CONCAT (_Float, SUFFIX) +#define TYPE_NAN (TYPE) (0.0 / 0.0) +#define TYPE_INF (TYPE) (1.0 / 0.0) +#define TYPE_PI (TYPE)3.14159265358979323846 + +/* Needed to account for float types with padding */ +#ifndef TYPE_BITS +#define TYPE_BITS (sizeof (TYPE) * 8) +#endif + +#define assert_biteq(a, b, ...) \ + do \ + { \ + TYPE _a = a; \ + TYPE _b = b; \ + /* We make a reasonable assumption that the end of the useful bits is \ + byte-aligned, even for types that have padding. */ \ + if (memcmp (&_a, &_b, TYPE_BITS / 8)) \ + { \ + printf ("a (%#llx) != b (%#llx) ", _a, _b); \ + printf (__VA_ARGS__); \ + exit (1); \ + } \ + } \ + while (0) + +void exit (int); +int printf (const char *, ...); +int memcmp (const void *, const void *, size_t); + +#define NUM_INPUTS 16 + +/* Populated with an ascending bitpattern */ +volatile TYPE in_pat[NUM_INPUTS] = { TYPE_NAN }; +/* Also check some semantically meaningful values */ +volatile TYPE in_vals[NUM_INPUTS] = { + 0.0, -0.0, 1.0, -1.0, + 123.45678, -123.45678, TYPE_INF, -TYPE_INF, + TYPE_NAN, -TYPE_NAN, FLT_MAC (MAX), -FLT_MAC (MAX), + FLT_MAC (MIN), -FLT_MAC (MIN), TYPE_PI, -TYPE_PI, +}; + +volatile int va_i_res = 0; +volatile TYPE va_res[NUM_INPUTS] = { TYPE_NAN }; +volatile TYPE pass_res[NUM_INPUTS] = { TYPE_NAN }; +volatile TYPE pass_res2[NUM_INPUTS] = { TYPE_NAN }; +volatile TYPE add_res = TYPE_NAN; +volatile TYPE sub_res = TYPE_NAN; +volatile TYPE mul_res = TYPE_NAN; +volatile TYPE div_res = TYPE_NAN; + +void __attribute__ ((noinline)) +do_pass (TYPE x0, TYPE x1, TYPE x2, TYPE x3, TYPE x4, TYPE x5, TYPE x6, + TYPE x7, TYPE x8, TYPE x9, TYPE x10, TYPE x11, TYPE x12, TYPE x13, + TYPE x14, TYPE x15) +{ + pass_res[0] = x0; + pass_res[1] = x1; + pass_res[2] = x2; + pass_res[3] = x3; + pass_res[4] = x4; + pass_res[5] = x5; + pass_res[6] = x6; + pass_res[7] = x7; + pass_res[8] = x8; + pass_res[9] = x9; + pass_res[10] = x10; + pass_res[11] = x11; + pass_res[12] = x12; + pass_res[13] = x13; + pass_res[14] = x14; + pass_res[15] = x15; +} + +/* Add a perturbation to help catch stack misalignments */ +void __attribute__ ((noinline)) +do_pass2 (char _c, TYPE x0, TYPE x1, TYPE x2, TYPE x3, TYPE x4, TYPE x5, + TYPE x6, TYPE x7, TYPE x8, TYPE x9, TYPE x10, TYPE x11, TYPE x12, + TYPE x13, TYPE x14, TYPE x15) +{ + pass_res2[0] = x0; + pass_res2[1] = x1; + pass_res2[2] = x2; + pass_res2[3] = x3; + pass_res2[4] = x4; + pass_res2[5] = x5; + pass_res2[6] = x6; + pass_res2[7] = x7; + pass_res2[8] = x8; + pass_res2[9] = x9; + pass_res2[10] = x10; + pass_res2[11] = x11; + pass_res2[12] = x12; + pass_res2[13] = x13; + pass_res2[14] = x14; + pass_res2[15] = x15; +} + +TYPE __attribute__ ((noinline)) +do_return (volatile TYPE *p) +{ + return *p; +} + +void __attribute__ ((noinline)) +do_va (int _unused, ...) +{ + va_list va; + va_start (va); + for (int i = 0; i < NUM_INPUTS; ++i) + { + va_res[i] = va_arg (va, TYPE); + } + va_end (va); +} + +/* Check basic operations which may involve the libcall ABI */ +void __attribute__ ((noinline)) +do_math (TYPE a, TYPE b) +{ + add_res = a + b; + sub_res = a - b; + mul_res = a * b; + div_res = a / b; +} + +void +test_one (volatile TYPE in[NUM_INPUTS]) +{ + do_pass (in[0], in[1], in[2], in[3], in[4], in[5], in[6], in[7], in[8], + in[9], in[10], in[11], in[12], in[13], in[14], in[15]); + do_pass2 (0, in[0], in[1], in[2], in[3], in[4], in[5], in[6], in[7], in[8], + in[9], in[10], in[11], in[12], in[13], in[14], in[15]); + do_va (0, in[0], in[1], in[2], in[3], in[4], in[5], in[6], in[7], in[8], + in[9], in[10], in[11], in[12], in[13], in[14], in[15] + + ); + + for (int i = 0; i < NUM_INPUTS; ++i) + { + assert_biteq (in[i], pass_res[i], "pass error at index %d\n", i); + assert_biteq (in[i], pass_res2[i], "pass2 error at index %d\n", i); + assert_biteq (in[i], do_return (&in[i]), "return error at index %d\n", + i); + assert_biteq (in[i], va_res[i], "va error at index %d\n", i); + } +} + +int +main () +{ + for (int i = 0; i < NUM_INPUTS * sizeof (TYPE); ++i) + { + /* Populate with an increasing bitpattern */ + ((unsigned char *)in_pat)[i] = (i % 254) + 1; + } + + test_one (in_pat); + test_one (in_vals); + + do_math (1.5, -3.0); + assert_biteq (add_res, -1.5, "add error\n"); + assert_biteq (sub_res, 4.5, "sub error\n"); + assert_biteq (mul_res, -4.5, "mul error\n"); + assert_biteq (div_res, -0.5, "div error\n"); +} -- 2.39.5 (Apple Git-154)