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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |