[Bug c/89573] -fexcess-precision=standard doesn't work for conversion to integer of multiplication
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89573 --- Comment #8 from Richard Biener --- https://sourceware.org/bugzilla/show_bug.cgi?id=24346
[Bug c/89573] -fexcess-precision=standard doesn't work for conversion to integer of multiplication
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89573 Richard Biener changed: What|Removed |Added Status|UNCONFIRMED |RESOLVED Resolution|--- |MOVED --- Comment #7 from Richard Biener --- (In reply to jos...@codesourcery.com from comment #6) > On Thu, 14 Mar 2019, rguenther at suse dot de wrote: > > > I see. This means the different cases in the testcase in question are > > not equivalent (when excess precision is involved) and thus the > > expectation that they produce the same value is wrong which means the > > bug is INVALID? > > Yes. With, again, the question of whether glibc should be avoiding > returning with excess precision from log and other libm functions (where > at present it only tries to avoid excess range, and excess precision for > fully-determined IEEE functions such as sqrt). OK, so there's no GCC bug but forcing the glibc result to double "fixes" the issue. I'll re-file a glibc bug then. For reference, the following works as intended: #include #include int main(int argc, char **argv) { double p = 0.00053447623258905705; double inv_log_of_base = 1.41668185; volatile double lg = log(p); int r = lg * inv_log_of_base; printf("a: %d\n", r); double gr = log(p) * inv_log_of_base; printf("b: %g\n", gr); double g = log(p); int c = g * inv_log_of_base; printf("c: %d\n", c); return 0; }
[Bug c/89573] -fexcess-precision=standard doesn't work for conversion to integer of multiplication
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89573 --- Comment #6 from joseph at codesourcery dot com --- On Thu, 14 Mar 2019, rguenther at suse dot de wrote: > I see. This means the different cases in the testcase in question are > not equivalent (when excess precision is involved) and thus the > expectation that they produce the same value is wrong which means the > bug is INVALID? Yes. With, again, the question of whether glibc should be avoiding returning with excess precision from log and other libm functions (where at present it only tries to avoid excess range, and excess precision for fully-determined IEEE functions such as sqrt).
[Bug c/89573] -fexcess-precision=standard doesn't work for conversion to integer of multiplication
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89573 --- Comment #5 from rguenther at suse dot de --- On Wed, 13 Mar 2019, joseph at codesourcery dot com wrote: > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89573 > > --- Comment #4 from joseph at codesourcery dot com dot com> --- > On Mon, 11 Mar 2019, rguenth at gcc dot gnu.org wrote: > > > > I wouldn't expect such a cast to be generated on the result of the > > > multiplication; I'd expect long double to be converted directly to int. > > > There is, indeed, a test of that (see test_cast in > > > gcc.target/i386/excess-precision-1.c). > > > > Exactly why? The multiplication result has excess precision here. > > Do you say an extra rounding step to double precision cannot change > > the conversion to integer result or do you say such extra rounding step > > isn't allowed here? IMHO this is exactly the "issue" pointed out by > > the testcase. > > The extra rounding step isn't allowed by the language semantics as I > understand them. The result of the double multiplication is represented > with the range and precision of long double and must be converted directly > to int, not to double and then to int. I see. This means the different cases in the testcase in question are not equivalent (when excess precision is involved) and thus the expectation that they produce the same value is wrong which means the bug is INVALID?
[Bug c/89573] -fexcess-precision=standard doesn't work for conversion to integer of multiplication
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89573 --- Comment #4 from joseph at codesourcery dot com --- On Mon, 11 Mar 2019, rguenth at gcc dot gnu.org wrote: > > I wouldn't expect such a cast to be generated on the result of the > > multiplication; I'd expect long double to be converted directly to int. > > There is, indeed, a test of that (see test_cast in > > gcc.target/i386/excess-precision-1.c). > > Exactly why? The multiplication result has excess precision here. > Do you say an extra rounding step to double precision cannot change > the conversion to integer result or do you say such extra rounding step > isn't allowed here? IMHO this is exactly the "issue" pointed out by > the testcase. The extra rounding step isn't allowed by the language semantics as I understand them. The result of the double multiplication is represented with the range and precision of long double and must be converted directly to int, not to double and then to int. > Note the frontend _does_ originally emit (int) (double) ((long double) log (p) > * (long double) inv_log_of_base) but the conversion to double is elided The front end should not be emitting such a conversion to double. An EXCESS_PRECISION_EXPR is not a conversion (and convert_for_assignment removes an EXCESS_PRECISION_EXPR very early, before converting to the desired type). > by convert_to_real in the code piece I qouted. The truncation to double should not be removed because it should fail the real_can_shorten_arithmetic test, as well as failing the !excess_precision_type (newtype) test (the former is testing whether removing such a truncation is valid in the sense of not affecting the result, the latter is testing whether the change of type for arithmetic would run into the back end not actually having proper arithmetic operations for the narrower type).
[Bug c/89573] -fexcess-precision=standard doesn't work for conversion to integer of multiplication
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89573 --- Comment #3 from Richard Biener --- (In reply to jos...@codesourcery.com from comment #2) > On Mon, 4 Mar 2019, rguenth at gcc dot gnu.org wrote: > > > where the first result is off. The IL looks like > > > > int r = (int) ((long double) log (p) * (long double) inv_log_of_base); > > > > where possibly the missing cast to (double) is elided by bogus optimization > > (didn't try to track down the issue yet). > > What missing cast to double? > > I wouldn't expect such a cast to be generated on the result of the > multiplication; I'd expect long double to be converted directly to int. > There is, indeed, a test of that (see test_cast in > gcc.target/i386/excess-precision-1.c). Exactly why? The multiplication result has excess precision here. Do you say an extra rounding step to double precision cannot change the conversion to integer result or do you say such extra rounding step isn't allowed here? IMHO this is exactly the "issue" pointed out by the testcase. Note the frontend _does_ originally emit (int) (double) ((long double) log (p) * (long double) inv_log_of_base) but the conversion to double is elided by convert_to_real in the code piece I qouted.
[Bug c/89573] -fexcess-precision=standard doesn't work for conversion to integer of multiplication
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89573 --- Comment #2 from joseph at codesourcery dot com --- On Mon, 4 Mar 2019, rguenth at gcc dot gnu.org wrote: > where the first result is off. The IL looks like > > int r = (int) ((long double) log (p) * (long double) inv_log_of_base); > > where possibly the missing cast to (double) is elided by bogus optimization > (didn't try to track down the issue yet). What missing cast to double? I wouldn't expect such a cast to be generated on the result of the multiplication; I'd expect long double to be converted directly to int. There is, indeed, a test of that (see test_cast in gcc.target/i386/excess-precision-1.c). You could argue about whether the result of log should be converted to double (the GCC IR is unable to represent that a function might return a result with excess range and precision, as far as it's concerned the return value of log is always representable in double) - but if the issue is with the return value of log, that would be a glibc issue, where maybe glibc should avoid excess precision in return values (currently it only does so for functions with exactly determined IEEE results, and otherwise acts to avoid excess range but not excess precision in return values). In the presence of Annex F a function defined by the user cannot return with excess range or precision, but that may not apply to standard library functions which don't need to behave as if written in standard C. convert_to_real_1 has a detailed check for when conversions can be removed (see the "Sometimes this transformation is safe" comment), but that shouldn't be relevant here (it's cases like (float)((double)float * (double)float) where removing conversions is safe).
[Bug c/89573] -fexcess-precision=standard doesn't work for conversion to integer of multiplication
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89573 Richard Biener changed: What|Removed |Added CC||jsm28 at gcc dot gnu.org --- Comment #1 from Richard Biener --- The FE correctly builds <<< Unknown tree: excess_precision_expr (long double) __builtin_log (p) * (long double) inv_log_of_base >>> but then convert_for_assignment seems to elide via convert_to_real_1: /* Convert (outertype)((innertype0)a+(innertype1)b) into ((newtype)a+(newtype)b) where newtype is the widest mode from all of these. */ 304 case PLUS_EXPR: 305 case MINUS_EXPR: 306 case MULT_EXPR: 307 case RDIV_EXPR: 308{ 309 tree arg0 = strip_float_extensions (TREE_OPERAND (expr, 0)); 310 tree arg1 = strip_float_extensions (TREE_OPERAND (expr, 1)); where strip_float_extensions makes the comment not true (because we ignore the casts to long double). Maybe the code in convert_and_check 1627 if (TREE_CODE (expr) == EXCESS_PRECISION_EXPR) 1628{ 1629 tree orig_type = TREE_TYPE (expr); 1630 expr = TREE_OPERAND (expr, 0); 1631 expr_for_warning = convert (orig_type, expr); 1632 if (orig_type == type) 1633return expr_for_warning; shouldn't use convert here but convert_to_real_1 with fold_p = false? But then other code may simply elide the conversions (can we really ignore the extra rounding performed by the outer truncating conversion, ever?)