1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -mtriple=amdgcn-amd-amdhsa -instcombine -S | FileCheck %s
3
4define float @ldexp_f32_undef_undef() {
5; CHECK-LABEL: @ldexp_f32_undef_undef(
6; CHECK-NEXT:    ret float 0x7FF8000000000000
7;
8  %call = call float @llvm.amdgcn.ldexp.f32(float undef, i32 undef)
9  ret float %call
10}
11
12; If the exponent is 0, it doesn't matter if the first argument is
13; constant or not.
14define void @ldexp_f32_exp0(float %x) {
15; CHECK-LABEL: @ldexp_f32_exp0(
16; CHECK-NEXT:    store volatile float [[X:%.*]], float addrspace(1)* undef, align 4
17; CHECK-NEXT:    store volatile float [[X]], float addrspace(1)* undef, align 4
18; CHECK-NEXT:    [[ONE:%.*]] = call float @llvm.amdgcn.ldexp.f32(float [[X]], i32 1)
19; CHECK-NEXT:    store volatile float [[ONE]], float addrspace(1)* undef, align 4
20; CHECK-NEXT:    ret void
21;
22  %zero = call float @llvm.amdgcn.ldexp.f32(float %x, i32 0)
23  store volatile float %zero, float addrspace(1)* undef
24
25  %undef = call float @llvm.amdgcn.ldexp.f32(float %x, i32 undef)
26  store volatile float %undef, float addrspace(1)* undef
27
28  %one = call float @llvm.amdgcn.ldexp.f32(float %x, i32 1)
29  store volatile float %one, float addrspace(1)* undef
30  ret void
31}
32
33; Test variable exponent but zero or undef value.
34define void @ldexp_f32_val0(i32 %y) {
35; CHECK-LABEL: @ldexp_f32_val0(
36; CHECK-NEXT:    store volatile float 0.000000e+00, float addrspace(1)* undef, align 4
37; CHECK-NEXT:    store volatile float -0.000000e+00, float addrspace(1)* undef, align 4
38; CHECK-NEXT:    store volatile float 0x7FF8000000000000, float addrspace(1)* undef, align 4
39; CHECK-NEXT:    ret void
40;
41  %zero = call float @llvm.amdgcn.ldexp.f32(float 0.0, i32 %y)
42  store volatile float %zero, float addrspace(1)* undef
43
44  %neg.zero = call float @llvm.amdgcn.ldexp.f32(float -0.0, i32 %y)
45  store volatile float %neg.zero, float addrspace(1)* undef
46
47  %undef = call float @llvm.amdgcn.ldexp.f32(float undef, i32 %y)
48  store volatile float %undef, float addrspace(1)* undef
49  ret void
50}
51
52define void @ldexp_f32_val_infinity(i32 %y) {
53; CHECK-LABEL: @ldexp_f32_val_infinity(
54; CHECK-NEXT:    store volatile float 0x7FF0000000000000, float addrspace(1)* undef, align 4
55; CHECK-NEXT:    store volatile float 0xFFF0000000000000, float addrspace(1)* undef, align 4
56; CHECK-NEXT:    store volatile float 0x7FF0000000000000, float addrspace(1)* undef, align 4
57; CHECK-NEXT:    store volatile float 0xFFF0000000000000, float addrspace(1)* undef, align 4
58; CHECK-NEXT:    ret void
59;
60  %inf = call float @llvm.amdgcn.ldexp.f32(float 0x7ff0000000000000, i32 %y)
61  store volatile float %inf, float addrspace(1)* undef
62
63  %neg.inf = call float @llvm.amdgcn.ldexp.f32(float 0xfff0000000000000, i32 %y)
64  store volatile float %neg.inf, float addrspace(1)* undef
65
66  %inf.zero = call float @llvm.amdgcn.ldexp.f32(float 0x7ff0000000000000, i32 0)
67  store volatile float %inf.zero, float addrspace(1)* undef
68
69  %neg.inf.zero = call float @llvm.amdgcn.ldexp.f32(float 0xfff0000000000000, i32 0)
70  store volatile float %neg.inf.zero, float addrspace(1)* undef
71
72  ret void
73}
74
75; Signaling nan should be quieted.
76; Technically this depends on the ieee_mode in the mode register.
77define void @ldexp_f32_val_nan(i32 %y) {
78; CHECK-LABEL: @ldexp_f32_val_nan(
79; CHECK-NEXT:    store volatile float 0x7FF8001000000000, float addrspace(1)* undef, align 4
80; CHECK-NEXT:    store volatile float 0xFFF8000100000000, float addrspace(1)* undef, align 4
81; CHECK-NEXT:    store volatile float 0x7FF8000020000000, float addrspace(1)* undef, align 4
82; CHECK-NEXT:    store volatile float 0xFFFFFFFFE0000000, float addrspace(1)* undef, align 4
83; CHECK-NEXT:    ret void
84;
85  %plus.qnan = call float @llvm.amdgcn.ldexp.f32(float 0x7ff0001000000000, i32 %y)
86  store volatile float %plus.qnan, float addrspace(1)* undef
87
88  %neg.qnan = call float @llvm.amdgcn.ldexp.f32(float 0xfff0000100000000, i32 %y)
89  store volatile float %neg.qnan, float addrspace(1)* undef
90
91  %plus.snan = call float @llvm.amdgcn.ldexp.f32(float 0x7FF0000020000000, i32 %y)
92  store volatile float %plus.snan, float addrspace(1)* undef
93
94  %neg.snan = call float @llvm.amdgcn.ldexp.f32(float 0xFFF7FFFFE0000000, i32 %y)
95  store volatile float %neg.snan, float addrspace(1)* undef
96
97  ret void
98}
99
100define void @ldexp_f32_val_nan_strictfp(i32 %y) #0 {
101; CHECK-LABEL: @ldexp_f32_val_nan_strictfp(
102; CHECK-NEXT:    [[PLUS_QNAN:%.*]] = call float @llvm.amdgcn.ldexp.f32(float 0x7FF0001000000000, i32 [[Y:%.*]]) [[ATTR0:#.*]]
103; CHECK-NEXT:    store volatile float [[PLUS_QNAN]], float addrspace(1)* undef, align 4
104; CHECK-NEXT:    [[NEG_QNAN:%.*]] = call float @llvm.amdgcn.ldexp.f32(float 0xFFF0000100000000, i32 [[Y]]) [[ATTR0]]
105; CHECK-NEXT:    store volatile float [[NEG_QNAN]], float addrspace(1)* undef, align 4
106; CHECK-NEXT:    [[PLUS_SNAN:%.*]] = call float @llvm.amdgcn.ldexp.f32(float 0x7FF0000020000000, i32 [[Y]]) [[ATTR0]]
107; CHECK-NEXT:    store volatile float [[PLUS_SNAN]], float addrspace(1)* undef, align 4
108; CHECK-NEXT:    [[NEG_SNAN:%.*]] = call float @llvm.amdgcn.ldexp.f32(float 0xFFF7FFFFE0000000, i32 [[Y]]) [[ATTR0]]
109; CHECK-NEXT:    store volatile float [[NEG_SNAN]], float addrspace(1)* undef, align 4
110; CHECK-NEXT:    store volatile float 0x7FF8000000000000, float addrspace(1)* undef, align 4
111; CHECK-NEXT:    ret void
112;
113  %plus.qnan = call float @llvm.amdgcn.ldexp.f32(float 0x7ff0001000000000, i32 %y) #0
114  store volatile float %plus.qnan, float addrspace(1)* undef
115
116  %neg.qnan = call float @llvm.amdgcn.ldexp.f32(float 0xfff0000100000000, i32 %y) #0
117  store volatile float %neg.qnan, float addrspace(1)* undef
118
119  %plus.snan = call float @llvm.amdgcn.ldexp.f32(float 0x7FF0000020000000, i32 %y) #0
120  store volatile float %plus.snan, float addrspace(1)* undef
121
122  %neg.snan = call float @llvm.amdgcn.ldexp.f32(float 0xFFF7FFFFE0000000, i32 %y) #0
123  store volatile float %neg.snan, float addrspace(1)* undef
124
125  %undef = call float @llvm.amdgcn.ldexp.f32(float undef, i32 %y) #0
126  store volatile float %undef, float addrspace(1)* undef
127
128  ret void
129}
130
131define void @ldexp_f32_0() {
132; CHECK-LABEL: @ldexp_f32_0(
133; CHECK-NEXT:    store volatile float 0.000000e+00, float addrspace(1)* undef, align 4
134; CHECK-NEXT:    store volatile float -0.000000e+00, float addrspace(1)* undef, align 4
135; CHECK-NEXT:    store volatile float 0.000000e+00, float addrspace(1)* undef, align 4
136; CHECK-NEXT:    store volatile float 0.000000e+00, float addrspace(1)* undef, align 4
137; CHECK-NEXT:    store volatile float 0.000000e+00, float addrspace(1)* undef, align 4
138; CHECK-NEXT:    store volatile float 0.000000e+00, float addrspace(1)* undef, align 4
139; CHECK-NEXT:    store volatile float 0.000000e+00, float addrspace(1)* undef, align 4
140; CHECK-NEXT:    ret void
141;
142  %zero = call float @llvm.amdgcn.ldexp.f32(float 0.0, i32 0)
143  store volatile float %zero, float addrspace(1)* undef
144
145  %neg.zero = call float @llvm.amdgcn.ldexp.f32(float -0.0, i32 0)
146  store volatile float %neg.zero, float addrspace(1)* undef
147
148  %one = call float @llvm.amdgcn.ldexp.f32(float 0.0, i32 1)
149  store volatile float %one, float addrspace(1)* undef
150
151  %min.exp = call float @llvm.amdgcn.ldexp.f32(float 0.0, i32 -126)
152  store volatile float %min.exp, float addrspace(1)* undef
153
154  %min.exp.sub1 = call float @llvm.amdgcn.ldexp.f32(float 0.0, i32 -127)
155  store volatile float %min.exp.sub1, float addrspace(1)* undef
156
157  %max.exp = call float @llvm.amdgcn.ldexp.f32(float 0.0, i32 127)
158  store volatile float %max.exp, float addrspace(1)* undef
159
160  %max.exp.plus1 = call float @llvm.amdgcn.ldexp.f32(float 0.0, i32 128)
161  store volatile float %max.exp.plus1, float addrspace(1)* undef
162
163  ret void
164}
165
166; Should be able to ignore strictfp in this case
167define void @ldexp_f32_0_strictfp(float %x) #0 {
168; CHECK-LABEL: @ldexp_f32_0_strictfp(
169; CHECK-NEXT:    store volatile float 0.000000e+00, float addrspace(1)* undef, align 4
170; CHECK-NEXT:    store volatile float -0.000000e+00, float addrspace(1)* undef, align 4
171; CHECK-NEXT:    store volatile float 0.000000e+00, float addrspace(1)* undef, align 4
172; CHECK-NEXT:    [[UNKNOWN_ZERO:%.*]] = call float @llvm.amdgcn.ldexp.f32(float [[X:%.*]], i32 0) [[ATTR0]]
173; CHECK-NEXT:    store volatile float [[UNKNOWN_ZERO]], float addrspace(1)* undef, align 4
174; CHECK-NEXT:    [[UNKNOWN_UNDEF:%.*]] = call float @llvm.amdgcn.ldexp.f32(float [[X]], i32 undef) [[ATTR0]]
175; CHECK-NEXT:    store volatile float [[UNKNOWN_UNDEF]], float addrspace(1)* undef, align 4
176; CHECK-NEXT:    [[DENORMAL_0:%.*]] = call float @llvm.amdgcn.ldexp.f32(float 0x380FFFFFC0000000, i32 0) [[ATTR0]]
177; CHECK-NEXT:    store volatile float [[DENORMAL_0]], float addrspace(1)* undef, align 4
178; CHECK-NEXT:    [[DENORMAL_1:%.*]] = call float @llvm.amdgcn.ldexp.f32(float 0x380FFFFFC0000000, i32 1) [[ATTR0]]
179; CHECK-NEXT:    store volatile float [[DENORMAL_1]], float addrspace(1)* undef, align 4
180; CHECK-NEXT:    ret void
181;
182  %zero = call float @llvm.amdgcn.ldexp.f32(float 0.0, i32 0) #0
183  store volatile float %zero, float addrspace(1)* undef
184
185  %neg.zero = call float @llvm.amdgcn.ldexp.f32(float -0.0, i32 0) #0
186  store volatile float %neg.zero, float addrspace(1)* undef
187
188  %one = call float @llvm.amdgcn.ldexp.f32(float 0.0, i32 1) #0
189  store volatile float %one, float addrspace(1)* undef
190
191  %unknown.zero = call float @llvm.amdgcn.ldexp.f32(float %x, i32 0) #0
192  store volatile float %unknown.zero, float addrspace(1)* undef
193
194  %unknown.undef = call float @llvm.amdgcn.ldexp.f32(float %x, i32 undef) #0
195  store volatile float %unknown.undef, float addrspace(1)* undef
196
197  %denormal.0 = call float @llvm.amdgcn.ldexp.f32(float 0x380FFFFFC0000000, i32 0) #0
198  store volatile float %denormal.0, float addrspace(1)* undef
199
200  %denormal.1 = call float @llvm.amdgcn.ldexp.f32(float 0x380FFFFFC0000000, i32 1) #0
201  store volatile float %denormal.1, float addrspace(1)* undef
202
203  ret void
204}
205
206define void @ldexp_f32() {
207; CHECK-LABEL: @ldexp_f32(
208; CHECK-NEXT:    store volatile float 2.000000e+00, float addrspace(1)* undef, align 4
209; CHECK-NEXT:    store volatile float 4.000000e+00, float addrspace(1)* undef, align 4
210; CHECK-NEXT:    store volatile float 8.000000e+00, float addrspace(1)* undef, align 4
211; CHECK-NEXT:    store volatile float 5.000000e-01, float addrspace(1)* undef, align 4
212; CHECK-NEXT:    store volatile float 0x3810000000000000, float addrspace(1)* undef, align 4
213; CHECK-NEXT:    store volatile float 0x3800000000000000, float addrspace(1)* undef, align 4
214; CHECK-NEXT:    store volatile float 0x47E0000000000000, float addrspace(1)* undef, align 4
215; CHECK-NEXT:    store volatile float 0x7FF0000000000000, float addrspace(1)* undef, align 4
216; CHECK-NEXT:    store volatile float -2.000000e+00, float addrspace(1)* undef, align 4
217; CHECK-NEXT:    store volatile float -4.000000e+00, float addrspace(1)* undef, align 4
218; CHECK-NEXT:    store volatile float -8.000000e+00, float addrspace(1)* undef, align 4
219; CHECK-NEXT:    store volatile float -5.000000e-01, float addrspace(1)* undef, align 4
220; CHECK-NEXT:    store volatile float 0xB810000000000000, float addrspace(1)* undef, align 4
221; CHECK-NEXT:    store volatile float 0xB800000000000000, float addrspace(1)* undef, align 4
222; CHECK-NEXT:    store volatile float 0xC7E0000000000000, float addrspace(1)* undef, align 4
223; CHECK-NEXT:    store volatile float 0xFFF0000000000000, float addrspace(1)* undef, align 4
224; CHECK-NEXT:    store volatile float 0x44D5000000000000, float addrspace(1)* undef, align 4
225; CHECK-NEXT:    ret void
226;
227  %one.one = call float @llvm.amdgcn.ldexp.f32(float 1.0, i32 1)
228  store volatile float %one.one, float addrspace(1)* undef
229
230  %one.two = call float @llvm.amdgcn.ldexp.f32(float 1.0, i32 2)
231  store volatile float %one.two, float addrspace(1)* undef
232
233  %one.three = call float @llvm.amdgcn.ldexp.f32(float 1.0, i32 3)
234  store volatile float %one.three, float addrspace(1)* undef
235
236  %one.negone = call float @llvm.amdgcn.ldexp.f32(float 1.0, i32 -1)
237  store volatile float %one.negone, float addrspace(1)* undef
238
239  %one.min.exp = call float @llvm.amdgcn.ldexp.f32(float 1.0, i32 -126)
240  store volatile float %one.min.exp, float addrspace(1)* undef
241
242  %one.min.exp.sub1 = call float @llvm.amdgcn.ldexp.f32(float 1.0, i32 -127)
243  store volatile float %one.min.exp.sub1, float addrspace(1)* undef
244
245  %one.max.exp = call float @llvm.amdgcn.ldexp.f32(float 1.0, i32 127)
246  store volatile float %one.max.exp, float addrspace(1)* undef
247
248  %one.max.exp.plus1 = call float @llvm.amdgcn.ldexp.f32(float 1.0, i32 128)
249  store volatile float %one.max.exp.plus1, float addrspace(1)* undef
250
251  %neg.one.one = call float @llvm.amdgcn.ldexp.f32(float -1.0, i32 1)
252  store volatile float %neg.one.one, float addrspace(1)* undef
253
254  %neg.one.two = call float @llvm.amdgcn.ldexp.f32(float -1.0, i32 2)
255  store volatile float %neg.one.two, float addrspace(1)* undef
256
257  %neg.one.three = call float @llvm.amdgcn.ldexp.f32(float -1.0, i32 3)
258  store volatile float %neg.one.three, float addrspace(1)* undef
259
260  %neg.one.negone = call float @llvm.amdgcn.ldexp.f32(float -1.0, i32 -1)
261  store volatile float %neg.one.negone, float addrspace(1)* undef
262
263  %neg.one.min.exp = call float @llvm.amdgcn.ldexp.f32(float -1.0, i32 -126)
264  store volatile float %neg.one.min.exp, float addrspace(1)* undef
265
266  %neg.one.min.exp.sub1 = call float @llvm.amdgcn.ldexp.f32(float -1.0, i32 -127)
267  store volatile float %neg.one.min.exp.sub1, float addrspace(1)* undef
268
269  %neg.one.max.exp = call float @llvm.amdgcn.ldexp.f32(float -1.0, i32 127)
270  store volatile float %neg.one.max.exp, float addrspace(1)* undef
271
272  %neg.one.max.exp.plus1 = call float @llvm.amdgcn.ldexp.f32(float -1.0, i32 128)
273  store volatile float %neg.one.max.exp.plus1, float addrspace(1)* undef
274
275  %fortytwo.seven = call float @llvm.amdgcn.ldexp.f32(float 42.0, i32 73)
276  store volatile float %fortytwo.seven, float addrspace(1)* undef
277
278  ret void
279}
280
281; Technically we should probably flush these depending on the expected
282; denormal mode of the function, but no other IR constant folding
283; considers this.
284define void @ldexp_f32_denormal() {
285; CHECK-LABEL: @ldexp_f32_denormal(
286; CHECK-NEXT:    store volatile float 0x380FFFFFC0000000, float addrspace(1)* undef, align 4
287; CHECK-NEXT:    store volatile float 0x381FFFFFC0000000, float addrspace(1)* undef, align 4
288; CHECK-NEXT:    ret void
289;
290  %denormal.0 = call float @llvm.amdgcn.ldexp.f32(float 0x380FFFFFC0000000, i32 0)
291  store volatile float %denormal.0, float addrspace(1)* undef
292
293  %denormal.1 = call float @llvm.amdgcn.ldexp.f32(float 0x380FFFFFC0000000, i32 1)
294  store volatile float %denormal.1, float addrspace(1)* undef
295
296  ret void
297}
298
299define void @ldexp_f64() {
300; CHECK-LABEL: @ldexp_f64(
301; CHECK-NEXT:    store volatile double 2.000000e+00, double addrspace(1)* undef, align 8
302; CHECK-NEXT:    store volatile double 4.000000e+00, double addrspace(1)* undef, align 8
303; CHECK-NEXT:    store volatile double 0x44D5000000000000, double addrspace(1)* undef, align 8
304; CHECK-NEXT:    ret void
305;
306  %one.one = call double @llvm.amdgcn.ldexp.f64(double 1.0, i32 1)
307  store volatile double %one.one, double addrspace(1)* undef
308
309  %one.two = call double @llvm.amdgcn.ldexp.f64(double 1.0, i32 2)
310  store volatile double %one.two, double addrspace(1)* undef
311
312  %fortytwo.seven = call double @llvm.amdgcn.ldexp.f64(double 42.0, i32 73)
313  store volatile double %fortytwo.seven, double addrspace(1)* undef
314
315  ret void
316}
317
318define void @ldexp_f16() {
319; CHECK-LABEL: @ldexp_f16(
320; CHECK-NEXT:    store volatile half 0xH4000, half addrspace(1)* undef, align 2
321; CHECK-NEXT:    store volatile half 0xH4400, half addrspace(1)* undef, align 2
322; CHECK-NEXT:    store volatile half 0xH7C00, half addrspace(1)* undef, align 2
323; CHECK-NEXT:    ret void
324;
325  %one.one = call half @llvm.amdgcn.ldexp.f16(half 1.0, i32 1)
326  store volatile half %one.one, half addrspace(1)* undef
327
328  %one.two = call half @llvm.amdgcn.ldexp.f16(half 1.0, i32 2)
329  store volatile half %one.two, half addrspace(1)* undef
330
331  %fortytwo.seven = call half @llvm.amdgcn.ldexp.f16(half 42.0, i32 73)
332  store volatile half %fortytwo.seven, half addrspace(1)* undef
333
334  ret void
335}
336
337declare half @llvm.amdgcn.ldexp.f16(half, i32) #1
338declare float @llvm.amdgcn.ldexp.f32(float, i32) #1
339declare double @llvm.amdgcn.ldexp.f64(double, i32) #1
340
341attributes #0 = { strictfp }
342attributes #1 = { nounwind readnone speculatable }
343