]> gcc.gnu.org Git - gcc.git/commit
c++: Implement excess precision support for C++ [PR107097, PR323]
authorJakub Jelinek <jakub@redhat.com>
Fri, 14 Oct 2022 07:28:57 +0000 (09:28 +0200)
committerJakub Jelinek <jakub@redhat.com>
Fri, 14 Oct 2022 07:28:57 +0000 (09:28 +0200)
commit98e341130f87984af07c884fea773c0bb3cc8821
tree2517b1b2ca58af9d2c34a5aaa25ea3e3cc568366
parent18981635127c6701733dc052aa054e569271b733
c++: Implement excess precision support for C++ [PR107097, PR323]

The following patch implements excess precision support for C++.
Like for C, it uses EXCESS_PRECISION_EXPR tree to say that its operand
is evaluated in excess precision and what the semantic type of the
expression is.
In most places I've followed what the C FE does in similar spots, so
e.g. for binary ops if one or both operands are already
EXCESS_PRECISION_EXPR, strip those away or for operations that might need
excess precision (+, -, *, /) check if the operands should use excess
precision and convert to that type and at the end wrap into
EXCESS_PRECISION_EXPR with the common semantic type.
This patch follows the C99 handling where it differs from C11 handling.

There are some cases which needed to be handled differently, the C FE can
just strip EXCESS_PRECISION_EXPR (replace it with its operand) when handling
explicit cast, but that IMHO isn't right for C++ - the discovery what exact
conversion should be used (e.g. if user conversion or standard or their
sequence) should be decided based on the semantic type (i.e. type of
EXCESS_PRECISION_EXPR), and that decision continues in convert_like* where
we pick the right user conversion, again, if say some class has ctor
from double and long double and we are on ia32 with standard excess
precision promoting float/double to long double, then we should pick the
ctor from double.  Or when some other class has ctor from just double,
and EXCESS_PRECISION_EXPR semantic type is float, we should choose the
user ctor from double, but actually just convert the long double excess
precision to double and not to float first.  We need to make sure
even identity conversion converts from excess precision to the semantic one
though, but if identity is chained with other conversions, we don't want
the identity next_conversion to drop to semantic precision only to widen
afterwards.

The existing testcases tweaks were for cases on i686-linux where excess
precision breaks those tests, e.g. if we have
  double d = 4.2;
  if (d == 4.2)
then it does the expected thing only with -fexcess-precision=fast,
because with -fexcess-precision=standard it is actually
  double d = 4.2;
  if ((long double) d == 4.2L)
where 4.2L is different from 4.2.  I've added -fexcess-precision=fast
to some tests and changed other tests to use constants that are exactly
representable and don't suffer from these excess precision issues.

There is one exception, pr68180.C looks like a bug in the patch which is
also present in the C FE (so I'd like to get it resolved incrementally
in both).  Reduced testcase:
typedef float __attribute__((vector_size (16))) float32x4_t;
float32x4_t foo(float32x4_t x, float y) { return x + y; }
with -m32 -std=c11 -Wno-psabi or -m32 -std=c++17 -Wno-psabi
it is rejected with:
pr68180.c:2:52: error: conversion of scalar ‘long double’ to vector ‘float32x4_t’ {aka ‘__vector(4) float’} involves truncation
but without excess precision (say just -std=c11 -Wno-psabi or -std=c++17 -Wno-psabi)
it is accepted.  Perhaps we should pass down the semantic type to
scalar_to_vector and use the semantic type rather than excess precision type
in the diagnostics.

2022-10-14  Jakub Jelinek  <jakub@redhat.com>

