xref: /llvm-project/llvm/test/Transforms/InstCombine/fadd-fsub-factor.ll (revision a105877646d68e48cdeeeadd9d1e075dc3c5d68d)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -passes=instcombine -S | FileCheck %s
3
4; =========================================================================
5;
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
11;
12; =========================================================================
13
14; Minimum FMF - the final result requires/propagates FMF.
15
16define 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]]
21;
22  %t1 = fmul float %x, %z
23  %t2 = fmul float %y, %z
24  %r = fadd reassoc nsz float %t1, %t2
25  ret float %r
26}
27
28; Verify vector types and commuted operands.
29
30define <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]]
35;
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
39  ret <2 x float> %r
40}
41
42; Verify vector types, commuted operands, FMF propagation.
43
44define <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]]
49;
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
53  ret <2 x float> %r
54}
55
56; Verify different scalar type, commuted operands, FMF propagation.
57
58define 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]]
63;
64  %t1 = fmul double %z, %x
65  %t2 = fmul fast double %y, %z
66  %r = fadd reassoc nsz nnan double %t1, %t2
67  ret double %r
68}
69
70; Negative test - verify the fold is not done with only 'reassoc' ('nsz' is required).
71
72define 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]]
78;
79  %t1 = fmul fast float %x, %z
80  %t2 = fmul fast float %y, %z
81  %r = fadd reassoc float %t1, %t2
82  ret float %r
83}
84
85declare void @use(float)
86
87; Negative test - extra uses should disable the fold.
88
89define 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]]
96;
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)
101  ret float %r
102}
103
104; Negative test - extra uses should disable the fold.
105
106define 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]]
113;
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)
118  ret float %r
119}
120
121; Negative test - extra uses should disable the fold.
122
123define 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]]
131;
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)
137  ret float %r
138}
139
140; Minimum FMF - the final result requires/propagates FMF.
141
142define 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]]
147;
148  %t1 = fmul half %x, %z
149  %t2 = fmul half %y, %z
150  %r = fsub reassoc nsz half %t1, %t2
151  ret half %r
152}
153
154; Verify vector types and commuted operands.
155
156define <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]]
161;
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
165  ret <2 x float> %r
166}
167
168; Verify vector types, commuted operands, FMF propagation.
169
170define <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]]
175;
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
179  ret <2 x float> %r
180}
181
182; Verify different scalar type, commuted operands, FMF propagation.
183
184define 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]]
189;
190  %t1 = fmul double %z, %x
191  %t2 = fmul fast double %z, %y
192  %r = fsub reassoc nsz nnan double %t1, %t2
193  ret double %r
194}
195
196; Negative test - verify the fold is not done with only 'nsz' ('reassoc' is required).
197
198define 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]]
204;
205  %t1 = fmul fast float %z, %x
206  %t2 = fmul fast float %y, %z
207  %r = fsub nsz float %t1, %t2
208  ret float %r
209}
210
211; Negative test - extra uses should disable the fold.
212
213define 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]]
220;
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)
225  ret float %r
226}
227
228; Negative test - extra uses should disable the fold.
229
230define 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]]
237;
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)
242  ret float %r
243}
244
245; Negative test - extra uses should disable the fold.
246
247define 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]]
255;
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)
261  ret float %r
262}
263
264; Common divisor
265
266define 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]]
271;
272  %t1 = fdiv double %x, %z
273  %t2 = fdiv double %y, %z
274  %r = fadd reassoc nsz double %t1, %t2
275  ret double %r
276}
277
278define 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]]
283;
284  %t1 = fdiv fast float %x, %z
285  %t2 = fdiv nnan float %y, %z
286  %r = fsub reassoc nsz float %t1, %t2
287  ret float %r
288}
289
290; Verify vector types.
291
292define <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]]
297;
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
301  ret <2 x double> %r
302}
303
304; Verify vector types.
305
306define <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]]
311;
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
315  ret <2 x float> %r
316}
317
318; Negative test - common operand is not divisor.
319
320define 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]]
326;
327  %t1 = fdiv fast float %z, %y
328  %t2 = fdiv fast float %z, %x
329  %r = fadd fast float %t1, %t2
330  ret float %r
331}
332
333; Negative test - common operand is not divisor.
334
335define 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]]
341;
342  %t1 = fdiv fast float %z, %y
343  %t2 = fdiv fast float %x, %z
344  %r = fsub fast float %t1, %t2
345  ret float %r
346}
347
348; Negative test - verify the fold is not done with only 'nsz' ('reassoc' is required).
349
350define 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]]
356;
357  %t1 = fdiv fast float %y, %x
358  %t2 = fdiv fast float %z, %x
359  %t3 = fadd nsz float %t1, %t2
360  ret float %t3
361}
362
363; Negative test - verify the fold is not done with only 'reassoc' ('nsz' is required).
364
365define 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]]
371;
372  %t1 = fdiv fast float %y, %x
373  %t2 = fdiv fast float %z, %x
374  %t3 = fsub reassoc float %t1, %t2
375  ret float %t3
376}
377
378; Negative test - extra uses should disable the fold.
379
380define 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]]
387;
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)
392  ret float %r
393}
394
395; Negative test - extra uses should disable the fold.
396
397define 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]]
404;
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)
409  ret float %r
410}
411
412; Negative test - extra uses should disable the fold.
413
414define 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]]
422;
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)
428  ret float %r
429}
430
431; Constants are fine to combine if they are not denorms.
432
433define 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]]
437;
438  %t1 = fdiv fast float 0x3810000000000000, %x
439  %t2 = fdiv fast float 0x3800000000000000, %x
440  %r = fadd fast float %t1, %t2
441  ret float %r
442}
443
444; Negative test - disabled if x+y is denormal.
445
446define 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]]
452;
453  %t1 = fdiv fast float 0xB810000000000000, %x
454  %t2 = fdiv fast float 0x3800000000000000, %x
455  %r = fadd fast float %t1, %t2
456  ret float %r
457}
458
459; Negative test - disabled if x-y is denormal.
460
461define 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]]
467;
468  %t1 = fdiv fast float 0x3810000000000000, %x
469  %t2 = fdiv fast float 0x3800000000000000, %x
470  %r = fsub fast float %t1, %t2
471  ret float %r
472}
473
474define float @lerp_commute0(float %a, float %b, float %c) {
475; CHECK-LABEL: @lerp_commute0(
476; CHECK-NEXT:    [[TMP1:%.*]] = fsub fast float [[B:%.*]], [[A:%.*]]
477; CHECK-NEXT:    [[TMP2:%.*]] = fmul fast float [[C:%.*]], [[TMP1]]
478; CHECK-NEXT:    [[ADD:%.*]] = fadd fast float [[A]], [[TMP2]]
479; CHECK-NEXT:    ret float [[ADD]]
480;
481  %sub = fsub fast float 1.0, %c
482  %mul = fmul fast float %sub, %a
483  %bc = fmul fast float %c, %b
484  %add = fadd fast float %mul, %bc
485  ret float %add
486}
487
488define <2 x float> @lerp_commute1(<2 x float> %a, <2 x float> %b, <2 x float> %c) {
489; CHECK-LABEL: @lerp_commute1(
490; CHECK-NEXT:    [[TMP1:%.*]] = fsub fast <2 x float> [[B:%.*]], [[A:%.*]]
491; CHECK-NEXT:    [[TMP2:%.*]] = fmul fast <2 x float> [[C:%.*]], [[TMP1]]
492; CHECK-NEXT:    [[ADD:%.*]] = fadd fast <2 x float> [[A]], [[TMP2]]
493; CHECK-NEXT:    ret <2 x float> [[ADD]]
494;
495  %sub = fsub <2 x float> <float 1.0, float 1.0>, %c
496  %mul = fmul <2 x float> %sub, %a
497  %bc = fmul <2 x float> %c, %b
498  %add = fadd fast <2 x float> %bc, %mul
499  ret <2 x float> %add
500}
501
502define float @lerp_commute2(float %a, float %b, float %c) {
503; CHECK-LABEL: @lerp_commute2(
504; CHECK-NEXT:    [[TMP1:%.*]] = fsub reassoc nsz float [[B:%.*]], [[A:%.*]]
505; CHECK-NEXT:    [[TMP2:%.*]] = fmul reassoc nsz float [[C:%.*]], [[TMP1]]
506; CHECK-NEXT:    [[ADD:%.*]] = fadd reassoc nsz float [[A]], [[TMP2]]
507; CHECK-NEXT:    ret float [[ADD]]
508;
509  %sub = fsub float 1.0, %c
510  %mul = fmul float %sub, %a
511  %bc = fmul float %b, %c
512  %add = fadd reassoc nsz float %mul, %bc
513  ret float %add
514}
515
516define float @lerp_commute3(float %a, float %b, float %c) {
517; CHECK-LABEL: @lerp_commute3(
518; CHECK-NEXT:    [[TMP1:%.*]] = fsub reassoc ninf nsz float [[B:%.*]], [[A:%.*]]
519; CHECK-NEXT:    [[TMP2:%.*]] = fmul reassoc ninf nsz float [[C:%.*]], [[TMP1]]
520; CHECK-NEXT:    [[ADD:%.*]] = fadd reassoc ninf nsz float [[A]], [[TMP2]]
521; CHECK-NEXT:    ret float [[ADD]]
522;
523  %sub = fsub fast float 1.0, %c
524  %mul = fmul float %sub, %a
525  %bc = fmul float %b, %c
526  %add = fadd reassoc nsz ninf float %bc, %mul
527  ret float %add
528}
529
530define double @lerp_commute4(double %a, double %b, double %c) {
531; CHECK-LABEL: @lerp_commute4(
532; CHECK-NEXT:    [[TMP1:%.*]] = fsub fast double [[B:%.*]], [[A:%.*]]
533; CHECK-NEXT:    [[TMP2:%.*]] = fmul fast double [[C:%.*]], [[TMP1]]
534; CHECK-NEXT:    [[ADD:%.*]] = fadd fast double [[A]], [[TMP2]]
535; CHECK-NEXT:    ret double [[ADD]]
536;
537  %sub = fsub fast double 1.0, %c
538  %mul = fmul fast double %a, %sub
539  %bc = fmul fast double %c, %b
540  %add = fadd fast double %mul, %bc
541  ret double %add
542}
543
544define double @lerp_commute5(double %a, double %b, double %c) {
545; CHECK-LABEL: @lerp_commute5(
546; CHECK-NEXT:    [[TMP1:%.*]] = fsub fast double [[B:%.*]], [[A:%.*]]
547; CHECK-NEXT:    [[TMP2:%.*]] = fmul fast double [[C:%.*]], [[TMP1]]
548; CHECK-NEXT:    [[ADD:%.*]] = fadd fast double [[A]], [[TMP2]]
549; CHECK-NEXT:    ret double [[ADD]]
550;
551  %sub = fsub fast double 1.0, %c
552  %mul = fmul fast double %a, %sub
553  %bc = fmul fast double %c, %b
554  %add = fadd fast double %bc, %mul
555  ret double %add
556}
557
558define half @lerp_commute6(half %a, half %b, half %c) {
559; CHECK-LABEL: @lerp_commute6(
560; CHECK-NEXT:    [[TMP1:%.*]] = fsub fast half [[B:%.*]], [[A:%.*]]
561; CHECK-NEXT:    [[TMP2:%.*]] = fmul fast half [[C:%.*]], [[TMP1]]
562; CHECK-NEXT:    [[ADD:%.*]] = fadd fast half [[A]], [[TMP2]]
563; CHECK-NEXT:    ret half [[ADD]]
564;
565  %sub = fsub fast half 1.0, %c
566  %mul = fmul fast half %a, %sub
567  %bc = fmul fast half %b, %c
568  %add = fadd fast half %mul, %bc
569  ret half %add
570}
571
572define half @lerp_commute7(half %a, half %b, half %c) {
573; CHECK-LABEL: @lerp_commute7(
574; CHECK-NEXT:    [[TMP1:%.*]] = fsub fast half [[B:%.*]], [[A:%.*]]
575; CHECK-NEXT:    [[TMP2:%.*]] = fmul fast half [[C:%.*]], [[TMP1]]
576; CHECK-NEXT:    [[ADD:%.*]] = fadd fast half [[A]], [[TMP2]]
577; CHECK-NEXT:    ret half [[ADD]]
578;
579  %sub = fsub fast half 1.0, %c
580  %mul = fmul fast half %a, %sub
581  %bc = fmul fast half %b, %c
582  %add = fadd fast half %bc, %mul
583  ret half %add
584}
585
586define float @lerp_extra_use1(float %a, float %b, float %c) {
587; CHECK-LABEL: @lerp_extra_use1(
588; CHECK-NEXT:    [[SUB:%.*]] = fsub fast float 1.000000e+00, [[C:%.*]]
589; CHECK-NEXT:    [[MUL:%.*]] = fmul fast float [[A:%.*]], [[SUB]]
590; CHECK-NEXT:    [[BC:%.*]] = fmul fast float [[B:%.*]], [[C]]
591; CHECK-NEXT:    call void @use(float [[BC]])
592; CHECK-NEXT:    [[ADD:%.*]] = fadd fast float [[BC]], [[MUL]]
593; CHECK-NEXT:    ret float [[ADD]]
594;
595  %sub = fsub fast float 1.0, %c
596  %mul = fmul fast float %a, %sub
597  %bc = fmul fast float %b, %c
598  call void @use(float %bc)
599  %add = fadd fast float %bc, %mul
600  ret float %add
601}
602
603define float @lerp_extra_use2(float %a, float %b, float %c) {
604; CHECK-LABEL: @lerp_extra_use2(
605; CHECK-NEXT:    [[SUB:%.*]] = fsub fast float 1.000000e+00, [[C:%.*]]
606; CHECK-NEXT:    [[MUL:%.*]] = fmul fast float [[A:%.*]], [[SUB]]
607; CHECK-NEXT:    call void @use(float [[MUL]])
608; CHECK-NEXT:    [[BC:%.*]] = fmul fast float [[B:%.*]], [[C]]
609; CHECK-NEXT:    [[ADD:%.*]] = fadd fast float [[BC]], [[MUL]]
610; CHECK-NEXT:    ret float [[ADD]]
611;
612  %sub = fsub fast float 1.0, %c
613  %mul = fmul fast float %a, %sub
614  call void @use(float %mul)
615  %bc = fmul fast float %b, %c
616  %add = fadd fast float %bc, %mul
617  ret float %add
618}
619
620define float @lerp_extra_use3(float %a, float %b, float %c) {
621; CHECK-LABEL: @lerp_extra_use3(
622; CHECK-NEXT:    [[SUB:%.*]] = fsub fast float 1.000000e+00, [[C:%.*]]
623; CHECK-NEXT:    call void @use(float [[SUB]])
624; CHECK-NEXT:    [[MUL:%.*]] = fmul fast float [[A:%.*]], [[SUB]]
625; CHECK-NEXT:    [[BC:%.*]] = fmul fast float [[B:%.*]], [[C]]
626; CHECK-NEXT:    [[ADD:%.*]] = fadd fast float [[BC]], [[MUL]]
627; CHECK-NEXT:    ret float [[ADD]]
628;
629  %sub = fsub fast float 1.0, %c
630  call void @use(float %sub)
631  %mul = fmul fast float %a, %sub
632  %bc = fmul fast float %b, %c
633  %add = fadd fast float %bc, %mul
634  ret float %add
635}
636