https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126641
--- Comment #17 from GCC Commits <cvs-commit at gcc dot gnu.org> --- The master branch has been updated by Jakub Jelinek <[email protected]>: https://gcc.gnu.org/g:255207b2ce6168cd9620980d448dc23e2488de7f commit r17-3056-g255207b2ce6168cd9620980d448dc23e2488de7f Author: Jakub Jelinek <[email protected]> Date: Fri Aug 7 09:45:04 2026 +0200 range-op-float, value-range: Fix up float_widen_lhs_range [PR126641] The recent change to make float_widen_lhs_range work on multiple subrange pairs broke e.g. the following testcase or various other things, set_significand is often called with SIGNIFICANT_BITS as the second argument and overflows the storage (in my case 3 elt array, if 192 is passed that stores [3]). The culprit is in the PR109008 optimization, float_widen_lhs_range produces something that isn't really a valid range for the corresponding type, it is the passed in valid range slightly extended if needed. The extension can be +-1ulp from the largest representable finite values (negative/positive) or +-0.5ulp in between some representable finite values, or in some cases +-1ulp. The reason for this hack is that extending by full representable 1ulp in all cases is simply too much, especially if that extension means going from the largest representable finite value to +-infinity. The function is used in various frange reverse ops and the intent is that this adjusted range doesn't really survive after the reverse operation handler, we should call some frange_arithmetic etc. call and that should handle even the not exactly representable in type (but representable in the gcc internal format, 160 bit precision, wide range of exponents) values, we do range_arithmetic which produces something in the gcc internal format and then round it to the mode of the desired type. Now, the r17-2929 change broke this, because it uses union_ -> frange_fusible_p -> frange_nextafter on those not exactly representable values and frange_nextafter -> real_nextafter quite understandably doesn't work properly on those values, to find the next after value it assumes the input is representable. The following patch fixes this by changing float_widen_lhs_range into a frange method, where users instead of doing wlhs = float_widen_lhs_range (type, lhs); do wlhs = lhs; wlhs.widen (type); and the new method widens the range directly on m_pairs elements, doesn't use set/union_. Because *this should be a canonicalized range, I think the widening shouldn't change the range canonicalization properties (like m_kind etc.), the extension is always just a tiny bit, shouldn't jump from finite to infinite or to NaN etc. The only thing that can happen is that e.g. with -frounding-math if the original range has 1ulp hole in betweenn pairs (say ~[0.5, 0.5] range that the widening of 0.5-1ulp could result in 0.5 and 0.5+1ulp on the other bound also to 0.5 could result in the same value, so the code just merges pairs in such rare cases. And we need to avoid copying the range, e.g. operator= invokes range verification which again calls frange_fusible_p -> frange_nextafter. 2026-08-07 Jakub Jelinek <[email protected]> PR tree-optimization/126641 * value-range.h (class frange): Declare widen method. * range-op-float.cc (float_widen_bound): Move to value-range.cc. (float_widen_lhs_range): Remove. (operator_plus::op1_range, operator_minus::op1_range, operator_minus::op2_range, operator_mult::op1_range, foperator_div::op1_range, foperator_div::op2_range, operator_cast::op1_range, range_op_float_tests): Replace X = float_widen_lhs_range (T, R) with X = R; X.widen (T). * value-range.cc (float_widen_bound): New, moved from range-op-float.cc. (frange::widen): New method, partially based on float_widen_lhs_range, but replace lhs with *this and avoid using set/union_ to construct range, instead modify m_pair and m_num_ranges directly. * real.cc (set_significand_bit, clear_significand_bit, test_significand_bit): Add gcc_checking_assert (n < SIGNIFICAND_BITS). (clear_significand_below): Add gcc_checking_assert (n <= SIGNIFICAND_BITS). * gcc.dg/pr126641.c: New test. Reviewed-by: Richard Biener <[email protected]> Reviewed-by: Aldy Hernandez <[email protected]>
