1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -instsimplify -S | FileCheck %s
3
4;; x * 0 ==> 0 when no-nans and no-signed-zero
5define float @mul_zero_1(float %a) {
6; CHECK-LABEL: @mul_zero_1(
7; CHECK-NEXT:    ret float 0.000000e+00
8;
9  %b = fmul nsz nnan float %a, 0.0
10  ret float %b
11}
12
13define float @mul_zero_2(float %a) {
14; CHECK-LABEL: @mul_zero_2(
15; CHECK-NEXT:    ret float 0.000000e+00
16;
17  %b = fmul fast float 0.0, %a
18  ret float %b
19}
20
21define <2 x float> @mul_zero_nsz_nnan_vec_undef(<2 x float> %a) {
22; CHECK-LABEL: @mul_zero_nsz_nnan_vec_undef(
23; CHECK-NEXT:    ret <2 x float> zeroinitializer
24;
25  %b = fmul nsz nnan <2 x float> %a, <float 0.0, float undef>
26  ret <2 x float> %b
27}
28
29;; x * 0 =/=> 0 when there could be nans or -0
30define float @no_mul_zero_1(float %a) {
31; CHECK-LABEL: @no_mul_zero_1(
32; CHECK-NEXT:    [[B:%.*]] = fmul nsz float [[A:%.*]], 0.000000e+00
33; CHECK-NEXT:    ret float [[B]]
34;
35  %b = fmul nsz float %a, 0.0
36  ret float %b
37}
38
39define float @no_mul_zero_2(float %a) {
40; CHECK-LABEL: @no_mul_zero_2(
41; CHECK-NEXT:    [[B:%.*]] = fmul nnan float [[A:%.*]], 0.000000e+00
42; CHECK-NEXT:    ret float [[B]]
43;
44  %b = fmul nnan float %a, 0.0
45  ret float %b
46}
47
48define float @no_mul_zero_3(float %a) {
49; CHECK-LABEL: @no_mul_zero_3(
50; CHECK-NEXT:    [[B:%.*]] = fmul float [[A:%.*]], 0.000000e+00
51; CHECK-NEXT:    ret float [[B]]
52;
53  %b = fmul float %a, 0.0
54  ret float %b
55}
56
57; -X + X --> 0.0 (with nnan on the fadd)
58
59define float @fadd_fnegx(float %x) {
60; CHECK-LABEL: @fadd_fnegx(
61; CHECK-NEXT:    ret float 0.000000e+00
62;
63  %negx = fsub float -0.0, %x
64  %r = fadd nnan float %negx, %x
65  ret float %r
66}
67
68; X + -X --> 0.0 (with nnan on the fadd)
69
70define <2 x float> @fadd_fnegx_commute_vec(<2 x float> %x) {
71; CHECK-LABEL: @fadd_fnegx_commute_vec(
72; CHECK-NEXT:    ret <2 x float> zeroinitializer
73;
74  %negx = fsub <2 x float> <float -0.0, float -0.0>, %x
75  %r = fadd nnan <2 x float> %x, %negx
76  ret <2 x float> %r
77}
78
79define <2 x float> @fadd_fnegx_commute_vec_undef(<2 x float> %x) {
80; CHECK-LABEL: @fadd_fnegx_commute_vec_undef(
81; CHECK-NEXT:    ret <2 x float> zeroinitializer
82;
83  %negx = fsub <2 x float> <float undef, float -0.0>, %x
84  %r = fadd nnan <2 x float> %x, %negx
85  ret <2 x float> %r
86}
87
88; https://bugs.llvm.org/show_bug.cgi?id=26958
89; https://bugs.llvm.org/show_bug.cgi?id=27151
90
91define float @fadd_fneg_nan(float %x) {
92; CHECK-LABEL: @fadd_fneg_nan(
93; CHECK-NEXT:    [[T:%.*]] = fsub nnan float -0.000000e+00, [[X:%.*]]
94; CHECK-NEXT:    [[COULD_BE_NAN:%.*]] = fadd ninf float [[T]], [[X]]
95; CHECK-NEXT:    ret float [[COULD_BE_NAN]]
96;
97  %t = fsub nnan float -0.0, %x
98  %could_be_nan = fadd ninf float %t, %x
99  ret float %could_be_nan
100}
101
102define float @fadd_fneg_nan_commute(float %x) {
103; CHECK-LABEL: @fadd_fneg_nan_commute(
104; CHECK-NEXT:    [[T:%.*]] = fsub nnan ninf float -0.000000e+00, [[X:%.*]]
105; CHECK-NEXT:    [[COULD_BE_NAN:%.*]] = fadd float [[X]], [[T]]
106; CHECK-NEXT:    ret float [[COULD_BE_NAN]]
107;
108  %t = fsub nnan ninf float -0.0, %x
109  %could_be_nan = fadd float %x, %t
110  ret float %could_be_nan
111}
112
113; X + (0.0 - X) --> 0.0 (with nnan on the fadd)
114
115define float @fadd_fsub_nnan_ninf(float %x) {
116; CHECK-LABEL: @fadd_fsub_nnan_ninf(
117; CHECK-NEXT:    ret float 0.000000e+00
118;
119  %sub = fsub float 0.0, %x
120  %zero = fadd nnan ninf float %x, %sub
121  ret float %zero
122}
123
124; (0.0 - X) + X --> 0.0 (with nnan on the fadd)
125
126define <2 x float> @fadd_fsub_nnan_ninf_commute_vec(<2 x float> %x) {
127; CHECK-LABEL: @fadd_fsub_nnan_ninf_commute_vec(
128; CHECK-NEXT:    ret <2 x float> zeroinitializer
129;
130  %sub = fsub <2 x float> zeroinitializer, %x
131  %zero = fadd nnan ninf <2 x float> %sub, %x
132  ret <2 x float> %zero
133}
134
135; 'ninf' is not required because 'nnan' allows us to assume
136; that X is not INF or -INF (adding opposite INFs would be NaN).
137
138define float @fadd_fsub_nnan(float %x) {
139; CHECK-LABEL: @fadd_fsub_nnan(
140; CHECK-NEXT:    ret float 0.000000e+00
141;
142  %sub = fsub float 0.0, %x
143  %zero = fadd nnan float %sub, %x
144  ret float %zero
145}
146
147; fsub nnan x, x ==> 0.0
148define float @fsub_x_x(float %a) {
149; CHECK-LABEL: @fsub_x_x(
150; CHECK-NEXT:    [[NO_ZERO1:%.*]] = fsub ninf float [[A:%.*]], [[A]]
151; CHECK-NEXT:    [[NO_ZERO2:%.*]] = fsub float [[A]], [[A]]
152; CHECK-NEXT:    [[NO_ZERO:%.*]] = fadd float [[NO_ZERO1]], [[NO_ZERO2]]
153; CHECK-NEXT:    ret float [[NO_ZERO]]
154;
155; X - X ==> 0
156  %zero1 = fsub nnan float %a, %a
157
158; Dont fold
159  %no_zero1 = fsub ninf float %a, %a
160  %no_zero2 = fsub float %a, %a
161  %no_zero = fadd float %no_zero1, %no_zero2
162
163; Should get folded
164  %ret = fadd nsz float %no_zero, %zero1
165
166  ret float %ret
167}
168
169; fsub nsz 0.0, (fsub 0.0, X) ==> X
170define float @fsub_0_0_x(float %a) {
171; CHECK-LABEL: @fsub_0_0_x(
172; CHECK-NEXT:    ret float [[A:%.*]]
173;
174  %t1 = fsub float 0.0, %a
175  %ret = fsub nsz float 0.0, %t1
176  ret float %ret
177}
178
179define <2 x float> @fsub_0_0_x_vec_undef1(<2 x float> %a) {
180; CHECK-LABEL: @fsub_0_0_x_vec_undef1(
181; CHECK-NEXT:    ret <2 x float> [[A:%.*]]
182;
183  %t1 = fsub <2 x float> <float 0.0, float undef>, %a
184  %ret = fsub nsz <2 x float> zeroinitializer, %t1
185  ret <2 x float> %ret
186}
187
188define <2 x float> @fsub_0_0_x_vec_undef2(<2 x float> %a) {
189; CHECK-LABEL: @fsub_0_0_x_vec_undef2(
190; CHECK-NEXT:    ret <2 x float> [[A:%.*]]
191;
192  %t1 = fsub <2 x float> zeroinitializer, %a
193  %ret = fsub nsz <2 x float> <float undef, float -0.0>, %t1
194  ret <2 x float> %ret
195}
196
197; fadd nsz X, 0 ==> X
198
199define <2 x float> @fadd_zero_nsz_vec(<2 x float> %x) {
200; CHECK-LABEL: @fadd_zero_nsz_vec(
201; CHECK-NEXT:    ret <2 x float> [[X:%.*]]
202;
203  %r = fadd nsz <2 x float> %x, zeroinitializer
204  ret <2 x float> %r
205}
206
207define <2 x float> @fadd_zero_nsz_vec_undef(<2 x float> %x) {
208; CHECK-LABEL: @fadd_zero_nsz_vec_undef(
209; CHECK-NEXT:    ret <2 x float> [[X:%.*]]
210;
211  %r = fadd nsz <2 x float> %x, <float 0.0, float undef>
212  ret <2 x float> %r
213}
214
215define float @nofold_fadd_x_0(float %a) {
216; CHECK-LABEL: @nofold_fadd_x_0(
217; CHECK-NEXT:    [[NO_ZERO1:%.*]] = fadd ninf float [[A:%.*]], 0.000000e+00
218; CHECK-NEXT:    [[NO_ZERO2:%.*]] = fadd nnan float [[A]], 0.000000e+00
219; CHECK-NEXT:    [[NO_ZERO:%.*]] = fadd float [[NO_ZERO1]], [[NO_ZERO2]]
220; CHECK-NEXT:    ret float [[NO_ZERO]]
221;
222; Dont fold
223  %no_zero1 = fadd ninf float %a, 0.0
224  %no_zero2 = fadd nnan float %a, 0.0
225  %no_zero = fadd float %no_zero1, %no_zero2
226  ret float %no_zero
227}
228
229; fdiv nsz nnan 0, X ==> 0
230; 0 / X -> 0
231
232define double @fdiv_zero_by_x(double %x) {
233; CHECK-LABEL: @fdiv_zero_by_x(
234; CHECK-NEXT:    ret double 0.000000e+00
235;
236  %r = fdiv nnan nsz double 0.0, %x
237  ret double %r
238}
239
240define <2 x double> @fdiv_zero_by_x_vec_undef(<2 x double> %x) {
241; CHECK-LABEL: @fdiv_zero_by_x_vec_undef(
242; CHECK-NEXT:    ret <2 x double> zeroinitializer
243;
244  %r = fdiv nnan nsz <2 x double> <double 0.0, double undef>, %x
245  ret <2 x double> %r
246}
247
248; 0 % X -> 0
249; nsz is not necessary - frem result always has the sign of the dividend
250
251define double @frem_zero_by_x(double %x) {
252; CHECK-LABEL: @frem_zero_by_x(
253; CHECK-NEXT:    ret double 0.000000e+00
254;
255  %r = frem nnan double 0.0, %x
256  ret double %r
257}
258
259define <2 x double> @frem_poszero_by_x_vec_undef(<2 x double> %x) {
260; CHECK-LABEL: @frem_poszero_by_x_vec_undef(
261; CHECK-NEXT:    ret <2 x double> zeroinitializer
262;
263  %r = frem nnan <2 x double> <double 0.0, double undef>, %x
264  ret <2 x double> %r
265}
266
267; -0 % X -> -0
268; nsz is not necessary - frem result always has the sign of the dividend
269
270define double @frem_negzero_by_x(double %x) {
271; CHECK-LABEL: @frem_negzero_by_x(
272; CHECK-NEXT:    ret double -0.000000e+00
273;
274  %r = frem nnan double -0.0, %x
275  ret double %r
276}
277
278define <2 x double> @frem_negzero_by_x_vec_undef(<2 x double> %x) {
279; CHECK-LABEL: @frem_negzero_by_x_vec_undef(
280; CHECK-NEXT:    ret <2 x double> <double -0.000000e+00, double -0.000000e+00>
281;
282  %r = frem nnan <2 x double> <double undef, double -0.0>, %x
283  ret <2 x double> %r
284}
285
286define float @fdiv_self(float %f) {
287; CHECK-LABEL: @fdiv_self(
288; CHECK-NEXT:    ret float 1.000000e+00
289;
290  %div = fdiv nnan float %f, %f
291  ret float %div
292}
293
294define float @fdiv_self_invalid(float %f) {
295; CHECK-LABEL: @fdiv_self_invalid(
296; CHECK-NEXT:    [[DIV:%.*]] = fdiv float [[F:%.*]], [[F]]
297; CHECK-NEXT:    ret float [[DIV]]
298;
299  %div = fdiv float %f, %f
300  ret float %div
301}
302
303define float @fdiv_neg1(float %f) {
304; CHECK-LABEL: @fdiv_neg1(
305; CHECK-NEXT:    ret float -1.000000e+00
306;
307  %neg = fsub fast float -0.000000e+00, %f
308  %div = fdiv nnan float %neg, %f
309  ret float %div
310}
311
312define float @fdiv_neg2(float %f) {
313; CHECK-LABEL: @fdiv_neg2(
314; CHECK-NEXT:    ret float -1.000000e+00
315;
316  %neg = fsub fast float 0.000000e+00, %f
317  %div = fdiv nnan float %neg, %f
318  ret float %div
319}
320
321define float @fdiv_neg_invalid(float %f) {
322; CHECK-LABEL: @fdiv_neg_invalid(
323; CHECK-NEXT:    [[NEG:%.*]] = fsub fast float -0.000000e+00, [[F:%.*]]
324; CHECK-NEXT:    [[DIV:%.*]] = fdiv float [[NEG]], [[F]]
325; CHECK-NEXT:    ret float [[DIV]]
326;
327  %neg = fsub fast float -0.000000e+00, %f
328  %div = fdiv float %neg, %f
329  ret float %div
330}
331
332define float @fdiv_neg_swapped1(float %f) {
333; CHECK-LABEL: @fdiv_neg_swapped1(
334; CHECK-NEXT:    ret float -1.000000e+00
335;
336  %neg = fsub float -0.000000e+00, %f
337  %div = fdiv nnan float %f, %neg
338  ret float %div
339}
340
341define float @fdiv_neg_swapped2(float %f) {
342; CHECK-LABEL: @fdiv_neg_swapped2(
343; CHECK-NEXT:    ret float -1.000000e+00
344;
345  %neg = fsub float 0.000000e+00, %f
346  %div = fdiv nnan float %f, %neg
347  ret float %div
348}
349
350; PR21126: http://llvm.org/bugs/show_bug.cgi?id=21126
351; With loose math, sqrt(X) * sqrt(X) is just X.
352
353declare double @llvm.sqrt.f64(double)
354
355define double @sqrt_squared(double %f) {
356; CHECK-LABEL: @sqrt_squared(
357; CHECK-NEXT:    ret double [[F:%.*]]
358;
359  %sqrt = call double @llvm.sqrt.f64(double %f)
360  %mul = fmul reassoc nnan nsz double %sqrt, %sqrt
361  ret double %mul
362}
363
364; Negative tests for the above transform: we need all 3 of those flags.
365
366define double @sqrt_squared_not_fast_enough1(double %f) {
367; CHECK-LABEL: @sqrt_squared_not_fast_enough1(
368; CHECK-NEXT:    [[SQRT:%.*]] = call double @llvm.sqrt.f64(double [[F:%.*]])
369; CHECK-NEXT:    [[MUL:%.*]] = fmul nnan nsz double [[SQRT]], [[SQRT]]
370; CHECK-NEXT:    ret double [[MUL]]
371;
372  %sqrt = call double @llvm.sqrt.f64(double %f)
373  %mul = fmul nnan nsz double %sqrt, %sqrt
374  ret double %mul
375}
376
377define double @sqrt_squared_not_fast_enough2(double %f) {
378; CHECK-LABEL: @sqrt_squared_not_fast_enough2(
379; CHECK-NEXT:    [[SQRT:%.*]] = call double @llvm.sqrt.f64(double [[F:%.*]])
380; CHECK-NEXT:    [[MUL:%.*]] = fmul reassoc nnan double [[SQRT]], [[SQRT]]
381; CHECK-NEXT:    ret double [[MUL]]
382;
383  %sqrt = call double @llvm.sqrt.f64(double %f)
384  %mul = fmul reassoc nnan double %sqrt, %sqrt
385  ret double %mul
386}
387
388define double @sqrt_squared_not_fast_enough3(double %f) {
389; CHECK-LABEL: @sqrt_squared_not_fast_enough3(
390; CHECK-NEXT:    [[SQRT:%.*]] = call double @llvm.sqrt.f64(double [[F:%.*]])
391; CHECK-NEXT:    [[MUL:%.*]] = fmul reassoc nsz double [[SQRT]], [[SQRT]]
392; CHECK-NEXT:    ret double [[MUL]]
393;
394  %sqrt = call double @llvm.sqrt.f64(double %f)
395  %mul = fmul reassoc nsz double %sqrt, %sqrt
396  ret double %mul
397}
398
399