1  /* With -fwhole-program this is an excelent testcase for inlining IPA-SRAed
       2     functions into each other.  */
       3  /* { dg-do run } */
       4  /* { dg-options "-O2 -w -fno-ipa-cp -fwhole-program"  } */
       5  /* { dg-require-effective-target int32plus } */
       6  
       7  #define PART_PRECISION (sizeof (cpp_num_part) * 8)
       8  
       9  typedef unsigned int cpp_num_part;
      10  typedef struct cpp_num cpp_num;
      11  struct cpp_num
      12  {
      13     cpp_num_part high;
      14     cpp_num_part low;
      15     int unsignedp;  /* True if value should be treated as unsigned.  */
      16     int overflow;   /* True if the most recent calculation overflowed.  */
      17  };
      18  
      19  static  int
      20  num_positive (cpp_num num, unsigned int precision)
      21  {
      22     if (precision > PART_PRECISION)
      23       {
      24         precision -= PART_PRECISION;
      25         return (num.high & (cpp_num_part) 1 << (precision - 1)) == 0;
      26       }
      27  
      28     return (num.low & (cpp_num_part) 1 << (precision - 1)) == 0;
      29  }
      30  
      31  static cpp_num
      32  num_trim (cpp_num num, unsigned int precision)
      33  {
      34     if (precision > PART_PRECISION)
      35       {
      36         precision -= PART_PRECISION;
      37         if (precision < PART_PRECISION)
      38           num.high &= ((cpp_num_part) 1 << precision) - 1;
      39       }
      40     else
      41       {
      42         if (precision < PART_PRECISION)
      43           num.low &= ((cpp_num_part) 1 << precision) - 1;
      44         num.high = 0;
      45       }
      46  
      47     return num;
      48  }
      49  
      50  /* Shift NUM, of width PRECISION, right by N bits.  */
      51  static cpp_num
      52  num_rshift (cpp_num num, unsigned int precision, unsigned int n)
      53  {
      54     cpp_num_part sign_mask;
      55     int x = num_positive (num, precision);
      56  
      57     if (num.unsignedp || x)
      58       sign_mask = 0;
      59     else
      60       sign_mask = ~(cpp_num_part) 0;
      61  
      62     if (n >= precision)
      63       num.high = num.low = sign_mask;
      64     else
      65       {
      66         /* Sign-extend.  */
      67         if (precision < PART_PRECISION)
      68           num.high = sign_mask, num.low |= sign_mask << precision;
      69         else if (precision < 2 * PART_PRECISION)
      70           num.high |= sign_mask << (precision - PART_PRECISION);
      71  
      72         if (n >= PART_PRECISION)
      73           {
      74             n -= PART_PRECISION;
      75             num.low = num.high;
      76             num.high = sign_mask;
      77           }
      78  
      79         if (n)
      80           {
      81             num.low = (num.low >> n) | (num.high << (PART_PRECISION - n));
      82             num.high = (num.high >> n) | (sign_mask << (PART_PRECISION - n));
      83           }
      84       }
      85  
      86     num = num_trim (num, precision);
      87     num.overflow = 0;
      88     return num;
      89  }
      90                                #define num_zerop(num) ((num.low | num.high) == 0)
      91  #define num_eq(num1, num2) (num1.low == num2.low && num1.high == num2.high)
      92  
      93  cpp_num
      94  num_lshift (cpp_num num, unsigned int precision, unsigned int n)
      95  {
      96     if (n >= precision)
      97       {
      98         num.overflow = !num.unsignedp && !num_zerop (num);
      99         num.high = num.low = 0;
     100       }
     101     else
     102       {
     103         cpp_num orig;
     104         unsigned int m = n;
     105  
     106         orig = num;
     107         if (m >= PART_PRECISION)
     108           {
     109             m -= PART_PRECISION;
     110             num.high = num.low;
     111             num.low = 0;
     112           }
     113         if (m)
     114           {
     115             num.high = (num.high << m) | (num.low >> (PART_PRECISION - m));
     116             num.low <<= m;
     117           }
     118         num = num_trim (num, precision);
     119  
     120         if (num.unsignedp)
     121           num.overflow = 0;
     122         else
     123           {
     124             cpp_num maybe_orig = num_rshift (num, precision, n);
     125             num.overflow = !num_eq (orig, maybe_orig);
     126           }
     127       }
     128  
     129     return num;
     130  }
     131  
     132  unsigned int precision = 64;
     133  unsigned int n = 16;
     134  
     135  cpp_num num = { 0, 3, 0, 0 };
     136  
     137  int main()
     138  {
     139     cpp_num res = num_lshift (num, 64, n);
     140  
     141     if (res.low != 0x30000)
     142       abort ();
     143  
     144     if (res.high != 0)
     145       abort ();
     146  
     147     if (res.overflow != 0)
     148       abort ();
     149  
     150     exit (0);
     151  }