Compiler: Target: i686-linux-gnu GNU C (Ubuntu 4.8.4-2ubuntu1~14.04.3) version 4.8.4 (i686-linux-gnu) Compile option: -std=c99 The 4 expressions in the program below should give all the same answer. When using the mentioned compiler that has FLT_EVAL_METHOD=2 gives 3 different answers. The program: # include <stdio.h> # include <float.h> int main() { float f = 1.0; double d = 1.0; int i, j; #ifdef FLT_EVAL_METHOD printf("FLT_EVAL_METHOD: %d\n", FLT_EVAL_METHOD ); #endif i = 0x10001234; i += f; printf("i += f; \t0x%x\n", i ); i = 0x10001234; i += 1.0f; printf("i += 1.0f;\t0x%x\n", i ); i = 0x10001234; i = i + f; printf("i = i + f;\t0x%x\n", i ); i = 0x10001234; i = i + 1.0f; printf("i = i + 1.0f;\t0x%x\n", i ); } The results: FLT_EVAL_METHOD: 2 i += f; 0x10001240 i += 1.0f; 0x10001235 i = i + f; 0x10001241 i = i + 1.0f; 0x10001241 The correct answers is 0x10001241: the expression should be evaluated in long double.
That's the problem when you have too many answers: the right answer should be 0x10001235
Working on patches (first making compound assignments consistent with arithmetic operators in implementing the understanding of C99 semantics where integer conversions to floating point has no excess precision and 0x10001241 is the right answer, then making binary operators and conditional expressions also support post-N1531 C11 semantics where such implicit conversions have excess precision and 0x10001235 is the right answer).
Author: jsm28 Date: Fri Sep 1 16:29:49 2017 New Revision: 251603 URL: https://gcc.gnu.org/viewcvs?rev=251603&root=gcc&view=rev Log: Fix excess precision handling of compound assignments (PR c/82071). PR c/82071 reports how compound assignment operators such as += handle excess precision inconsistently with the same operation done with a plain assignment and binary operator. There were (at least) two problems with how compound assignments handled excess precision. The EXCESS_PRECISION_EXPR for an argument with excess precision was removed too early, resulting in build_binary_op being called with an rhs operand whose type reflected the evaluation format, so not having sufficient information to achieve the intended semantics in all cases, and then the code called c_fully_fold on the results of build_binary_op without allowing for the possibility of an EXCESS_PRECISION_EXPR as the result, so leading to double rounding of the result (first to its semantic type, then to the type of the LHS of the assignment) instead of the intended single rounding. This patch fixes those problems by keeping EXCESS_PRECISION_EXPRs further through build_modify_expr (and build_atomic_assign which it calls) and only removing them locally where appropriate. Note that while this patch should achieve *consistency*, that's consistency with the understanding of C99 semantics that I originally intended to implement. For the particular case in the testcase, C11 semantics (from N1531) differ from that understanding of C99 semantics, in that an implicit conversion of an integer to floating point can have excess precision. I intend to implement those C11 semantics separately (conditional on flag_isoc11) (which will also mean that building conditional expressions can produce a result with excess precision even when the arguments lack excess precision, where previously it could not), and not to close the bug until that is also done. Tested for x86_64-pc-linux-gnu. PR c/82071 gcc/c: * c-typeck.c (build_atomic_assign): Handle argument with excess precision. Ensure any EXCESS_PRECISION_EXPR is present in argument passed to build_binary_op and convert_for_assignment but not for call to c_fully_fold. (build_modify_expr): Do not remove EXCESS_PRECISION_EXPR early. Ensure build_binary_op is called with argument with original semantic type. Avoid calling c_fully_fold with an EXCESS_PRECISION_EXPR from build_binary_op. gcc/testsuite: * gcc.target/i386/excess-precision-7.c: New test. Added: trunk/gcc/testsuite/gcc.target/i386/excess-precision-7.c Modified: trunk/gcc/c/ChangeLog trunk/gcc/c/c-typeck.c trunk/gcc/testsuite/ChangeLog
Author: jsm28 Date: Fri Sep 15 20:49:02 2017 New Revision: 252847 URL: https://gcc.gnu.org/viewcvs?rev=252847&root=gcc&view=rev Log: 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. Added: trunk/gcc/testsuite/gcc.target/i386/excess-precision-8.c Modified: trunk/gcc/c/ChangeLog trunk/gcc/c/c-typeck.c trunk/gcc/testsuite/ChangeLog
Fixed for GCC 8.
*** Bug 82775 has been marked as a duplicate of this bug. ***
The master branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>: https://gcc.gnu.org/g:16ec267063c8ce60769888d4097bcd158410adc8 commit r13-3291-g16ec267063c8ce60769888d4097bcd158410adc8 Author: Jakub Jelinek <jakub@redhat.com> Date: Fri Oct 14 09:33:23 2022 +0200 c++: Excess precision for ? int : float or int == float [PR107097, PR82071, PR87390] The following incremental patch implements the C11 behavior (for all C++ versions) for cond ? int : float cond ? float : int int cmp float float cmp int where int is any integral type, float any floating point type with excess precision and cmp ==, !=, >, <, >=, <= and <=>. 2022-10-14 Jakub Jelinek <jakub@redhat.com> PR c/82071 PR c/87390 PR c++/107097 gcc/cp/ * cp-tree.h (cp_ep_convert_and_check): Remove. * cvt.cc (cp_ep_convert_and_check): Remove. * call.cc (build_conditional_expr): Use excess precision for ?: with one arm floating and another integral. Don't convert first to semantic result type from integral types. (convert_like_internal): Don't call cp_ep_convert_and_check, instead just strip EXCESS_PRECISION_EXPR before calling cp_convert_and_check or cp_convert. * typeck.cc (cp_build_binary_op): Set may_need_excess_precision for comparisons or SPACESHIP_EXPR with at least one operand integral. Don't compute semantic_result_type if build_type is non-NULL. Call cp_convert_and_check instead of cp_ep_convert_and_check. gcc/testsuite/ * gcc.target/i386/excess-precision-8.c: For C++ wrap abort and exit declarations into extern "C" block. * gcc.target/i386/excess-precision-10.c: Likewise. * g++.target/i386/excess-precision-7.C: Remove. * g++.target/i386/excess-precision-8.C: New test. * g++.target/i386/excess-precision-9.C: Remove. * g++.target/i386/excess-precision-10.C: New test. * g++.target/i386/excess-precision-12.C: New test.