1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -instcombine -S | FileCheck %s
6 define float @test1(float %x, float %y) {
8 ; CHECK-NEXT: [[T1:%.*]] = fsub float [[X:%.*]], [[Y:%.*]]
9 ; CHECK-NEXT: [[T2:%.*]] = fsub float -0.000000e+00, [[T1]]
10 ; CHECK-NEXT: ret float [[T2]]
12 %t1 = fsub float %x, %y
13 %t2 = fsub float -0.0, %t1
17 define 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]]
23 %t1 = fsub float %x, %y
28 ; Can't do anything with the test above because -0.0 - 0.0 = -0.0, but if we have nsz:
31 define float @neg_sub_nsz(float %x, float %y) {
32 ; CHECK-LABEL: @neg_sub_nsz(
33 ; CHECK-NEXT: [[TMP1:%.*]] = fsub nsz float [[Y:%.*]], [[X:%.*]]
34 ; CHECK-NEXT: ret float [[TMP1]]
36 %t1 = fsub float %x, %y
37 %t2 = fsub nsz float -0.0, %t1
41 ; FIXME: This combine isn't working.
42 define float @unary_neg_sub_nsz(float %x, float %y) {
43 ; CHECK-LABEL: @unary_neg_sub_nsz(
44 ; CHECK-NEXT: [[T1:%.*]] = fsub float [[X:%.*]], [[Y:%.*]]
45 ; CHECK-NEXT: [[T2:%.*]] = fneg nsz float [[T1]]
46 ; CHECK-NEXT: ret float [[T2]]
48 %t1 = fsub float %x, %y
49 %t2 = fneg nsz float %t1
53 ; If the subtract has another use, we don't do the transform (even though it
54 ; doesn't increase the IR instruction count) because we assume that fneg is
55 ; easier to analyze and generally cheaper than generic fsub.
57 declare void @use(float)
58 declare void @use2(float, double)
60 define float @neg_sub_nsz_extra_use(float %x, float %y) {
61 ; CHECK-LABEL: @neg_sub_nsz_extra_use(
62 ; CHECK-NEXT: [[T1:%.*]] = fsub float [[X:%.*]], [[Y:%.*]]
63 ; CHECK-NEXT: [[T2:%.*]] = fsub nsz float -0.000000e+00, [[T1]]
64 ; CHECK-NEXT: call void @use(float [[T1]])
65 ; CHECK-NEXT: ret float [[T2]]
67 %t1 = fsub float %x, %y
68 %t2 = fsub nsz float -0.0, %t1
69 call void @use(float %t1)
73 define float @unary_neg_sub_nsz_extra_use(float %x, float %y) {
74 ; CHECK-LABEL: @unary_neg_sub_nsz_extra_use(
75 ; CHECK-NEXT: [[T1:%.*]] = fsub float [[X:%.*]], [[Y:%.*]]
76 ; CHECK-NEXT: [[T2:%.*]] = fneg nsz float [[T1]]
77 ; CHECK-NEXT: call void @use(float [[T1]])
78 ; CHECK-NEXT: ret float [[T2]]
80 %t1 = fsub float %x, %y
81 %t2 = fneg nsz float %t1
82 call void @use(float %t1)
86 ; With nsz: Z - (X - Y) --> Z + (Y - X)
88 define float @sub_sub_nsz(float %x, float %y, float %z) {
89 ; CHECK-LABEL: @sub_sub_nsz(
90 ; CHECK-NEXT: [[TMP1:%.*]] = fsub nsz float [[Y:%.*]], [[X:%.*]]
91 ; CHECK-NEXT: [[T2:%.*]] = fadd nsz float [[TMP1]], [[Z:%.*]]
92 ; CHECK-NEXT: ret float [[T2]]
94 %t1 = fsub float %x, %y
95 %t2 = fsub nsz float %z, %t1
99 ; With nsz and reassoc: Y - ((X * 5) + Y) --> X * -5
101 define float @sub_add_neg_x(float %x, float %y) {
102 ; CHECK-LABEL: @sub_add_neg_x(
103 ; CHECK-NEXT: [[R:%.*]] = fmul reassoc nsz float [[X:%.*]], -5.000000e+00
104 ; CHECK-NEXT: ret float [[R]]
106 %mul = fmul float %x, 5.000000e+00
107 %add = fadd float %mul, %y
108 %r = fsub nsz reassoc float %y, %add
112 ; Same as above: if 'Z' is not -0.0, swap fsub operands and convert to fadd.
114 define float @sub_sub_known_not_negzero(float %x, float %y) {
115 ; CHECK-LABEL: @sub_sub_known_not_negzero(
116 ; CHECK-NEXT: [[TMP1:%.*]] = fsub float [[Y:%.*]], [[X:%.*]]
117 ; CHECK-NEXT: [[T2:%.*]] = fadd float [[TMP1]], 4.200000e+01
118 ; CHECK-NEXT: ret float [[T2]]
120 %t1 = fsub float %x, %y
121 %t2 = fsub float 42.0, %t1
125 ; <rdar://problem/7530098>
127 define double @test2(double %x, double %y) {
128 ; CHECK-LABEL: @test2(
129 ; CHECK-NEXT: [[T1:%.*]] = fadd double [[X:%.*]], [[Y:%.*]]
130 ; CHECK-NEXT: [[T2:%.*]] = fsub double [[X]], [[T1]]
131 ; CHECK-NEXT: ret double [[T2]]
133 %t1 = fadd double %x, %y
134 %t2 = fsub double %x, %t1
140 define float @constant_op1(float %x, float %y) {
141 ; CHECK-LABEL: @constant_op1(
142 ; CHECK-NEXT: [[R:%.*]] = fadd float [[X:%.*]], -4.200000e+01
143 ; CHECK-NEXT: ret float [[R]]
145 %r = fsub float %x, 42.0
149 define <2 x float> @constant_op1_vec(<2 x float> %x, <2 x float> %y) {
150 ; CHECK-LABEL: @constant_op1_vec(
151 ; CHECK-NEXT: [[R:%.*]] = fadd <2 x float> [[X:%.*]], <float -4.200000e+01, float 4.200000e+01>
152 ; CHECK-NEXT: ret <2 x float> [[R]]
154 %r = fsub <2 x float> %x, <float 42.0, float -42.0>
158 define <2 x float> @constant_op1_vec_undef(<2 x float> %x, <2 x float> %y) {
159 ; CHECK-LABEL: @constant_op1_vec_undef(
160 ; CHECK-NEXT: [[R:%.*]] = fadd <2 x float> [[X:%.*]], <float undef, float 4.200000e+01>
161 ; CHECK-NEXT: ret <2 x float> [[R]]
163 %r = fsub <2 x float> %x, <float undef, float -42.0>
169 define float @neg_op1(float %x, float %y) {
170 ; CHECK-LABEL: @neg_op1(
171 ; CHECK-NEXT: [[R:%.*]] = fadd float [[X:%.*]], [[Y:%.*]]
172 ; CHECK-NEXT: ret float [[R]]
174 %negy = fsub float -0.0, %y
175 %r = fsub float %x, %negy
179 define float @unary_neg_op1(float %x, float %y) {
180 ; CHECK-LABEL: @unary_neg_op1(
181 ; CHECK-NEXT: [[R:%.*]] = fadd float [[X:%.*]], [[Y:%.*]]
182 ; CHECK-NEXT: ret float [[R]]
184 %negy = fneg float %y
185 %r = fsub float %x, %negy
189 define <2 x float> @neg_op1_vec(<2 x float> %x, <2 x float> %y) {
190 ; CHECK-LABEL: @neg_op1_vec(
191 ; CHECK-NEXT: [[R:%.*]] = fadd <2 x float> [[X:%.*]], [[Y:%.*]]
192 ; CHECK-NEXT: ret <2 x float> [[R]]
194 %negy = fsub <2 x float> <float -0.0, float -0.0>, %y
195 %r = fsub <2 x float> %x, %negy
199 define <2 x float> @unary_neg_op1_vec(<2 x float> %x, <2 x float> %y) {
200 ; CHECK-LABEL: @unary_neg_op1_vec(
201 ; CHECK-NEXT: [[R:%.*]] = fadd <2 x float> [[X:%.*]], [[Y:%.*]]
202 ; CHECK-NEXT: ret <2 x float> [[R]]
204 %negy = fneg <2 x float> %y
205 %r = fsub <2 x float> %x, %negy
209 define <2 x float> @neg_op1_vec_undef(<2 x float> %x, <2 x float> %y) {
210 ; CHECK-LABEL: @neg_op1_vec_undef(
211 ; CHECK-NEXT: [[R:%.*]] = fadd <2 x float> [[X:%.*]], [[Y:%.*]]
212 ; CHECK-NEXT: ret <2 x float> [[R]]
214 %negy = fsub <2 x float> <float -0.0, float undef>, %y
215 %r = fsub <2 x float> %x, %negy
219 ; Similar to above - but look through fpext/fptrunc casts to find the fneg.
221 define double @neg_ext_op1(float %a, double %b) {
222 ; CHECK-LABEL: @neg_ext_op1(
223 ; CHECK-NEXT: [[TMP1:%.*]] = fpext float [[A:%.*]] to double
224 ; CHECK-NEXT: [[T3:%.*]] = fadd double [[TMP1]], [[B:%.*]]
225 ; CHECK-NEXT: ret double [[T3]]
227 %t1 = fsub float -0.0, %a
228 %t2 = fpext float %t1 to double
229 %t3 = fsub double %b, %t2
233 define double @unary_neg_ext_op1(float %a, double %b) {
234 ; CHECK-LABEL: @unary_neg_ext_op1(
235 ; CHECK-NEXT: [[TMP1:%.*]] = fpext float [[A:%.*]] to double
236 ; CHECK-NEXT: [[T3:%.*]] = fadd double [[TMP1]], [[B:%.*]]
237 ; CHECK-NEXT: ret double [[T3]]
240 %t2 = fpext float %t1 to double
241 %t3 = fsub double %b, %t2
245 ; Verify that vectors work too.
247 define <2 x float> @neg_trunc_op1(<2 x double> %a, <2 x float> %b) {
248 ; CHECK-LABEL: @neg_trunc_op1(
249 ; CHECK-NEXT: [[TMP1:%.*]] = fptrunc <2 x double> [[A:%.*]] to <2 x float>
250 ; CHECK-NEXT: [[T3:%.*]] = fadd <2 x float> [[TMP1]], [[B:%.*]]
251 ; CHECK-NEXT: ret <2 x float> [[T3]]
253 %t1 = fsub <2 x double> <double -0.0, double -0.0>, %a
254 %t2 = fptrunc <2 x double> %t1 to <2 x float>
255 %t3 = fsub <2 x float> %b, %t2
259 define <2 x float> @unary_neg_trunc_op1(<2 x double> %a, <2 x float> %b) {
260 ; CHECK-LABEL: @unary_neg_trunc_op1(
261 ; CHECK-NEXT: [[TMP1:%.*]] = fptrunc <2 x double> [[A:%.*]] to <2 x float>
262 ; CHECK-NEXT: [[T3:%.*]] = fadd <2 x float> [[TMP1]], [[B:%.*]]
263 ; CHECK-NEXT: ret <2 x float> [[T3]]
265 %t1 = fneg <2 x double> %a
266 %t2 = fptrunc <2 x double> %t1 to <2 x float>
267 %t3 = fsub <2 x float> %b, %t2
271 ; No FMF needed, but they should propagate to the fadd.
273 define double @neg_ext_op1_fast(float %a, double %b) {
274 ; CHECK-LABEL: @neg_ext_op1_fast(
275 ; CHECK-NEXT: [[TMP1:%.*]] = fpext float [[A:%.*]] to double
276 ; CHECK-NEXT: [[T3:%.*]] = fadd fast double [[TMP1]], [[B:%.*]]
277 ; CHECK-NEXT: ret double [[T3]]
279 %t1 = fsub float -0.0, %a
280 %t2 = fpext float %t1 to double
281 %t3 = fsub fast double %b, %t2
285 define double @unary_neg_ext_op1_fast(float %a, double %b) {
286 ; CHECK-LABEL: @unary_neg_ext_op1_fast(
287 ; CHECK-NEXT: [[TMP1:%.*]] = fpext float [[A:%.*]] to double
288 ; CHECK-NEXT: [[T3:%.*]] = fadd fast double [[TMP1]], [[B:%.*]]
289 ; CHECK-NEXT: ret double [[T3]]
292 %t2 = fpext float %t1 to double
293 %t3 = fsub fast double %b, %t2
297 ; Extra use should prevent the transform.
299 define float @neg_ext_op1_extra_use(half %a, float %b) {
300 ; CHECK-LABEL: @neg_ext_op1_extra_use(
301 ; CHECK-NEXT: [[T1:%.*]] = fsub half 0xH8000, [[A:%.*]]
302 ; CHECK-NEXT: [[T2:%.*]] = fpext half [[T1]] to float
303 ; CHECK-NEXT: [[T3:%.*]] = fsub float [[B:%.*]], [[T2]]
304 ; CHECK-NEXT: call void @use(float [[T2]])
305 ; CHECK-NEXT: ret float [[T3]]
307 %t1 = fsub half -0.0, %a
308 %t2 = fpext half %t1 to float
309 %t3 = fsub float %b, %t2
310 call void @use(float %t2)
314 define float @unary_neg_ext_op1_extra_use(half %a, float %b) {
315 ; CHECK-LABEL: @unary_neg_ext_op1_extra_use(
316 ; CHECK-NEXT: [[T1:%.*]] = fneg half [[A:%.*]]
317 ; CHECK-NEXT: [[T2:%.*]] = fpext half [[T1]] to float
318 ; CHECK-NEXT: [[T3:%.*]] = fsub float [[B:%.*]], [[T2]]
319 ; CHECK-NEXT: call void @use(float [[T2]])
320 ; CHECK-NEXT: ret float [[T3]]
323 %t2 = fpext half %t1 to float
324 %t3 = fsub float %b, %t2
325 call void @use(float %t2)
329 ; One-use fptrunc is always hoisted above fneg, so the corresponding
330 ; multi-use bug for fptrunc isn't visible with a fold starting from
333 define float @neg_trunc_op1_extra_use(double %a, float %b) {
334 ; CHECK-LABEL: @neg_trunc_op1_extra_use(
335 ; CHECK-NEXT: [[TMP1:%.*]] = fptrunc double [[A:%.*]] to float
336 ; CHECK-NEXT: [[T2:%.*]] = fsub float -0.000000e+00, [[TMP1]]
337 ; CHECK-NEXT: [[T3:%.*]] = fadd float [[TMP1]], [[B:%.*]]
338 ; CHECK-NEXT: call void @use(float [[T2]])
339 ; CHECK-NEXT: ret float [[T3]]
341 %t1 = fsub double -0.0, %a
342 %t2 = fptrunc double %t1 to float
343 %t3 = fsub float %b, %t2
344 call void @use(float %t2)
348 ; FIXME: This combine isn't working.
349 define float @unary_neg_trunc_op1_extra_use(double %a, float %b) {
350 ; CHECK-LABEL: @unary_neg_trunc_op1_extra_use(
351 ; CHECK-NEXT: [[T1:%.*]] = fneg double [[A:%.*]]
352 ; CHECK-NEXT: [[T2:%.*]] = fptrunc double [[T1]] to float
353 ; CHECK-NEXT: [[T3:%.*]] = fsub float [[B:%.*]], [[T2]]
354 ; CHECK-NEXT: call void @use(float [[T2]])
355 ; CHECK-NEXT: ret float [[T3]]
358 %t2 = fptrunc double %t1 to float
359 %t3 = fsub float %b, %t2
360 call void @use(float %t2)
364 ; Extra uses should prevent the transform.
366 define float @neg_trunc_op1_extra_uses(double %a, float %b) {
367 ; CHECK-LABEL: @neg_trunc_op1_extra_uses(
368 ; CHECK-NEXT: [[T1:%.*]] = fsub double -0.000000e+00, [[A:%.*]]
369 ; CHECK-NEXT: [[T2:%.*]] = fptrunc double [[T1]] to float
370 ; CHECK-NEXT: [[T3:%.*]] = fsub float [[B:%.*]], [[T2]]
371 ; CHECK-NEXT: call void @use2(float [[T2]], double [[T1]])
372 ; CHECK-NEXT: ret float [[T3]]
374 %t1 = fsub double -0.0, %a
375 %t2 = fptrunc double %t1 to float
376 %t3 = fsub float %b, %t2
377 call void @use2(float %t2, double %t1)
381 define float @unary_neg_trunc_op1_extra_uses(double %a, float %b) {
382 ; CHECK-LABEL: @unary_neg_trunc_op1_extra_uses(
383 ; CHECK-NEXT: [[T1:%.*]] = fneg double [[A:%.*]]
384 ; CHECK-NEXT: [[T2:%.*]] = fptrunc double [[T1]] to float
385 ; CHECK-NEXT: [[T3:%.*]] = fsub float [[B:%.*]], [[T2]]
386 ; CHECK-NEXT: call void @use2(float [[T2]], double [[T1]])
387 ; CHECK-NEXT: ret float [[T3]]
390 %t2 = fptrunc double %t1 to float
391 %t3 = fsub float %b, %t2
392 call void @use2(float %t2, double %t1)
396 ; Don't negate a constant expression to form fadd and induce infinite looping:
397 ; https://bugs.llvm.org/show_bug.cgi?id=37605
399 @b = external global i16, align 1
401 define float @PR37605(float %conv) {
402 ; CHECK-LABEL: @PR37605(
403 ; CHECK-NEXT: [[SUB:%.*]] = fsub float [[CONV:%.*]], bitcast (i32 ptrtoint (i16* @b to i32) to float)
404 ; CHECK-NEXT: ret float [[SUB]]
406 %sub = fsub float %conv, bitcast (i32 ptrtoint (i16* @b to i32) to float)