diff options
author | Joseph Myers <joseph@codesourcery.com> | 2017-09-15 21:49:02 +0100 |
---|---|---|
committer | Joseph Myers <jsm28@gcc.gnu.org> | 2017-09-15 21:49:02 +0100 |
commit | bb75facd248a5030b5acd533ba4092e2d7fcd90b (patch) | |
tree | a2d582df96776e5ee98ca319d118ce0de2bbb2d8 /gcc | |
parent | c01df3c86f72656e44ec1952b4e8019961ed7a4a (diff) | |
download | gcc-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/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/c/c-typeck.c | 30 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/excess-precision-8.c | 61 |
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); +} |