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

--- Comment #4 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
So, even
__attribute__((noipa)) void
foo (int x)
{
  __int128 t = 0x7fffffffffffffffffffffffffffffffwb;
  if (!__builtin_mul_overflow_p (t, x, (_BitInt (127)) 0))
    __builtin_abort ();
}

int
main ()
{
  foo (8);
}
is miscompiled but with s/127/128/ it is not.
Seems the problem is that first in GIMPLE opts we optimize the
signed __int128 INT128_MAX argument into unsigned _BitInt(127) argument of the
same value (which is generally fine, __builtin_mul_overflow is defined as the
two operands extended to infinite precision, multiplied and then whether it is
representable in the selected result type or not.
The _BitInt support commit then added to expand_mul_overflow:
 /* Unsigned types with smaller than mode precision, even if they have most
    significant bit set, are still zero-extended.  */
 if (uns0_p && TYPE_PRECISION (TREE_TYPE (arg0)) < GET_MODE_PRECISION (mode))
   pos_neg0 = 1;
 if (uns1_p && TYPE_PRECISION (TREE_TYPE (arg1)) < GET_MODE_PRECISION (mode))
   pos_neg1 = 1;
which is also correct, for the 0x7fffffffffffffffffffffffffffffffuwb we
shouldn't treat it as pos_neg1 = 2 because it has the most significant bit (bit
127) set.
But then we take the
  /* s1 * u2 -> sr  */
  if (!uns0_p && uns1_p && !unsr_p)
    {
      switch (pos_neg1)
        {
        case 1:
          goto do_main;
patch and goto do_main to perform the signed multiplication, but
          unsigned int mprec1 = prec;
          if (arg1 != error_mark_node)
            mprec1 = get_min_precision (arg1, sign);
will do the completely wrong thing, sign is SIGNED and for the
0x7fffffffffffffffffffffffffffffffuwb INTEGER_CST in unsigned _BitInt(127) type
that returns 1 (when treated as signed it is -1).

Reply via email to