• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -instcombine -S | FileCheck %s
3
4; PR4374
5
6define float @test1(float %x, float %y) {
7; CHECK-LABEL: @test1(
8; CHECK-NEXT:    [[T1:%.*]] = fsub float [[X:%.*]], [[Y:%.*]]
9; CHECK-NEXT:    [[T2:%.*]] = fneg float [[T1]]
10; CHECK-NEXT:    ret float [[T2]]
11;
12  %t1 = fsub float %x, %y
13  %t2 = fsub float -0.0, %t1
14  ret float %t2
15}
16
17define float @test1_unary(float %x, float %y) {
18; CHECK-LABEL: @test1_unary(
19; CHECK-NEXT:    [[T1:%.*]] = fsub float [[X:%.*]], [[Y:%.*]]
20; CHECK-NEXT:    [[T2:%.*]] = fneg float [[T1]]
21; CHECK-NEXT:    ret float [[T2]]
22;
23  %t1 = fsub float %x, %y
24  %t2 = fneg float %t1
25  ret float %t2
26}
27
28; Can't do anything with the test above because -0.0 - 0.0 = -0.0, but if we have nsz:
29; -(X - Y) --> Y - X
30
31define float @neg_sub_nsz(float %x, float %y) {
32; CHECK-LABEL: @neg_sub_nsz(
33; CHECK-NEXT:    [[T2:%.*]] = fsub nsz float [[Y:%.*]], [[X:%.*]]
34; CHECK-NEXT:    ret float [[T2]]
35;
36  %t1 = fsub float %x, %y
37  %t2 = fsub nsz float -0.0, %t1
38  ret float %t2
39}
40
41define float @unary_neg_sub_nsz(float %x, float %y) {
42; CHECK-LABEL: @unary_neg_sub_nsz(
43; CHECK-NEXT:    [[T2:%.*]] = fsub nsz float [[Y:%.*]], [[X:%.*]]
44; CHECK-NEXT:    ret float [[T2]]
45;
46  %t1 = fsub float %x, %y
47  %t2 = fneg nsz float %t1
48  ret float %t2
49}
50
51; If the subtract has another use, we don't do the transform (even though it
52; doesn't increase the IR instruction count) because we assume that fneg is
53; easier to analyze and generally cheaper than generic fsub.
54
55declare void @use(float)
56declare void @use2(float, double)
57
58define float @neg_sub_nsz_extra_use(float %x, float %y) {
59; CHECK-LABEL: @neg_sub_nsz_extra_use(
60; CHECK-NEXT:    [[T1:%.*]] = fsub float [[X:%.*]], [[Y:%.*]]
61; CHECK-NEXT:    [[T2:%.*]] = fneg nsz float [[T1]]
62; CHECK-NEXT:    call void @use(float [[T1]])
63; CHECK-NEXT:    ret float [[T2]]
64;
65  %t1 = fsub float %x, %y
66  %t2 = fsub nsz float -0.0, %t1
67  call void @use(float %t1)
68  ret float %t2
69}
70
71define float @unary_neg_sub_nsz_extra_use(float %x, float %y) {
72; CHECK-LABEL: @unary_neg_sub_nsz_extra_use(
73; CHECK-NEXT:    [[T1:%.*]] = fsub float [[X:%.*]], [[Y:%.*]]
74; CHECK-NEXT:    [[T2:%.*]] = fneg nsz float [[T1]]
75; CHECK-NEXT:    call void @use(float [[T1]])
76; CHECK-NEXT:    ret float [[T2]]
77;
78  %t1 = fsub float %x, %y
79  %t2 = fneg nsz float %t1
80  call void @use(float %t1)
81  ret float %t2
82}
83
84; With nsz: Z - (X - Y) --> Z + (Y - X)
85
86define float @sub_sub_nsz(float %x, float %y, float %z) {
87; CHECK-LABEL: @sub_sub_nsz(
88; CHECK-NEXT:    [[TMP1:%.*]] = fsub nsz float [[Y:%.*]], [[X:%.*]]
89; CHECK-NEXT:    [[T2:%.*]] = fadd nsz float [[TMP1]], [[Z:%.*]]
90; CHECK-NEXT:    ret float [[T2]]
91;
92  %t1 = fsub float %x, %y
93  %t2 = fsub nsz float %z, %t1
94  ret float %t2
95}
96
97; With nsz and reassoc: Y - ((X * 5) + Y) --> X * -5
98
99define float @sub_add_neg_x(float %x, float %y) {
100; CHECK-LABEL: @sub_add_neg_x(
101; CHECK-NEXT:    [[R:%.*]] = fmul reassoc nsz float [[X:%.*]], -5.000000e+00
102; CHECK-NEXT:    ret float [[R]]
103;
104  %mul = fmul float %x, 5.000000e+00
105  %add = fadd float %mul, %y
106  %r = fsub nsz reassoc float %y, %add
107  ret float %r
108}
109
110; Same as above: if 'Z' is not -0.0, swap fsub operands and convert to fadd.
111
112define float @sub_sub_known_not_negzero(float %x, float %y) {
113; CHECK-LABEL: @sub_sub_known_not_negzero(
114; CHECK-NEXT:    [[TMP1:%.*]] = fsub float [[Y:%.*]], [[X:%.*]]
115; CHECK-NEXT:    [[T2:%.*]] = fadd float [[TMP1]], 4.200000e+01
116; CHECK-NEXT:    ret float [[T2]]
117;
118  %t1 = fsub float %x, %y
119  %t2 = fsub float 42.0, %t1
120  ret float %t2
121}
122
123; <rdar://problem/7530098>
124
125define double @test2(double %x, double %y) {
126; CHECK-LABEL: @test2(
127; CHECK-NEXT:    [[T1:%.*]] = fadd double [[X:%.*]], [[Y:%.*]]
128; CHECK-NEXT:    [[T2:%.*]] = fsub double [[X]], [[T1]]
129; CHECK-NEXT:    ret double [[T2]]
130;
131  %t1 = fadd double %x, %y
132  %t2 = fsub double %x, %t1
133  ret double %t2
134}
135
136; X - C --> X + (-C)
137
138define float @constant_op1(float %x, float %y) {
139; CHECK-LABEL: @constant_op1(
140; CHECK-NEXT:    [[R:%.*]] = fadd float [[X:%.*]], -4.200000e+01
141; CHECK-NEXT:    ret float [[R]]
142;
143  %r = fsub float %x, 42.0
144  ret float %r
145}
146
147define <2 x float> @constant_op1_vec(<2 x float> %x, <2 x float> %y) {
148; CHECK-LABEL: @constant_op1_vec(
149; CHECK-NEXT:    [[R:%.*]] = fadd <2 x float> [[X:%.*]], <float -4.200000e+01, float 4.200000e+01>
150; CHECK-NEXT:    ret <2 x float> [[R]]
151;
152  %r = fsub <2 x float> %x, <float 42.0, float -42.0>
153  ret <2 x float> %r
154}
155
156define <2 x float> @constant_op1_vec_undef(<2 x float> %x, <2 x float> %y) {
157; CHECK-LABEL: @constant_op1_vec_undef(
158; CHECK-NEXT:    [[R:%.*]] = fadd <2 x float> [[X:%.*]], <float undef, float 4.200000e+01>
159; CHECK-NEXT:    ret <2 x float> [[R]]
160;
161  %r = fsub <2 x float> %x, <float undef, float -42.0>
162  ret <2 x float> %r
163}
164
165; X - (-Y) --> X + Y
166
167define float @neg_op1(float %x, float %y) {
168; CHECK-LABEL: @neg_op1(
169; CHECK-NEXT:    [[R:%.*]] = fadd float [[X:%.*]], [[Y:%.*]]
170; CHECK-NEXT:    ret float [[R]]
171;
172  %negy = fsub float -0.0, %y
173  %r = fsub float %x, %negy
174  ret float %r
175}
176
177define float @unary_neg_op1(float %x, float %y) {
178; CHECK-LABEL: @unary_neg_op1(
179; CHECK-NEXT:    [[R:%.*]] = fadd float [[X:%.*]], [[Y:%.*]]
180; CHECK-NEXT:    ret float [[R]]
181;
182  %negy = fneg float %y
183  %r = fsub float %x, %negy
184  ret float %r
185}
186
187define <2 x float> @neg_op1_vec(<2 x float> %x, <2 x float> %y) {
188; CHECK-LABEL: @neg_op1_vec(
189; CHECK-NEXT:    [[R:%.*]] = fadd <2 x float> [[X:%.*]], [[Y:%.*]]
190; CHECK-NEXT:    ret <2 x float> [[R]]
191;
192  %negy = fsub <2 x float> <float -0.0, float -0.0>, %y
193  %r = fsub <2 x float> %x, %negy
194  ret <2 x float> %r
195}
196
197define <2 x float> @unary_neg_op1_vec(<2 x float> %x, <2 x float> %y) {
198; CHECK-LABEL: @unary_neg_op1_vec(
199; CHECK-NEXT:    [[R:%.*]] = fadd <2 x float> [[X:%.*]], [[Y:%.*]]
200; CHECK-NEXT:    ret <2 x float> [[R]]
201;
202  %negy = fneg <2 x float> %y
203  %r = fsub <2 x float> %x, %negy
204  ret <2 x float> %r
205}
206
207define <2 x float> @neg_op1_vec_undef(<2 x float> %x, <2 x float> %y) {
208; CHECK-LABEL: @neg_op1_vec_undef(
209; CHECK-NEXT:    [[R:%.*]] = fadd <2 x float> [[X:%.*]], [[Y:%.*]]
210; CHECK-NEXT:    ret <2 x float> [[R]]
211;
212  %negy = fsub <2 x float> <float -0.0, float undef>, %y
213  %r = fsub <2 x float> %x, %negy
214  ret <2 x float> %r
215}
216
217; Similar to above - but look through fpext/fptrunc casts to find the fneg.
218
219define double @neg_ext_op1(float %a, double %b) {
220; CHECK-LABEL: @neg_ext_op1(
221; CHECK-NEXT:    [[TMP1:%.*]] = fpext float [[A:%.*]] to double
222; CHECK-NEXT:    [[T3:%.*]] = fadd double [[TMP1]], [[B:%.*]]
223; CHECK-NEXT:    ret double [[T3]]
224;
225  %t1 = fsub float -0.0, %a
226  %t2 = fpext float %t1 to double
227  %t3 = fsub double %b, %t2
228  ret double %t3
229}
230
231define double @unary_neg_ext_op1(float %a, double %b) {
232; CHECK-LABEL: @unary_neg_ext_op1(
233; CHECK-NEXT:    [[TMP1:%.*]] = fpext float [[A:%.*]] to double
234; CHECK-NEXT:    [[T3:%.*]] = fadd double [[TMP1]], [[B:%.*]]
235; CHECK-NEXT:    ret double [[T3]]
236;
237  %t1 = fneg float %a
238  %t2 = fpext float %t1 to double
239  %t3 = fsub double %b, %t2
240  ret double %t3
241}
242
243; Verify that vectors work too.
244
245define <2 x float> @neg_trunc_op1(<2 x double> %a, <2 x float> %b) {
246; CHECK-LABEL: @neg_trunc_op1(
247; CHECK-NEXT:    [[TMP1:%.*]] = fptrunc <2 x double> [[A:%.*]] to <2 x float>
248; CHECK-NEXT:    [[T3:%.*]] = fadd <2 x float> [[TMP1]], [[B:%.*]]
249; CHECK-NEXT:    ret <2 x float> [[T3]]
250;
251  %t1 = fsub <2 x double> <double -0.0, double -0.0>, %a
252  %t2 = fptrunc <2 x double> %t1 to <2 x float>
253  %t3 = fsub <2 x float> %b, %t2
254  ret <2 x float> %t3
255}
256
257define <2 x float> @unary_neg_trunc_op1(<2 x double> %a, <2 x float> %b) {
258; CHECK-LABEL: @unary_neg_trunc_op1(
259; CHECK-NEXT:    [[TMP1:%.*]] = fptrunc <2 x double> [[A:%.*]] to <2 x float>
260; CHECK-NEXT:    [[T3:%.*]] = fadd <2 x float> [[TMP1]], [[B:%.*]]
261; CHECK-NEXT:    ret <2 x float> [[T3]]
262;
263  %t1 = fneg <2 x double> %a
264  %t2 = fptrunc <2 x double> %t1 to <2 x float>
265  %t3 = fsub <2 x float> %b, %t2
266  ret <2 x float> %t3
267}
268
269; No FMF needed, but they should propagate to the fadd.
270
271define double @neg_ext_op1_fast(float %a, double %b) {
272; CHECK-LABEL: @neg_ext_op1_fast(
273; CHECK-NEXT:    [[TMP1:%.*]] = fpext float [[A:%.*]] to double
274; CHECK-NEXT:    [[T3:%.*]] = fadd fast double [[TMP1]], [[B:%.*]]
275; CHECK-NEXT:    ret double [[T3]]
276;
277  %t1 = fsub float -0.0, %a
278  %t2 = fpext float %t1 to double
279  %t3 = fsub fast double %b, %t2
280  ret double %t3
281}
282
283define double @unary_neg_ext_op1_fast(float %a, double %b) {
284; CHECK-LABEL: @unary_neg_ext_op1_fast(
285; CHECK-NEXT:    [[TMP1:%.*]] = fpext float [[A:%.*]] to double
286; CHECK-NEXT:    [[T3:%.*]] = fadd fast double [[TMP1]], [[B:%.*]]
287; CHECK-NEXT:    ret double [[T3]]
288;
289  %t1 = fneg float %a
290  %t2 = fpext float %t1 to double
291  %t3 = fsub fast double %b, %t2
292  ret double %t3
293}
294
295; Extra use should prevent the transform.
296
297define float @neg_ext_op1_extra_use(half %a, float %b) {
298; CHECK-LABEL: @neg_ext_op1_extra_use(
299; CHECK-NEXT:    [[T1:%.*]] = fneg half [[A:%.*]]
300; CHECK-NEXT:    [[T2:%.*]] = fpext half [[T1]] to float
301; CHECK-NEXT:    [[T3:%.*]] = fsub float [[B:%.*]], [[T2]]
302; CHECK-NEXT:    call void @use(float [[T2]])
303; CHECK-NEXT:    ret float [[T3]]
304;
305  %t1 = fsub half -0.0, %a
306  %t2 = fpext half %t1 to float
307  %t3 = fsub float %b, %t2
308  call void @use(float %t2)
309  ret float %t3
310}
311
312define float @unary_neg_ext_op1_extra_use(half %a, float %b) {
313; CHECK-LABEL: @unary_neg_ext_op1_extra_use(
314; CHECK-NEXT:    [[T1:%.*]] = fneg half [[A:%.*]]
315; CHECK-NEXT:    [[T2:%.*]] = fpext half [[T1]] to float
316; CHECK-NEXT:    [[T3:%.*]] = fsub float [[B:%.*]], [[T2]]
317; CHECK-NEXT:    call void @use(float [[T2]])
318; CHECK-NEXT:    ret float [[T3]]
319;
320  %t1 = fneg half %a
321  %t2 = fpext half %t1 to float
322  %t3 = fsub float %b, %t2
323  call void @use(float %t2)
324  ret float %t3
325}
326
327; One-use fptrunc is always hoisted above fneg, so the corresponding
328; multi-use bug for fptrunc isn't visible with a fold starting from
329; the last fsub.
330
331define float @neg_trunc_op1_extra_use(double %a, float %b) {
332; CHECK-LABEL: @neg_trunc_op1_extra_use(
333; CHECK-NEXT:    [[TMP1:%.*]] = fptrunc double [[A:%.*]] to float
334; CHECK-NEXT:    [[T2:%.*]] = fneg float [[TMP1]]
335; CHECK-NEXT:    [[T3:%.*]] = fadd float [[TMP1]], [[B:%.*]]
336; CHECK-NEXT:    call void @use(float [[T2]])
337; CHECK-NEXT:    ret float [[T3]]
338;
339  %t1 = fsub double -0.0, %a
340  %t2 = fptrunc double %t1 to float
341  %t3 = fsub float %b, %t2
342  call void @use(float %t2)
343  ret float %t3
344}
345
346define float @unary_neg_trunc_op1_extra_use(double %a, float %b) {
347; CHECK-LABEL: @unary_neg_trunc_op1_extra_use(
348; CHECK-NEXT:    [[TMP1:%.*]] = fptrunc double [[A:%.*]] to float
349; CHECK-NEXT:    [[T2:%.*]] = fneg float [[TMP1]]
350; CHECK-NEXT:    [[T3:%.*]] = fadd float [[TMP1]], [[B:%.*]]
351; CHECK-NEXT:    call void @use(float [[T2]])
352; CHECK-NEXT:    ret float [[T3]]
353;
354  %t1 = fneg double %a
355  %t2 = fptrunc double %t1 to float
356  %t3 = fsub float %b, %t2
357  call void @use(float %t2)
358  ret float %t3
359}
360
361; Extra uses should prevent the transform.
362
363define float @neg_trunc_op1_extra_uses(double %a, float %b) {
364; CHECK-LABEL: @neg_trunc_op1_extra_uses(
365; CHECK-NEXT:    [[T1:%.*]] = fneg double [[A:%.*]]
366; CHECK-NEXT:    [[T2:%.*]] = fptrunc double [[T1]] to float
367; CHECK-NEXT:    [[T3:%.*]] = fsub float [[B:%.*]], [[T2]]
368; CHECK-NEXT:    call void @use2(float [[T2]], double [[T1]])
369; CHECK-NEXT:    ret float [[T3]]
370;
371  %t1 = fsub double -0.0, %a
372  %t2 = fptrunc double %t1 to float
373  %t3 = fsub float %b, %t2
374  call void @use2(float %t2, double %t1)
375  ret float %t3
376}
377
378define float @unary_neg_trunc_op1_extra_uses(double %a, float %b) {
379; CHECK-LABEL: @unary_neg_trunc_op1_extra_uses(
380; CHECK-NEXT:    [[T1:%.*]] = fneg double [[A:%.*]]
381; CHECK-NEXT:    [[T2:%.*]] = fptrunc double [[T1]] to float
382; CHECK-NEXT:    [[T3:%.*]] = fsub float [[B:%.*]], [[T2]]
383; CHECK-NEXT:    call void @use2(float [[T2]], double [[T1]])
384; CHECK-NEXT:    ret float [[T3]]
385;
386  %t1 = fneg double %a
387  %t2 = fptrunc double %t1 to float
388  %t3 = fsub float %b, %t2
389  call void @use2(float %t2, double %t1)
390  ret float %t3
391}
392
393; Don't negate a constant expression to form fadd and induce infinite looping:
394; https://bugs.llvm.org/show_bug.cgi?id=37605
395
396@b = external global i16, align 1
397
398define float @PR37605(float %conv) {
399; CHECK-LABEL: @PR37605(
400; CHECK-NEXT:    [[SUB:%.*]] = fsub float [[CONV:%.*]], bitcast (i32 ptrtoint (i16* @b to i32) to float)
401; CHECK-NEXT:    ret float [[SUB]]
402;
403  %sub = fsub float %conv, bitcast (i32 ptrtoint (i16* @b to i32) to float)
404  ret float %sub
405}
406
407define double @fsub_fdiv_fneg1(double %x, double %y, double %z) {
408; CHECK-LABEL: @fsub_fdiv_fneg1(
409; CHECK-NEXT:    [[TMP1:%.*]] = fdiv double [[X:%.*]], [[Y:%.*]]
410; CHECK-NEXT:    [[R:%.*]] = fadd double [[TMP1]], [[Z:%.*]]
411; CHECK-NEXT:    ret double [[R]]
412;
413  %neg = fsub double -0.000000e+00, %x
414  %div = fdiv double %neg, %y
415  %r = fsub double %z, %div
416  ret double %r
417}
418
419define <2 x double> @fsub_fdiv_fneg2(<2 x double> %x, <2 x double> %y, <2 x double> %z) {
420; CHECK-LABEL: @fsub_fdiv_fneg2(
421; CHECK-NEXT:    [[TMP1:%.*]] = fdiv <2 x double> [[Y:%.*]], [[X:%.*]]
422; CHECK-NEXT:    [[R:%.*]] = fadd <2 x double> [[TMP1]], [[Z:%.*]]
423; CHECK-NEXT:    ret <2 x double> [[R]]
424;
425  %neg = fsub <2 x double> <double -0.0, double -0.0>, %x
426  %div = fdiv <2 x double> %y, %neg
427  %r = fsub <2 x double> %z, %div
428  ret <2 x double> %r
429}
430
431define double @fsub_fmul_fneg1(double %x, double %y, double %z) {
432; CHECK-LABEL: @fsub_fmul_fneg1(
433; CHECK-NEXT:    [[TMP1:%.*]] = fmul double [[X:%.*]], [[Y:%.*]]
434; CHECK-NEXT:    [[R:%.*]] = fadd double [[TMP1]], [[Z:%.*]]
435; CHECK-NEXT:    ret double [[R]]
436;
437  %neg = fsub double -0.000000e+00, %x
438  %mul = fmul double %neg, %y
439  %r = fsub double %z, %mul
440  ret double %r
441}
442
443define double @fsub_fmul_fneg2(double %x, double %y, double %z) {
444; CHECK-LABEL: @fsub_fmul_fneg2(
445; CHECK-NEXT:    [[TMP1:%.*]] = fmul double [[X:%.*]], [[Y:%.*]]
446; CHECK-NEXT:    [[R:%.*]] = fadd double [[TMP1]], [[Z:%.*]]
447; CHECK-NEXT:    ret double [[R]]
448;
449  %neg = fsub double -0.000000e+00, %x
450  %mul = fmul double %y, %neg
451  %r = fsub double %z, %mul
452  ret double %r
453}
454
455define float @fsub_fdiv_fneg1_extra_use(float %x, float %y, float %z) {
456; CHECK-LABEL: @fsub_fdiv_fneg1_extra_use(
457; CHECK-NEXT:    [[NEG:%.*]] = fneg float [[X:%.*]]
458; CHECK-NEXT:    [[DIV:%.*]] = fdiv float [[NEG]], [[Y:%.*]]
459; CHECK-NEXT:    call void @use(float [[DIV]])
460; CHECK-NEXT:    [[R:%.*]] = fsub float [[Z:%.*]], [[DIV]]
461; CHECK-NEXT:    ret float [[R]]
462;
463  %neg = fsub float -0.000000e+00, %x
464  %div = fdiv float %neg, %y
465  call void @use(float %div)
466  %r = fsub float %z, %div
467  ret float %r
468}
469
470define float @fsub_fdiv_fneg2_extra_use(float %x, float %y, float %z) {
471; CHECK-LABEL: @fsub_fdiv_fneg2_extra_use(
472; CHECK-NEXT:    [[NEG:%.*]] = fneg float [[X:%.*]]
473; CHECK-NEXT:    [[DIV:%.*]] = fdiv float [[Y:%.*]], [[NEG]]
474; CHECK-NEXT:    call void @use(float [[DIV]])
475; CHECK-NEXT:    [[R:%.*]] = fsub float [[Z:%.*]], [[DIV]]
476; CHECK-NEXT:    ret float [[R]]
477;
478  %neg = fsub float -0.000000e+00, %x
479  %div = fdiv float %y, %neg
480  call void @use(float %div)
481  %r = fsub float %z, %div
482  ret float %r
483}
484
485declare void @use_vec(<2 x float>)
486
487define <2 x float> @fsub_fmul_fneg1_extra_use(<2 x float> %x, <2 x float> %y, <2 x float> %z) {
488; CHECK-LABEL: @fsub_fmul_fneg1_extra_use(
489; CHECK-NEXT:    [[NEG:%.*]] = fneg <2 x float> [[X:%.*]]
490; CHECK-NEXT:    [[MUL:%.*]] = fmul <2 x float> [[NEG]], [[Y:%.*]]
491; CHECK-NEXT:    call void @use_vec(<2 x float> [[MUL]])
492; CHECK-NEXT:    [[R:%.*]] = fsub <2 x float> [[Z:%.*]], [[MUL]]
493; CHECK-NEXT:    ret <2 x float> [[R]]
494;
495  %neg = fsub <2 x float> <float -0.0, float -0.0>, %x
496  %mul = fmul <2 x float> %neg, %y
497  call void @use_vec(<2 x float> %mul)
498  %r = fsub <2 x float> %z, %mul
499  ret <2 x float> %r
500}
501
502define float @fsub_fmul_fneg2_extra_use(float %x, float %y, float %z) {
503; CHECK-LABEL: @fsub_fmul_fneg2_extra_use(
504; CHECK-NEXT:    [[NEG:%.*]] = fneg float [[X:%.*]]
505; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[NEG]], [[Y:%.*]]
506; CHECK-NEXT:    call void @use(float [[MUL]])
507; CHECK-NEXT:    [[R:%.*]] = fsub float [[Z:%.*]], [[MUL]]
508; CHECK-NEXT:    ret float [[R]]
509;
510  %neg = fsub float -0.000000e+00, %x
511  %mul = fmul float %y, %neg
512  call void @use(float %mul)
513  %r = fsub float %z, %mul
514  ret float %r
515}
516
517define float @fsub_fdiv_fneg1_extra_use2(float %x, float %y, float %z) {
518; CHECK-LABEL: @fsub_fdiv_fneg1_extra_use2(
519; CHECK-NEXT:    [[NEG:%.*]] = fneg float [[X:%.*]]
520; CHECK-NEXT:    call void @use(float [[NEG]])
521; CHECK-NEXT:    [[TMP1:%.*]] = fdiv float [[X]], [[Y:%.*]]
522; CHECK-NEXT:    [[R:%.*]] = fadd float [[TMP1]], [[Z:%.*]]
523; CHECK-NEXT:    ret float [[R]]
524;
525  %neg = fsub float -0.000000e+00, %x
526  call void @use(float %neg)
527  %div = fdiv float %neg, %y
528  %r = fsub float %z, %div
529  ret float %r
530}
531
532define float @fsub_fdiv_fneg2_extra_use2(float %x, float %y, float %z) {
533; CHECK-LABEL: @fsub_fdiv_fneg2_extra_use2(
534; CHECK-NEXT:    [[NEG:%.*]] = fneg float [[X:%.*]]
535; CHECK-NEXT:    call void @use(float [[NEG]])
536; CHECK-NEXT:    [[TMP1:%.*]] = fdiv float [[Y:%.*]], [[X]]
537; CHECK-NEXT:    [[R:%.*]] = fadd float [[TMP1]], [[Z:%.*]]
538; CHECK-NEXT:    ret float [[R]]
539;
540  %neg = fsub float -0.000000e+00, %x
541  call void @use(float %neg)
542  %div = fdiv float %y, %neg
543  %r = fsub float %z, %div
544  ret float %r
545}
546
547define <2 x float> @fsub_fmul_fneg1_extra_use2(<2 x float> %x, <2 x float> %y, <2 x float> %z) {
548; CHECK-LABEL: @fsub_fmul_fneg1_extra_use2(
549; CHECK-NEXT:    [[NEG:%.*]] = fneg <2 x float> [[X:%.*]]
550; CHECK-NEXT:    call void @use_vec(<2 x float> [[NEG]])
551; CHECK-NEXT:    [[TMP1:%.*]] = fmul <2 x float> [[X]], [[Y:%.*]]
552; CHECK-NEXT:    [[R:%.*]] = fadd <2 x float> [[TMP1]], [[Z:%.*]]
553; CHECK-NEXT:    ret <2 x float> [[R]]
554;
555  %neg = fsub <2 x float> <float -0.0, float -0.0>, %x
556  call void @use_vec(<2 x float> %neg)
557  %mul = fmul <2 x float> %neg, %y
558  %r = fsub <2 x float> %z, %mul
559  ret <2 x float> %r
560}
561
562define float @fsub_fmul_fneg2_extra_use2(float %x, float %y, float %z) {
563; CHECK-LABEL: @fsub_fmul_fneg2_extra_use2(
564; CHECK-NEXT:    [[NEG:%.*]] = fneg float [[X:%.*]]
565; CHECK-NEXT:    call void @use(float [[NEG]])
566; CHECK-NEXT:    [[TMP1:%.*]] = fmul float [[X]], [[Y:%.*]]
567; CHECK-NEXT:    [[R:%.*]] = fadd float [[TMP1]], [[Z:%.*]]
568; CHECK-NEXT:    ret float [[R]]
569;
570  %neg = fsub float -0.000000e+00, %x
571  call void @use(float %neg)
572  %mul = fmul float %y, %neg
573  %r = fsub float %z, %mul
574  ret float %r
575}
576
577define float @fsub_fdiv_fneg1_extra_use3(float %x, float %y, float %z) {
578; CHECK-LABEL: @fsub_fdiv_fneg1_extra_use3(
579; CHECK-NEXT:    [[NEG:%.*]] = fneg float [[X:%.*]]
580; CHECK-NEXT:    call void @use(float [[NEG]])
581; CHECK-NEXT:    [[DIV:%.*]] = fdiv float [[NEG]], [[Y:%.*]]
582; CHECK-NEXT:    call void @use(float [[DIV]])
583; CHECK-NEXT:    [[R:%.*]] = fsub float [[Z:%.*]], [[DIV]]
584; CHECK-NEXT:    ret float [[R]]
585;
586  %neg = fsub float -0.000000e+00, %x
587  call void @use(float %neg)
588  %div = fdiv float %neg, %y
589  call void @use(float %div)
590  %r = fsub float %z, %div
591  ret float %r
592}
593
594define float @fsub_fdiv_fneg2_extra_use3(float %x, float %y, float %z) {
595; CHECK-LABEL: @fsub_fdiv_fneg2_extra_use3(
596; CHECK-NEXT:    [[NEG:%.*]] = fneg float [[X:%.*]]
597; CHECK-NEXT:    call void @use(float [[NEG]])
598; CHECK-NEXT:    [[DIV:%.*]] = fdiv float [[Y:%.*]], [[NEG]]
599; CHECK-NEXT:    call void @use(float [[DIV]])
600; CHECK-NEXT:    [[R:%.*]] = fsub float [[Z:%.*]], [[DIV]]
601; CHECK-NEXT:    ret float [[R]]
602;
603  %neg = fsub float -0.000000e+00, %x
604  call void @use(float %neg)
605  %div = fdiv float %y, %neg
606  call void @use(float %div)
607  %r = fsub float %z, %div
608  ret float %r
609}
610
611define <2 x float> @fsub_fmul_fneg1_extra_use3(<2 x float> %x, <2 x float> %y, <2 x float> %z) {
612; CHECK-LABEL: @fsub_fmul_fneg1_extra_use3(
613; CHECK-NEXT:    [[NEG:%.*]] = fneg <2 x float> [[X:%.*]]
614; CHECK-NEXT:    call void @use_vec(<2 x float> [[NEG]])
615; CHECK-NEXT:    [[MUL:%.*]] = fmul <2 x float> [[NEG]], [[Y:%.*]]
616; CHECK-NEXT:    call void @use_vec(<2 x float> [[MUL]])
617; CHECK-NEXT:    [[R:%.*]] = fsub <2 x float> [[Z:%.*]], [[MUL]]
618; CHECK-NEXT:    ret <2 x float> [[R]]
619;
620  %neg = fsub <2 x float> <float -0.0, float -0.0>, %x
621  call void @use_vec(<2 x float> %neg)
622  %mul = fmul <2 x float> %neg, %y
623  call void @use_vec(<2 x float> %mul)
624  %r = fsub <2 x float> %z, %mul
625  ret <2 x float> %r
626}
627
628define float @fsub_fmul_fneg2_extra_use3(float %x, float %y, float %z) {
629; CHECK-LABEL: @fsub_fmul_fneg2_extra_use3(
630; CHECK-NEXT:    [[NEG:%.*]] = fneg float [[X:%.*]]
631; CHECK-NEXT:    call void @use(float [[NEG]])
632; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[NEG]], [[Y:%.*]]
633; CHECK-NEXT:    call void @use(float [[MUL]])
634; CHECK-NEXT:    [[R:%.*]] = fsub float [[Z:%.*]], [[MUL]]
635; CHECK-NEXT:    ret float [[R]]
636;
637  %neg = fsub float -0.000000e+00, %x
638  call void @use(float %neg)
639  %mul = fmul float %y, %neg
640  call void @use(float %mul)
641  %r = fsub float %z, %mul
642  ret float %r
643}
644
645; Negative test - can't reassociate without FMF.
646
647define float @fsub_fsub(float %x, float %y, float %z) {
648; CHECK-LABEL: @fsub_fsub(
649; CHECK-NEXT:    [[XY:%.*]] = fsub float [[X:%.*]], [[Y:%.*]]
650; CHECK-NEXT:    [[XYZ:%.*]] = fsub float [[XY]], [[Z:%.*]]
651; CHECK-NEXT:    ret float [[XYZ]]
652;
653  %xy = fsub float %x, %y
654  %xyz = fsub float %xy, %z
655  ret float %xyz
656}
657
658; Negative test - can't reassociate without enough FMF.
659
660define float @fsub_fsub_nsz(float %x, float %y, float %z) {
661; CHECK-LABEL: @fsub_fsub_nsz(
662; CHECK-NEXT:    [[XY:%.*]] = fsub float [[X:%.*]], [[Y:%.*]]
663; CHECK-NEXT:    [[XYZ:%.*]] = fsub nsz float [[XY]], [[Z:%.*]]
664; CHECK-NEXT:    ret float [[XYZ]]
665;
666  %xy = fsub float %x, %y
667  %xyz = fsub nsz float %xy, %z
668  ret float %xyz
669}
670
671; Negative test - can't reassociate without enough FMF.
672
673define float @fsub_fsub_reassoc(float %x, float %y, float %z) {
674; CHECK-LABEL: @fsub_fsub_reassoc(
675; CHECK-NEXT:    [[XY:%.*]] = fsub float [[X:%.*]], [[Y:%.*]]
676; CHECK-NEXT:    [[XYZ:%.*]] = fsub reassoc float [[XY]], [[Z:%.*]]
677; CHECK-NEXT:    ret float [[XYZ]]
678;
679  %xy = fsub float %x, %y
680  %xyz = fsub reassoc float %xy, %z
681  ret float %xyz
682}
683
684define float @fsub_fsub_nsz_reassoc(float %x, float %y, float %z) {
685; CHECK-LABEL: @fsub_fsub_nsz_reassoc(
686; CHECK-NEXT:    [[TMP1:%.*]] = fadd reassoc nsz float [[Y:%.*]], [[Z:%.*]]
687; CHECK-NEXT:    [[XYZ:%.*]] = fsub reassoc nsz float [[X:%.*]], [[TMP1]]
688; CHECK-NEXT:    ret float [[XYZ]]
689;
690  %xy = fsub float %x, %y
691  %xyz = fsub nsz reassoc float %xy, %z
692  ret float %xyz
693}
694
695define <2 x double> @fsub_fsub_fast_vec(<2 x double> %x, <2 x double> %y, <2 x double> %z) {
696; CHECK-LABEL: @fsub_fsub_fast_vec(
697; CHECK-NEXT:    [[TMP1:%.*]] = fadd fast <2 x double> [[Y:%.*]], [[Z:%.*]]
698; CHECK-NEXT:    [[XYZ:%.*]] = fsub fast <2 x double> [[X:%.*]], [[TMP1]]
699; CHECK-NEXT:    ret <2 x double> [[XYZ]]
700;
701  %xy = fsub fast <2 x double> %x, %y
702  %xyz = fsub fast reassoc <2 x double> %xy, %z
703  ret <2 x double> %xyz
704}
705
706; Negative test - don't reassociate and increase instructions.
707
708define float @fsub_fsub_nsz_reassoc_extra_use(float %x, float %y, float %z) {
709; CHECK-LABEL: @fsub_fsub_nsz_reassoc_extra_use(
710; CHECK-NEXT:    [[XY:%.*]] = fsub float [[X:%.*]], [[Y:%.*]]
711; CHECK-NEXT:    call void @use(float [[XY]])
712; CHECK-NEXT:    [[XYZ:%.*]] = fsub reassoc nsz float [[XY]], [[Z:%.*]]
713; CHECK-NEXT:    ret float [[XYZ]]
714;
715  %xy = fsub float %x, %y
716  call void @use(float %xy)
717  %xyz = fsub nsz reassoc float %xy, %z
718  ret float %xyz
719}
720
721define float @fneg_fsub(float %x, float %y) {
722; CHECK-LABEL: @fneg_fsub(
723; CHECK-NEXT:    [[NEGX:%.*]] = fneg float [[X:%.*]]
724; CHECK-NEXT:    [[SUB:%.*]] = fsub float [[NEGX]], [[Y:%.*]]
725; CHECK-NEXT:    ret float [[SUB]]
726;
727  %negx = fneg float %x
728  %sub = fsub float %negx, %y
729  ret float %sub
730}
731
732define float @fneg_fsub_nsz(float %x, float %y) {
733; CHECK-LABEL: @fneg_fsub_nsz(
734; CHECK-NEXT:    [[TMP1:%.*]] = fadd nsz float [[X:%.*]], [[Y:%.*]]
735; CHECK-NEXT:    [[SUB:%.*]] = fneg nsz float [[TMP1]]
736; CHECK-NEXT:    ret float [[SUB]]
737;
738  %negx = fneg float %x
739  %sub = fsub nsz float %negx, %y
740  ret float %sub
741}
742
743define float @fake_fneg_fsub_fast(float %x, float %y) {
744; CHECK-LABEL: @fake_fneg_fsub_fast(
745; CHECK-NEXT:    [[TMP1:%.*]] = fadd fast float [[X:%.*]], [[Y:%.*]]
746; CHECK-NEXT:    [[SUB:%.*]] = fneg fast float [[TMP1]]
747; CHECK-NEXT:    ret float [[SUB]]
748;
749  %negx = fsub float -0.0, %x
750  %sub = fsub fast float %negx, %y
751  ret float %sub
752}
753
754define float @fake_fneg_fsub_fast_extra_use(float %x, float %y) {
755; CHECK-LABEL: @fake_fneg_fsub_fast_extra_use(
756; CHECK-NEXT:    [[NEGX:%.*]] = fneg float [[X:%.*]]
757; CHECK-NEXT:    call void @use(float [[NEGX]])
758; CHECK-NEXT:    [[SUB:%.*]] = fsub fast float [[NEGX]], [[Y:%.*]]
759; CHECK-NEXT:    ret float [[SUB]]
760;
761  %negx = fsub float -0.0, %x
762  call void @use(float %negx)
763  %sub = fsub fast float %negx, %y
764  ret float %sub
765}
766
767define <2 x float> @fake_fneg_fsub_vec(<2 x float> %x, <2 x float> %y) {
768; CHECK-LABEL: @fake_fneg_fsub_vec(
769; CHECK-NEXT:    [[TMP1:%.*]] = fadd nsz <2 x float> [[X:%.*]], [[Y:%.*]]
770; CHECK-NEXT:    [[SUB:%.*]] = fneg nsz <2 x float> [[TMP1]]
771; CHECK-NEXT:    ret <2 x float> [[SUB]]
772;
773  %negx = fsub <2 x float> <float -0.0, float -0.0>, %x
774  %sub = fsub nsz <2 x float> %negx, %y
775  ret <2 x float> %sub
776}
777
778define float @fneg_fsub_constant(float %x) {
779; CHECK-LABEL: @fneg_fsub_constant(
780; CHECK-NEXT:    [[SUB:%.*]] = fsub nsz float -4.200000e+01, [[X:%.*]]
781; CHECK-NEXT:    ret float [[SUB]]
782;
783  %negx = fneg float %x
784  %sub = fsub nsz float %negx, 42.0
785  ret float %sub
786}
787
788; ((w-x) + y) - z --> (w+y) - (x+z)
789
790define float @fsub_fadd_fsub_reassoc(float %w, float %x, float %y, float %z) {
791; CHECK-LABEL: @fsub_fadd_fsub_reassoc(
792; CHECK-NEXT:    [[TMP1:%.*]] = fadd reassoc nsz float [[W:%.*]], [[Y:%.*]]
793; CHECK-NEXT:    [[TMP2:%.*]] = fadd reassoc nsz float [[X:%.*]], [[Z:%.*]]
794; CHECK-NEXT:    [[S2:%.*]] = fsub reassoc nsz float [[TMP1]], [[TMP2]]
795; CHECK-NEXT:    ret float [[S2]]
796;
797  %s1 = fsub reassoc nsz float %w, %x
798  %a = fadd reassoc nsz float %s1, %y
799  %s2 = fsub reassoc nsz float %a, %z
800  ret float %s2
801}
802
803; FMF on the last op is enough to do the transform; vectors work too.
804
805define <2 x float> @fsub_fadd_fsub_reassoc_commute(<2 x float> %w, <2 x float> %x, <2 x float> %y, <2 x float> %z) {
806; CHECK-LABEL: @fsub_fadd_fsub_reassoc_commute(
807; CHECK-NEXT:    [[D:%.*]] = fdiv <2 x float> [[Y:%.*]], <float 4.200000e+01, float -4.200000e+01>
808; CHECK-NEXT:    [[TMP1:%.*]] = fadd fast <2 x float> [[D]], [[W:%.*]]
809; CHECK-NEXT:    [[TMP2:%.*]] = fadd fast <2 x float> [[X:%.*]], [[Z:%.*]]
810; CHECK-NEXT:    [[S2:%.*]] = fsub fast <2 x float> [[TMP1]], [[TMP2]]
811; CHECK-NEXT:    ret <2 x float> [[S2]]
812;
813  %d = fdiv <2 x float> %y, <float 42.0, float -42.0> ; thwart complexity-based canonicalization
814  %s1 = fsub <2 x float> %w, %x
815  %a = fadd <2 x float> %d, %s1
816  %s2 = fsub fast <2 x float> %a, %z
817  ret <2 x float> %s2
818}
819
820; (v-w) + (x-y) - z --> (v+x) - (w+y+z)
821
822define float @fsub_fadd_fsub_reassoc_twice(float %v, float %w, float %x, float %y, float %z) {
823; CHECK-LABEL: @fsub_fadd_fsub_reassoc_twice(
824; CHECK-NEXT:    [[TMP1:%.*]] = fadd reassoc nsz float [[W:%.*]], [[Z:%.*]]
825; CHECK-NEXT:    [[TMP2:%.*]] = fadd reassoc nsz float [[X:%.*]], [[V:%.*]]
826; CHECK-NEXT:    [[TMP3:%.*]] = fadd reassoc nsz float [[TMP1]], [[Y:%.*]]
827; CHECK-NEXT:    [[S3:%.*]] = fsub reassoc nsz float [[TMP2]], [[TMP3]]
828; CHECK-NEXT:    ret float [[S3]]
829;
830  %s1 = fsub reassoc nsz float %v, %w
831  %s2 = fsub reassoc nsz float %x, %y
832  %a = fadd reassoc nsz float %s1, %s2
833  %s3 = fsub reassoc nsz float %a, %z
834  ret float %s3
835}
836
837; negative test - FMF
838
839define float @fsub_fadd_fsub_not_reassoc(float %w, float %x, float %y, float %z) {
840; CHECK-LABEL: @fsub_fadd_fsub_not_reassoc(
841; CHECK-NEXT:    [[S1:%.*]] = fsub fast float [[W:%.*]], [[X:%.*]]
842; CHECK-NEXT:    [[A:%.*]] = fadd fast float [[S1]], [[Y:%.*]]
843; CHECK-NEXT:    [[S2:%.*]] = fsub nsz float [[A]], [[Z:%.*]]
844; CHECK-NEXT:    ret float [[S2]]
845;
846  %s1 = fsub fast float %w, %x
847  %a = fadd fast float %s1, %y
848  %s2 = fsub nsz float %a, %z
849  ret float %s2
850}
851
852; negative test - uses
853
854define float @fsub_fadd_fsub_reassoc_use1(float %w, float %x, float %y, float %z) {
855; CHECK-LABEL: @fsub_fadd_fsub_reassoc_use1(
856; CHECK-NEXT:    [[S1:%.*]] = fsub fast float [[W:%.*]], [[X:%.*]]
857; CHECK-NEXT:    call void @use(float [[S1]])
858; CHECK-NEXT:    [[A:%.*]] = fadd fast float [[S1]], [[Y:%.*]]
859; CHECK-NEXT:    [[S2:%.*]] = fsub fast float [[A]], [[Z:%.*]]
860; CHECK-NEXT:    ret float [[S2]]
861;
862  %s1 = fsub fast float %w, %x
863  call void @use(float %s1)
864  %a = fadd fast float %s1, %y
865  %s2 = fsub fast float %a, %z
866  ret float %s2
867}
868
869; negative test - uses
870
871define float @fsub_fadd_fsub_reassoc_use2(float %w, float %x, float %y, float %z) {
872; CHECK-LABEL: @fsub_fadd_fsub_reassoc_use2(
873; CHECK-NEXT:    [[S1:%.*]] = fsub fast float [[W:%.*]], [[X:%.*]]
874; CHECK-NEXT:    [[A:%.*]] = fadd fast float [[S1]], [[Y:%.*]]
875; CHECK-NEXT:    call void @use(float [[A]])
876; CHECK-NEXT:    [[S2:%.*]] = fsub fast float [[A]], [[Z:%.*]]
877; CHECK-NEXT:    ret float [[S2]]
878;
879  %s1 = fsub fast float %w, %x
880  %a = fadd fast float %s1, %y
881  call void @use(float %a)
882  %s2 = fsub fast float %a, %z
883  ret float %s2
884}
885