• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -mtriple=x86_64-unknown-linux-gnu < %s -instcombine -S | FileCheck %s
3
4; Make sure libcalls are replaced with intrinsic calls.
5
6declare float @llvm.fabs.f32(float)
7declare double @llvm.fabs.f64(double)
8declare fp128 @llvm.fabs.f128(fp128)
9
10declare float @fabsf(float)
11declare double @fabs(double)
12declare fp128 @fabsl(fp128)
13declare float @llvm.fma.f32(float, float, float)
14declare float @llvm.fmuladd.f32(float, float, float)
15
16define float @replace_fabs_call_f32(float %x) {
17; CHECK-LABEL: @replace_fabs_call_f32(
18; CHECK-NEXT:    [[FABSF:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
19; CHECK-NEXT:    ret float [[FABSF]]
20;
21  %fabsf = tail call float @fabsf(float %x)
22  ret float %fabsf
23}
24
25define double @replace_fabs_call_f64(double %x) {
26; CHECK-LABEL: @replace_fabs_call_f64(
27; CHECK-NEXT:    [[FABS:%.*]] = call double @llvm.fabs.f64(double [[X:%.*]])
28; CHECK-NEXT:    ret double [[FABS]]
29;
30  %fabs = tail call double @fabs(double %x)
31  ret double %fabs
32}
33
34define fp128 @replace_fabs_call_f128(fp128 %x) {
35; CHECK-LABEL: @replace_fabs_call_f128(
36; CHECK-NEXT:    [[FABSL:%.*]] = call fp128 @llvm.fabs.f128(fp128 [[X:%.*]])
37; CHECK-NEXT:    ret fp128 [[FABSL]]
38;
39  %fabsl = tail call fp128 @fabsl(fp128 %x)
40  ret fp128 %fabsl
41}
42
43; Make sure fast math flags are preserved when replacing the libcall.
44define float @fmf_replace_fabs_call_f32(float %x) {
45; CHECK-LABEL: @fmf_replace_fabs_call_f32(
46; CHECK-NEXT:    [[FABSF:%.*]] = call nnan float @llvm.fabs.f32(float [[X:%.*]])
47; CHECK-NEXT:    ret float [[FABSF]]
48;
49  %fabsf = tail call nnan float @fabsf(float %x)
50  ret float %fabsf
51}
52
53; Make sure all intrinsic calls are eliminated when the input is known
54; positive.
55
56; The fabs cannot be eliminated because %x may be a NaN
57
58define float @square_fabs_intrinsic_f32(float %x) {
59; CHECK-LABEL: @square_fabs_intrinsic_f32(
60; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X:%.*]], [[X]]
61; CHECK-NEXT:    [[FABSF:%.*]] = tail call float @llvm.fabs.f32(float [[MUL]])
62; CHECK-NEXT:    ret float [[FABSF]]
63;
64  %mul = fmul float %x, %x
65  %fabsf = tail call float @llvm.fabs.f32(float %mul)
66  ret float %fabsf
67}
68
69define double @square_fabs_intrinsic_f64(double %x) {
70; CHECK-LABEL: @square_fabs_intrinsic_f64(
71; CHECK-NEXT:    [[MUL:%.*]] = fmul double [[X:%.*]], [[X]]
72; CHECK-NEXT:    [[FABS:%.*]] = tail call double @llvm.fabs.f64(double [[MUL]])
73; CHECK-NEXT:    ret double [[FABS]]
74;
75  %mul = fmul double %x, %x
76  %fabs = tail call double @llvm.fabs.f64(double %mul)
77  ret double %fabs
78}
79
80define fp128 @square_fabs_intrinsic_f128(fp128 %x) {
81; CHECK-LABEL: @square_fabs_intrinsic_f128(
82; CHECK-NEXT:    [[MUL:%.*]] = fmul fp128 [[X:%.*]], [[X]]
83; CHECK-NEXT:    [[FABSL:%.*]] = tail call fp128 @llvm.fabs.f128(fp128 [[MUL]])
84; CHECK-NEXT:    ret fp128 [[FABSL]]
85;
86  %mul = fmul fp128 %x, %x
87  %fabsl = tail call fp128 @llvm.fabs.f128(fp128 %mul)
88  ret fp128 %fabsl
89}
90
91define float @square_nnan_fabs_intrinsic_f32(float %x) {
92; CHECK-LABEL: @square_nnan_fabs_intrinsic_f32(
93; CHECK-NEXT:    [[MUL:%.*]] = fmul nnan float [[X:%.*]], [[X]]
94; CHECK-NEXT:    ret float [[MUL]]
95;
96  %mul = fmul nnan float %x, %x
97  %fabsf = call float @llvm.fabs.f32(float %mul)
98  ret float %fabsf
99}
100
101; Shrinking a library call to a smaller type should not be inhibited by nor inhibit the square optimization.
102
103define float @square_fabs_shrink_call1(float %x) {
104; CHECK-LABEL: @square_fabs_shrink_call1(
105; CHECK-NEXT:    [[TMP1:%.*]] = fmul float [[X:%.*]], [[X]]
106; CHECK-NEXT:    [[TRUNC:%.*]] = call float @llvm.fabs.f32(float [[TMP1]])
107; CHECK-NEXT:    ret float [[TRUNC]]
108;
109  %ext = fpext float %x to double
110  %sq = fmul double %ext, %ext
111  %fabs = call double @fabs(double %sq)
112  %trunc = fptrunc double %fabs to float
113  ret float %trunc
114}
115
116define float @square_fabs_shrink_call2(float %x) {
117; CHECK-LABEL: @square_fabs_shrink_call2(
118; CHECK-NEXT:    [[SQ:%.*]] = fmul float [[X:%.*]], [[X]]
119; CHECK-NEXT:    [[TRUNC:%.*]] = call float @llvm.fabs.f32(float [[SQ]])
120; CHECK-NEXT:    ret float [[TRUNC]]
121;
122  %sq = fmul float %x, %x
123  %ext = fpext float %sq to double
124  %fabs = call double @fabs(double %ext)
125  %trunc = fptrunc double %fabs to float
126  ret float %trunc
127}
128
129define float @fabs_select_constant_negative_positive(i32 %c) {
130; CHECK-LABEL: @fabs_select_constant_negative_positive(
131; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0
132; CHECK-NEXT:    [[FABS:%.*]] = select i1 [[CMP]], float 1.000000e+00, float 2.000000e+00
133; CHECK-NEXT:    ret float [[FABS]]
134;
135  %cmp = icmp eq i32 %c, 0
136  %select = select i1 %cmp, float -1.0, float 2.0
137  %fabs = call float @llvm.fabs.f32(float %select)
138  ret float %fabs
139}
140
141define float @fabs_select_constant_positive_negative(i32 %c) {
142; CHECK-LABEL: @fabs_select_constant_positive_negative(
143; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0
144; CHECK-NEXT:    [[FABS:%.*]] = select i1 [[CMP]], float 1.000000e+00, float 2.000000e+00
145; CHECK-NEXT:    ret float [[FABS]]
146;
147  %cmp = icmp eq i32 %c, 0
148  %select = select i1 %cmp, float 1.0, float -2.0
149  %fabs = call float @llvm.fabs.f32(float %select)
150  ret float %fabs
151}
152
153define float @fabs_select_constant_negative_negative(i32 %c) {
154; CHECK-LABEL: @fabs_select_constant_negative_negative(
155; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0
156; CHECK-NEXT:    [[FABS:%.*]] = select i1 [[CMP]], float 1.000000e+00, float 2.000000e+00
157; CHECK-NEXT:    ret float [[FABS]]
158;
159  %cmp = icmp eq i32 %c, 0
160  %select = select i1 %cmp, float -1.0, float -2.0
161  %fabs = call float @llvm.fabs.f32(float %select)
162  ret float %fabs
163}
164
165define float @fabs_select_constant_neg0(i32 %c) {
166; CHECK-LABEL: @fabs_select_constant_neg0(
167; CHECK-NEXT:    ret float 0.000000e+00
168;
169  %cmp = icmp eq i32 %c, 0
170  %select = select i1 %cmp, float -0.0, float 0.0
171  %fabs = call float @llvm.fabs.f32(float %select)
172  ret float %fabs
173}
174
175define float @fabs_select_var_constant_negative(i32 %c, float %x) {
176; CHECK-LABEL: @fabs_select_var_constant_negative(
177; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0
178; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[CMP]], float [[X:%.*]], float -1.000000e+00
179; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SELECT]])
180; CHECK-NEXT:    ret float [[FABS]]
181;
182  %cmp = icmp eq i32 %c, 0
183  %select = select i1 %cmp, float %x, float -1.0
184  %fabs = call float @llvm.fabs.f32(float %select)
185  ret float %fabs
186}
187
188; The fabs cannot be eliminated because %x may be a NaN
189
190define float @square_fma_fabs_intrinsic_f32(float %x) {
191; CHECK-LABEL: @square_fma_fabs_intrinsic_f32(
192; CHECK-NEXT:    [[FMA:%.*]] = call float @llvm.fma.f32(float [[X:%.*]], float [[X]], float 1.000000e+00)
193; CHECK-NEXT:    [[FABSF:%.*]] = call float @llvm.fabs.f32(float [[FMA]])
194; CHECK-NEXT:    ret float [[FABSF]]
195;
196  %fma = call float @llvm.fma.f32(float %x, float %x, float 1.0)
197  %fabsf = call float @llvm.fabs.f32(float %fma)
198  ret float %fabsf
199}
200
201; The fabs cannot be eliminated because %x may be a NaN
202
203define float @square_nnan_fma_fabs_intrinsic_f32(float %x) {
204; CHECK-LABEL: @square_nnan_fma_fabs_intrinsic_f32(
205; CHECK-NEXT:    [[FMA:%.*]] = call nnan float @llvm.fma.f32(float [[X:%.*]], float [[X]], float 1.000000e+00)
206; CHECK-NEXT:    ret float [[FMA]]
207;
208  %fma = call nnan float @llvm.fma.f32(float %x, float %x, float 1.0)
209  %fabsf = call float @llvm.fabs.f32(float %fma)
210  ret float %fabsf
211}
212
213define float @square_fmuladd_fabs_intrinsic_f32(float %x) {
214; CHECK-LABEL: @square_fmuladd_fabs_intrinsic_f32(
215; CHECK-NEXT:    [[FMULADD:%.*]] = call float @llvm.fmuladd.f32(float [[X:%.*]], float [[X]], float 1.000000e+00)
216; CHECK-NEXT:    [[FABSF:%.*]] = call float @llvm.fabs.f32(float [[FMULADD]])
217; CHECK-NEXT:    ret float [[FABSF]]
218;
219  %fmuladd = call float @llvm.fmuladd.f32(float %x, float %x, float 1.0)
220  %fabsf = call float @llvm.fabs.f32(float %fmuladd)
221  ret float %fabsf
222}
223
224define float @square_nnan_fmuladd_fabs_intrinsic_f32(float %x) {
225; CHECK-LABEL: @square_nnan_fmuladd_fabs_intrinsic_f32(
226; CHECK-NEXT:    [[FMULADD:%.*]] = call nnan float @llvm.fmuladd.f32(float [[X:%.*]], float [[X]], float 1.000000e+00)
227; CHECK-NEXT:    ret float [[FMULADD]]
228;
229  %fmuladd = call nnan float @llvm.fmuladd.f32(float %x, float %x, float 1.0)
230  %fabsf = call float @llvm.fabs.f32(float %fmuladd)
231  ret float %fabsf
232}
233
234; Don't introduce a second fpext
235
236define double @multi_use_fabs_fpext(float %x) {
237; CHECK-LABEL: @multi_use_fabs_fpext(
238; CHECK-NEXT:    [[FPEXT:%.*]] = fpext float [[X:%.*]] to double
239; CHECK-NEXT:    [[FABS:%.*]] = call double @llvm.fabs.f64(double [[FPEXT]])
240; CHECK-NEXT:    store volatile double [[FPEXT]], double* undef, align 8
241; CHECK-NEXT:    ret double [[FABS]]
242;
243  %fpext = fpext float %x to double
244  %fabs = call double @llvm.fabs.f64(double %fpext)
245  store volatile double %fpext, double* undef
246  ret double %fabs
247}
248
249; Negative test for the fabs folds below: we require nnan, so
250; we won't always clear the sign bit of a NaN value.
251
252define double @select_fcmp_ole_zero(double %x) {
253; CHECK-LABEL: @select_fcmp_ole_zero(
254; CHECK-NEXT:    [[LEZERO:%.*]] = fcmp ole double [[X:%.*]], 0.000000e+00
255; CHECK-NEXT:    [[NEGX:%.*]] = fsub double 0.000000e+00, [[X]]
256; CHECK-NEXT:    [[FABS:%.*]] = select i1 [[LEZERO]], double [[NEGX]], double [[X]]
257; CHECK-NEXT:    ret double [[FABS]]
258;
259  %lezero = fcmp ole double %x, 0.0
260  %negx = fsub double 0.0, %x
261  %fabs = select i1 %lezero, double %negx, double %x
262  ret double %fabs
263}
264
265; X <= 0.0 ? (0.0 - X) : X --> fabs(X)
266
267define double @select_fcmp_nnan_ole_zero(double %x) {
268; CHECK-LABEL: @select_fcmp_nnan_ole_zero(
269; CHECK-NEXT:    [[TMP1:%.*]] = call nnan double @llvm.fabs.f64(double [[X:%.*]])
270; CHECK-NEXT:    ret double [[TMP1]]
271;
272  %lezero = fcmp nnan ole double %x, 0.0
273  %negx = fsub double 0.0, %x
274  %fabs = select i1 %lezero, double %negx, double %x
275  ret double %fabs
276}
277
278; X <= -0.0 ? (0.0 - X) : X --> fabs(X)
279
280define <2 x float> @select_fcmp_nnan_ole_negzero(<2 x float> %x) {
281; CHECK-LABEL: @select_fcmp_nnan_ole_negzero(
282; CHECK-NEXT:    [[TMP1:%.*]] = call nnan <2 x float> @llvm.fabs.v2f32(<2 x float> [[X:%.*]])
283; CHECK-NEXT:    ret <2 x float> [[TMP1]]
284;
285  %lezero = fcmp nnan ole <2 x float> %x, <float -0.0, float -0.0>
286  %negx = fsub <2 x float> <float 0.0, float undef>, %x
287  %fabs = select <2 x i1> %lezero, <2 x float> %negx, <2 x float> %x
288  ret <2 x float> %fabs
289}
290
291; X > 0.0 ? X : (0.0 - X) --> fabs(X)
292
293define fp128 @select_fcmp_nnan_ogt_zero(fp128 %x) {
294; CHECK-LABEL: @select_fcmp_nnan_ogt_zero(
295; CHECK-NEXT:    [[TMP1:%.*]] = call nnan fp128 @llvm.fabs.f128(fp128 [[X:%.*]])
296; CHECK-NEXT:    ret fp128 [[TMP1]]
297;
298  %gtzero = fcmp nnan ogt fp128 %x, zeroinitializer
299  %negx = fsub fp128 zeroinitializer, %x
300  %fabs = select i1 %gtzero, fp128 %x, fp128 %negx
301  ret fp128 %fabs
302}
303
304; X > -0.0 ? X : (0.0 - X) --> fabs(X)
305
306define half @select_fcmp_nnan_ogt_negzero(half %x) {
307; CHECK-LABEL: @select_fcmp_nnan_ogt_negzero(
308; CHECK-NEXT:    [[TMP1:%.*]] = call nnan half @llvm.fabs.f16(half [[X:%.*]])
309; CHECK-NEXT:    ret half [[TMP1]]
310;
311  %gtzero = fcmp nnan ogt half %x, -0.0
312  %negx = fsub half 0.0, %x
313  %fabs = select i1 %gtzero, half %x, half %negx
314  ret half %fabs
315}
316
317; X < 0.0 ? -X : X --> fabs(X)
318
319define double @select_fcmp_nnan_nsz_olt_zero(double %x) {
320; CHECK-LABEL: @select_fcmp_nnan_nsz_olt_zero(
321; CHECK-NEXT:    [[TMP1:%.*]] = call nnan nsz double @llvm.fabs.f64(double [[X:%.*]])
322; CHECK-NEXT:    ret double [[TMP1]]
323;
324  %ltzero = fcmp nnan nsz olt double %x, 0.0
325  %negx = fsub double -0.0, %x
326  %fabs = select i1 %ltzero, double %negx, double %x
327  ret double %fabs
328}
329
330; X < -0.0 ? -X : X --> fabs(X)
331
332define float @select_fcmp_nnan_nsz_olt_negzero(float %x) {
333; CHECK-LABEL: @select_fcmp_nnan_nsz_olt_negzero(
334; CHECK-NEXT:    [[TMP1:%.*]] = call nnan ninf nsz float @llvm.fabs.f32(float [[X:%.*]])
335; CHECK-NEXT:    ret float [[TMP1]]
336;
337  %ltzero = fcmp nnan nsz ninf olt float %x, -0.0
338  %negx = fsub float -0.0, %x
339  %fabs = select i1 %ltzero, float %negx, float %x
340  ret float %fabs
341}
342
343; X <= 0.0 ? -X : X --> fabs(X)
344
345define double @select_fcmp_nnan_nsz_ole_zero(double %x) {
346; CHECK-LABEL: @select_fcmp_nnan_nsz_ole_zero(
347; CHECK-NEXT:    [[TMP1:%.*]] = call fast double @llvm.fabs.f64(double [[X:%.*]])
348; CHECK-NEXT:    ret double [[TMP1]]
349;
350  %lezero = fcmp fast ole double %x, 0.0
351  %negx = fsub double -0.0, %x
352  %fabs = select i1 %lezero, double %negx, double %x
353  ret double %fabs
354}
355
356; X <= -0.0 ? -X : X --> fabs(X)
357
358define float @select_fcmp_nnan_nsz_ole_negzero(float %x) {
359; CHECK-LABEL: @select_fcmp_nnan_nsz_ole_negzero(
360; CHECK-NEXT:    [[TMP1:%.*]] = call nnan nsz float @llvm.fabs.f32(float [[X:%.*]])
361; CHECK-NEXT:    ret float [[TMP1]]
362;
363  %lezero = fcmp nnan nsz ole float %x, -0.0
364  %negx = fsub float -0.0, %x
365  %fabs = select i1 %lezero, float %negx, float %x
366  ret float %fabs
367}
368
369; X > 0.0 ? X : (0.0 - X) --> fabs(X)
370
371define <2 x float> @select_fcmp_nnan_nsz_ogt_zero(<2 x float> %x) {
372; CHECK-LABEL: @select_fcmp_nnan_nsz_ogt_zero(
373; CHECK-NEXT:    [[TMP1:%.*]] = call nnan nsz arcp <2 x float> @llvm.fabs.v2f32(<2 x float> [[X:%.*]])
374; CHECK-NEXT:    ret <2 x float> [[TMP1]]
375;
376  %gtzero = fcmp nnan nsz arcp ogt <2 x float> %x, zeroinitializer
377  %negx = fsub <2 x float> <float -0.0, float -0.0>, %x
378  %fabs = select <2 x i1> %gtzero, <2 x float> %x, <2 x float> %negx
379  ret <2 x float> %fabs
380}
381
382; X > -0.0 ? X : (0.0 - X) --> fabs(X)
383
384define half @select_fcmp_nnan_nsz_ogt_negzero(half %x) {
385; CHECK-LABEL: @select_fcmp_nnan_nsz_ogt_negzero(
386; CHECK-NEXT:    [[TMP1:%.*]] = call fast half @llvm.fabs.f16(half [[X:%.*]])
387; CHECK-NEXT:    ret half [[TMP1]]
388;
389  %gtzero = fcmp fast ogt half %x, -0.0
390  %negx = fsub half 0.0, %x
391  %fabs = select i1 %gtzero, half %x, half %negx
392  ret half %fabs
393}
394
395; X > 0.0 ? X : (0.0 - X) --> fabs(X)
396
397define <2 x double> @select_fcmp_nnan_nsz_oge_zero(<2 x double> %x) {
398; CHECK-LABEL: @select_fcmp_nnan_nsz_oge_zero(
399; CHECK-NEXT:    [[TMP1:%.*]] = call reassoc nnan nsz <2 x double> @llvm.fabs.v2f64(<2 x double> [[X:%.*]])
400; CHECK-NEXT:    ret <2 x double> [[TMP1]]
401;
402  %gezero = fcmp nnan nsz reassoc oge <2 x double> %x, zeroinitializer
403  %negx = fsub <2 x double> <double -0.0, double -0.0>, %x
404  %fabs = select <2 x i1> %gezero, <2 x double> %x, <2 x double> %negx
405  ret <2 x double> %fabs
406}
407
408; X > -0.0 ? X : (0.0 - X) --> fabs(X)
409
410define half @select_fcmp_nnan_nsz_oge_negzero(half %x) {
411; CHECK-LABEL: @select_fcmp_nnan_nsz_oge_negzero(
412; CHECK-NEXT:    [[TMP1:%.*]] = call nnan nsz half @llvm.fabs.f16(half [[X:%.*]])
413; CHECK-NEXT:    ret half [[TMP1]]
414;
415  %gezero = fcmp nnan nsz oge half %x, -0.0
416  %negx = fsub half -0.0, %x
417  %fabs = select i1 %gezero, half %x, half %negx
418  ret half %fabs
419}
420
421