• 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
4declare void @use(float)
5
6define float @fneg_fneg(float %a) {
7;
8; CHECK-LABEL: @fneg_fneg(
9; CHECK-NEXT:    ret float [[A:%.*]]
10;
11  %f = fneg float %a
12  %r = fneg float %f
13  ret float %r
14}
15
16; -(X * C) --> X * (-C)
17
18define float @fmul_fsub(float %x) {
19; CHECK-LABEL: @fmul_fsub(
20; CHECK-NEXT:    [[R:%.*]] = fmul float [[X:%.*]], -4.200000e+01
21; CHECK-NEXT:    ret float [[R]]
22;
23  %m = fmul float %x, 42.0
24  %r = fsub float -0.0, %m
25  ret float %r
26}
27
28define float @fmul_fneg(float %x) {
29; CHECK-LABEL: @fmul_fneg(
30; CHECK-NEXT:    [[R:%.*]] = fmul float [[X:%.*]], -4.200000e+01
31; CHECK-NEXT:    ret float [[R]]
32;
33  %m = fmul float %x, 42.0
34  %r = fneg float %m
35  ret float %r
36}
37
38; Fast math is not required, but it should be propagated.
39
40define float @fmul_fsub_fmf(float %x) {
41; CHECK-LABEL: @fmul_fsub_fmf(
42; CHECK-NEXT:    [[R:%.*]] = fmul reassoc nsz float [[X:%.*]], -4.200000e+01
43; CHECK-NEXT:    ret float [[R]]
44;
45  %m = fmul float %x, 42.0
46  %r = fsub reassoc nsz float -0.0, %m
47  ret float %r
48}
49
50define float @fmul_fneg_fmf(float %x) {
51; CHECK-LABEL: @fmul_fneg_fmf(
52; CHECK-NEXT:    [[R:%.*]] = fmul reassoc nsz float [[X:%.*]], -4.200000e+01
53; CHECK-NEXT:    ret float [[R]]
54;
55  %m = fmul float %x, 42.0
56  %r = fneg reassoc nsz float %m
57  ret float %r
58}
59
60; Extra use prevents the fold. We don't want to replace the fneg with an fmul.
61
62define float @fmul_fsub_extra_use(float %x) {
63; CHECK-LABEL: @fmul_fsub_extra_use(
64; CHECK-NEXT:    [[M:%.*]] = fmul float [[X:%.*]], 4.200000e+01
65; CHECK-NEXT:    [[R:%.*]] = fneg float [[M]]
66; CHECK-NEXT:    call void @use(float [[M]])
67; CHECK-NEXT:    ret float [[R]]
68;
69  %m = fmul float %x, 42.0
70  %r = fsub float -0.0, %m
71  call void @use(float %m)
72  ret float %r
73}
74
75define float @fmul_fneg_extra_use(float %x) {
76; CHECK-LABEL: @fmul_fneg_extra_use(
77; CHECK-NEXT:    [[M:%.*]] = fmul float [[X:%.*]], 4.200000e+01
78; CHECK-NEXT:    [[R:%.*]] = fneg float [[M]]
79; CHECK-NEXT:    call void @use(float [[M]])
80; CHECK-NEXT:    ret float [[R]]
81;
82  %m = fmul float %x, 42.0
83  %r = fneg float %m
84  call void @use(float %m)
85  ret float %r
86}
87
88; Try a vector. Use special constants (NaN, INF, undef) because they don't change anything.
89
90define <4 x double> @fmul_fsub_vec(<4 x double> %x) {
91; CHECK-LABEL: @fmul_fsub_vec(
92; CHECK-NEXT:    [[R:%.*]] = fmul <4 x double> [[X:%.*]], <double -4.200000e+01, double 0xFFF8000000000000, double 0xFFF0000000000000, double undef>
93; CHECK-NEXT:    ret <4 x double> [[R]]
94;
95  %m = fmul <4 x double> %x, <double 42.0, double 0x7FF8000000000000, double 0x7FF0000000000000, double undef>
96  %r = fsub <4 x double> <double -0.0, double -0.0, double -0.0, double -0.0>, %m
97  ret <4 x double> %r
98}
99
100define <4 x double> @fmul_fneg_vec(<4 x double> %x) {
101; CHECK-LABEL: @fmul_fneg_vec(
102; CHECK-NEXT:    [[R:%.*]] = fmul <4 x double> [[X:%.*]], <double -4.200000e+01, double 0xFFF8000000000000, double 0xFFF0000000000000, double undef>
103; CHECK-NEXT:    ret <4 x double> [[R]]
104;
105  %m = fmul <4 x double> %x, <double 42.0, double 0x7FF8000000000000, double 0x7FF0000000000000, double undef>
106  %r = fneg <4 x double> %m
107  ret <4 x double> %r
108}
109
110; -(X / C) --> X / (-C)
111
112define float @fdiv_op1_constant_fsub(float %x) {
113; CHECK-LABEL: @fdiv_op1_constant_fsub(
114; CHECK-NEXT:    [[R:%.*]] = fdiv float [[X:%.*]], 4.200000e+01
115; CHECK-NEXT:    ret float [[R]]
116;
117  %d = fdiv float %x, -42.0
118  %r = fsub float -0.0, %d
119  ret float %r
120}
121
122define float @fdiv_op1_constant_fneg(float %x) {
123; CHECK-LABEL: @fdiv_op1_constant_fneg(
124; CHECK-NEXT:    [[R:%.*]] = fdiv float [[X:%.*]], 4.200000e+01
125; CHECK-NEXT:    ret float [[R]]
126;
127  %d = fdiv float %x, -42.0
128  %r = fneg float %d
129  ret float %r
130}
131
132; Fast math is not required, but it should be propagated.
133
134define float @fdiv_op1_constant_fsub_fmf(float %x) {
135; CHECK-LABEL: @fdiv_op1_constant_fsub_fmf(
136; CHECK-NEXT:    [[R:%.*]] = fdiv nnan float [[X:%.*]], 4.200000e+01
137; CHECK-NEXT:    ret float [[R]]
138;
139  %d = fdiv float %x, -42.0
140  %r = fsub nnan float -0.0, %d
141  ret float %r
142}
143
144define float @fdiv_op1_constant_fneg_fmf(float %x) {
145; CHECK-LABEL: @fdiv_op1_constant_fneg_fmf(
146; CHECK-NEXT:    [[R:%.*]] = fdiv nnan float [[X:%.*]], 4.200000e+01
147; CHECK-NEXT:    ret float [[R]]
148;
149  %d = fdiv float %x, -42.0
150  %r = fneg nnan float %d
151  ret float %r
152}
153
154; Extra use prevents the fold. We don't want to replace the fneg with an fdiv.
155
156define float @fdiv_op1_constant_fsub_extra_use(float %x) {
157; CHECK-LABEL: @fdiv_op1_constant_fsub_extra_use(
158; CHECK-NEXT:    [[D:%.*]] = fdiv float [[X:%.*]], 4.200000e+01
159; CHECK-NEXT:    [[R:%.*]] = fneg float [[D]]
160; CHECK-NEXT:    call void @use(float [[D]])
161; CHECK-NEXT:    ret float [[R]]
162;
163  %d = fdiv float %x, 42.0
164  %r = fsub float -0.0, %d
165  call void @use(float %d)
166  ret float %r
167}
168
169define float @fdiv_op1_constant_fneg_extra_use(float %x) {
170; CHECK-LABEL: @fdiv_op1_constant_fneg_extra_use(
171; CHECK-NEXT:    [[D:%.*]] = fdiv float [[X:%.*]], 4.200000e+01
172; CHECK-NEXT:    [[R:%.*]] = fneg float [[D]]
173; CHECK-NEXT:    call void @use(float [[D]])
174; CHECK-NEXT:    ret float [[R]]
175;
176  %d = fdiv float %x, 42.0
177  %r = fneg float %d
178  call void @use(float %d)
179  ret float %r
180}
181
182; Try a vector. Use special constants (NaN, INF, undef) because they don't change anything.
183
184define <4 x double> @fdiv_op1_constant_fsub_vec(<4 x double> %x) {
185; CHECK-LABEL: @fdiv_op1_constant_fsub_vec(
186; CHECK-NEXT:    [[R:%.*]] = fdiv <4 x double> [[X:%.*]], <double 4.200000e+01, double 0x7FF800000ABCD000, double 0x7FF0000000000000, double undef>
187; CHECK-NEXT:    ret <4 x double> [[R]]
188;
189  %d = fdiv <4 x double> %x, <double -42.0, double 0xFFF800000ABCD000, double 0xFFF0000000000000, double undef>
190  %r = fsub <4 x double> <double -0.0, double -0.0, double -0.0, double -0.0>, %d
191  ret <4 x double> %r
192}
193
194define <4 x double> @fdiv_op1_constant_fneg_vec(<4 x double> %x) {
195; CHECK-LABEL: @fdiv_op1_constant_fneg_vec(
196; CHECK-NEXT:    [[R:%.*]] = fdiv <4 x double> [[X:%.*]], <double 4.200000e+01, double 0x7FF800000ABCD000, double 0x7FF0000000000000, double undef>
197; CHECK-NEXT:    ret <4 x double> [[R]]
198;
199  %d = fdiv <4 x double> %x, <double -42.0, double 0xFFF800000ABCD000, double 0xFFF0000000000000, double undef>
200  %r = fneg <4 x double> %d
201  ret <4 x double> %r
202}
203
204; -(C / X) --> (-C) / X
205
206define float @fdiv_op0_constant_fsub(float %x) {
207; CHECK-LABEL: @fdiv_op0_constant_fsub(
208; CHECK-NEXT:    [[R:%.*]] = fdiv float -4.200000e+01, [[X:%.*]]
209; CHECK-NEXT:    ret float [[R]]
210;
211  %d = fdiv float 42.0, %x
212  %r = fsub float -0.0, %d
213  ret float %r
214}
215
216define float @fdiv_op0_constant_fneg(float %x) {
217; CHECK-LABEL: @fdiv_op0_constant_fneg(
218; CHECK-NEXT:    [[R:%.*]] = fdiv float -4.200000e+01, [[X:%.*]]
219; CHECK-NEXT:    ret float [[R]]
220;
221  %d = fdiv float 42.0, %x
222  %r = fneg float %d
223  ret float %r
224}
225
226; Fast math is not required, but it should be propagated.
227
228define float @fdiv_op0_constant_fsub_fmf(float %x) {
229; CHECK-LABEL: @fdiv_op0_constant_fsub_fmf(
230; CHECK-NEXT:    [[R:%.*]] = fdiv fast float -4.200000e+01, [[X:%.*]]
231; CHECK-NEXT:    ret float [[R]]
232;
233  %d = fdiv float 42.0, %x
234  %r = fsub fast float -0.0, %d
235  ret float %r
236}
237
238define float @fdiv_op0_constant_fneg_fmf(float %x) {
239; CHECK-LABEL: @fdiv_op0_constant_fneg_fmf(
240; CHECK-NEXT:    [[R:%.*]] = fdiv fast float -4.200000e+01, [[X:%.*]]
241; CHECK-NEXT:    ret float [[R]]
242;
243  %d = fdiv float 42.0, %x
244  %r = fneg fast float %d
245  ret float %r
246}
247
248; Extra use prevents the fold. We don't want to replace the fneg with an fdiv.
249
250define float @fdiv_op0_constant_fsub_extra_use(float %x) {
251; CHECK-LABEL: @fdiv_op0_constant_fsub_extra_use(
252; CHECK-NEXT:    [[D:%.*]] = fdiv float -4.200000e+01, [[X:%.*]]
253; CHECK-NEXT:    [[R:%.*]] = fneg float [[D]]
254; CHECK-NEXT:    call void @use(float [[D]])
255; CHECK-NEXT:    ret float [[R]]
256;
257  %d = fdiv float -42.0, %x
258  %r = fsub float -0.0, %d
259  call void @use(float %d)
260  ret float %r
261}
262
263define float @fdiv_op0_constant_fneg_extra_use(float %x) {
264; CHECK-LABEL: @fdiv_op0_constant_fneg_extra_use(
265; CHECK-NEXT:    [[D:%.*]] = fdiv float -4.200000e+01, [[X:%.*]]
266; CHECK-NEXT:    [[R:%.*]] = fneg float [[D]]
267; CHECK-NEXT:    call void @use(float [[D]])
268; CHECK-NEXT:    ret float [[R]]
269;
270  %d = fdiv float -42.0, %x
271  %r = fneg float %d
272  call void @use(float %d)
273  ret float %r
274}
275
276; Try a vector. Use special constants (NaN, INF, undef) because they don't change anything.
277
278define <4 x double> @fdiv_op0_constant_fsub_vec(<4 x double> %x) {
279; CHECK-LABEL: @fdiv_op0_constant_fsub_vec(
280; CHECK-NEXT:    [[R:%.*]] = fdiv <4 x double> <double 4.200000e+01, double 0xFFF8000000000000, double 0x7FF0000000000000, double undef>, [[X:%.*]]
281; CHECK-NEXT:    ret <4 x double> [[R]]
282;
283  %d = fdiv <4 x double> <double -42.0, double 0x7FF8000000000000, double 0xFFF0000000000000, double undef>, %x
284  %r = fsub <4 x double> <double -0.0, double -0.0, double -0.0, double -0.0>, %d
285  ret <4 x double> %r
286}
287
288define <4 x double> @fdiv_op0_constant_fneg_vec(<4 x double> %x) {
289; CHECK-LABEL: @fdiv_op0_constant_fneg_vec(
290; CHECK-NEXT:    [[R:%.*]] = fdiv <4 x double> <double 4.200000e+01, double 0xFFF8000000000000, double 0x7FF0000000000000, double undef>, [[X:%.*]]
291; CHECK-NEXT:    ret <4 x double> [[R]]
292;
293  %d = fdiv <4 x double> <double -42.0, double 0x7FF8000000000000, double 0xFFF0000000000000, double undef>, %x
294  %r = fneg <4 x double> %d
295  ret <4 x double> %r
296}
297
298; Sink FP negation through a select:
299; c ? -x : -y --> -(c ? x : y)
300
301define <2 x double> @fneg_fneg_sel(<2 x double> %x, <2 x double> %y, i1 %cond) {
302; CHECK-LABEL: @fneg_fneg_sel(
303; CHECK-NEXT:    [[SEL_V:%.*]] = select i1 [[COND:%.*]], <2 x double> [[X:%.*]], <2 x double> [[Y:%.*]]
304; CHECK-NEXT:    [[SEL:%.*]] = fneg <2 x double> [[SEL_V]]
305; CHECK-NEXT:    ret <2 x double> [[SEL]]
306;
307  %n1 = fneg <2 x double> %x
308  %n2 = fneg <2 x double> %y
309  %sel = select i1 %cond, <2 x double> %n1, <2 x double> %n2
310  ret <2 x double> %sel
311}
312
313; An extra use is allowed.
314
315define float @fneg_fneg_sel_extra_use1(float %x, float %y, i1 %cond) {
316; CHECK-LABEL: @fneg_fneg_sel_extra_use1(
317; CHECK-NEXT:    [[N1:%.*]] = fneg float [[X:%.*]]
318; CHECK-NEXT:    call void @use(float [[N1]])
319; CHECK-NEXT:    [[SEL_V:%.*]] = select i1 [[COND:%.*]], float [[X]], float [[Y:%.*]]
320; CHECK-NEXT:    [[SEL:%.*]] = fneg float [[SEL_V]]
321; CHECK-NEXT:    ret float [[SEL]]
322;
323  %n1 = fneg float %x
324  call void @use(float %n1)
325  %n2 = fneg float %y
326  %sel = select i1 %cond, float %n1, float %n2
327  ret float %sel
328}
329
330define float @fneg_fneg_sel_extra_use2(float %x, float %y, i1 %cond) {
331; CHECK-LABEL: @fneg_fneg_sel_extra_use2(
332; CHECK-NEXT:    [[N2:%.*]] = fneg float [[Y:%.*]]
333; CHECK-NEXT:    call void @use(float [[N2]])
334; CHECK-NEXT:    [[SEL_V:%.*]] = select i1 [[COND:%.*]], float [[X:%.*]], float [[Y]]
335; CHECK-NEXT:    [[SEL:%.*]] = fneg float [[SEL_V]]
336; CHECK-NEXT:    ret float [[SEL]]
337;
338  %n1 = fneg float %x
339  %n2 = fneg float %y
340  call void @use(float %n2)
341  %sel = select i1 %cond, float %n1, float %n2
342  ret float %sel
343}
344
345; Legacy form of fneg should work too.
346
347define float @fsub_fsub_sel_extra_use1(float %x, float %y, i1 %cond) {
348; CHECK-LABEL: @fsub_fsub_sel_extra_use1(
349; CHECK-NEXT:    [[N1:%.*]] = fneg float [[X:%.*]]
350; CHECK-NEXT:    call void @use(float [[N1]])
351; CHECK-NEXT:    [[SEL_V:%.*]] = select i1 [[COND:%.*]], float [[X]], float [[Y:%.*]]
352; CHECK-NEXT:    [[SEL:%.*]] = fneg float [[SEL_V]]
353; CHECK-NEXT:    ret float [[SEL]]
354;
355  %n1 = fsub float -0.0, %x
356  call void @use(float %n1)
357  %n2 = fsub float -0.0, %y
358  %sel = select i1 %cond, float %n1, float %n2
359  ret float %sel
360}
361
362; Negative test: but 2 extra uses would require an extra instruction.
363
364define float @fneg_fneg_sel_extra_use3(float %x, float %y, i1 %cond) {
365; CHECK-LABEL: @fneg_fneg_sel_extra_use3(
366; CHECK-NEXT:    [[N1:%.*]] = fneg float [[X:%.*]]
367; CHECK-NEXT:    call void @use(float [[N1]])
368; CHECK-NEXT:    [[N2:%.*]] = fneg float [[Y:%.*]]
369; CHECK-NEXT:    call void @use(float [[N2]])
370; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND:%.*]], float [[N1]], float [[N2]]
371; CHECK-NEXT:    ret float [[SEL]]
372;
373  %n1 = fneg float %x
374  call void @use(float %n1)
375  %n2 = fneg float %y
376  call void @use(float %n2)
377  %sel = select i1 %cond, float %n1, float %n2
378  ret float %sel
379}
380
381; Negative test
382
383define float @fneg_fadd_constant(float %x) {
384; CHECK-LABEL: @fneg_fadd_constant(
385; CHECK-NEXT:    [[A:%.*]] = fadd float [[X:%.*]], 4.200000e+01
386; CHECK-NEXT:    [[R:%.*]] = fneg float [[A]]
387; CHECK-NEXT:    ret float [[R]]
388;
389  %a = fadd float %x, 42.0
390  %r = fneg float %a
391  ret float %r
392}
393
394; Negative test
395
396define float @fake_nsz_fadd_constant(float %x) {
397; CHECK-LABEL: @fake_nsz_fadd_constant(
398; CHECK-NEXT:    [[A:%.*]] = fadd float [[X:%.*]], 4.200000e+01
399; CHECK-NEXT:    [[R:%.*]] = fneg float [[A]]
400; CHECK-NEXT:    ret float [[R]]
401;
402  %a = fadd float %x, 42.0
403  %r = fsub float -0.0, %a
404  ret float %r
405}
406
407; -(X + C) --> -C - X
408
409define float @fneg_nsz_fadd_constant(float %x) {
410; CHECK-LABEL: @fneg_nsz_fadd_constant(
411; CHECK-NEXT:    [[R:%.*]] = fsub nsz float -4.200000e+01, [[X:%.*]]
412; CHECK-NEXT:    ret float [[R]]
413;
414  %a = fadd float %x, 42.0
415  %r = fneg nsz float %a
416  ret float %r
417}
418
419; -(X + C) --> -C - X
420
421define float @fake_fneg_nsz_fadd_constant(float %x) {
422; CHECK-LABEL: @fake_fneg_nsz_fadd_constant(
423; CHECK-NEXT:    [[R:%.*]] = fsub fast float -4.200000e+01, [[X:%.*]]
424; CHECK-NEXT:    ret float [[R]]
425;
426  %a = fadd float %x, 42.0
427  %r = fsub fast float -0.0, %a
428  ret float %r
429}
430
431; Negative test
432
433define float @fneg_nsz_fadd_constant_extra_use(float %x) {
434; CHECK-LABEL: @fneg_nsz_fadd_constant_extra_use(
435; CHECK-NEXT:    [[A:%.*]] = fadd float [[X:%.*]], 4.200000e+01
436; CHECK-NEXT:    call void @use(float [[A]])
437; CHECK-NEXT:    [[R:%.*]] = fneg nsz float [[A]]
438; CHECK-NEXT:    ret float [[R]]
439;
440  %a = fadd float %x, 42.0
441  call void @use(float %a)
442  %r = fneg nsz float %a
443  ret float %r
444}
445
446; Negative test
447
448define float @fake_fneg_nsz_fadd_constant_extra_use(float %x) {
449; CHECK-LABEL: @fake_fneg_nsz_fadd_constant_extra_use(
450; CHECK-NEXT:    [[A:%.*]] = fadd float [[X:%.*]], 4.200000e+01
451; CHECK-NEXT:    call void @use(float [[A]])
452; CHECK-NEXT:    [[R:%.*]] = fneg fast float [[A]]
453; CHECK-NEXT:    ret float [[R]]
454;
455  %a = fadd float %x, 42.0
456  call void @use(float %a)
457  %r = fsub fast float -0.0, %a
458  ret float %r
459}
460
461; -(X + C) --> -C - X
462
463define <2 x float> @fneg_nsz_fadd_constant_vec(<2 x float> %x) {
464; CHECK-LABEL: @fneg_nsz_fadd_constant_vec(
465; CHECK-NEXT:    [[R:%.*]] = fsub reassoc nnan nsz <2 x float> <float -4.200000e+01, float -4.300000e+01>, [[X:%.*]]
466; CHECK-NEXT:    ret <2 x float> [[R]]
467;
468  %a = fadd <2 x float> %x, <float 42.0, float 43.0>
469  %r = fneg nsz nnan reassoc <2 x float> %a
470  ret <2 x float> %r
471}
472
473; -(X + C) --> -C - X
474
475define <2 x float> @fake_fneg_nsz_fadd_constant_vec(<2 x float> %x) {
476; CHECK-LABEL: @fake_fneg_nsz_fadd_constant_vec(
477; CHECK-NEXT:    [[R:%.*]] = fsub nsz <2 x float> <float -4.200000e+01, float undef>, [[X:%.*]]
478; CHECK-NEXT:    ret <2 x float> [[R]]
479;
480  %a = fadd <2 x float> %x, <float 42.0, float undef>
481  %r = fsub nsz <2 x float> <float undef, float -0.0>, %a
482  ret <2 x float> %r
483}
484
485@g = external global i16, align 1
486
487define float @fneg_nsz_fadd_constant_expr(float %x) {
488; CHECK-LABEL: @fneg_nsz_fadd_constant_expr(
489; CHECK-NEXT:    [[R:%.*]] = fsub nsz float fneg (float bitcast (i32 ptrtoint (i16* @g to i32) to float)), [[X:%.*]]
490; CHECK-NEXT:    ret float [[R]]
491;
492  %a = fadd float %x, bitcast (i32 ptrtoint (i16* @g to i32) to float)
493  %r = fneg nsz float %a
494  ret float %r
495}
496
497define float @fake_fneg_nsz_fadd_constant_expr(float %x) {
498; CHECK-LABEL: @fake_fneg_nsz_fadd_constant_expr(
499; CHECK-NEXT:    [[R:%.*]] = fsub nsz float fneg (float bitcast (i32 ptrtoint (i16* @g to i32) to float)), [[X:%.*]]
500; CHECK-NEXT:    ret float [[R]]
501;
502  %a = fadd float %x, bitcast (i32 ptrtoint (i16* @g to i32) to float)
503  %r = fsub nsz float -0.0, %a
504  ret float %r
505}
506