1; RUN: opt < %s -instcombine -S | FileCheck %s
2
3; Make sure all library calls are eliminated when the input is known positive.
4
5declare float @fabsf(float)
6declare double @fabs(double)
7declare fp128 @fabsl(fp128)
8declare float @llvm.fma.f32(float, float, float)
9declare float @llvm.fmuladd.f32(float, float, float)
10
11define float @square_fabs_call_f32(float %x) {
12  %mul = fmul float %x, %x
13  %fabsf = tail call float @fabsf(float %mul)
14  ret float %fabsf
15
16; CHECK-LABEL: square_fabs_call_f32(
17; CHECK-NEXT: %mul = fmul float %x, %x
18; CHECK-NEXT: %fabsf = tail call float @fabsf(float %mul)
19; CHECK-NEXT: ret float %fabsf
20}
21
22define double @square_fabs_call_f64(double %x) {
23  %mul = fmul double %x, %x
24  %fabs = tail call double @fabs(double %mul)
25  ret double %fabs
26
27; CHECK-LABEL: square_fabs_call_f64(
28; CHECK-NEXT: %mul = fmul double %x, %x
29; CHECK-NEXT: %fabs = tail call double @fabs(double %mul)
30; CHECK-NEXT: ret double %fabs
31}
32
33define fp128 @square_fabs_call_f128(fp128 %x) {
34  %mul = fmul fp128 %x, %x
35  %fabsl = tail call fp128 @fabsl(fp128 %mul)
36  ret fp128 %fabsl
37
38; CHECK-LABEL: square_fabs_call_f128(
39; CHECK-NEXT: %mul = fmul fp128 %x, %x
40; CHECK-NEXT: %fabsl = tail call fp128 @fabsl(fp128 %mul)
41; CHECK-NEXT: ret fp128 %fabsl
42}
43
44; Make sure all intrinsic calls are eliminated when the input is known
45; positive.
46
47declare float @llvm.fabs.f32(float)
48declare double @llvm.fabs.f64(double)
49declare fp128 @llvm.fabs.f128(fp128)
50
51; The fabs cannot be eliminated because %x may be a NaN
52define float @square_fabs_intrinsic_f32(float %x) {
53  %mul = fmul float %x, %x
54  %fabsf = tail call float @llvm.fabs.f32(float %mul)
55  ret float %fabsf
56
57; CHECK-LABEL: square_fabs_intrinsic_f32(
58; CHECK-NEXT: %mul = fmul float %x, %x
59; CHECK-NEXT: %fabsf = tail call float @llvm.fabs.f32(float %mul)
60; CHECK-NEXT: ret float %fabsf
61}
62
63define double @square_fabs_intrinsic_f64(double %x) {
64  %mul = fmul double %x, %x
65  %fabs = tail call double @llvm.fabs.f64(double %mul)
66  ret double %fabs
67
68; CHECK-LABEL: square_fabs_intrinsic_f64(
69; CHECK-NEXT: %mul = fmul double %x, %x
70; CHECK-NEXT: %fabs = tail call double @llvm.fabs.f64(double %mul)
71; CHECK-NEXT: ret double %fabs
72}
73
74define fp128 @square_fabs_intrinsic_f128(fp128 %x) {
75  %mul = fmul fp128 %x, %x
76  %fabsl = tail call fp128 @llvm.fabs.f128(fp128 %mul)
77  ret fp128 %fabsl
78
79; CHECK-LABEL: square_fabs_intrinsic_f128(
80; CHECK-NEXT: %mul = fmul fp128 %x, %x
81; CHECK-NEXT: %fabsl = tail call fp128 @llvm.fabs.f128(fp128 %mul)
82; CHECK-NEXT: ret fp128 %fabsl
83}
84
85define float @square_nnan_fabs_intrinsic_f32(float %x) {
86  %mul = fmul nnan float %x, %x
87  %fabsf = call float @llvm.fabs.f32(float %mul)
88  ret float %fabsf
89
90; CHECK-LABEL: square_nnan_fabs_intrinsic_f32(
91; CHECK-NEXT: %mul = fmul nnan float %x, %x
92; CHECK-NEXT: ret float %mul
93}
94
95; Shrinking a library call to a smaller type should not be inhibited by nor inhibit the square optimization.
96
97define float @square_fabs_shrink_call1(float %x) {
98  %ext = fpext float %x to double
99  %sq = fmul double %ext, %ext
100  %fabs = call double @fabs(double %sq)
101  %trunc = fptrunc double %fabs to float
102  ret float %trunc
103
104; CHECK-LABEL: square_fabs_shrink_call1(
105; CHECK-NEXT: %ext = fpext float %x to double
106; CHECK-NEXT: %sq = fmul double %ext, %ext
107; CHECK-NEXT: call double @fabs(double %sq)
108; CHECK-NEXT: %trunc = fptrunc double %fabs to float
109; CHECK-NEXT: ret float %trunc
110}
111
112define float @square_fabs_shrink_call2(float %x) {
113  %sq = fmul float %x, %x
114  %ext = fpext float %sq to double
115  %fabs = call double @fabs(double %ext)
116  %trunc = fptrunc double %fabs to float
117  ret float %trunc
118
119; CHECK-LABEL: square_fabs_shrink_call2(
120; CHECK-NEXT: %sq = fmul float %x, %x
121; CHECK-NEXT: %fabsf = call float @fabsf(float %sq)
122; CHECK-NEXT: ret float %fabsf
123}
124
125; CHECK-LABEL: @fabs_select_constant_negative_positive(
126; CHECK: %fabs = select i1 %cmp, float 1.000000e+00, float 2.000000e+00
127; CHECK-NEXT: ret float %fabs
128define float @fabs_select_constant_negative_positive(i32 %c) {
129  %cmp = icmp eq i32 %c, 0
130  %select = select i1 %cmp, float -1.0, float 2.0
131  %fabs = call float @llvm.fabs.f32(float %select)
132  ret float %fabs
133}
134
135; CHECK-LABEL: @fabs_select_constant_positive_negative(
136; CHECK: %fabs = select i1 %cmp, float 1.000000e+00, float 2.000000e+00
137; CHECK-NEXT: ret float %fabs
138define float @fabs_select_constant_positive_negative(i32 %c) {
139  %cmp = icmp eq i32 %c, 0
140  %select = select i1 %cmp, float 1.0, float -2.0
141  %fabs = call float @llvm.fabs.f32(float %select)
142  ret float %fabs
143}
144
145; CHECK-LABEL: @fabs_select_constant_negative_negative(
146; CHECK: %fabs = select i1 %cmp, float 1.000000e+00, float 2.000000e+00
147; CHECK-NEXT: ret float %fabs
148define float @fabs_select_constant_negative_negative(i32 %c) {
149  %cmp = icmp eq i32 %c, 0
150  %select = select i1 %cmp, float -1.0, float -2.0
151  %fabs = call float @llvm.fabs.f32(float %select)
152  ret float %fabs
153}
154
155; CHECK-LABEL: @fabs_select_constant_neg0(
156; CHECK-NEXT: ret float 0.0
157define float @fabs_select_constant_neg0(i32 %c) {
158  %cmp = icmp eq i32 %c, 0
159  %select = select i1 %cmp, float -0.0, float 0.0
160  %fabs = call float @llvm.fabs.f32(float %select)
161  ret float %fabs
162}
163
164; CHECK-LABEL: @fabs_select_var_constant_negative(
165; CHECK: %select = select i1 %cmp, float %x, float -1.000000e+00
166; CHECK: %fabs = call float @llvm.fabs.f32(float %select)
167define float @fabs_select_var_constant_negative(i32 %c, float %x) {
168  %cmp = icmp eq i32 %c, 0
169  %select = select i1 %cmp, float %x, float -1.0
170  %fabs = call float @llvm.fabs.f32(float %select)
171  ret float %fabs
172}
173
174; The fabs cannot be eliminated because %x may be a NaN
175define float @square_fma_fabs_intrinsic_f32(float %x) {
176  %fma = call float @llvm.fma.f32(float %x, float %x, float 1.0)
177  %fabsf = call float @llvm.fabs.f32(float %fma)
178  ret float %fabsf
179
180; CHECK-LABEL: @square_fma_fabs_intrinsic_f32(
181; CHECK-NEXT: %fma = call float @llvm.fma.f32(float %x, float %x, float 1.000000e+00)
182; CHECK-NEXT: %fabsf = call float @llvm.fabs.f32(float %fma)
183; CHECK-NEXT: ret float %fabsf
184}
185
186; The fabs cannot be eliminated because %x may be a NaN
187define float @square_nnan_fma_fabs_intrinsic_f32(float %x) {
188  %fma = call nnan float @llvm.fma.f32(float %x, float %x, float 1.0)
189  %fabsf = call float @llvm.fabs.f32(float %fma)
190  ret float %fabsf
191
192; CHECK-LABEL: @square_nnan_fma_fabs_intrinsic_f32(
193; CHECK-NEXT: %fma = call nnan float @llvm.fma.f32(float %x, float %x, float 1.000000e+00)
194; CHECK-NEXT: ret float %fma
195}
196
197define float @square_fmuladd_fabs_intrinsic_f32(float %x) {
198  %fmuladd = call float @llvm.fmuladd.f32(float %x, float %x, float 1.0)
199  %fabsf = call float @llvm.fabs.f32(float %fmuladd)
200  ret float %fabsf
201
202; CHECK-LABEL: @square_fmuladd_fabs_intrinsic_f32(
203; CHECK-NEXT: %fmuladd = call float @llvm.fmuladd.f32(float %x, float %x, float 1.000000e+00)
204; CHECK-NEXT: %fabsf = call float @llvm.fabs.f32(float %fmuladd)
205; CHECK-NEXT: ret float %fabsf
206}
207
208define float @square_nnan_fmuladd_fabs_intrinsic_f32(float %x) {
209  %fmuladd = call nnan float @llvm.fmuladd.f32(float %x, float %x, float 1.0)
210  %fabsf = call float @llvm.fabs.f32(float %fmuladd)
211  ret float %fabsf
212
213; CHECK-LABEL: @square_nnan_fmuladd_fabs_intrinsic_f32(
214; CHECK-NEXT: %fmuladd = call nnan float @llvm.fmuladd.f32(float %x, float %x, float 1.000000e+00)
215; CHECK-NEXT: ret float %fmuladd
216}
217