PR middle-end/323
PR c++/107097
gcc/
* doc/invoke.texi (-fexcess-precision=standard): Mention that the
option now also works in C++.
gcc/c-family/
* c-common.def (EXCESS_PRECISION_EXPR): Remove comment part about
the tree being specific to C/ObjC.
* c-opts.cc (c_common_post_options): Handle flag_excess_precision
in C++ the same as in C.
* c-lex.cc (interpret_float): Set const_type to excess_precision ()
even for C++.
gcc/cp/
* parser.cc (cp_parser_primary_expression): Handle
EXCESS_PRECISION_EXPR with REAL_CST operand the same as REAL_CST.
* cvt.cc (cp_ep_convert_and_check): New function.
* call.cc (build_conditional_expr): Add excess precision support.
When type_after_usual_arithmetic_conversions returns error_mark_node,
use gcc_checking_assert that it is because of uncomparable floating
point ranks instead of checking all those conditions and make it
work also with complex types.
(convert_like_internal): Likewise.  Add NESTED_P argument, pass true
to recursive calls to convert_like.
(convert_like): Add NESTED_P argument, pass it through to
convert_like_internal.  For other overload pass false to it.
(convert_like_with_context): Pass false to NESTED_P.
(convert_arg_to_ellipsis): Add excess precision support.
(magic_varargs_p): For __builtin_is{finite,inf,inf_sign,nan,normal}
and __builtin_fpclassify return 2 instead of 1, document what it
means.
(build_over_call): Don't handle former magic 2 which is no longer
used, instead for magic 1 remove EXCESS_PRECISION_EXPR.
(perform_direct_initialization_if_possible): Pass false to NESTED_P
convert_like argument.
* constexpr.cc (cxx_eval_constant_expression): Handle
EXCESS_PRECISION_EXPR.
(potential_constant_expression_1): Likewise.
* pt.cc (tsubst_copy, tsubst_copy_and_build): Likewise.
* cp-tree.h (cp_ep_convert_and_check): Declare.
* cp-gimplify.cc (cp_fold): Handle EXCESS_PRECISION_EXPR.
* typeck.cc (cp_common_type): For COMPLEX_TYPEs, return error_mark_node
if recursive call returned it.
(convert_arguments): For magic 1 remove EXCESS_PRECISION_EXPR.
(cp_build_binary_op): Add excess precision support.  When
cp_common_type returns error_mark_node, use gcc_checking_assert that
it is because of uncomparable floating point ranks instead of checking
all those conditions and make it work also with complex types.
(cp_build_unary_op): Likewise.
(cp_build_compound_expr): Likewise.
(build_static_cast_1): Remove EXCESS_PRECISION_EXPR.
gcc/testsuite/
* gcc.target/i386/excess-precision-1.c: For C++ wrap abort and
exit declarations into extern "C" block.
* gcc.target/i386/excess-precision-2.c: Likewise.
* gcc.target/i386/excess-precision-3.c: Likewise.  Remove
check_float_nonproto and check_double_nonproto tests for C++.
* gcc.target/i386/excess-precision-7.c: For C++ wrap abort and
exit declarations into extern "C" block.
* gcc.target/i386/excess-precision-9.c: Likewise.
* g++.target/i386/excess-precision-1.C: New test.
* g++.target/i386/excess-precision-2.C: New test.
* g++.target/i386/excess-precision-3.C: New test.
* g++.target/i386/excess-precision-4.C: New test.
* g++.target/i386/excess-precision-5.C: New test.
* g++.target/i386/excess-precision-6.C: New test.
* g++.target/i386/excess-precision-7.C: New test.
* g++.target/i386/excess-precision-9.C: New test.
* g++.target/i386/excess-precision-11.C: New test.
* c-c++-common/dfp/convert-bfp-10.c: Add -fexcess-precision=fast
as dg-additional-options.
* c-c++-common/dfp/compare-eq-const.c: Likewise.
* g++.dg/cpp1z/constexpr-96862.C: Likewise.
* g++.dg/cpp1z/decomp12.C (main): Use 2.25 instead of 2.3 to
avoid excess precision differences.
* g++.dg/other/thunk1.C: Add -fexcess-precision=fast
as dg-additional-options.
* g++.dg/vect/pr64410.cc: Likewise.
* g++.dg/cpp1y/pr68180.C: Likewise.
* g++.dg/vect/pr89653.cc: Likewise.
* g++.dg/cpp0x/variadic-tuple.C: Likewise.
* g++.dg/cpp0x/nsdmi-union1.C: Use 4.25 instead of 4.2 to
avoid excess precision differences.
* g++.old-deja/g++.brendan/copy9.C: Add -fexcess-precision=fast
as dg-additional-options.
* g++.old-deja/g++.brendan/overload7.C: Likewise.
38 files changed:
gcc/c-family/c-common.def
gcc/c-family/c-lex.cc
gcc/c-family/c-opts.cc
gcc/cp/call.cc
gcc/cp/constexpr.cc
gcc/cp/cp-gimplify.cc
gcc/cp/cp-tree.h
gcc/cp/cvt.cc
gcc/cp/parser.cc
gcc/cp/pt.cc
gcc/cp/typeck.cc
gcc/doc/invoke.texi
gcc/testsuite/c-c++-common/dfp/compare-eq-const.c
gcc/testsuite/c-c++-common/dfp/convert-bfp-10.c
gcc/testsuite/g++.dg/cpp0x/nsdmi-union1.C
gcc/testsuite/g++.dg/cpp0x/variadic-tuple.C
gcc/testsuite/g++.dg/cpp1y/pr68180.C
gcc/testsuite/g++.dg/cpp1z/constexpr-96862.C
gcc/testsuite/g++.dg/cpp1z/decomp12.C
gcc/testsuite/g++.dg/other/thunk1.C
gcc/testsuite/g++.dg/vect/pr64410.cc
gcc/testsuite/g++.dg/vect/pr89653.cc
gcc/testsuite/g++.old-deja/g++.brendan/copy9.C
gcc/testsuite/g++.old-deja/g++.brendan/overload7.C
gcc/testsuite/g++.target/i386/excess-precision-1.C [new file with mode: 0644]
gcc/testsuite/g++.target/i386/excess-precision-11.C [new file with mode: 0644]
gcc/testsuite/g++.target/i386/excess-precision-2.C [new file with mode: 0644]
gcc/testsuite/g++.target/i386/excess-precision-3.C [new file with mode: 0644]
gcc/testsuite/g++.target/i386/excess-precision-4.C [new file with mode: 0644]
gcc/testsuite/g++.target/i386/excess-precision-5.C [new file with mode: 0644]
gcc/testsuite/g++.target/i386/excess-precision-6.C [new file with mode: 0644]
gcc/testsuite/g++.target/i386/excess-precision-7.C [new file with mode: 0644]
gcc/testsuite/g++.target/i386/excess-precision-9.C [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/excess-precision-1.c
gcc/testsuite/gcc.target/i386/excess-precision-2.c
gcc/testsuite/gcc.target/i386/excess-precision-3.c
gcc/testsuite/gcc.target/i386/excess-precision-7.c
gcc/testsuite/gcc.target/i386/excess-precision-9.c
This page took 0.086101 seconds and 6 git commands to generate.