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.
This commit is contained in:
parent
f3707a55ac
commit
5b68fb47bd
3 changed files with 63 additions and 27 deletions
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue