aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2023-01-06 19:31:26 +0000
committerJoseph Myers <joseph@codesourcery.com>2023-01-06 19:31:26 +0000
commit5b68fb47bd24abc2e6a65e5617f586d1c1b81d4e (patch)
treed5951144716ceb901447d8ef2d4449cab1f991c3
parentf3707a55acb980fbcd412ceb980b5621decb4dc0 (diff)
downloadgcc-5b68fb47bd24abc2e6a65e5617f586d1c1b81d4e.zip
gcc-5b68fb47bd24abc2e6a65e5617f586d1c1b81d4e.tar.gz
gcc-5b68fb47bd24abc2e6a65e5617f586d1c1b81d4e.tar.bz2
c: C2x semantics for __builtin_tgmath
__builtin_tgmath implements <tgmath.h> semantics for integer generic arguments that handle cases involving _FloatN / _FloatNx types as specified in TS 18661-3 plus some defect fixes. C2x has further changes to the semantics for <tgmath.h> macros with such types, which should also be considered defect fixes (although handled through the integration of TS 18661-3 in C2x rather than through an issue tracking process). Specifically, the rules were changed because of problems raised with using the macros with the evaluation format types such as float_t and _Float32_t: the older version of the rules didn't allow passing _FloatN / _FloatNx types to the narrowing macros returning float or double, or passing float / double / long double to the narrowing macros returning _FloatN / _FloatNx, which was a problem with the evaluation format types which could be either kind of type depending on the value of FLT_EVAL_METHOD. Thus the new rules allow cases of mixing types which were not allowed before - which is not itself a problem for __builtin_tgmath - and, as part of the changes, the handling of integer arguments was also changed: if there is any _FloatNx generic argument, integer generic arguments are treated as _Float32x (not double), while the rule about treating integer arguments to narrowing macros returning _FloatN or _FloatNx as _Float64 not double was removed (no longer needed now double is a valid argument to such macros). Implement the changes for __builtin_tgmath. (The changes also added a rule that if any argument is _DecimalNx, integer arguments are treated as _Decimal64x, but GCC doesn't support _DecimalNx types so nothing is done about that.) I have a corresponding glibc patch to update glibc test expectations for C2x and also ensure that appropriate semantics are followed when GCC 7 through 12 are used with <tgmath.h> (avoiding __builtin_tgmath in cases where it doesn't match the C2x semantics). Bootstrapped with no regressions for x86_64-pc-linux-gnu. gcc/ * doc/extend.texi (__builtin_tgmath): Do not restate standard rule for handling real integer types. gcc/c/ * c-parser.cc (c_parser_postfix_expression): Handle integer generic arguments to functions passed to __builtin_tgmath as _Float32x if any argument has _FloatNx or _Complex _FloatNx type. Do not handle integer arguments to some narrowing functions as _Float64. gcc/testsuite/ * gcc.dg/builtin-tgmath-3.c: Update expectations and add more tests.
-rw-r--r--gcc/c/c-parser.cc42
-rw-r--r--gcc/doc/extend.texi5
-rw-r--r--gcc/testsuite/gcc.dg/builtin-tgmath-3.c43
3 files changed, 63 insertions, 27 deletions
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 7d6960f..3a59980 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -10276,16 +10276,17 @@ c_parser_postfix_expression (c_parser *parser)
types are treated as _Decimal64 if any type-generic
argument is decimal, or if the only alternatives for
type-generic arguments are of decimal types, and are
- otherwise treated as double (or _Complex double for
- complex integer types, or _Float64 or _Complex _Float64
- if all the return types are the same _FloatN or
- _FloatNx type). After that adjustment, types are
- combined following the usual arithmetic conversions.
- If the function only accepts complex arguments, a
- complex type is produced. */
+ otherwise treated as _Float32x (or _Complex _Float32x
+ for complex integer types) if any type-generic argument
+ has _FloatNx type, otherwise as double (or _Complex
+ double for complex integer types). After that
+ adjustment, types are combined following the usual
+ arithmetic conversions. If the function only accepts
+ complex arguments, a complex type is produced. */
bool arg_complex = all_complex;
bool arg_binary = all_binary;
bool arg_int_decimal = all_decimal;
+ bool arg_int_floatnx = false;
for (unsigned int j = 1; j <= nargs; j++)
{
if (parm_kind[j] == tgmath_fixed)
@@ -10380,20 +10381,17 @@ c_parser_postfix_expression (c_parser *parser)
goto out;
}
}
+ tree rtype = TYPE_MAIN_VARIANT (type);
+ if (TREE_CODE (rtype) == COMPLEX_TYPE)
+ rtype = TREE_TYPE (rtype);
+ if (SCALAR_FLOAT_TYPE_P (rtype))
+ for (unsigned int j = 0; j < NUM_FLOATNX_TYPES; j++)
+ if (rtype == FLOATNX_TYPE_NODE (j))
+ {
+ arg_int_floatnx = true;
+ break;
+ }
}
- /* For a macro rounding its result to a narrower type, map
- integer types to _Float64 not double if the return type
- is a _FloatN or _FloatNx type. */
- bool arg_int_float64 = false;
- if (parm_kind[0] == tgmath_fixed
- && SCALAR_FLOAT_TYPE_P (parm_first[0])
- && float64_type_node != NULL_TREE)
- for (unsigned int j = 0; j < NUM_FLOATN_NX_TYPES; j++)
- if (parm_first[0] == FLOATN_TYPE_NODE (j))
- {
- arg_int_float64 = true;
- break;
- }
tree arg_real = NULL_TREE;
for (unsigned int j = 1; j <= nargs; j++)
{
@@ -10406,8 +10404,8 @@ c_parser_postfix_expression (c_parser *parser)
if (INTEGRAL_TYPE_P (type))
type = (arg_int_decimal
? dfloat64_type_node
- : arg_int_float64
- ? float64_type_node
+ : arg_int_floatnx
+ ? float32x_type_node
: double_type_node);
if (arg_real == NULL_TREE)
arg_real = type;
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 68d7760..1103e99 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -13923,9 +13923,8 @@ corresponding to @var{t} for each function.
The standard rules for @code{<tgmath.h>} macros are used to find a
common type @var{u} from the types of the arguments for parameters
whose types vary between the functions; complex integer types (a GNU
-extension) are treated like @code{_Complex double} for this purpose
-(or @code{_Complex _Float64} if all the function return types are the
-same @code{_Float@var{n}} or @code{_Float@var{n}x} type).
+extension) are treated like the complex type corresponding to the real
+floating type that would be chosen for the corresponding real integer type.
If the function return types vary, or are all the same integer type,
the function called is the one for which @var{t} is @var{u}, and it is
an error if there is no such function. If the function return types
diff --git a/gcc/testsuite/gcc.dg/builtin-tgmath-3.c b/gcc/testsuite/gcc.dg/builtin-tgmath-3.c
index 35364ea..6521130 100644
--- a/gcc/testsuite/gcc.dg/builtin-tgmath-3.c
+++ b/gcc/testsuite/gcc.dg/builtin-tgmath-3.c
@@ -1,10 +1,12 @@
-/* Test __builtin_tgmath: integer arguments mapped to _Float64. */
+/* Test __builtin_tgmath: integer arguments with _FloatN / _FloatNx. */
/* { dg-do run } */
/* { dg-options "" } */
/* { dg-add-options float32 } */
/* { dg-add-options float64 } */
+/* { dg-add-options float32x } */
/* { dg-require-effective-target float32_runtime } */
/* { dg-require-effective-target float64_runtime } */
+/* { dg-require-effective-target float32x_runtime } */
extern void abort (void);
extern void exit (int);
@@ -18,7 +20,11 @@ extern void exit (int);
} \
while (0)
+extern double var_d;
extern _Float32 var_f32;
+extern _Float64 var_f64;
+extern _Float32x var_f32x;
+extern _Complex _Float32x var_cf32x;
_Float32 t1f (float x) { return x + 1; }
_Float32 t1d (double x) { return x + 2; }
@@ -39,12 +45,45 @@ test_1 (void)
CHECK_CALL (t1v (d), 4, var_f32);
CHECK_CALL (t1v (ld), 6, var_f32);
CHECK_CALL (t1v (f64), 8, var_f32);
- CHECK_CALL (t1v (i), 9, var_f32);
+ CHECK_CALL (t1v (i), 7, var_f32);
+}
+
+float t2f (float x, float y) { return 10 * x + y; }
+double t2d (double x, double y) { return 100 * x + y; }
+long double t2l (long double x, long double y) { return 1000 * x + y; }
+_Float32x t2f32x (_Float32x x, _Float32x y) { return 10000 * x + y; }
+_Float64 t2f64 (_Float64 x, _Float64 y) { return 100000 * x + y; }
+
+_Complex _Float32x
+ct2f32x (_Complex _Float32x x, _Complex _Float32x y)
+{
+ return 1000000 * x + y;
+}
+
+#define t2v(x, y) __builtin_tgmath (t2f, t2d, t2l, t2f32x, t2f64, ct2f32x, x, y)
+
+static void
+test_2 (void)
+{
+ double d = 3;
+ _Float64 f64 = 6;
+ _Float32x f32x = 7;
+ int i = 5;
+ _Complex _Float32x cf32x = 8;
+ CHECK_CALL (t2v (f32x, i), 70005, var_f32x);
+ CHECK_CALL (t2v (i, f32x), 50007, var_f32x);
+ CHECK_CALL (t2v (f64, i), 600005, var_f64);
+ CHECK_CALL (t2v (i, f64), 500006, var_f64);
+ CHECK_CALL (t2v (d, i), 305, var_d);
+ CHECK_CALL (t2v (i, d), 503, var_d);
+ CHECK_CALL (t2v (cf32x, i), 8000005, var_cf32x);
+ CHECK_CALL (t2v (i, cf32x), 5000008, var_cf32x);
}
int
main (void)
{
test_1 ();
+ test_2 ();
exit (0);
}