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

--- Comment #1 from GCC Commits <cvs-commit at gcc dot gnu.org> ---
The master branch has been updated by Kyrylo Tkachov <[email protected]>:

https://gcc.gnu.org/g:e8621d3bdaf022078b98614a003ea2f5bf95e7b4

commit r17-5260-ge8621d3bdaf022078b98614a003ea2f5bf95e7b4
Author: Kyrylo Tkachov <[email protected]>
Date:   Thu Oct 15 20:08:43 2026 +0200

    match-sat-alu.pd: Check operand types of signed SAT_ADD [PR127916]

    .SAT_ADD saturates in the type of its first operand.  Two
    signed_integer_sat_add forms do not check that this is the result type.

    The .ADD_OVERFLOW (X, Y) form lost its types_match check in r15-6406:

      signed char
      another_sat (int a, int b)
      {
        signed char r;
        if (__builtin_add_overflow (a, b, &r))
          return a < 0 ? SCHAR_MIN : SCHAR_MAX;
        return r;
      }

      __complex__ signed char _6;
      ...
      _6 = .ADD_OVERFLOW (a_4(D), b_5(D));
      _2 = IMAGPART_EXPR <_6>;
      if (_2 != 0)
      ...
      _1 = REALPART_EXPR <_6>;
      ...
      _11 = _10 ^ 127;
      # _3 = PHI <_11(4), _1(3)>

    widening_mul replaces the PHI with _3 = .SAT_ADD (a_4(D), b_5(D)), which
    saturates in int, so another_sat (-1, 200) returns -57 instead of -128.
    The vectorizer goes wrong in the same way.  Operands of the other sign
    and constants that do not fit the result type also go wrong.

    The IMM = -1 form matches X + -1 under a conversion to the result type,
    which can change the precision:

      short
      dec (int a)
      {
        unsigned ua = a, r = ua - 1;
        if ((a & (int) -ua) < 0)
          r = 0x8000u;
        return r;
      }

    At -Os this ICEs in wi::eq_p when checking is enabled.  Without checking,
    dec (INT_MIN) returns 0 instead of -32768.

    Require X to have the result type in both forms.  In the .ADD_OVERFLOW
    form, also require Y to have it or to be a constant that fits it.  Both
    callers convert such a constant.  Assert in the SAT_ADD callers that the
    first operand has the result type.

    Narrower Y operands no longer match.  Trunk got those right only because
    expand converts each .SAT_ADD operand.

    Bootstrapped and tested as part of the series on
    aarch64-unknown-linux-gnu and x86_64-pc-linux-gnu.

            PR tree-optimization/127916

    gcc/ChangeLog:

            * match-sat-alu.pd (signed_integer_sat_add): Check the operand
types
            of the .ADD_OVERFLOW form and of the IMM = -1 form.
            * tree-ssa-math-opts.cc (match_saturation_add_with_assign): Assert
            that the first operand has the type of the result.
            (match_saturation_add): Likewise.
            * tree-vect-patterns.cc (vect_recog_sat_add_pattern): Likewise.

    gcc/testsuite/ChangeLog:

            * gcc.dg/torture/pr127916.c: New test.

    Signed-off-by: Kyrylo Tkachov <[email protected]>

Reply via email to