Commit bb75facd by Joseph Myers Committed by Joseph Myers

Implement C11 excess precision semantics for conversions (PR c/82071).

C11 semantics for excess precision (from N1531) are that an implicit
conversion (from the usual arithmetic conversions, not by assignment)
from integer to floating point has a result in the corresponding
evaluation format of that floating-point type, so possibly with excess
precision (whereas a cast or conversion by assignment from integer to
floating point must produce a value without excess range or precision,
as always).  This patch makes GCC support those semantics if
flag_isoc11 (which in turn means that conditional expressions need to
support generating a result with excess precision even if neither
operand had excess precision).

C99 is less than entirely clear in this regard, but my reading as
outlined at <https://gcc.gnu.org/ml/gcc-patches/2008-11/msg00105.html>
is that the results of conversions from integer to floating-point
types are always expected to be representable in the target type
without excess precision, and this patch conservatively keeps these
semantics for pre-C11 (i.e. if an older standard is explicitly
selected).

Bootstrapped with no regressions on x86_64-pc-linux-gnu.

	PR c/82071

gcc/c:
	* c-typeck.c (ep_convert_and_check): Just call convert_and_check
	for C11.
	(build_conditional_expr): For C11, generate result with excess
	precision when one argument is an integer and the other is of a
	type using excess precision.

gcc/testsuite:
	* gcc.target/i386/excess-precision-8.c: New test.

From-SVN: r252847
parent c01df3c8
2017-09-15 Joseph Myers <joseph@codesourcery.com>
PR c/82071
* c-typeck.c (ep_convert_and_check): Just call convert_and_check
for C11.
(build_conditional_expr): For C11, generate result with excess
precision when one argument is an integer and the other is of a
type using excess precision.
2017-09-15 Bernd Edlinger <bernd.edlinger@hotmail.de>
* c-typeck.c (build_c_cast): Implement -Wcast-align=strict.
......
......@@ -4866,7 +4866,9 @@ ep_convert_and_check (location_t loc, tree type, tree expr,
if (TREE_TYPE (expr) == type)
return expr;
if (!semantic_type)
/* For C11, integer conversions may have results with excess
precision. */
if (flag_isoc11 || !semantic_type)
return convert_and_check (loc, type, expr);
if (TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE
......@@ -4994,7 +4996,31 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp,
&& (code2 == INTEGER_TYPE || code2 == REAL_TYPE
|| code2 == COMPLEX_TYPE))
{
result_type = c_common_type (type1, type2);
/* In C11, a conditional expression between a floating-point
type and an integer type should convert the integer type to
the evaluation format of the floating-point type, with
possible excess precision. */
tree eptype1 = type1;
tree eptype2 = type2;
if (flag_isoc11)
{
tree eptype;
if (ANY_INTEGRAL_TYPE_P (type1)
&& (eptype = excess_precision_type (type2)) != NULL_TREE)
{
eptype2 = eptype;
if (!semantic_result_type)
semantic_result_type = c_common_type (type1, type2);
}
else if (ANY_INTEGRAL_TYPE_P (type2)
&& (eptype = excess_precision_type (type1)) != NULL_TREE)
{
eptype1 = eptype;
if (!semantic_result_type)
semantic_result_type = c_common_type (type1, type2);
}
}
result_type = c_common_type (eptype1, eptype2);
if (result_type == error_mark_node)
return error_mark_node;
do_warn_double_promotion (result_type, type1, type2,
......
2017-09-15 Joseph Myers <joseph@codesourcery.com>
PR c/82071
* gcc.target/i386/excess-precision-8.c: New test.
2017-09-15 Manuel Lopez-Ibanez <manu@gcc.gnu.org>
Paolo Carlini <paolo.carlini@oracle.com>
......
/* Excess precision tests. Test C11 semantics for conversions from
integers to floating point: no excess precision for either explicit
conversions, but excess precision for implicit conversions. */
/* { dg-do run } */
/* { dg-options "-std=c11 -mfpmath=387 -fexcess-precision=standard" } */
extern void abort (void);
extern void exit (int);
int
main (void)
{
float f = 1.0f;
int i;
i = 0x10001234;
if ((float) i != 0x10001240)
abort ();
i = 0x10001234;
i += f;
if (i != 0x10001235)
abort ();
i = 0x10001234;
i += 1.0f;
if (i != 0x10001235)
abort ();
i = 0x10001234;
i = i + f;
if (i != 0x10001235)
abort ();
i = 0x10001234;
i = i + 1.0f;
if (i != 0x10001235)
abort ();
i = 0x10001235;
i = (1 ? i : 1.0f);
if (i != 0x10001235)
abort ();
i = 0x10001235;
i = (1 ? i : f);
if (i != 0x10001235)
abort ();
i = 0x10001235;
i = (0 ? 1.0f :i);
if (i != 0x10001235)
abort ();
i = 0x10001235;
i = (0 ? f : i);
if (i != 0x10001235)
abort ();
exit (0);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment