aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2017-09-15 21:49:02 +0100
committerJoseph Myers <jsm28@gcc.gnu.org>2017-09-15 21:49:02 +0100
commitbb75facd248a5030b5acd533ba4092e2d7fcd90b (patch)
treea2d582df96776e5ee98ca319d118ce0de2bbb2d8 /gcc
parentc01df3c86f72656e44ec1952b4e8019961ed7a4a (diff)
downloadgcc-bb75facd248a5030b5acd533ba4092e2d7fcd90b.zip
gcc-bb75facd248a5030b5acd533ba4092e2d7fcd90b.tar.gz
gcc-bb75facd248a5030b5acd533ba4092e2d7fcd90b.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/c/ChangeLog9
-rw-r--r--gcc/c/c-typeck.c30
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.target/i386/excess-precision-8.c61
4 files changed, 103 insertions, 2 deletions
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index e8e0fb0..742867a 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -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.
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 1956d45..73e7460 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -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,
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 57425159..b9bb9c6 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 0000000..c0a31ed
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/excess-precision-8.c
@@ -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);
+}