https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107879

--- Comment #8 from CVS Commits <cvs-commit at gcc dot gnu.org> ---
The master branch has been updated by Jakub Jelinek <ja...@gcc.gnu.org>:

https://gcc.gnu.org/g:4500baaccb6e4d696e223c338bbdf7705c3646dd

commit r13-4492-g4500baaccb6e4d696e223c338bbdf7705c3646dd
Author: Jakub Jelinek <ja...@redhat.com>
Date:   Mon Dec 5 11:17:42 2022 +0100

    range-op-float: Fix up multiplication and division reverse operation
[PR107879]

    While for the normal cases it seems to be correct to implement
    reverse multiplication (op1_range/op2_range) through division
    with float_binary_op_range_finish, reverse division (op1_range)
    through multiplication with float_binary_op_range_finish or
    (op2_range) through division with float_binary_op_range_finish,
    as e.g. following testcase shows for the corner cases it is
    incorrect.
    Say on the testcase we are doing reverse multiplication, we
    have [-0., 0.] range (no NAN) on lhs and VARYING on op1 (or op2).
    We implement that through division, because x from
    lhs = x * op2
    is
    x = lhs / op2
    For the division, [-0., 0.] / VARYING is computed (IMHO correctly)
    as [-0., 0.] +-NAN, because 0 / anything but 0 or NAN is still
    0 and 0 / 0 is NAN and ditto 0 / NAN.  And then we just
    float_binary_op_range_finish, which figures out that because lhs
    can't be NAN, neither operand can be NAN.  So, the end range is
    [-0., 0.].  But that is not correct for the reverse multiplication.
    When the result is 0, if op2 can be zero, then x can be anything
    (VARYING), to be precise anything but INF (unless result can be NAN),
    because anything * 0 is 0 (or NAN for INF).  While if op2 must be
    non-zero, then x must be 0.  Of course the sign logic
    (signbit(x) = signbit(lhs) ^ signbit(op2)) still holds, so it actually
    isn't full VARYING if both lhs and op2 have known sign bits.
    And going through other corner cases one by one shows other differences
    between what we compute for the corresponding forward operation and
    what we should compute for the reverse operations.
    The following patch is slightly conservative and includes INF
    (in case of result including 0 and not NAN) in the ranges or
    0 in the ranges (in case of result including INF and not NAN).
    The latter is what happens anyway because we flush denormals to 0,
    and the former just not to deal with all the corner cases.
    So, the end test is that for reverse multiplication and division
    op2_range the cases we need to adjust to VARYING or VARYING positive
    or VARYING negative are if lhs and op? ranges both contain 0,
    or both contain some infinity, while for division op1_range the
    corner case is if lhs range contains 0 and op2 range contains INF or vice
    versa.  Otherwise I believe ranges from the corresponding operation
    are ok, or could be slightly more conservative (e.g. for
    reverse multiplication, if op? range is singleton INF and lhs
    range doesn't include any INF, then x's range should be UNDEFINED or
    known NAN (depending on if lhs can be NAN), while the division computes
    [-0., 0.] +-NAN; or similarly if op? range is only 0 and lhs range
    doesn't include 0, division would compute +INF +-NAN, or -INF +-NAN,
    or (for lack of multipart franges -INF +INF +-NAN just VARYING +-NAN),
    while again it is UNDEFINED or known NAN.

    Oh, and I found by code inspection wrong condition for the division's
    known NAN result, due to thinko it would trigger not just when
    both operands are known to be 0 or both are known to be INF, but
    when either both are known to be 0, or at least one is known to be INF.

    2022-12-05  Jakub Jelinek  <ja...@redhat.com>

            PR tree-optimization/107879
            * range-op-float.cc (foperator_mult::op1_range): If both
            lhs and op2 ranges contain zero or both ranges contain
            some infinity, set r range to zero_to_inf_range depending on
            signbit_known_p.
            (foperator_div::op2_range): Similarly for lhs and op1 ranges.
            (foperator_div::op1_range): If lhs range contains zero and op2
            range contains some infinity or vice versa, set r range to
            zero_to_inf_range depending on signbit_known_p.
            (foperator_div::rv_fold): Fix up condition for returning known NAN.

Reply via email to