From: Paul F. <pj...@wa...> - 2021-10-21 21:02:50
|
On 21/10/2021 20:45, Florian Weimer wrote: > * Paul Floyd: > >> Unless someone else has an Idea this is going to need some debugging >> inside Valgrind. > It's probably the glibc implementation that is incorrectly executed by > valgrind. “g++ -fno-builtin” reproduces the issue with the original > sources. Yes, this is what is happening. Stepping through libc cbrtl with debuginfo, outside of Valgrind the return is where the arrow is, presumably fpclassify saying that it is FP_ZERO. xe is an int, can't imagine comparing it to zero is going to be a problem. 54 if (xe == 0 && fpclassify (x) <= FP_ZERO) │ >55 return x + x; The enum values returned by fpclassify are FP_NAN 0, FP_INFINITE 1, FP_ZERO 2. Inside Valgrind this test is false, and the (wrong) value that is calculated corresponds to the expressions and constants in the code. # define fpclassify(x) __builtin_fpclassify (FP_NAN, FP_INFINITE, \ FP_NORMAL, FP_SUBNORMAL, FP_ZERO, x) From what I see this builtin performs /* fpclassify(x) -> isnan(x) ? FP_NAN : (fabs(x) == Inf ? FP_INFINITE : (fabs(x) >= DBL_MIN ? FP_NORMAL : (x == 0 ? FP_ZERO : FP_SUBNORMAL))). */ For the first test, it looks like there is a 'fucomi'.That will set the parity flag if the input is NaN, but I only see ZF set. The next test is another 'fucomi' comparing to the largest long double followed by a 'ja', testing for Inf. The result is just CF set - less than. The third test is a 'fcompi' with ldbl_min. This sets ZF, and is followed by a 'jae'. That's wrong. That would mean 0.0 == ldbl_min. If internally we are working with double precision that it's to be expected that ldbl_min underflows to 0.0 and the comparison is true. It's a shame the libc test is done in this order. I don't see any easy fix for this. A+ Paul |