1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -instcombine -S | FileCheck %s
3
4; Check the libcall and the intrinsic for each case with differing FMF.
5
6; The transform to sqrt is allowed as long as we deal with -0.0 and -INF.
7
8define double @pow_libcall_half_no_FMF(double %x) {
9; CHECK-LABEL: @pow_libcall_half_no_FMF(
10; CHECK-NEXT:    [[SQRT:%.*]] = call double @sqrt(double [[X:%.*]])
11; CHECK-NEXT:    [[ABS:%.*]] = call double @llvm.fabs.f64(double [[SQRT]])
12; CHECK-NEXT:    [[ISINF:%.*]] = fcmp oeq double [[X]], 0xFFF0000000000000
13; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[ISINF]], double 0x7FF0000000000000, double [[ABS]]
14; CHECK-NEXT:    ret double [[TMP1]]
15;
16  %pow = call double @pow(double %x, double 5.0e-01)
17  ret double %pow
18}
19
20define double @pow_intrinsic_half_no_FMF(double %x) {
21; CHECK-LABEL: @pow_intrinsic_half_no_FMF(
22; CHECK-NEXT:    [[SQRT:%.*]] = call double @llvm.sqrt.f64(double [[X:%.*]])
23; CHECK-NEXT:    [[ABS:%.*]] = call double @llvm.fabs.f64(double [[SQRT]])
24; CHECK-NEXT:    [[ISINF:%.*]] = fcmp oeq double [[X]], 0xFFF0000000000000
25; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[ISINF]], double 0x7FF0000000000000, double [[ABS]]
26; CHECK-NEXT:    ret double [[TMP1]]
27;
28  %pow = call double @llvm.pow.f64(double %x, double 5.0e-01)
29  ret double %pow
30}
31
32; This makes no difference, but FMF are propagated.
33
34define double @pow_libcall_half_approx(double %x) {
35; CHECK-LABEL: @pow_libcall_half_approx(
36; CHECK-NEXT:    [[SQRT:%.*]] = call afn double @sqrt(double [[X:%.*]])
37; CHECK-NEXT:    [[ABS:%.*]] = call afn double @llvm.fabs.f64(double [[SQRT]])
38; CHECK-NEXT:    [[ISINF:%.*]] = fcmp afn oeq double [[X]], 0xFFF0000000000000
39; CHECK-NEXT:    [[TMP1:%.*]] = select afn i1 [[ISINF]], double 0x7FF0000000000000, double [[ABS]]
40; CHECK-NEXT:    ret double [[TMP1]]
41;
42  %pow = call afn double @pow(double %x, double 5.0e-01)
43  ret double %pow
44}
45
46define <2 x double> @pow_intrinsic_half_approx(<2 x double> %x) {
47; CHECK-LABEL: @pow_intrinsic_half_approx(
48; CHECK-NEXT:    [[SQRT:%.*]] = call afn <2 x double> @llvm.sqrt.v2f64(<2 x double> [[X:%.*]])
49; CHECK-NEXT:    [[ABS:%.*]] = call afn <2 x double> @llvm.fabs.v2f64(<2 x double> [[SQRT]])
50; CHECK-NEXT:    [[ISINF:%.*]] = fcmp afn oeq <2 x double> [[X]], <double 0xFFF0000000000000, double 0xFFF0000000000000>
51; CHECK-NEXT:    [[TMP1:%.*]] = select afn <2 x i1> [[ISINF]], <2 x double> <double 0x7FF0000000000000, double 0x7FF0000000000000>, <2 x double> [[ABS]]
52; CHECK-NEXT:    ret <2 x double> [[TMP1]]
53;
54  %pow = call afn <2 x double> @llvm.pow.v2f64(<2 x double> %x, <2 x double> <double 5.0e-01, double 5.0e-01>)
55  ret <2 x double> %pow
56}
57
58define float @powf_intrinsic_half_fast(float %x) {
59; CHECK-LABEL: @powf_intrinsic_half_fast(
60; CHECK-NEXT:    [[SQRT:%.*]] = call fast float @llvm.sqrt.f32(float [[X:%.*]])
61; CHECK-NEXT:    ret float [[SQRT]]
62;
63  %pow = call fast float @llvm.pow.f32(float %x, float 5.0e-01)
64  ret float %pow
65}
66
67; If we can disregard INFs, no need for a select.
68
69define double @pow_libcall_half_ninf(double %x) {
70; CHECK-LABEL: @pow_libcall_half_ninf(
71; CHECK-NEXT:    [[SQRT:%.*]] = call ninf double @sqrt(double [[X:%.*]])
72; CHECK-NEXT:    [[ABS:%.*]] = call ninf double @llvm.fabs.f64(double [[SQRT]])
73; CHECK-NEXT:    ret double [[ABS]]
74;
75  %pow = call ninf double @pow(double %x, double 5.0e-01)
76  ret double %pow
77}
78
79define <2 x double> @pow_intrinsic_half_ninf(<2 x double> %x) {
80; CHECK-LABEL: @pow_intrinsic_half_ninf(
81; CHECK-NEXT:    [[SQRT:%.*]] = call ninf <2 x double> @llvm.sqrt.v2f64(<2 x double> [[X:%.*]])
82; CHECK-NEXT:    [[ABS:%.*]] = call ninf <2 x double> @llvm.fabs.v2f64(<2 x double> [[SQRT]])
83; CHECK-NEXT:    ret <2 x double> [[ABS]]
84;
85  %pow = call ninf <2 x double> @llvm.pow.v2f64(<2 x double> %x, <2 x double> <double 5.0e-01, double 5.0e-01>)
86  ret <2 x double> %pow
87}
88
89; If we can disregard -0.0, no need for fabs.
90
91define double @pow_libcall_half_nsz(double %x) {
92; CHECK-LABEL: @pow_libcall_half_nsz(
93; CHECK-NEXT:    [[SQRT:%.*]] = call nsz double @sqrt(double [[X:%.*]])
94; CHECK-NEXT:    [[ISINF:%.*]] = fcmp nsz oeq double [[X]], 0xFFF0000000000000
95; CHECK-NEXT:    [[TMP1:%.*]] = select nsz i1 [[ISINF]], double 0x7FF0000000000000, double [[SQRT]]
96; CHECK-NEXT:    ret double [[TMP1]]
97;
98  %pow = call nsz double @pow(double %x, double 5.0e-01)
99  ret double %pow
100}
101
102define double @pow_intrinsic_half_nsz(double %x) {
103; CHECK-LABEL: @pow_intrinsic_half_nsz(
104; CHECK-NEXT:    [[SQRT:%.*]] = call nsz double @llvm.sqrt.f64(double [[X:%.*]])
105; CHECK-NEXT:    [[ISINF:%.*]] = fcmp nsz oeq double [[X]], 0xFFF0000000000000
106; CHECK-NEXT:    [[TMP1:%.*]] = select nsz i1 [[ISINF]], double 0x7FF0000000000000, double [[SQRT]]
107; CHECK-NEXT:    ret double [[TMP1]]
108;
109  %pow = call nsz double @llvm.pow.f64(double %x, double 5.0e-01)
110  ret double %pow
111}
112
113; This is just sqrt.
114
115define float @pow_libcall_half_ninf_nsz(float %x) {
116; CHECK-LABEL: @pow_libcall_half_ninf_nsz(
117; CHECK-NEXT:    [[SQRTF:%.*]] = call ninf nsz float @sqrtf(float [[X:%.*]])
118; CHECK-NEXT:    ret float [[SQRTF]]
119;
120  %pow = call ninf nsz float @powf(float %x, float 5.0e-01)
121  ret float %pow
122}
123
124define double @pow_intrinsic_half_ninf_nsz(double %x) {
125; CHECK-LABEL: @pow_intrinsic_half_ninf_nsz(
126; CHECK-NEXT:    [[SQRT:%.*]] = call ninf nsz double @llvm.sqrt.f64(double [[X:%.*]])
127; CHECK-NEXT:    ret double [[SQRT]]
128;
129  %pow = call ninf nsz double @llvm.pow.f64(double %x, double 5.0e-01)
130  ret double %pow
131}
132
133; Overspecified FMF to test propagation to the new op(s).
134
135define float @pow_libcall_half_fast(float %x) {
136; CHECK-LABEL: @pow_libcall_half_fast(
137; CHECK-NEXT:    [[SQRTF:%.*]] = call fast float @sqrtf(float [[X:%.*]])
138; CHECK-NEXT:    ret float [[SQRTF]]
139;
140  %pow = call fast float @powf(float %x, float 5.0e-01)
141  ret float %pow
142}
143
144define double @pow_intrinsic_half_fast(double %x) {
145; CHECK-LABEL: @pow_intrinsic_half_fast(
146; CHECK-NEXT:    [[SQRT:%.*]] = call fast double @llvm.sqrt.f64(double [[X:%.*]])
147; CHECK-NEXT:    ret double [[SQRT]]
148;
149  %pow = call fast double @llvm.pow.f64(double %x, double 5.0e-01)
150  ret double %pow
151}
152
153; This should not be transformed without some kind of FMF.
154; -0.5 means take the reciprocal.
155
156define float @pow_libcall_neghalf_no_FMF(float %x) {
157; CHECK-LABEL: @pow_libcall_neghalf_no_FMF(
158; CHECK-NEXT:    [[POW:%.*]] = call float @powf(float [[X:%.*]], float -5.000000e-01)
159; CHECK-NEXT:    ret float [[POW]]
160;
161  %pow = call float @powf(float %x, float -5.0e-01)
162  ret float %pow
163}
164
165; Transform to sqrt+fdiv because 'reassoc' allows an extra rounding step.
166; Use 'fabs' to handle -0.0 correctly.
167; Use 'select' to handle -INF correctly.
168
169define float @pow_libcall_neghalf_reassoc(float %x) {
170; CHECK-LABEL: @pow_libcall_neghalf_reassoc(
171; CHECK-NEXT:    [[SQRTF:%.*]] = call reassoc float @sqrtf(float [[X:%.*]])
172; CHECK-NEXT:    [[ABS:%.*]] = call reassoc float @llvm.fabs.f32(float [[SQRTF]])
173; CHECK-NEXT:    [[ISINF:%.*]] = fcmp reassoc oeq float [[X]], 0xFFF0000000000000
174; CHECK-NEXT:    [[ABS_OP:%.*]] = fdiv reassoc float 1.000000e+00, [[ABS]]
175; CHECK-NEXT:    [[RECIPROCAL:%.*]] = select i1 [[ISINF]], float 0.000000e+00, float [[ABS_OP]]
176; CHECK-NEXT:    ret float [[RECIPROCAL]]
177;
178  %pow = call reassoc float @powf(float %x, float -5.0e-01)
179  ret float %pow
180}
181
182; Transform to sqrt+fdiv because 'afn' allows an extra rounding step.
183; Use 'fabs' to handle -0.0 correctly.
184; Use 'select' to handle -INF correctly.
185
186define float @pow_libcall_neghalf_afn(float %x) {
187; CHECK-LABEL: @pow_libcall_neghalf_afn(
188; CHECK-NEXT:    [[SQRTF:%.*]] = call afn float @sqrtf(float [[X:%.*]])
189; CHECK-NEXT:    [[ABS:%.*]] = call afn float @llvm.fabs.f32(float [[SQRTF]])
190; CHECK-NEXT:    [[ISINF:%.*]] = fcmp afn oeq float [[X]], 0xFFF0000000000000
191; CHECK-NEXT:    [[ABS_OP:%.*]] = fdiv afn float 1.000000e+00, [[ABS]]
192; CHECK-NEXT:    [[RECIPROCAL:%.*]] = select i1 [[ISINF]], float 0.000000e+00, float [[ABS_OP]]
193; CHECK-NEXT:    ret float [[RECIPROCAL]]
194;
195  %pow = call afn float @powf(float %x, float -5.0e-01)
196  ret float %pow
197}
198
199; This should not be transformed without some kind of FMF.
200
201define <2 x double> @pow_intrinsic_neghalf_no_FMF(<2 x double> %x) {
202; CHECK-LABEL: @pow_intrinsic_neghalf_no_FMF(
203; CHECK-NEXT:    [[POW:%.*]] = call <2 x double> @llvm.pow.v2f64(<2 x double> [[X:%.*]], <2 x double> <double -5.000000e-01, double -5.000000e-01>)
204; CHECK-NEXT:    ret <2 x double> [[POW]]
205;
206  %pow = call <2 x double> @llvm.pow.v2f64(<2 x double> %x, <2 x double> <double -5.0e-01, double -5.0e-01>)
207  ret <2 x double> %pow
208}
209
210; Transform to sqrt+fdiv because 'reassoc' allows an extra rounding step.
211; Use 'fabs' to handle -0.0 correctly.
212; Use 'select' to handle -INF correctly.
213
214define <2 x double> @pow_intrinsic_neghalf_reassoc(<2 x double> %x) {
215; CHECK-LABEL: @pow_intrinsic_neghalf_reassoc(
216; CHECK-NEXT:    [[SQRT:%.*]] = call reassoc <2 x double> @llvm.sqrt.v2f64(<2 x double> [[X:%.*]])
217; CHECK-NEXT:    [[ABS:%.*]] = call reassoc <2 x double> @llvm.fabs.v2f64(<2 x double> [[SQRT]])
218; CHECK-NEXT:    [[ISINF:%.*]] = fcmp reassoc oeq <2 x double> [[X]], <double 0xFFF0000000000000, double 0xFFF0000000000000>
219; CHECK-NEXT:    [[ABS_OP:%.*]] = fdiv reassoc <2 x double> <double 1.000000e+00, double 1.000000e+00>, [[ABS]]
220; CHECK-NEXT:    [[RECIPROCAL:%.*]] = select <2 x i1> [[ISINF]], <2 x double> zeroinitializer, <2 x double> [[ABS_OP]]
221; CHECK-NEXT:    ret <2 x double> [[RECIPROCAL]]
222;
223  %pow = call reassoc <2 x double> @llvm.pow.v2f64(<2 x double> %x, <2 x double> <double -5.0e-01, double -5.0e-01>)
224  ret <2 x double> %pow
225}
226
227; Transform to sqrt+fdiv because 'afn' allows an extra rounding step.
228; Use 'fabs' to handle -0.0 correctly.
229; Use 'select' to handle -INF correctly.
230
231define <2 x double> @pow_intrinsic_neghalf_afn(<2 x double> %x) {
232; CHECK-LABEL: @pow_intrinsic_neghalf_afn(
233; CHECK-NEXT:    [[SQRT:%.*]] = call afn <2 x double> @llvm.sqrt.v2f64(<2 x double> [[X:%.*]])
234; CHECK-NEXT:    [[ABS:%.*]] = call afn <2 x double> @llvm.fabs.v2f64(<2 x double> [[SQRT]])
235; CHECK-NEXT:    [[ISINF:%.*]] = fcmp afn oeq <2 x double> [[X]], <double 0xFFF0000000000000, double 0xFFF0000000000000>
236; CHECK-NEXT:    [[ABS_OP:%.*]] = fdiv afn <2 x double> <double 1.000000e+00, double 1.000000e+00>, [[ABS]]
237; CHECK-NEXT:    [[RECIPROCAL:%.*]] = select <2 x i1> [[ISINF]], <2 x double> zeroinitializer, <2 x double> [[ABS_OP]]
238; CHECK-NEXT:    ret <2 x double> [[RECIPROCAL]]
239;
240  %pow = call afn <2 x double> @llvm.pow.v2f64(<2 x double> %x, <2 x double> <double -5.0e-01, double -5.0e-01>)
241  ret <2 x double> %pow
242}
243
244; If we can disregard INFs, no need for a select.
245
246define double @pow_libcall_neghalf_ninf(double %x) {
247; CHECK-LABEL: @pow_libcall_neghalf_ninf(
248; CHECK-NEXT:    [[SQRT:%.*]] = call ninf afn double @sqrt(double [[X:%.*]])
249; CHECK-NEXT:    [[ABS:%.*]] = call ninf afn double @llvm.fabs.f64(double [[SQRT]])
250; CHECK-NEXT:    [[RECIPROCAL:%.*]] = fdiv ninf afn double 1.000000e+00, [[ABS]]
251; CHECK-NEXT:    ret double [[RECIPROCAL]]
252;
253  %pow = call afn ninf double @pow(double %x, double -5.0e-01)
254  ret double %pow
255}
256
257define <2 x double> @pow_intrinsic_neghalf_ninf(<2 x double> %x) {
258; CHECK-LABEL: @pow_intrinsic_neghalf_ninf(
259; CHECK-NEXT:    [[SQRT:%.*]] = call ninf afn <2 x double> @llvm.sqrt.v2f64(<2 x double> [[X:%.*]])
260; CHECK-NEXT:    [[ABS:%.*]] = call ninf afn <2 x double> @llvm.fabs.v2f64(<2 x double> [[SQRT]])
261; CHECK-NEXT:    [[RECIPROCAL:%.*]] = fdiv ninf afn <2 x double> <double 1.000000e+00, double 1.000000e+00>, [[ABS]]
262; CHECK-NEXT:    ret <2 x double> [[RECIPROCAL]]
263;
264  %pow = call afn ninf <2 x double> @llvm.pow.v2f64(<2 x double> %x, <2 x double> <double -5.0e-01, double -5.0e-01>)
265  ret <2 x double> %pow
266}
267
268; If we can disregard -0.0, no need for fabs.
269
270define double @pow_libcall_neghalf_nsz(double %x) {
271; CHECK-LABEL: @pow_libcall_neghalf_nsz(
272; CHECK-NEXT:    [[SQRT:%.*]] = call nsz afn double @sqrt(double [[X:%.*]])
273; CHECK-NEXT:    [[ISINF:%.*]] = fcmp nsz afn oeq double [[X]], 0xFFF0000000000000
274; CHECK-NEXT:    [[SQRT_OP:%.*]] = fdiv nsz afn double 1.000000e+00, [[SQRT]]
275; CHECK-NEXT:    [[RECIPROCAL:%.*]] = select i1 [[ISINF]], double 0.000000e+00, double [[SQRT_OP]]
276; CHECK-NEXT:    ret double [[RECIPROCAL]]
277;
278  %pow = call afn nsz double @pow(double %x, double -5.0e-01)
279  ret double %pow
280}
281
282define double @pow_intrinsic_neghalf_nsz(double %x) {
283; CHECK-LABEL: @pow_intrinsic_neghalf_nsz(
284; CHECK-NEXT:    [[SQRT:%.*]] = call nsz afn double @llvm.sqrt.f64(double [[X:%.*]])
285; CHECK-NEXT:    [[ISINF:%.*]] = fcmp nsz afn oeq double [[X]], 0xFFF0000000000000
286; CHECK-NEXT:    [[SQRT_OP:%.*]] = fdiv nsz afn double 1.000000e+00, [[SQRT]]
287; CHECK-NEXT:    [[RECIPROCAL:%.*]] = select i1 [[ISINF]], double 0.000000e+00, double [[SQRT_OP]]
288; CHECK-NEXT:    ret double [[RECIPROCAL]]
289;
290  %pow = call afn nsz double @llvm.pow.f64(double %x, double -5.0e-01)
291  ret double %pow
292}
293
294; This is just recip-sqrt.
295
296define double @pow_intrinsic_neghalf_ninf_nsz(double %x) {
297; CHECK-LABEL: @pow_intrinsic_neghalf_ninf_nsz(
298; CHECK-NEXT:    [[SQRT:%.*]] = call ninf nsz afn double @llvm.sqrt.f64(double [[X:%.*]])
299; CHECK-NEXT:    [[RECIPROCAL:%.*]] = fdiv ninf nsz afn double 1.000000e+00, [[SQRT]]
300; CHECK-NEXT:    ret double [[RECIPROCAL]]
301;
302  %pow = call afn ninf nsz double @llvm.pow.f64(double %x, double -5.0e-01)
303  ret double %pow
304}
305
306define float @pow_libcall_neghalf_ninf_nsz(float %x) {
307; CHECK-LABEL: @pow_libcall_neghalf_ninf_nsz(
308; CHECK-NEXT:    [[SQRTF:%.*]] = call ninf nsz afn float @sqrtf(float [[X:%.*]])
309; CHECK-NEXT:    [[RECIPROCAL:%.*]] = fdiv ninf nsz afn float 1.000000e+00, [[SQRTF]]
310; CHECK-NEXT:    ret float [[RECIPROCAL]]
311;
312  %pow = call afn ninf nsz float @powf(float %x, float -5.0e-01)
313  ret float %pow
314}
315
316; Overspecified FMF to test propagation to the new op(s).
317
318define float @pow_libcall_neghalf_fast(float %x) {
319; CHECK-LABEL: @pow_libcall_neghalf_fast(
320; CHECK-NEXT:    [[SQRTF:%.*]] = call fast float @sqrtf(float [[X:%.*]])
321; CHECK-NEXT:    [[RECIPROCAL:%.*]] = fdiv fast float 1.000000e+00, [[SQRTF]]
322; CHECK-NEXT:    ret float [[RECIPROCAL]]
323;
324  %pow = call fast float @powf(float %x, float -5.0e-01)
325  ret float %pow
326}
327
328define double @pow_intrinsic_neghalf_fast(double %x) {
329; CHECK-LABEL: @pow_intrinsic_neghalf_fast(
330; CHECK-NEXT:    [[SQRT:%.*]] = call fast double @llvm.sqrt.f64(double [[X:%.*]])
331; CHECK-NEXT:    [[RECIPROCAL:%.*]] = fdiv fast double 1.000000e+00, [[SQRT]]
332; CHECK-NEXT:    ret double [[RECIPROCAL]]
333;
334  %pow = call fast double @llvm.pow.f64(double %x, double -5.0e-01)
335  ret double %pow
336}
337
338declare double @llvm.pow.f64(double, double) #0
339declare float @llvm.pow.f32(float, float) #0
340declare <2 x double> @llvm.pow.v2f64(<2 x double>, <2 x double>) #0
341declare <2 x float> @llvm.pow.v2f32(<2 x float>, <2 x float>) #0
342declare <4 x float> @llvm.pow.v4f32(<4 x float>, <4 x float>) #0
343declare double @pow(double, double)
344declare float @powf(float, float)
345
346attributes #0 = { nounwind readnone speculatable }
347attributes #1 = { nounwind readnone }
348