1 // RUN: %clang_cc1 -ffixed-point -triple x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,SIGNED
2 // RUN: %clang_cc1 -ffixed-point -triple x86_64-unknown-linux-gnu -S -emit-llvm %s -o - -fpadding-on-unsigned-fixed-point | FileCheck %s --check-prefixes=CHECK,UNSIGNED
3 
4 // Between different fixed point types
5 short _Accum sa_const = 2.5hk; // CHECK-DAG: @sa_const  = {{.*}}global i16 320, align 2
6 _Accum a_const = 2.5hk;        // CHECK-DAG: @a_const   = {{.*}}global i32 81920, align 4
7 short _Accum sa_const2 = 2.5k; // CHECK-DAG: @sa_const2 = {{.*}}global i16 320, align 2
8 
9 short _Accum sa_from_f_const = 0.5r; // CHECK-DAG: sa_from_f_const = {{.*}}global i16 64, align 2
10 _Fract f_from_sa_const = 0.5hk;      // CHECK-DAG: f_from_sa_const = {{.*}}global i16 16384, align 2
11 
12 unsigned short _Accum usa_const = 2.5uk;
13 unsigned _Accum ua_const = 2.5uhk;
14 // SIGNED-DAG: @usa_const  = {{.*}}global i16 640, align 2
15 // SIGNED-DAG: @ua_const   = {{.*}}global i32 163840, align 4
16 // UNSIGNED-DAG:    @usa_const  = {{.*}}global i16 320, align 2
17 // UNSIGNED-DAG:    @ua_const   = {{.*}}global i32 81920, align 4
18 
19 // FixedPoint to integer
20 int i_const = -128.0hk;  // CHECK-DAG: @i_const  = {{.*}}global i32 -128, align 4
21 int i_const2 = 128.0hk;  // CHECK-DAG: @i_const2 = {{.*}}global i32 128, align 4
22 int i_const3 = -128.0k;  // CHECK-DAG: @i_const3 = {{.*}}global i32 -128, align 4
23 int i_const4 = 128.0k;   // CHECK-DAG: @i_const4 = {{.*}}global i32 128, align 4
24 short s_const = -128.0k; // CHECK-DAG: @s_const  = {{.*}}global i16 -128, align 2
25 short s_const2 = 128.0k; // CHECK-DAG: @s_const2 = {{.*}}global i16 128, align 2
26 
27 // Integer to fixed point
28 short _Accum sa_const5 = 2;    // CHECK-DAG: @sa_const5 = {{.*}}global i16 256, align 2
29 short _Accum sa_const6 = -2;   // CHECK-DAG: @sa_const6 = {{.*}}global i16 -256, align 2
30 short _Accum sa_const7 = -256; // CHECK-DAG: @sa_const7 = {{.*}}global i16 -32768, align 2
31 
32 // Signedness
33 unsigned short _Accum usa_const2 = 2.5hk;
34 // SIGNED-DAG: @usa_const2  = {{.*}}global i16 640, align 2
35 // UNSIGNED-DAG:    @usa_const2  = {{.*}}global i16 320, align 2
36 short _Accum sa_const3 = 2.5hk; // CHECK-DAG: @sa_const3 = {{.*}}global i16 320, align 2
37 
38 int i_const5 = 128.0uhk;
39 unsigned int ui_const = 128.0hk;
40 // CHECK-DAG: @i_const5  = {{.*}}global i32 128, align 4
41 // CHECK-DAG: @ui_const  = {{.*}}global i32 128, align 4
42 
43 short _Accum sa_const9 = 2u; // CHECK-DAG: @sa_const9 = {{.*}}global i16 256, align 2
44 unsigned short _Accum usa_const3 = 2;
45 // SIGNED-DAG: @usa_const3 = {{.*}}global i16 512, align 2
46 // UNSIGNED-DAG:    @usa_const3 = {{.*}}global i16 256, align 2
47 
48 // Overflow (this is undefined but allowed)
49 short _Accum sa_const4 = 256.0k;
50 unsigned int ui_const2 = -2.5hk;
51 short _Accum sa_const8 = 256;
52 unsigned short _Accum usa_const4 = -2;
53 
54 // Saturation
55 _Sat short _Accum sat_sa_const = 2.5hk;   // CHECK-DAG: @sat_sa_const  = {{.*}}global i16 320, align 2
56 _Sat short _Accum sat_sa_const2 = 256.0k; // CHECK-DAG: @sat_sa_const2 = {{.*}}global i16 32767, align 2
57 _Sat unsigned short _Accum sat_usa_const = -1.0hk;
58 // CHECK-DAG: @sat_usa_const = {{.*}}global i16 0, align 2
59 _Sat unsigned short _Accum sat_usa_const2 = 256.0k;
60 // SIGNED-DAG: @sat_usa_const2 = {{.*}}global i16 -1, align 2
61 // UNSIGNED-DAG:    @sat_usa_const2 = {{.*}}global i16 32767, align 2
62 
63 _Sat short _Accum sat_sa_const3 = 256;  // CHECK-DAG: @sat_sa_const3 = {{.*}}global i16 32767, align 2
64 _Sat short _Accum sat_sa_const4 = -257; // CHECK-DAG: @sat_sa_const4 = {{.*}}global i16 -32768, align 2
65 _Sat unsigned short _Accum sat_usa_const3 = -1;
66 // CHECK-DAG: @sat_usa_const3 = {{.*}}global i16 0, align 2
67 _Sat unsigned short _Accum sat_usa_const4 = 256;
68 // SIGNED-DAG: @sat_usa_const4 = {{.*}}global i16 -1, align 2
69 // UNSIGNED-DAG:    @sat_usa_const4 = {{.*}}global i16 32767, align 2
70 
TestFixedPointCastSameType()71 void TestFixedPointCastSameType() {
72   _Accum a = 2.5k;
73   _Accum a2 = a;
74   // CHECK:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
75   // CHECK-NEXT: store i32 [[ACCUM]], i32* %a2, align 4
76 
77   a2 = (_Accum)a;
78   // CHECK:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
79   // CHECK-NEXT: store i32 [[ACCUM]], i32* %a2, align 4
80 }
81 
TestFixedPointCastDown()82 void TestFixedPointCastDown() {
83   long _Accum la = 2.5lk;
84   _Accum a = la;
85   // CHECK:      [[LACCUM:%[0-9a-z]+]] = load i64, i64* %la, align 8
86   // CHECK-NEXT: [[ACCUM_AS_I64:%[0-9a-z]+]] = ashr i64 [[LACCUM]], 16
87   // CHECK-NEXT: [[ACCUM:%[0-9a-z]+]] = trunc i64 [[ACCUM_AS_I64]] to i32
88   // CHECK-NEXT: store i32 [[ACCUM]], i32* %a, align 4
89 
90   a = (_Accum)la;
91   // CHECK:      [[LACCUM:%[0-9a-z]+]] = load i64, i64* %la, align 8
92   // CHECK-NEXT: [[ACCUM_AS_I64:%[0-9a-z]+]] = ashr i64 [[LACCUM]], 16
93   // CHECK-NEXT: [[ACCUM:%[0-9a-z]+]] = trunc i64 [[ACCUM_AS_I64]] to i32
94   // CHECK-NEXT: store i32 [[ACCUM]], i32* %a, align 4
95 
96   short _Accum sa = a;
97   // CHECK:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
98   // CHECK-NEXT: [[SACCUM_AS_I32:%[0-9a-z]+]] = ashr i32 [[ACCUM]], 8
99   // CHECK-NEXT: [[SACCUM:%[0-9a-z]+]] = trunc i32 [[SACCUM_AS_I32]] to i16
100   // CHECK-NEXT: store i16 [[SACCUM]], i16* %sa, align 2
101 
102   sa = (short _Accum)a;
103   // CHECK:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
104   // CHECK-NEXT: [[SACCUM_AS_I32:%[0-9a-z]+]] = ashr i32 [[ACCUM]], 8
105   // CHECK-NEXT: [[SACCUM:%[0-9a-z]+]] = trunc i32 [[SACCUM_AS_I32]] to i16
106   // CHECK-NEXT: store i16 [[SACCUM]], i16* %sa, align 2
107 }
108 
TestFixedPointCastUp()109 void TestFixedPointCastUp() {
110   short _Accum sa = 2.5hk;
111   _Accum a = sa;
112   // CHECK:      [[SACCUM:%[0-9a-z]+]] = load i16, i16* %sa, align 2
113   // CHECK-NEXT: [[SACCUM_BUFF:%[0-9a-z]+]] = sext i16 [[SACCUM]] to i32
114   // CHECK-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i32 [[SACCUM_BUFF]], 8
115   // CHECK-NEXT: store i32 [[ACCUM]], i32* %a, align 4
116 
117   long _Accum la = a;
118   // CHECK:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
119   // CHECK-NEXT: [[ACCUM_BUFF:%[0-9a-z]+]] = sext i32 [[ACCUM]] to i64
120   // CHECK-NEXT: [[LACCUM:%[0-9a-z]+]] = shl i64 [[ACCUM_BUFF]], 16
121   // CHECK-NEXT: store i64 [[LACCUM]], i64* %la, align 8
122 
123   a = (_Accum)sa;
124   // CHECK:      [[SACCUM:%[0-9a-z]+]] = load i16, i16* %sa, align 2
125   // CHECK-NEXT: [[SACCUM_BUFF:%[0-9a-z]+]] = sext i16 [[SACCUM]] to i32
126   // CHECK-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i32 [[SACCUM_BUFF]], 8
127   // CHECK-NEXT: store i32 [[ACCUM]], i32* %a, align 4
128 
129   la = (long _Accum)a;
130   // CHECK:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
131   // CHECK-NEXT: [[ACCUM_BUFF:%[0-9a-z]+]] = sext i32 [[ACCUM]] to i64
132   // CHECK-NEXT: [[LACCUM:%[0-9a-z]+]] = shl i64 [[ACCUM_BUFF]], 16
133   // CHECK-NEXT: store i64 [[LACCUM]], i64* %la, align 8
134 }
135 
TestFixedPointCastSignedness()136 void TestFixedPointCastSignedness() {
137   _Accum a = 2.5k;
138   unsigned _Accum ua = a;
139   // SIGNED:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
140   // SIGNED-NEXT: [[UACCUM:%[0-9a-z]+]] = shl i32 [[ACCUM]], 1
141   // SIGNED-NEXT: store i32 [[UACCUM]], i32* %ua, align 4
142   // UNSIGNED:      TestFixedPointCastSignedness
143   // UNSIGNED:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
144   // UNSIGNED-NEXT: store i32 [[ACCUM]], i32* %ua, align 4
145 
146   a = ua;
147   // SIGNED:      [[UACCUM:%[0-9a-z]+]] = load i32, i32* %ua, align 4
148   // SIGNED-NEXT: [[ACCUM:%[0-9a-z]+]] = lshr i32 [[UACCUM]], 1
149   // SIGNED-NEXT: store i32 [[ACCUM]], i32* %a, align 4
150   // UNSIGNED:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %ua, align 4
151   // UNSIGNED-NEXT: store i32 [[ACCUM]], i32* %a, align 4
152 
153   ua = (unsigned _Accum)a;
154   // SIGNED:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
155   // SIGNED-NEXT: [[UACCUM:%[0-9a-z]+]] = shl i32 [[ACCUM]], 1
156   // SIGNED-NEXT: store i32 [[UACCUM]], i32* %ua, align 4
157   // UNSIGNED:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
158   // UNSIGNED-NEXT: store i32 [[ACCUM]], i32* %ua, align 4
159 
160   a = (_Accum)ua;
161   // SIGNED:      [[UACCUM:%[0-9a-z]+]] = load i32, i32* %ua, align 4
162   // SIGNED-NEXT: [[ACCUM:%[0-9a-z]+]] = lshr i32 [[UACCUM]], 1
163   // SIGNED-NEXT: store i32 [[ACCUM]], i32* %a, align 4
164   // UNSIGNED:      [[UACCUM:%[0-9a-z]+]] = load i32, i32* %ua, align 4
165   // UNSIGNED-NEXT: store i32 [[UACCUM]], i32* %a, align 4
166 
167   _Accum a2;
168   unsigned long _Accum ula = a2;
169   // SIGNED:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a2, align 4
170   // SIGNED-NEXT: [[ACCUM_EXT:%[0-9a-z]+]] = sext i32 [[ACCUM]] to i64
171   // SIGNED-NEXT: [[LACCUM:%[0-9a-z]+]] = shl i64 [[ACCUM_EXT]], 17
172   // SIGNED-NEXT: store i64 [[LACCUM]], i64* %ula, align 8
173   // UNSIGNED:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a2, align 4
174   // UNSIGNED-NEXT: [[ACCUM_EXT:%[0-9a-z]+]] = sext i32 [[ACCUM]] to i64
175   // UNSIGNED-NEXT: [[LACCUM:%[0-9a-z]+]] = shl i64 [[ACCUM_EXT]], 16
176   // UNSIGNED-NEXT: store i64 [[LACCUM]], i64* %ula, align 8
177 }
178 
TestFixedPointCastSaturation()179 void TestFixedPointCastSaturation() {
180   _Accum a;
181   _Sat short _Accum sat_sa;
182   _Sat _Accum sat_a;
183   _Sat long _Accum sat_la;
184   _Sat unsigned short _Accum sat_usa;
185   _Sat unsigned _Accum sat_ua;
186   _Sat unsigned long _Accum sat_ula;
187   _Sat short _Fract sat_sf;
188   _Sat _Fract sat_f;
189   _Sat long _Fract sat_lf;
190 
191   // Casting down between types
192   sat_sa = sat_a;
193   // CHECK:      [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4
194   // CHECK-NEXT: [[ACCUM:%[0-9a-z]+]] = ashr i32 [[OLD_ACCUM]], 8
195   // CHECK-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[ACCUM]], 32767
196   // CHECK-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i32 32767, i32 [[ACCUM]]
197   // CHECK-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[RESULT]], -32768
198   // CHECK-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 -32768, i32 [[RESULT]]
199   // CHECK-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i32 [[RESULT2]] to i16
200   // CHECK-NEXT: store i16 [[RESULT_TRUNC]], i16* %sat_sa, align 2
201 
202   // Accum to Fract, decreasing scale
203   sat_sf = sat_a;
204   // CHECK:      [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4
205   // CHECK-NEXT: [[FRACT:%[0-9a-z]+]] = ashr i32 [[OLD_ACCUM]], 8
206   // CHECK-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[FRACT]], 127
207   // CHECK-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i32 127, i32 [[FRACT]]
208   // CHECK-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[RESULT]], -128
209   // CHECK-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 -128, i32 [[RESULT]]
210   // CHECK-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i32 [[RESULT2]] to i8
211   // CHECK-NEXT: store i8 [[RESULT_TRUNC]], i8* %sat_sf, align 1
212 
213   // Accum to Fract, same scale
214   sat_f = a;
215   // CHECK:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
216   // CHECK-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[ACCUM]], 32767
217   // CHECK-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i32 32767, i32 [[ACCUM]]
218   // CHECK-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[RESULT]], -32768
219   // CHECK-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 -32768, i32 [[RESULT]]
220   // CHECK-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i32 [[RESULT2]] to i16
221   // CHECK-NEXT: store i16 [[RESULT_TRUNC]], i16* %sat_f, align 2
222 
223   // Accum to Fract, increasing scale
224   sat_lf = sat_a;
225   // CHECK:      [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4
226   // CHECK-NEXT: [[RESIZE:%[0-9a-z]+]] = sext i32 [[OLD_ACCUM]] to i48
227   // CHECK-NEXT: [[FRACT:%[0-9a-z]+]] = shl i48 [[RESIZE]], 16
228   // CHECK-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i48 [[FRACT]], 2147483647
229   // CHECK-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i48 2147483647, i48 [[FRACT]]
230   // CHECK-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i48 [[RESULT]], -2147483648
231   // CHECK-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i48 -2147483648, i48 [[RESULT]]
232   // CHECK-NEXT: [[TRUNC:%[0-9a-z]+]] = trunc i48 [[RESULT2]] to i32
233   // CHECK-NEXT: store i32 [[TRUNC]], i32* %sat_lf, align 4
234 
235   // Signed to unsigned, decreasing scale
236   _Sat _Accum sat_a2;
237   sat_usa = sat_a2;
238   // SIGNED:      [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a2, align 4
239   // SIGNED-NEXT: [[ACCUM:%[0-9a-z]+]] = ashr i32 [[OLD_ACCUM]], 7
240   // SIGNED-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[ACCUM]], 65535
241   // SIGNED-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i32 65535, i32 [[ACCUM]]
242   // SIGNED-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[RESULT]], 0
243   // SIGNED-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 0, i32 [[RESULT]]
244   // SIGNED-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i32 [[RESULT2]] to i16
245   // SIGNED-NEXT: store i16 [[RESULT_TRUNC]], i16* %sat_usa, align 2
246   // UNSIGNED:      [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a2, align 4
247   // UNSIGNED-NEXT: [[ACCUM:%[0-9a-z]+]] = ashr i32 [[OLD_ACCUM]], 8
248   // UNSIGNED-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[ACCUM]], 32767
249   // UNSIGNED-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i32 32767, i32 [[ACCUM]]
250   // UNSIGNED-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[RESULT]], 0
251   // UNSIGNED-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 0, i32 [[RESULT]]
252   // UNSIGNED-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i32 [[RESULT2]] to i16
253   // UNSIGNED-NEXT: store i16 [[RESULT_TRUNC]], i16* %sat_usa, align 2
254 
255   // Signed to unsigned, increasing scale
256   sat_ua = sat_a;
257   // SIGNED:      [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4
258   // SIGNED-NEXT: [[RESIZE:%[0-9a-z]+]] = sext i32 [[OLD_ACCUM]] to i33
259   // SIGNED-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i33 [[RESIZE]], 1
260   // SIGNED-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i33 [[ACCUM]], 0
261   // SIGNED-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i33 0, i33 [[ACCUM]]
262   // SIGNED-NEXT: [[TRUNC:%[0-9a-z]+]] = trunc i33 [[RESULT2]] to i32
263   // SIGNED-NEXT: store i32 [[TRUNC]], i32* %sat_ua, align 4
264   // UNSIGNED:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4
265   // UNSIGNED-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[ACCUM]], 0
266   // UNSIGNED-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 0, i32 [[ACCUM]]
267   // UNSIGNED-NEXT: store i32 [[RESULT]], i32* %sat_ua, align 4
268 
269   // Nothing when saturating to the same type and size
270   sat_a = a;
271   // CHECK:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
272   // CHECK-NEXT: store i32 [[ACCUM]], i32* %sat_a, align 4
273 
274   // Nothing when assigning back
275   a = sat_a;
276   // CHECK:      [[SAT_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4
277   // CHECK-NEXT: store i32 [[SAT_ACCUM]], i32* %a, align 4
278 
279   // No overflow when casting from fract to signed accum
280   sat_a = sat_f;
281   // CHECK:      [[FRACT:%[0-9a-z]+]] = load i16, i16* %sat_f, align 2
282   // CHECK-NEXT: [[FRACT_EXT:%[0-9a-z]+]] = sext i16 [[FRACT]] to i32
283   // CHECK-NEXT: store i32 [[FRACT_EXT]], i32* %sat_a, align 4
284 
285   // Only get overflow checking if signed fract to unsigned accum
286   sat_ua = sat_sf;
287   // SIGNED:      [[FRACT:%[0-9a-z]+]] = load i8, i8* %sat_sf, align 1
288   // SIGNED-NEXT: [[FRACT_EXT:%[0-9a-z]+]] = sext i8 [[FRACT]] to i32
289   // SIGNED-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i32 [[FRACT_EXT]], 9
290   // SIGNED-NEXT: [[IS_NEG:%[0-9a-z]+]] = icmp slt i32 [[ACCUM]], 0
291   // SIGNED-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[IS_NEG]], i32 0, i32 [[ACCUM]]
292   // SIGNED-NEXT: store i32 [[RESULT]], i32* %sat_ua, align 4
293   // UNSIGNED:      [[FRACT:%[0-9a-z]+]] = load i8, i8* %sat_sf, align 1
294   // UNSIGNED-NEXT: [[FRACT_EXT:%[0-9a-z]+]] = sext i8 [[FRACT]] to i32
295   // UNSIGNED-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i32 [[FRACT_EXT]], 8
296   // UNSIGNED-NEXT: [[IS_NEG:%[0-9a-z]+]] = icmp slt i32 [[ACCUM]], 0
297   // UNSIGNED-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[IS_NEG]], i32 0, i32 [[ACCUM]]
298   // UNSIGNED-NEXT: store i32 [[RESULT]], i32* %sat_ua, align 4
299 }
300 
TestFixedPointCastBetFractAccum()301 void TestFixedPointCastBetFractAccum() {
302   short _Accum sa;
303   _Accum a;
304   long _Accum la;
305   short _Fract sf;
306   _Fract f;
307   long _Fract lf;
308   unsigned _Accum ua;
309   unsigned _Fract uf;
310 
311   // To lower scale
312   sf = a;
313   // CHECK:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
314   // CHECK-NEXT: [[FRACT:%[0-9a-z]+]] = ashr i32 [[ACCUM]], 8
315   // CHECK-NEXT: [[FRACT_TRUNC:%[0-9a-z]+]] = trunc i32 [[FRACT]] to i8
316   // CHECK-NEXT: store i8 [[FRACT_TRUNC]], i8* %sf, align 1
317 
318   // To higher scale
319   a = sf;
320   // CHECK:      [[FRACT:%[0-9a-z]+]] = load i8, i8* %sf, align 1
321   // CHECK-NEXT: [[FRACT_EXT:%[0-9a-z]+]] = sext i8 [[FRACT]] to i32
322   // CHECK-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i32 [[FRACT_EXT]], 8
323   // CHECK-NEXT: store i32 [[ACCUM]], i32* %a, align 4
324 
325   // To same scale
326   f = a;
327   // CHECK:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
328   // CHECK-NEXT: [[FRACT:%[0-9a-z]+]] = trunc i32 [[ACCUM]] to i16
329   // CHECK-NEXT: store i16 [[FRACT]], i16* %f, align 2
330 
331   a = f;
332   // CHECK:      [[FRACT:%[0-9a-z]+]] = load i16, i16* %f, align 2
333   // CHECK-NEXT: [[ACCUM:%[0-9a-z]+]] = sext i16 [[FRACT]] to i32
334   // CHECK-NEXT: store i32 [[ACCUM]], i32* %a, align 4
335 
336   // To unsigned
337   ua = uf;
338   // CHECK:      [[FRACT:%[0-9a-z]+]] = load i16, i16* %uf, align 2
339   // CHECK-NEXT: [[ACCUM:%[0-9a-z]+]] = zext i16 [[FRACT]] to i32
340   // CHECK-NEXT: store i32 [[ACCUM]], i32* %ua, align 4
341 
342   uf = ua;
343   // CHECK:      [[FRACT:%[0-9a-z]+]] = load i32, i32* %ua, align 4
344   // CHECK-NEXT: [[ACCUM:%[0-9a-z]+]] = trunc i32 [[FRACT]] to i16
345   // CHECK-NEXT: store i16 [[ACCUM]], i16* %uf, align 2
346 }
347 
TestFixedPointToInt()348 void TestFixedPointToInt() {
349   int i;
350   short _Accum sa;
351   unsigned short _Accum usa;
352 
353   // Will need to check for negative values
354   i = sa;
355   // CHECK:      [[FX:%[0-9]+]] = load i16, i16* %sa, align 2
356   // CHECK-NEXT: [[NEG:%[0-9]+]] = icmp slt i16 [[FX]], 0
357   // CHECK-NEXT: [[ROUNDED:%[0-9]+]] = add i16 [[FX]], 127
358   // CHECK-NEXT: [[VAL:%[0-9]+]] = select i1 [[NEG]], i16 [[ROUNDED]], i16 [[FX]]
359   // CHECK-NEXT: [[RES:%[a-z0-9]+]] = ashr i16 [[VAL]], 7
360   // CHECK-NEXT: [[RES2:%[a-z0-9]+]] = sext i16 [[RES]] to i32
361   // CHECK-NEXT: store i32 [[RES2]], i32* %i, align 4
362 
363   // No check needed for unsigned fixed points. Can just right shift.
364   i = usa;
365   // SIGNED:      [[FX:%[0-9]+]] = load i16, i16* %usa, align 2
366   // SIGNED-NEXT: [[INT:%[a-z0-9]+]] = lshr i16 [[FX]], 8
367   // SIGNED-NEXT: [[RES:%[a-z0-9]+]] = zext i16 [[INT]] to i32
368   // SIGNED-NEXT: store i32 [[RES]], i32* %i, align 4
369   // UNSIGNED:      [[FX:%[0-9]+]] = load i16, i16* %usa, align 2
370   // UNSIGNED-NEXT: [[INT:%[a-z0-9]+]] = lshr i16 [[FX]], 7
371   // UNSIGNED-NEXT: [[RES:%[a-z0-9]+]] = zext i16 [[INT]] to i32
372   // UNSIGNED-NEXT: store i32 [[RES]], i32* %i, align 4
373 }
374 
TestIntToFixedPoint()375 void TestIntToFixedPoint() {
376   short s;
377   int i, i2;
378   unsigned int ui;
379   short _Accum sa;
380   long _Accum la;
381   unsigned short _Accum usa;
382   _Sat short _Accum sat_sa;
383   _Sat unsigned short _Accum sat_usa;
384 
385   sa = i;
386   // CHECK:      [[I:%[0-9]+]] = load i32, i32* %i, align 4
387   // CHECK-NEXT: [[I_EXT:%[a-z0-9]+]] = trunc i32 [[I]] to i16
388   // CHECK-NEXT: [[FX:%[a-z0-9]+]] = shl i16 [[I_EXT]], 7
389   // CHECK-NEXT: store i16 [[FX]], i16* %sa, align 2
390 
391   sa = ui;
392   // CHECK:      [[I:%[0-9]+]] = load i32, i32* %ui, align 4
393   // CHECK-NEXT: [[I_EXT:%[a-z0-9]+]] = trunc i32 [[I]] to i16
394   // CHECK-NEXT: [[FX:%[a-z0-9]+]] = shl i16 [[I_EXT]], 7
395   // CHECK-NEXT: store i16 [[FX]], i16* %sa, align 2
396 
397   usa = i2;
398   // SIGNED:      [[I:%[0-9]+]] = load i32, i32* %i2, align 4
399   // SIGNED-NEXT: [[I_EXT:%[a-z0-9]+]] = trunc i32 [[I]] to i16
400   // SIGNED-NEXT: [[FX:%[a-z0-9]+]] = shl i16 [[I_EXT]], 8
401   // SIGNED-NEXT: store i16 [[FX]], i16* %usa, align 2
402   // UNSIGNED:      [[I:%[0-9]+]] = load i32, i32* %i2, align 4
403   // UNSIGNED-NEXT: [[I_EXT:%[a-z0-9]+]] = trunc i32 [[I]] to i16
404   // UNSIGNED-NEXT: [[FX:%[a-z0-9]+]] = shl i16 [[I_EXT]], 7
405   // UNSIGNED-NEXT: store i16 [[FX]], i16* %usa, align 2
406 
407   usa = ui;
408   // SIGNED:      [[I:%[0-9]+]] = load i32, i32* %ui, align 4
409   // SIGNED-NEXT: [[I_EXT:%[a-z0-9]+]] = trunc i32 [[I]] to i16
410   // SIGNED-NEXT: [[FX:%[a-z0-9]+]] = shl i16 [[I_EXT]], 8
411   // SIGNED-NEXT: store i16 [[FX]], i16* %usa, align 2
412   // UNSIGNED:      [[I:%[0-9]+]] = load i32, i32* %ui, align 4
413   // UNSIGNED-NEXT: [[I_EXT:%[a-z0-9]+]] = trunc i32 [[I]] to i16
414   // UNSIGNED-NEXT: [[FX:%[a-z0-9]+]] = shl i16 [[I_EXT]], 7
415   // UNSIGNED-NEXT: store i16 [[FX]], i16* %usa, align 2
416 
417   la = s;
418   // CHECK:      [[I:%[0-9]+]] = load i16, i16* %s, align 2
419   // CHECK-NEXT: [[I_EXT:%[a-z0-9]+]] = sext i16 [[I]] to i64
420   // CHECK-NEXT: [[FX:%[a-z0-9]+]] = shl i64 [[I_EXT]], 31
421   // CHECK-NEXT: store i64 [[FX]], i64* %la, align 8
422 }
423 
TestIntToSatFixedPoint()424 void TestIntToSatFixedPoint() {
425   int i, i2;
426   unsigned int ui;
427   _Sat short _Accum sat_sa;
428   _Sat unsigned short _Accum sat_usa;
429 
430   sat_sa = i;
431   // CHECK:      [[I:%[0-9]+]] = load i32, i32* %i, align 4
432   // CHECK-NEXT: [[I_EXT:%[a-z0-9]+]] = sext i32 [[I]] to i39
433   // CHECK-NEXT: [[FX:%[a-z0-9]+]] = shl i39 [[I_EXT]], 7
434   // CHECK-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i39 [[FX]], 32767
435   // CHECK-NEXT: [[SATMAX:%[a-z0-9]+]] = select i1 [[USE_MAX]], i39 32767, i39 [[FX]]
436   // CHECK-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i39 [[SATMAX]], -32768
437   // CHECK-NEXT: [[SATMIN:%[a-z0-9]+]] = select i1 [[USE_MIN]], i39 -32768, i39 [[SATMAX]]
438   // CHECK-NEXT: [[RES:%[a-z0-9]+]] = trunc i39 [[SATMIN]] to i16
439   // CHECK-NEXT: store i16 [[RES]], i16* %sat_sa, align 2
440 
441   sat_sa = ui;
442   // CHECK:      [[I:%[0-9]+]] = load i32, i32* %ui, align 4
443   // CHECK-NEXT: [[I_EXT:%[a-z0-9]+]] = zext i32 [[I]] to i39
444   // CHECK-NEXT: [[FX:%[a-z0-9]+]] = shl i39 [[I_EXT]], 7
445   // CHECK-NEXT: [[USE_MAX:%[0-9]+]] = icmp ugt i39 [[FX]], 32767
446   // CHECK-NEXT: [[SATMAX:%[a-z0-9]+]] = select i1 [[USE_MAX]], i39 32767, i39 [[FX]]
447   // CHECK-NEXT: [[RES:%[a-z0-9]+]] = trunc i39 [[SATMAX]] to i16
448   // CHECK-NEXT: store i16 [[RES]], i16* %sat_sa, align 2
449 
450   sat_usa = i2;
451   // SIGNED:      [[I:%[0-9]+]] = load i32, i32* %i2, align 4
452   // SIGNED-NEXT: [[I_EXT:%[a-z0-9]+]] = sext i32 [[I]] to i40
453   // SIGNED-NEXT: [[FX:%[a-z0-9]+]] = shl i40 [[I_EXT]], 8
454   // SIGNED-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i40 [[FX]], 65535
455   // SIGNED-NEXT: [[SATMAX:%[a-z0-9]+]] = select i1 [[USE_MAX]], i40 65535, i40 [[FX]]
456   // SIGNED-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i40 [[SATMAX]], 0
457   // SIGNED-NEXT: [[SATMIN:%[a-z0-9]+]] = select i1 [[USE_MIN]], i40 0, i40 [[SATMAX]]
458   // SIGNED-NEXT: [[RES:%[a-z0-9]+]] = trunc i40 [[SATMIN]] to i16
459   // SIGNED-NEXT: store i16 [[RES]], i16* %sat_usa, align 2
460   // UNSIGNED:      [[I:%[0-9]+]] = load i32, i32* %i2, align 4
461   // UNSIGNED-NEXT: [[I_EXT:%[a-z0-9]+]] = sext i32 [[I]] to i39
462   // UNSIGNED-NEXT: [[FX:%[a-z0-9]+]] = shl i39 [[I_EXT]], 7
463   // UNSIGNED-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i39 [[FX]], 32767
464   // UNSIGNED-NEXT: [[SATMAX:%[a-z0-9]+]] = select i1 [[USE_MAX]], i39 32767, i39 [[FX]]
465   // UNSIGNED-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i39 [[SATMAX]], 0
466   // UNSIGNED-NEXT: [[SATMIN:%[a-z0-9]+]] = select i1 [[USE_MIN]], i39 0, i39 [[SATMAX]]
467   // UNSIGNED-NEXT: [[RES:%[a-z0-9]+]] = trunc i39 [[SATMIN]] to i16
468   // UNSIGNED-NEXT: store i16 [[RES]], i16* %sat_usa, align 2
469 
470   sat_usa = ui;
471   // SIGNED:      [[I:%[0-9]+]] = load i32, i32* %ui, align 4
472   // SIGNED-NEXT: [[I_EXT:%[a-z0-9]+]] = zext i32 [[I]] to i40
473   // SIGNED-NEXT: [[FX:%[a-z0-9]+]] = shl i40 [[I_EXT]], 8
474   // SIGNED-NEXT: [[USE_MAX:%[0-9]+]] = icmp ugt i40 [[FX]], 65535
475   // SIGNED-NEXT: [[SATMAX:%[a-z0-9]+]] = select i1 [[USE_MAX]], i40 65535, i40 [[FX]]
476   // SIGNED-NEXT: [[RES:%[a-z0-9]+]] = trunc i40 [[SATMAX]] to i16
477   // SIGNED-NEXT: store i16 [[RES]], i16* %sat_usa, align 2
478   // UNSIGNED:      [[I:%[0-9]+]] = load i32, i32* %ui, align 4
479   // UNSIGNED-NEXT: [[I_EXT:%[a-z0-9]+]] = zext i32 [[I]] to i39
480   // UNSIGNED-NEXT: [[FX:%[a-z0-9]+]] = shl i39 [[I_EXT]], 7
481   // UNSIGNED-NEXT: [[USE_MAX:%[0-9]+]] = icmp ugt i39 [[FX]], 32767
482   // UNSIGNED-NEXT: [[SATMAX:%[a-z0-9]+]] = select i1 [[USE_MAX]], i39 32767, i39 [[FX]]
483   // UNSIGNED-NEXT: [[RES:%[a-z0-9]+]] = trunc i39 [[SATMAX]] to i16
484   // UNSIGNED-NEXT: store i16 [[RES]], i16* %sat_usa, align 2
485 }
486