1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -instcombine -S | FileCheck %s
4 ; =========================================================================
6 ; Test FP factorization with patterns:
7 ; X * Z + Y * Z --> (X + Y) * Z (including all 4 commuted variants)
8 ; X * Z - Y * Z --> (X - Y) * Z (including all 4 commuted variants)
9 ; X / Z + Y / Z --> (X + Y) / Z
10 ; X / Z - Y / Z --> (X - Y) / Z
12 ; =========================================================================
14 ; Minimum FMF - the final result requires/propagates FMF.
16 define float @fmul_fadd(float %x, float %y, float %z) {
17 ; CHECK-LABEL: @fmul_fadd(
18 ; CHECK-NEXT: [[TMP1:%.*]] = fadd reassoc nsz float [[X:%.*]], [[Y:%.*]]
19 ; CHECK-NEXT: [[R:%.*]] = fmul reassoc nsz float [[TMP1]], [[Z:%.*]]
20 ; CHECK-NEXT: ret float [[R]]
22 %t1 = fmul float %x, %z
23 %t2 = fmul float %y, %z
24 %r = fadd reassoc nsz float %t1, %t2
28 ; Verify vector types and commuted operands.
30 define <2 x float> @fmul_fadd_commute1_vec(<2 x float> %x, <2 x float> %y, <2 x float> %z) {
31 ; CHECK-LABEL: @fmul_fadd_commute1_vec(
32 ; CHECK-NEXT: [[TMP1:%.*]] = fadd reassoc nsz <2 x float> [[X:%.*]], [[Y:%.*]]
33 ; CHECK-NEXT: [[R:%.*]] = fmul reassoc nsz <2 x float> [[TMP1]], [[Z:%.*]]
34 ; CHECK-NEXT: ret <2 x float> [[R]]
36 %t1 = fmul <2 x float> %z, %x
37 %t2 = fmul <2 x float> %z, %y
38 %r = fadd reassoc nsz <2 x float> %t1, %t2
42 ; Verify vector types, commuted operands, FMF propagation.
44 define <2 x float> @fmul_fadd_commute2_vec(<2 x float> %x, <2 x float> %y, <2 x float> %z) {
45 ; CHECK-LABEL: @fmul_fadd_commute2_vec(
46 ; CHECK-NEXT: [[TMP1:%.*]] = fadd reassoc ninf nsz <2 x float> [[X:%.*]], [[Y:%.*]]
47 ; CHECK-NEXT: [[R:%.*]] = fmul reassoc ninf nsz <2 x float> [[TMP1]], [[Z:%.*]]
48 ; CHECK-NEXT: ret <2 x float> [[R]]
50 %t1 = fmul fast <2 x float> %x, %z
51 %t2 = fmul nnan <2 x float> %z, %y
52 %r = fadd reassoc nsz ninf <2 x float> %t1, %t2
56 ; Verify different scalar type, commuted operands, FMF propagation.
58 define double @fmul_fadd_commute3(double %x, double %y, double %z) {
59 ; CHECK-LABEL: @fmul_fadd_commute3(
60 ; CHECK-NEXT: [[TMP1:%.*]] = fadd reassoc nnan nsz double [[X:%.*]], [[Y:%.*]]
61 ; CHECK-NEXT: [[R:%.*]] = fmul reassoc nnan nsz double [[TMP1]], [[Z:%.*]]
62 ; CHECK-NEXT: ret double [[R]]
64 %t1 = fmul double %z, %x
65 %t2 = fmul fast double %y, %z
66 %r = fadd reassoc nsz nnan double %t1, %t2
70 ; Negative test - verify the fold is not done with only 'reassoc' ('nsz' is required).
72 define float @fmul_fadd_not_enough_FMF(float %x, float %y, float %z) {
73 ; CHECK-LABEL: @fmul_fadd_not_enough_FMF(
74 ; CHECK-NEXT: [[T1:%.*]] = fmul fast float [[X:%.*]], [[Z:%.*]]
75 ; CHECK-NEXT: [[T2:%.*]] = fmul fast float [[Y:%.*]], [[Z]]
76 ; CHECK-NEXT: [[R:%.*]] = fadd reassoc float [[T1]], [[T2]]
77 ; CHECK-NEXT: ret float [[R]]
79 %t1 = fmul fast float %x, %z
80 %t2 = fmul fast float %y, %z
81 %r = fadd reassoc float %t1, %t2
85 declare void @use(float)
87 ; Negative test - extra uses should disable the fold.
89 define float @fmul_fadd_uses1(float %x, float %y, float %z) {
90 ; CHECK-LABEL: @fmul_fadd_uses1(
91 ; CHECK-NEXT: [[T1:%.*]] = fmul float [[Z:%.*]], [[X:%.*]]
92 ; CHECK-NEXT: [[T2:%.*]] = fmul float [[Y:%.*]], [[Z]]
93 ; CHECK-NEXT: [[R:%.*]] = fadd reassoc nsz float [[T1]], [[T2]]
94 ; CHECK-NEXT: call void @use(float [[T1]])
95 ; CHECK-NEXT: ret float [[R]]
97 %t1 = fmul float %z, %x
98 %t2 = fmul float %y, %z
99 %r = fadd reassoc nsz float %t1, %t2
100 call void @use(float %t1)
104 ; Negative test - extra uses should disable the fold.
106 define float @fmul_fadd_uses2(float %x, float %y, float %z) {
107 ; CHECK-LABEL: @fmul_fadd_uses2(
108 ; CHECK-NEXT: [[T1:%.*]] = fmul float [[Z:%.*]], [[X:%.*]]
109 ; CHECK-NEXT: [[T2:%.*]] = fmul float [[Z]], [[Y:%.*]]
110 ; CHECK-NEXT: [[R:%.*]] = fadd reassoc nsz float [[T1]], [[T2]]
111 ; CHECK-NEXT: call void @use(float [[T2]])
112 ; CHECK-NEXT: ret float [[R]]
114 %t1 = fmul float %z, %x
115 %t2 = fmul float %z, %y
116 %r = fadd reassoc nsz float %t1, %t2
117 call void @use(float %t2)
121 ; Negative test - extra uses should disable the fold.
123 define float @fmul_fadd_uses3(float %x, float %y, float %z) {
124 ; CHECK-LABEL: @fmul_fadd_uses3(
125 ; CHECK-NEXT: [[T1:%.*]] = fmul float [[X:%.*]], [[Z:%.*]]
126 ; CHECK-NEXT: [[T2:%.*]] = fmul float [[Z]], [[Y:%.*]]
127 ; CHECK-NEXT: [[R:%.*]] = fadd reassoc nsz float [[T1]], [[T2]]
128 ; CHECK-NEXT: call void @use(float [[T1]])
129 ; CHECK-NEXT: call void @use(float [[T2]])
130 ; CHECK-NEXT: ret float [[R]]
132 %t1 = fmul float %x, %z
133 %t2 = fmul float %z, %y
134 %r = fadd reassoc nsz float %t1, %t2
135 call void @use(float %t1)
136 call void @use(float %t2)
140 ; Minimum FMF - the final result requires/propagates FMF.
142 define half @fmul_fsub(half %x, half %y, half %z) {
143 ; CHECK-LABEL: @fmul_fsub(
144 ; CHECK-NEXT: [[TMP1:%.*]] = fsub reassoc nsz half [[X:%.*]], [[Y:%.*]]
145 ; CHECK-NEXT: [[R:%.*]] = fmul reassoc nsz half [[TMP1]], [[Z:%.*]]
146 ; CHECK-NEXT: ret half [[R]]
148 %t1 = fmul half %x, %z
149 %t2 = fmul half %y, %z
150 %r = fsub reassoc nsz half %t1, %t2
154 ; Verify vector types and commuted operands.
156 define <2 x float> @fmul_fsub_commute1_vec(<2 x float> %x, <2 x float> %y, <2 x float> %z) {
157 ; CHECK-LABEL: @fmul_fsub_commute1_vec(
158 ; CHECK-NEXT: [[TMP1:%.*]] = fsub reassoc nsz <2 x float> [[X:%.*]], [[Y:%.*]]
159 ; CHECK-NEXT: [[R:%.*]] = fmul reassoc nsz <2 x float> [[TMP1]], [[Z:%.*]]
160 ; CHECK-NEXT: ret <2 x float> [[R]]
162 %t1 = fmul <2 x float> %z, %x
163 %t2 = fmul <2 x float> %y, %z
164 %r = fsub reassoc nsz <2 x float> %t1, %t2
168 ; Verify vector types, commuted operands, FMF propagation.
170 define <2 x float> @fmul_fsub_commute2_vec(<2 x float> %x, <2 x float> %y, <2 x float> %z) {
171 ; CHECK-LABEL: @fmul_fsub_commute2_vec(
172 ; CHECK-NEXT: [[TMP1:%.*]] = fsub reassoc ninf nsz <2 x float> [[X:%.*]], [[Y:%.*]]
173 ; CHECK-NEXT: [[R:%.*]] = fmul reassoc ninf nsz <2 x float> [[TMP1]], [[Z:%.*]]
174 ; CHECK-NEXT: ret <2 x float> [[R]]
176 %t1 = fmul fast <2 x float> %x, %z
177 %t2 = fmul nnan <2 x float> %z, %y
178 %r = fsub reassoc nsz ninf <2 x float> %t1, %t2
182 ; Verify different scalar type, commuted operands, FMF propagation.
184 define double @fmul_fsub_commute3(double %x, double %y, double %z) {
185 ; CHECK-LABEL: @fmul_fsub_commute3(
186 ; CHECK-NEXT: [[TMP1:%.*]] = fsub reassoc nnan nsz double [[X:%.*]], [[Y:%.*]]
187 ; CHECK-NEXT: [[R:%.*]] = fmul reassoc nnan nsz double [[TMP1]], [[Z:%.*]]
188 ; CHECK-NEXT: ret double [[R]]
190 %t1 = fmul double %z, %x
191 %t2 = fmul fast double %z, %y
192 %r = fsub reassoc nsz nnan double %t1, %t2
196 ; Negative test - verify the fold is not done with only 'nsz' ('reassoc' is required).
198 define float @fmul_fsub_not_enough_FMF(float %x, float %y, float %z) {
199 ; CHECK-LABEL: @fmul_fsub_not_enough_FMF(
200 ; CHECK-NEXT: [[T1:%.*]] = fmul fast float [[Z:%.*]], [[X:%.*]]
201 ; CHECK-NEXT: [[T2:%.*]] = fmul fast float [[Y:%.*]], [[Z]]
202 ; CHECK-NEXT: [[R:%.*]] = fsub nsz float [[T1]], [[T2]]
203 ; CHECK-NEXT: ret float [[R]]
205 %t1 = fmul fast float %z, %x
206 %t2 = fmul fast float %y, %z
207 %r = fsub nsz float %t1, %t2
211 ; Negative test - extra uses should disable the fold.
213 define float @fmul_fsub_uses1(float %x, float %y, float %z) {
214 ; CHECK-LABEL: @fmul_fsub_uses1(
215 ; CHECK-NEXT: [[T1:%.*]] = fmul float [[X:%.*]], [[Z:%.*]]
216 ; CHECK-NEXT: [[T2:%.*]] = fmul float [[Y:%.*]], [[Z]]
217 ; CHECK-NEXT: [[R:%.*]] = fsub reassoc nsz float [[T1]], [[T2]]
218 ; CHECK-NEXT: call void @use(float [[T1]])
219 ; CHECK-NEXT: ret float [[R]]
221 %t1 = fmul float %x, %z
222 %t2 = fmul float %y, %z
223 %r = fsub reassoc nsz float %t1, %t2
224 call void @use(float %t1)
228 ; Negative test - extra uses should disable the fold.
230 define float @fmul_fsub_uses2(float %x, float %y, float %z) {
231 ; CHECK-LABEL: @fmul_fsub_uses2(
232 ; CHECK-NEXT: [[T1:%.*]] = fmul float [[Z:%.*]], [[X:%.*]]
233 ; CHECK-NEXT: [[T2:%.*]] = fmul float [[Z]], [[Y:%.*]]
234 ; CHECK-NEXT: [[R:%.*]] = fsub reassoc nsz float [[T1]], [[T2]]
235 ; CHECK-NEXT: call void @use(float [[T2]])
236 ; CHECK-NEXT: ret float [[R]]
238 %t1 = fmul float %z, %x
239 %t2 = fmul float %z, %y
240 %r = fsub reassoc nsz float %t1, %t2
241 call void @use(float %t2)
245 ; Negative test - extra uses should disable the fold.
247 define float @fmul_fsub_uses3(float %x, float %y, float %z) {
248 ; CHECK-LABEL: @fmul_fsub_uses3(
249 ; CHECK-NEXT: [[T1:%.*]] = fmul float [[X:%.*]], [[Z:%.*]]
250 ; CHECK-NEXT: [[T2:%.*]] = fmul float [[Y:%.*]], [[Z]]
251 ; CHECK-NEXT: [[R:%.*]] = fsub reassoc nsz float [[T1]], [[T2]]
252 ; CHECK-NEXT: call void @use(float [[T1]])
253 ; CHECK-NEXT: call void @use(float [[T2]])
254 ; CHECK-NEXT: ret float [[R]]
256 %t1 = fmul float %x, %z
257 %t2 = fmul float %y, %z
258 %r = fsub reassoc nsz float %t1, %t2
259 call void @use(float %t1)
260 call void @use(float %t2)
266 define double @fdiv_fadd(double %x, double %y, double %z) {
267 ; CHECK-LABEL: @fdiv_fadd(
268 ; CHECK-NEXT: [[TMP1:%.*]] = fadd reassoc nsz double [[X:%.*]], [[Y:%.*]]
269 ; CHECK-NEXT: [[R:%.*]] = fdiv reassoc nsz double [[TMP1]], [[Z:%.*]]
270 ; CHECK-NEXT: ret double [[R]]
272 %t1 = fdiv double %x, %z
273 %t2 = fdiv double %y, %z
274 %r = fadd reassoc nsz double %t1, %t2
278 define float @fdiv_fsub(float %x, float %y, float %z) {
279 ; CHECK-LABEL: @fdiv_fsub(
280 ; CHECK-NEXT: [[TMP1:%.*]] = fsub reassoc nsz float [[X:%.*]], [[Y:%.*]]
281 ; CHECK-NEXT: [[R:%.*]] = fdiv reassoc nsz float [[TMP1]], [[Z:%.*]]
282 ; CHECK-NEXT: ret float [[R]]
284 %t1 = fdiv fast float %x, %z
285 %t2 = fdiv nnan float %y, %z
286 %r = fsub reassoc nsz float %t1, %t2
290 ; Verify vector types.
292 define <2 x double> @fdiv_fadd_vec(<2 x double> %x, <2 x double> %y, <2 x double> %z) {
293 ; CHECK-LABEL: @fdiv_fadd_vec(
294 ; CHECK-NEXT: [[TMP1:%.*]] = fadd reassoc nsz <2 x double> [[X:%.*]], [[Y:%.*]]
295 ; CHECK-NEXT: [[R:%.*]] = fdiv reassoc nsz <2 x double> [[TMP1]], [[Z:%.*]]
296 ; CHECK-NEXT: ret <2 x double> [[R]]
298 %t1 = fdiv fast <2 x double> %x, %z
299 %t2 = fdiv <2 x double> %y, %z
300 %r = fadd reassoc nsz <2 x double> %t1, %t2
304 ; Verify vector types.
306 define <2 x float> @fdiv_fsub_vec(<2 x float> %x, <2 x float> %y, <2 x float> %z) {
307 ; CHECK-LABEL: @fdiv_fsub_vec(
308 ; CHECK-NEXT: [[TMP1:%.*]] = fsub reassoc nsz <2 x float> [[X:%.*]], [[Y:%.*]]
309 ; CHECK-NEXT: [[R:%.*]] = fdiv reassoc nsz <2 x float> [[TMP1]], [[Z:%.*]]
310 ; CHECK-NEXT: ret <2 x float> [[R]]
312 %t1 = fdiv <2 x float> %x, %z
313 %t2 = fdiv nnan <2 x float> %y, %z
314 %r = fsub reassoc nsz <2 x float> %t1, %t2
318 ; Negative test - common operand is not divisor.
320 define float @fdiv_fadd_commute1(float %x, float %y, float %z) {
321 ; CHECK-LABEL: @fdiv_fadd_commute1(
322 ; CHECK-NEXT: [[T1:%.*]] = fdiv fast float [[Z:%.*]], [[Y:%.*]]
323 ; CHECK-NEXT: [[T2:%.*]] = fdiv fast float [[Z]], [[X:%.*]]
324 ; CHECK-NEXT: [[R:%.*]] = fadd fast float [[T1]], [[T2]]
325 ; CHECK-NEXT: ret float [[R]]
327 %t1 = fdiv fast float %z, %y
328 %t2 = fdiv fast float %z, %x
329 %r = fadd fast float %t1, %t2
333 ; Negative test - common operand is not divisor.
335 define float @fdiv_fsub_commute2(float %x, float %y, float %z) {
336 ; CHECK-LABEL: @fdiv_fsub_commute2(
337 ; CHECK-NEXT: [[T1:%.*]] = fdiv fast float [[Z:%.*]], [[Y:%.*]]
338 ; CHECK-NEXT: [[T2:%.*]] = fdiv fast float [[X:%.*]], [[Z]]
339 ; CHECK-NEXT: [[R:%.*]] = fsub fast float [[T1]], [[T2]]
340 ; CHECK-NEXT: ret float [[R]]
342 %t1 = fdiv fast float %z, %y
343 %t2 = fdiv fast float %x, %z
344 %r = fsub fast float %t1, %t2
348 ; Negative test - verify the fold is not done with only 'nsz' ('reassoc' is required).
350 define float @fdiv_fadd_not_enough_FMF(float %x, float %y, float %z) {
351 ; CHECK-LABEL: @fdiv_fadd_not_enough_FMF(
352 ; CHECK-NEXT: [[T1:%.*]] = fdiv fast float [[Y:%.*]], [[X:%.*]]
353 ; CHECK-NEXT: [[T2:%.*]] = fdiv fast float [[Z:%.*]], [[X]]
354 ; CHECK-NEXT: [[T3:%.*]] = fadd nsz float [[T1]], [[T2]]
355 ; CHECK-NEXT: ret float [[T3]]
357 %t1 = fdiv fast float %y, %x
358 %t2 = fdiv fast float %z, %x
359 %t3 = fadd nsz float %t1, %t2
363 ; Negative test - verify the fold is not done with only 'reassoc' ('nsz' is required).
365 define float @fdiv_fsub_not_enough_FMF(float %x, float %y, float %z) {
366 ; CHECK-LABEL: @fdiv_fsub_not_enough_FMF(
367 ; CHECK-NEXT: [[T1:%.*]] = fdiv fast float [[Y:%.*]], [[X:%.*]]
368 ; CHECK-NEXT: [[T2:%.*]] = fdiv fast float [[Z:%.*]], [[X]]
369 ; CHECK-NEXT: [[T3:%.*]] = fsub reassoc float [[T1]], [[T2]]
370 ; CHECK-NEXT: ret float [[T3]]
372 %t1 = fdiv fast float %y, %x
373 %t2 = fdiv fast float %z, %x
374 %t3 = fsub reassoc float %t1, %t2
378 ; Negative test - extra uses should disable the fold.
380 define float @fdiv_fadd_uses1(float %x, float %y, float %z) {
381 ; CHECK-LABEL: @fdiv_fadd_uses1(
382 ; CHECK-NEXT: [[T1:%.*]] = fdiv fast float [[X:%.*]], [[Z:%.*]]
383 ; CHECK-NEXT: [[T2:%.*]] = fdiv fast float [[Y:%.*]], [[Z]]
384 ; CHECK-NEXT: [[R:%.*]] = fadd fast float [[T1]], [[T2]]
385 ; CHECK-NEXT: call void @use(float [[T1]])
386 ; CHECK-NEXT: ret float [[R]]
388 %t1 = fdiv fast float %x, %z
389 %t2 = fdiv fast float %y, %z
390 %r = fadd fast float %t1, %t2
391 call void @use(float %t1)
395 ; Negative test - extra uses should disable the fold.
397 define float @fdiv_fsub_uses2(float %x, float %y, float %z) {
398 ; CHECK-LABEL: @fdiv_fsub_uses2(
399 ; CHECK-NEXT: [[T1:%.*]] = fdiv fast float [[X:%.*]], [[Z:%.*]]
400 ; CHECK-NEXT: [[T2:%.*]] = fdiv fast float [[Y:%.*]], [[Z]]
401 ; CHECK-NEXT: [[R:%.*]] = fsub fast float [[T1]], [[T2]]
402 ; CHECK-NEXT: call void @use(float [[T2]])
403 ; CHECK-NEXT: ret float [[R]]
405 %t1 = fdiv fast float %x, %z
406 %t2 = fdiv fast float %y, %z
407 %r = fsub fast float %t1, %t2
408 call void @use(float %t2)
412 ; Negative test - extra uses should disable the fold.
414 define float @fdiv_fsub_uses3(float %x, float %y, float %z) {
415 ; CHECK-LABEL: @fdiv_fsub_uses3(
416 ; CHECK-NEXT: [[T1:%.*]] = fdiv fast float [[X:%.*]], [[Z:%.*]]
417 ; CHECK-NEXT: [[T2:%.*]] = fdiv fast float [[Y:%.*]], [[Z]]
418 ; CHECK-NEXT: [[R:%.*]] = fsub fast float [[T1]], [[T2]]
419 ; CHECK-NEXT: call void @use(float [[T1]])
420 ; CHECK-NEXT: call void @use(float [[T2]])
421 ; CHECK-NEXT: ret float [[R]]
423 %t1 = fdiv fast float %x, %z
424 %t2 = fdiv fast float %y, %z
425 %r = fsub fast float %t1, %t2
426 call void @use(float %t1)
427 call void @use(float %t2)
431 ; Constants are fine to combine if they are not denorms.
433 define float @fdiv_fadd_not_denorm(float %x) {
434 ; CHECK-LABEL: @fdiv_fadd_not_denorm(
435 ; CHECK-NEXT: [[R:%.*]] = fdiv fast float 0x3818000000000000, [[X:%.*]]
436 ; CHECK-NEXT: ret float [[R]]
438 %t1 = fdiv fast float 0x3810000000000000, %x
439 %t2 = fdiv fast float 0x3800000000000000, %x
440 %r = fadd fast float %t1, %t2
444 ; Negative test - disabled if x+y is denormal.
446 define float @fdiv_fadd_denorm(float %x) {
447 ; CHECK-LABEL: @fdiv_fadd_denorm(
448 ; CHECK-NEXT: [[T1:%.*]] = fdiv fast float 0xB810000000000000, [[X:%.*]]
449 ; CHECK-NEXT: [[T2:%.*]] = fdiv fast float 0x3800000000000000, [[X]]
450 ; CHECK-NEXT: [[R:%.*]] = fadd fast float [[T1]], [[T2]]
451 ; CHECK-NEXT: ret float [[R]]
453 %t1 = fdiv fast float 0xB810000000000000, %x
454 %t2 = fdiv fast float 0x3800000000000000, %x
455 %r = fadd fast float %t1, %t2
459 ; Negative test - disabled if x-y is denormal.
461 define float @fdiv_fsub_denorm(float %x) {
462 ; CHECK-LABEL: @fdiv_fsub_denorm(
463 ; CHECK-NEXT: [[T1:%.*]] = fdiv fast float 0x3810000000000000, [[X:%.*]]
464 ; CHECK-NEXT: [[T2:%.*]] = fdiv fast float 0x3800000000000000, [[X]]
465 ; CHECK-NEXT: [[R:%.*]] = fsub fast float [[T1]], [[T2]]
466 ; CHECK-NEXT: ret float [[R]]
468 %t1 = fdiv fast float 0x3810000000000000, %x
469 %t2 = fdiv fast float 0x3800000000000000, %x
470 %r = fsub fast float %t1, %t2