Implement C11 excess precision semantics for conversions (PR c/82071).
authorJoseph Myers <joseph@codesourcery.com>
Fri, 15 Sep 2017 20:49:02 +0000 (21:49 +0100)
committerJoseph Myers <jsm28@gcc.gnu.org>
Fri, 15 Sep 2017 20:49:02 +0000 (21:49 +0100)
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

gcc/c/ChangeLog
gcc/c/c-typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/i386/excess-precision-8.c [new file with mode: 0644]

index e8e0fb087d349d1db598c3f8143c9c4f281c7094..742867a6ad9fe53aa30e018224214c2f1da50c1e 100644 (file)
@@ -1,3 +1,12 @@
+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.
index 1956d45e2517a54945267b7716d0a62e9c4f9d24..73e74602f595b0a581ff7ed34f8aceff4cbe3518 100644 (file)
@@ -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,
index 574251590f9525907748c7ed7ba8793ed780cc09..b9bb9c62a8ec3bfaa74ef4ab33587f537c43772d 100644 (file)
@@ -1,3 +1,8 @@
+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>
 
diff --git a/gcc/testsuite/gcc.target/i386/excess-precision-8.c b/gcc/testsuite/gcc.target/i386/excess-precision-8.c
new file mode 100644 (file)
index 0000000..c0a31ed
--- /dev/null
@@ -0,0 +1,61 @@
+/* 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);
+}