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