http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55451



--- Comment #2 from Jakub Jelinek <jakub at gcc dot gnu.org> 2012-11-30 
09:56:02 UTC ---

I can't reproduce it with a cross-compiler, for me it optimizes into

  <bb 2>:

  _2 = VIEW_CONVERT_EXPR<SItype>(a_5(D));

  if (_2 == -2147483648)

    goto <bb 4>;

  else

    goto <bb 3>;



  <bb 3>:

  z_3 = -_2;



  <bb 4>:

  # z_6 = PHI <2147483647(2), z_3(3)>

  _4 = VIEW_CONVERT_EXPR<SQtype>(z_6);

  return _4;

but perhaps it is related to HWI size.  That said, the bug is clearly on the

fixed-point.c side:

  SQtype c;

  SItype x, y, z;

  memcpy (&y, &a, 4);

  x = 0;

  z = x - y;

  if (((x ^ y) >> (31 + 0)) & 1)

    {

      if (((z ^ x) >> (31 + 0)) & 1)

        {

          z = 1;

          z = z << (31 + 0);

          if (x >= 0)

            z--;

        }

    }

  memcpy (&c, &z, 4);

  return c;

If this routine is called with bits 0x80000000, then z = x - y; triggers

undefined signed overflow, and afterwards testing (very weirdo very fancy way)

for the most negative value (which is the only one that triggers undefined

signed overflow) is already way too late.  Note there is another undefined

signed overflow later on, z-- where z was previously the most negative signed

integer.



So, completely untested:

--- libgcc/fixed-bit.c    2011-11-04 07:49:37.000000000 +0100

+++ libgcc/fixed-bit.c    2012-11-30 10:52:45.559780132 +0100

@@ -569,16 +569,11 @@ FIXED_SSNEG (FIXED_C_TYPE a)

   INT_C_TYPE x, y, z;

   memcpy (&y, &a, FIXED_SIZE);

   x = 0;

-  z = x - y;

+  z = x - (UINT_C_TYPE) y;

   if (((x ^ y) >> I_F_BITS) & 1)

     {

       if (((z ^ x) >> I_F_BITS) & 1)

-        {

-          z = 1;

-          z = z << I_F_BITS;

-          if (x >= 0)

-            z--;

-        }

+    z = (((UINT_C_TYPE) 1) << I_F_BITS) - 1;

     }

 #if HAVE_PADDING_BITS

   z = z << PADDING_BITS;



could fix those two undefined behaviors.  That said, the existence of the x

variable which is set to 0, then xored with various things and tested if it is

>= 0, seems very nonsensical obfuscation to me.  Why not drop x altogether, and

just use z = - (UINT_C_TYPE) y; and y >> I_F_BITS resp. z >> I_F_BITS?

Reply via email to