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