1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -instcombine -S | FileCheck %s
4 ; Check the libcall and the intrinsic for each case with differing FMF.
6 ; The transform to sqrt is allowed as long as we deal with -0.0 and -INF.
8 define 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]]
16 %pow = call double @pow(double %x, double 5.0e-01)
20 define 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]]
28 %pow = call double @llvm.pow.f64(double %x, double 5.0e-01)
32 ; This makes no difference, but FMF are propagated.
34 define 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]]
42 %pow = call afn double @pow(double %x, double 5.0e-01)
46 define <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]]
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>)
58 define 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]]
63 %pow = call fast float @llvm.pow.f32(float %x, float 5.0e-01)
67 ; If we can disregard INFs, no need for a select.
69 define 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]]
75 %pow = call ninf double @pow(double %x, double 5.0e-01)
79 define <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]]
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>)
89 ; If we can disregard -0.0, no need for fabs.
91 define 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]]
98 %pow = call nsz double @pow(double %x, double 5.0e-01)
102 define 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]]
109 %pow = call nsz double @llvm.pow.f64(double %x, double 5.0e-01)
115 define 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]]
120 %pow = call ninf nsz float @powf(float %x, float 5.0e-01)
124 define 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]]
129 %pow = call ninf nsz double @llvm.pow.f64(double %x, double 5.0e-01)
133 ; Overspecified FMF to test propagation to the new op(s).
135 define 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]]
140 %pow = call fast float @powf(float %x, float 5.0e-01)
144 define 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]]
149 %pow = call fast double @llvm.pow.f64(double %x, double 5.0e-01)
153 ; -0.5 means take the reciprocal.
155 define float @pow_libcall_neghalf_no_FMF(float %x) {
156 ; CHECK-LABEL: @pow_libcall_neghalf_no_FMF(
157 ; CHECK-NEXT: [[SQRTF:%.*]] = call float @sqrtf(float [[X:%.*]])
158 ; CHECK-NEXT: [[ABS:%.*]] = call float @llvm.fabs.f32(float [[SQRTF]])
159 ; CHECK-NEXT: [[ISINF:%.*]] = fcmp oeq float [[X]], 0xFFF0000000000000
160 ; CHECK-NEXT: [[ABS_OP:%.*]] = fdiv float 1.000000e+00, [[ABS]]
161 ; CHECK-NEXT: [[RECIPROCAL:%.*]] = select i1 [[ISINF]], float 0.000000e+00, float [[ABS_OP]]
162 ; CHECK-NEXT: ret float [[RECIPROCAL]]
164 %pow = call float @powf(float %x, float -5.0e-01)
168 define <2 x double> @pow_intrinsic_neghalf_no_FMF(<2 x double> %x) {
169 ; CHECK-LABEL: @pow_intrinsic_neghalf_no_FMF(
170 ; CHECK-NEXT: [[SQRT:%.*]] = call <2 x double> @llvm.sqrt.v2f64(<2 x double> [[X:%.*]])
171 ; CHECK-NEXT: [[ABS:%.*]] = call <2 x double> @llvm.fabs.v2f64(<2 x double> [[SQRT]])
172 ; CHECK-NEXT: [[ISINF:%.*]] = fcmp oeq <2 x double> [[X]], <double 0xFFF0000000000000, double 0xFFF0000000000000>
173 ; CHECK-NEXT: [[ABS_OP:%.*]] = fdiv <2 x double> <double 1.000000e+00, double 1.000000e+00>, [[ABS]]
174 ; CHECK-NEXT: [[RECIPROCAL:%.*]] = select <2 x i1> [[ISINF]], <2 x double> zeroinitializer, <2 x double> [[ABS_OP]]
175 ; CHECK-NEXT: ret <2 x double> [[RECIPROCAL]]
177 %pow = call <2 x double> @llvm.pow.v2f64(<2 x double> %x, <2 x double> <double -5.0e-01, double -5.0e-01>)
178 ret <2 x double> %pow
181 ; If we can disregard INFs, no need for a select.
183 define double @pow_libcall_neghalf_ninf(double %x) {
184 ; CHECK-LABEL: @pow_libcall_neghalf_ninf(
185 ; CHECK-NEXT: [[SQRT:%.*]] = call ninf double @sqrt(double [[X:%.*]])
186 ; CHECK-NEXT: [[ABS:%.*]] = call ninf double @llvm.fabs.f64(double [[SQRT]])
187 ; CHECK-NEXT: [[RECIPROCAL:%.*]] = fdiv ninf double 1.000000e+00, [[ABS]]
188 ; CHECK-NEXT: ret double [[RECIPROCAL]]
190 %pow = call ninf double @pow(double %x, double -5.0e-01)
194 define <2 x double> @pow_intrinsic_neghalf_ninf(<2 x double> %x) {
195 ; CHECK-LABEL: @pow_intrinsic_neghalf_ninf(
196 ; CHECK-NEXT: [[SQRT:%.*]] = call ninf <2 x double> @llvm.sqrt.v2f64(<2 x double> [[X:%.*]])
197 ; CHECK-NEXT: [[ABS:%.*]] = call ninf <2 x double> @llvm.fabs.v2f64(<2 x double> [[SQRT]])
198 ; CHECK-NEXT: [[RECIPROCAL:%.*]] = fdiv ninf <2 x double> <double 1.000000e+00, double 1.000000e+00>, [[ABS]]
199 ; CHECK-NEXT: ret <2 x double> [[RECIPROCAL]]
201 %pow = call ninf <2 x double> @llvm.pow.v2f64(<2 x double> %x, <2 x double> <double -5.0e-01, double -5.0e-01>)
202 ret <2 x double> %pow
205 ; If we can disregard -0.0, no need for fabs.
207 define double @pow_libcall_neghalf_nsz(double %x) {
208 ; CHECK-LABEL: @pow_libcall_neghalf_nsz(
209 ; CHECK-NEXT: [[SQRT:%.*]] = call nsz double @sqrt(double [[X:%.*]])
210 ; CHECK-NEXT: [[ISINF:%.*]] = fcmp nsz oeq double [[X]], 0xFFF0000000000000
211 ; CHECK-NEXT: [[SQRT_OP:%.*]] = fdiv nsz double 1.000000e+00, [[SQRT]]
212 ; CHECK-NEXT: [[RECIPROCAL:%.*]] = select i1 [[ISINF]], double 0.000000e+00, double [[SQRT_OP]]
213 ; CHECK-NEXT: ret double [[RECIPROCAL]]
215 %pow = call nsz double @pow(double %x, double -5.0e-01)
219 define double @pow_intrinsic_neghalf_nsz(double %x) {
220 ; CHECK-LABEL: @pow_intrinsic_neghalf_nsz(
221 ; CHECK-NEXT: [[SQRT:%.*]] = call nsz double @llvm.sqrt.f64(double [[X:%.*]])
222 ; CHECK-NEXT: [[ISINF:%.*]] = fcmp nsz oeq double [[X]], 0xFFF0000000000000
223 ; CHECK-NEXT: [[SQRT_OP:%.*]] = fdiv nsz double 1.000000e+00, [[SQRT]]
224 ; CHECK-NEXT: [[RECIPROCAL:%.*]] = select i1 [[ISINF]], double 0.000000e+00, double [[SQRT_OP]]
225 ; CHECK-NEXT: ret double [[RECIPROCAL]]
227 %pow = call nsz double @llvm.pow.f64(double %x, double -5.0e-01)
231 ; This is just recip-sqrt.
233 define double @pow_intrinsic_neghalf_ninf_nsz(double %x) {
234 ; CHECK-LABEL: @pow_intrinsic_neghalf_ninf_nsz(
235 ; CHECK-NEXT: [[SQRT:%.*]] = call ninf nsz double @llvm.sqrt.f64(double [[X:%.*]])
236 ; CHECK-NEXT: [[RECIPROCAL:%.*]] = fdiv ninf nsz double 1.000000e+00, [[SQRT]]
237 ; CHECK-NEXT: ret double [[RECIPROCAL]]
239 %pow = call ninf nsz double @llvm.pow.f64(double %x, double -5.0e-01)
243 define float @pow_libcall_neghalf_ninf_nsz(float %x) {
244 ; CHECK-LABEL: @pow_libcall_neghalf_ninf_nsz(
245 ; CHECK-NEXT: [[SQRTF:%.*]] = call ninf nsz float @sqrtf(float [[X:%.*]])
246 ; CHECK-NEXT: [[RECIPROCAL:%.*]] = fdiv ninf nsz float 1.000000e+00, [[SQRTF]]
247 ; CHECK-NEXT: ret float [[RECIPROCAL]]
249 %pow = call ninf nsz float @powf(float %x, float -5.0e-01)
253 ; Overspecified FMF to test propagation to the new op(s).
255 define float @pow_libcall_neghalf_fast(float %x) {
256 ; CHECK-LABEL: @pow_libcall_neghalf_fast(
257 ; CHECK-NEXT: [[SQRTF:%.*]] = call fast float @sqrtf(float [[X:%.*]])
258 ; CHECK-NEXT: [[RECIPROCAL:%.*]] = fdiv fast float 1.000000e+00, [[SQRTF]]
259 ; CHECK-NEXT: ret float [[RECIPROCAL]]
261 %pow = call fast float @powf(float %x, float -5.0e-01)
265 define float @powf_libcall_neghalf_approx(float %x) {
266 ; CHECK-LABEL: @powf_libcall_neghalf_approx(
267 ; CHECK-NEXT: [[SQRTF:%.*]] = call afn float @sqrtf(float [[X:%.*]])
268 ; CHECK-NEXT: [[ABS:%.*]] = call afn float @llvm.fabs.f32(float [[SQRTF]])
269 ; CHECK-NEXT: [[ISINF:%.*]] = fcmp afn oeq float [[X]], 0xFFF0000000000000
270 ; CHECK-NEXT: [[ABS_OP:%.*]] = fdiv afn float 1.000000e+00, [[ABS]]
271 ; CHECK-NEXT: [[RECIPROCAL:%.*]] = select i1 [[ISINF]], float 0.000000e+00, float [[ABS_OP]]
272 ; CHECK-NEXT: ret float [[RECIPROCAL]]
274 %pow = call afn float @powf(float %x, float -5.0e-01)
278 define double @pow_intrinsic_neghalf_fast(double %x) {
279 ; CHECK-LABEL: @pow_intrinsic_neghalf_fast(
280 ; CHECK-NEXT: [[SQRT:%.*]] = call fast double @llvm.sqrt.f64(double [[X:%.*]])
281 ; CHECK-NEXT: [[RECIPROCAL:%.*]] = fdiv fast double 1.000000e+00, [[SQRT]]
282 ; CHECK-NEXT: ret double [[RECIPROCAL]]
284 %pow = call fast double @llvm.pow.f64(double %x, double -5.0e-01)
288 declare double @llvm.pow.f64(double, double) #0
289 declare float @llvm.pow.f32(float, float) #0
290 declare <2 x double> @llvm.pow.v2f64(<2 x double>, <2 x double>) #0
291 declare <2 x float> @llvm.pow.v2f32(<2 x float>, <2 x float>) #0
292 declare <4 x float> @llvm.pow.v4f32(<4 x float>, <4 x float>) #0
293 declare double @pow(double, double)
294 declare float @powf(float, float)
296 attributes #0 = { nounwind readnone speculatable }
297 attributes #1 = { nounwind readnone }