xref: /llvm-project/llvm/test/Transforms/InstSimplify/strictfp-fsub.ll (revision eb2558c5666cea0e509ae334ac20cf0f54a92032)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -passes=instsimplify -S | FileCheck %s
3
4;
5; constrained fsub
6;
7
8;
9; fsub X, +0 ==> X
10;
11
12define float @fsub_x_p0_defaultenv(float %a) #0 {
13; CHECK-LABEL: @fsub_x_p0_defaultenv(
14; CHECK-NEXT:    ret float [[A:%.*]]
15;
16  %ret = call float @llvm.experimental.constrained.fsub.f32(float %a, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore")
17  ret float %ret
18}
19
20; Missing nnan: must not fire.
21define float @fsub_x_p0_ebmaytrap(float %a) #0 {
22; CHECK-LABEL: @fsub_x_p0_ebmaytrap(
23; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[A:%.*]], float 0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
24; CHECK-NEXT:    ret float [[RET]]
25;
26  %ret = call float @llvm.experimental.constrained.fsub.f32(float %a, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
27  ret float %ret
28}
29
30define float @fsub_nnan_x_p0_ebmaytrap(float %a) #0 {
31; CHECK-LABEL: @fsub_nnan_x_p0_ebmaytrap(
32; CHECK-NEXT:    ret float [[A:%.*]]
33;
34  %ret = call nnan float @llvm.experimental.constrained.fsub.f32(float %a, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
35  ret float %ret
36}
37
38; Missing nnan: must not fire.
39define float @fsub_x_p0_ebstrict(float %a) #0 {
40; CHECK-LABEL: @fsub_x_p0_ebstrict(
41; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[A:%.*]], float 0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.strict")
42; CHECK-NEXT:    ret float [[RET]]
43;
44  %ret = call float @llvm.experimental.constrained.fsub.f32(float %a, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.strict")
45  ret float %ret
46}
47
48; The instruction is expected to remain, but the result isn't used.
49define float @fsub_nnan_x_p0_ebstrict(float %a) #0 {
50; CHECK-LABEL: @fsub_nnan_x_p0_ebstrict(
51; CHECK-NEXT:    [[RET:%.*]] = call nnan float @llvm.experimental.constrained.fsub.f32(float [[A:%.*]], float 0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.strict")
52; CHECK-NEXT:    ret float [[A]]
53;
54  %ret = call nnan float @llvm.experimental.constrained.fsub.f32(float %a, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.strict")
55  ret float %ret
56}
57
58; Test with a fast math flag set but that flag is not "nnan".
59define float @fsub_ninf_x_p0_ebstrict(float %a) #0 {
60; CHECK-LABEL: @fsub_ninf_x_p0_ebstrict(
61; CHECK-NEXT:    [[RET:%.*]] = call ninf float @llvm.experimental.constrained.fsub.f32(float [[A:%.*]], float 0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.strict")
62; CHECK-NEXT:    ret float [[RET]]
63;
64  %ret = call ninf float @llvm.experimental.constrained.fsub.f32(float %a, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.strict")
65  ret float %ret
66}
67
68; Round to -inf and if x is zero then the result is -0.0: must not fire
69define float @fsub_x_p0_neginf(float %a) #0 {
70; CHECK-LABEL: @fsub_x_p0_neginf(
71; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[A:%.*]], float 0.000000e+00, metadata !"round.downward", metadata !"fpexcept.ignore")
72; CHECK-NEXT:    ret float [[RET]]
73;
74  %ret = call float @llvm.experimental.constrained.fsub.f32(float %a, float 0.0, metadata !"round.downward", metadata !"fpexcept.ignore")
75  ret float %ret
76}
77
78; Dynamic rounding means the rounding mode might be to -inf:
79; Round to -inf and if x is zero then the result is -0.0: must not fire
80define float @fsub_x_p0_dynamic(float %a) #0 {
81; CHECK-LABEL: @fsub_x_p0_dynamic(
82; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[A:%.*]], float 0.000000e+00, metadata !"round.dynamic", metadata !"fpexcept.ignore")
83; CHECK-NEXT:    ret float [[RET]]
84;
85  %ret = call float @llvm.experimental.constrained.fsub.f32(float %a, float 0.0, metadata !"round.dynamic", metadata !"fpexcept.ignore")
86  ret float %ret
87}
88
89; With nsz we don't have to worry about -0.0 so the transform is valid.
90define float @fsub_nsz_x_p0_neginf(float %a) #0 {
91; CHECK-LABEL: @fsub_nsz_x_p0_neginf(
92; CHECK-NEXT:    ret float [[A:%.*]]
93;
94  %ret = call nsz float @llvm.experimental.constrained.fsub.f32(float %a, float 0.0, metadata !"round.downward", metadata !"fpexcept.ignore")
95  ret float %ret
96}
97
98; With nsz we don't have to worry about -0.0 so the transform is valid.
99define float @fsub_nsz_x_p0_dynamic(float %a) #0 {
100; CHECK-LABEL: @fsub_nsz_x_p0_dynamic(
101; CHECK-NEXT:    ret float [[A:%.*]]
102;
103  %ret = call nsz float @llvm.experimental.constrained.fsub.f32(float %a, float 0.0, metadata !"round.dynamic", metadata !"fpexcept.ignore")
104  ret float %ret
105}
106
107;
108; fsub X, -0 ==> X, when we know X is not -0
109; (fast math flag: nsz)
110;
111
112define float @fold_fsub_nsz_x_n0_defaultenv(float %a) #0 {
113; CHECK-LABEL: @fold_fsub_nsz_x_n0_defaultenv(
114; CHECK-NEXT:    ret float [[A:%.*]]
115;
116  %sub = call nsz float @llvm.experimental.constrained.fsub.f32(float %a, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore")
117  ret float %sub
118}
119
120; Missing nnan: must not fire.
121define float @fold_fsub_nsz_x_n0_ebmaytrap(float %a) #0 {
122; CHECK-LABEL: @fold_fsub_nsz_x_n0_ebmaytrap(
123; CHECK-NEXT:    [[SUB:%.*]] = call nsz float @llvm.experimental.constrained.fsub.f32(float [[A:%.*]], float -0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
124; CHECK-NEXT:    ret float [[SUB]]
125;
126  %sub = call nsz float @llvm.experimental.constrained.fsub.f32(float %a, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
127  ret float %sub
128}
129
130define float @fold_fsub_nnan_nsz_x_n0_ebmaytrap(float %a) #0 {
131; CHECK-LABEL: @fold_fsub_nnan_nsz_x_n0_ebmaytrap(
132; CHECK-NEXT:    ret float [[A:%.*]]
133;
134  %sub = call nnan nsz float @llvm.experimental.constrained.fsub.f32(float %a, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
135  ret float %sub
136}
137
138; Missing nnan: must not fire.
139define float @fold_fsub_nsz_x_n0_ebstrict(float %a) #0 {
140; CHECK-LABEL: @fold_fsub_nsz_x_n0_ebstrict(
141; CHECK-NEXT:    [[SUB:%.*]] = call nsz float @llvm.experimental.constrained.fsub.f32(float [[A:%.*]], float -0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.strict")
142; CHECK-NEXT:    ret float [[SUB]]
143;
144  %sub = call nsz float @llvm.experimental.constrained.fsub.f32(float %a, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.strict")
145  ret float %sub
146}
147
148; The instruction is expected to remain, but the result isn't used.
149define float @fold_fsub_nsz_nnan_x_n0_ebstrict(float %a) #0 {
150; CHECK-LABEL: @fold_fsub_nsz_nnan_x_n0_ebstrict(
151; CHECK-NEXT:    [[SUB:%.*]] = call nnan nsz float @llvm.experimental.constrained.fsub.f32(float [[A:%.*]], float -0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.strict")
152; CHECK-NEXT:    ret float [[A]]
153;
154  %sub = call nsz nnan float @llvm.experimental.constrained.fsub.f32(float %a, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.strict")
155  ret float %sub
156}
157
158;
159; fsub X, -0 ==> X, when we know X is not -0
160; (No "nsz" flags)
161;
162
163define float @fold_fsub_fabs_x_n0_defaultenv(float %a) #0 {
164; CHECK-LABEL: @fold_fsub_fabs_x_n0_defaultenv(
165; CHECK-NEXT:    [[ABSA:%.*]] = call float @llvm.fabs.f32(float [[A:%.*]]) #[[ATTR0:[0-9]+]]
166; CHECK-NEXT:    ret float [[ABSA]]
167;
168  %absa = call float @llvm.fabs.f32(float %a) #0
169  %sub = call float @llvm.experimental.constrained.fsub.f32(float %absa, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore")
170  ret float %sub
171}
172
173; Missing nnan: must not fire.
174define float @fold_fsub_fabs_x_n0_ebmaytrap(float %a) #0 {
175; CHECK-LABEL: @fold_fsub_fabs_x_n0_ebmaytrap(
176; CHECK-NEXT:    [[ABSA:%.*]] = call float @llvm.fabs.f32(float [[A:%.*]]) #[[ATTR0]]
177; CHECK-NEXT:    [[SUB:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[ABSA]], float -0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
178; CHECK-NEXT:    ret float [[SUB]]
179;
180  %absa = call float @llvm.fabs.f32(float %a) #0
181  %sub = call float @llvm.experimental.constrained.fsub.f32(float %absa, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
182  ret float %sub
183}
184
185define float @fold_fsub_fabs_nnan_x_n0_ebmaytrap(float %a) #0 {
186; CHECK-LABEL: @fold_fsub_fabs_nnan_x_n0_ebmaytrap(
187; CHECK-NEXT:    [[ABSA:%.*]] = call float @llvm.fabs.f32(float [[A:%.*]]) #[[ATTR0]]
188; CHECK-NEXT:    ret float [[ABSA]]
189;
190  %absa = call float @llvm.fabs.f32(float %a) #0
191  %sub = call nnan float @llvm.experimental.constrained.fsub.f32(float %absa, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
192  ret float %sub
193}
194
195; Missing nnan: must not fire.
196define float @fold_fsub_fabs_x_n0_ebstrict(float %a) #0 {
197; CHECK-LABEL: @fold_fsub_fabs_x_n0_ebstrict(
198; CHECK-NEXT:    [[ABSA:%.*]] = call float @llvm.fabs.f32(float [[A:%.*]]) #[[ATTR0]]
199; CHECK-NEXT:    [[SUB:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[ABSA]], float -0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.strict")
200; CHECK-NEXT:    ret float [[SUB]]
201;
202  %absa = call float @llvm.fabs.f32(float %a) #0
203  %sub = call float @llvm.experimental.constrained.fsub.f32(float %absa, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.strict")
204  ret float %sub
205}
206
207; The instruction is expected to remain, but the result isn't used.
208define float @fold_fsub_fabs_nnan_x_n0_ebstrict(float %a) #0 {
209; CHECK-LABEL: @fold_fsub_fabs_nnan_x_n0_ebstrict(
210; CHECK-NEXT:    [[ABSA:%.*]] = call float @llvm.fabs.f32(float [[A:%.*]]) #[[ATTR0]]
211; CHECK-NEXT:    [[SUB:%.*]] = call nnan float @llvm.experimental.constrained.fsub.f32(float [[ABSA]], float -0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.strict")
212; CHECK-NEXT:    ret float [[ABSA]]
213;
214  %absa = call float @llvm.fabs.f32(float %a) #0
215  %sub = call nnan float @llvm.experimental.constrained.fsub.f32(float %absa, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.strict")
216  ret float %sub
217}
218
219define float @fold_fsub_sitofp_x_n0_defaultenv(i32 %a) #0 {
220; CHECK-LABEL: @fold_fsub_sitofp_x_n0_defaultenv(
221; CHECK-NEXT:    [[FPA:%.*]] = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
222; CHECK-NEXT:    ret float [[FPA]]
223;
224  %fpa = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 %a, metadata !"round.tonearest", metadata !"fpexcept.ignore")
225  %sub = call float @llvm.experimental.constrained.fsub.f32(float %fpa, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore")
226  ret float %sub
227}
228
229;
230; fsub -0.0, (fneg X) ==> X
231;
232
233define float @fsub_fneg_n0_fnX_defaultenv(float %a) #0 {
234; CHECK-LABEL: @fsub_fneg_n0_fnX_defaultenv(
235; CHECK-NEXT:    ret float [[A:%.*]]
236;
237  %nega = fneg float %a
238  %ret = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.ignore")
239  ret float %ret
240}
241
242; Missing nnan: must not fire.
243define float @fsub_fneg_n0_fnX_ebmaytrap(float %a) #0 {
244; CHECK-LABEL: @fsub_fneg_n0_fnX_ebmaytrap(
245; CHECK-NEXT:    [[NEGA:%.*]] = fneg float [[A:%.*]]
246; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[NEGA]], metadata !"round.tonearest", metadata !"fpexcept.maytrap")
247; CHECK-NEXT:    ret float [[RET]]
248;
249  %nega = fneg float %a
250  %ret = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
251  ret float %ret
252}
253
254define float @fsub_fneg_nnan_n0_fnX_ebmaytrap(float %a) #0 {
255; CHECK-LABEL: @fsub_fneg_nnan_n0_fnX_ebmaytrap(
256; CHECK-NEXT:    ret float [[A:%.*]]
257;
258  %nega = fneg float %a
259  %ret = call nnan float @llvm.experimental.constrained.fsub.f32(float -0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
260  ret float %ret
261}
262
263; Missing nnan: must not fire.
264define float @fsub_fneg_n0_fnX_ebstrict(float %a) #0 {
265; CHECK-LABEL: @fsub_fneg_n0_fnX_ebstrict(
266; CHECK-NEXT:    [[NEGA:%.*]] = fneg float [[A:%.*]]
267; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[NEGA]], metadata !"round.tonearest", metadata !"fpexcept.strict")
268; CHECK-NEXT:    ret float [[RET]]
269;
270  %nega = fneg float %a
271  %ret = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.strict")
272  ret float %ret
273}
274
275; The instruction is expected to remain, but the result isn't used.
276define float @fsub_fneg_nnan_n0_fnX_ebstrict(float %a) #0 {
277; CHECK-LABEL: @fsub_fneg_nnan_n0_fnX_ebstrict(
278; CHECK-NEXT:    [[NEGA:%.*]] = fneg float [[A:%.*]]
279; CHECK-NEXT:    [[RET:%.*]] = call nnan float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[NEGA]], metadata !"round.tonearest", metadata !"fpexcept.strict")
280; CHECK-NEXT:    ret float [[A]]
281;
282  %nega = fneg float %a
283  %ret = call nnan float @llvm.experimental.constrained.fsub.f32(float -0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.strict")
284  ret float %ret
285}
286
287;
288; fsub -0.0, (fsub -0.0, X) ==> X
289;
290
291; TODO: This won't fire without m_FNeg() knowing the constrained intrinsics.
292define float @fsub_fsub_n0_fnX_defaultenv(float %a) #0 {
293; CHECK-LABEL: @fsub_fsub_n0_fnX_defaultenv(
294; CHECK-NEXT:    [[NEGA:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
295; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[NEGA]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
296; CHECK-NEXT:    ret float [[RET]]
297;
298  %nega = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore")
299  %ret = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.ignore")
300  ret float %ret
301}
302
303; Missing nnan: must not fire.
304define float @fsub_fsub_n0_fnX_ebmaytrap(float %a) #0 {
305; CHECK-LABEL: @fsub_fsub_n0_fnX_ebmaytrap(
306; CHECK-NEXT:    [[NEGA:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.maytrap")
307; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[NEGA]], metadata !"round.tonearest", metadata !"fpexcept.maytrap")
308; CHECK-NEXT:    ret float [[RET]]
309;
310  %nega = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
311  %ret = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
312  ret float %ret
313}
314
315; TODO: This won't fire without m_FNeg() knowing the constrained intrinsics.
316define float @fsub_fsub_nnan_n0_fnX_ebmaytrap(float %a) #0 {
317; CHECK-LABEL: @fsub_fsub_nnan_n0_fnX_ebmaytrap(
318; CHECK-NEXT:    [[NEGA:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.maytrap")
319; CHECK-NEXT:    [[RET:%.*]] = call nnan float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[NEGA]], metadata !"round.tonearest", metadata !"fpexcept.maytrap")
320; CHECK-NEXT:    ret float [[RET]]
321;
322  %nega = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
323  %ret = call nnan float @llvm.experimental.constrained.fsub.f32(float -0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
324  ret float %ret
325}
326
327; Missing nnan: must not fire.
328define float @fsub_fsub_n0_fnX_ebstrict(float %a) #0 {
329; CHECK-LABEL: @fsub_fsub_n0_fnX_ebstrict(
330; CHECK-NEXT:    [[NEGA:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.strict")
331; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[NEGA]], metadata !"round.tonearest", metadata !"fpexcept.strict")
332; CHECK-NEXT:    ret float [[RET]]
333;
334  %nega = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
335  %ret = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.strict")
336  ret float %ret
337}
338
339; TODO: This won't fire without m_FNeg() knowing the constrained intrinsics.
340define float @fsub_fsub_nnan_n0_fnX_ebstrict(float %a) #0 {
341; CHECK-LABEL: @fsub_fsub_nnan_n0_fnX_ebstrict(
342; CHECK-NEXT:    [[NEGA:%.*]] = call nnan float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.strict")
343; CHECK-NEXT:    [[RET:%.*]] = call nnan float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[NEGA]], metadata !"round.tonearest", metadata !"fpexcept.strict")
344; CHECK-NEXT:    ret float [[RET]]
345;
346  %nega = call nnan float @llvm.experimental.constrained.fsub.f32(float -0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
347  %ret = call nnan float @llvm.experimental.constrained.fsub.f32(float -0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.strict")
348  ret float %ret
349}
350
351;
352; fsub 0.0, (fneg X) ==> X if signed zeros are ignored.
353;
354
355define float @fsub_fneg_nsz_p0_fnX_defaultenv(float %a) #0 {
356; CHECK-LABEL: @fsub_fneg_nsz_p0_fnX_defaultenv(
357; CHECK-NEXT:    ret float [[A:%.*]]
358;
359  %nega = fneg float %a
360  %ret = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.ignore")
361  ret float %ret
362}
363
364; Missing nnan: must not fire.
365define float @fsub_fneg_nsz_p0_fnX_ebmaytrap(float %a) #0 {
366; CHECK-LABEL: @fsub_fneg_nsz_p0_fnX_ebmaytrap(
367; CHECK-NEXT:    [[NEGA:%.*]] = fneg float [[A:%.*]]
368; CHECK-NEXT:    [[RET:%.*]] = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[NEGA]], metadata !"round.tonearest", metadata !"fpexcept.maytrap")
369; CHECK-NEXT:    ret float [[RET]]
370;
371  %nega = fneg float %a
372  %ret = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
373  ret float %ret
374}
375
376define float @fsub_fneg_nsz_nnan_p0_fnX_ebmaytrap(float %a) #0 {
377; CHECK-LABEL: @fsub_fneg_nsz_nnan_p0_fnX_ebmaytrap(
378; CHECK-NEXT:    ret float [[A:%.*]]
379;
380  %nega = fneg float %a
381  %ret = call nnan nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
382  ret float %ret
383}
384
385; Missing nnan: must not fire.
386define float @fsub_fneg_nsz_p0_fnX_ebstrict(float %a) #0 {
387; CHECK-LABEL: @fsub_fneg_nsz_p0_fnX_ebstrict(
388; CHECK-NEXT:    [[NEGA:%.*]] = fneg float [[A:%.*]]
389; CHECK-NEXT:    [[RET:%.*]] = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[NEGA]], metadata !"round.tonearest", metadata !"fpexcept.strict")
390; CHECK-NEXT:    ret float [[RET]]
391;
392  %nega = fneg float %a
393  %ret = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.strict")
394  ret float %ret
395}
396
397; The instruction is expected to remain, but the result isn't used.
398define float @fsub_fneg_nnan_nsz_p0_fnX_ebstrict(float %a) #0 {
399; CHECK-LABEL: @fsub_fneg_nnan_nsz_p0_fnX_ebstrict(
400; CHECK-NEXT:    [[NEGA:%.*]] = fneg float [[A:%.*]]
401; CHECK-NEXT:    [[RET:%.*]] = call nnan nsz float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[NEGA]], metadata !"round.tonearest", metadata !"fpexcept.strict")
402; CHECK-NEXT:    ret float [[A]]
403;
404  %nega = fneg float %a
405  %ret = call nnan nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.strict")
406  ret float %ret
407}
408
409;
410; fsub 0.0, (fsub 0.0, X) ==> X if signed zeros are ignored.
411;
412
413; TODO: Need constrained intrinsic support in m_FNeg() and m_FSub to fire.
414define float @fsub_fsub_p0_nsz_fnX_defaultenv(float %a) #0 {
415; CHECK-LABEL: @fsub_fsub_p0_nsz_fnX_defaultenv(
416; CHECK-NEXT:    [[NEGA:%.*]] = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
417; CHECK-NEXT:    [[RET:%.*]] = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[NEGA]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
418; CHECK-NEXT:    ret float [[RET]]
419;
420  %nega = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore")
421  %ret = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.ignore")
422  ret float %ret
423}
424
425; Missing nnan: must not fire.
426define float @fsub_fsub_nsz_p0_fnX_ebmaytrap(float %a) #0 {
427; CHECK-LABEL: @fsub_fsub_nsz_p0_fnX_ebmaytrap(
428; CHECK-NEXT:    [[NEGA:%.*]] = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.maytrap")
429; CHECK-NEXT:    [[RET:%.*]] = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[NEGA]], metadata !"round.tonearest", metadata !"fpexcept.maytrap")
430; CHECK-NEXT:    ret float [[RET]]
431;
432  %nega = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
433  %ret = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
434  ret float %ret
435}
436
437; TODO: Need constrained intrinsic support in m_FNeg() and m_FSub to fire.
438define float @fsub_fsub_nnan_nsz_p0_fnX_ebmaytrap(float %a) #0 {
439; CHECK-LABEL: @fsub_fsub_nnan_nsz_p0_fnX_ebmaytrap(
440; CHECK-NEXT:    [[NEGA:%.*]] = call nnan nsz float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.maytrap")
441; CHECK-NEXT:    [[RET:%.*]] = call nnan nsz float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[NEGA]], metadata !"round.tonearest", metadata !"fpexcept.maytrap")
442; CHECK-NEXT:    ret float [[RET]]
443;
444  %nega = call nnan nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
445  %ret = call nnan nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
446  ret float %ret
447}
448
449; Missing nnan: must not fire.
450define float @fsub_fsub_nsz_p0_fnX_ebstrict(float %a) #0 {
451; CHECK-LABEL: @fsub_fsub_nsz_p0_fnX_ebstrict(
452; CHECK-NEXT:    [[NEGA:%.*]] = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.strict")
453; CHECK-NEXT:    [[RET:%.*]] = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[NEGA]], metadata !"round.tonearest", metadata !"fpexcept.strict")
454; CHECK-NEXT:    ret float [[RET]]
455;
456  %nega = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
457  %ret = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.strict")
458  ret float %ret
459}
460
461; TODO: Need constrained intrinsic support in m_FNeg() and m_FSub to fire.
462define float @fsub_fsub_nnan_nsz_p0_fnX_ebstrict(float %a) #0 {
463; CHECK-LABEL: @fsub_fsub_nnan_nsz_p0_fnX_ebstrict(
464; CHECK-NEXT:    [[NEGA:%.*]] = call nnan nsz float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.strict")
465; CHECK-NEXT:    [[RET:%.*]] = call nnan nsz float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[NEGA]], metadata !"round.tonearest", metadata !"fpexcept.strict")
466; CHECK-NEXT:    ret float [[RET]]
467;
468  %nega = call nnan nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
469  %ret = call nnan nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.strict")
470  ret float %ret
471}
472
473;
474; fsub nnan x, x ==> 0.0
475;
476
477; Missing nnan: must not fire.
478define float @fsub_x_x_defaultenv(float %a) #0 {
479; CHECK-LABEL: @fsub_x_x_defaultenv(
480; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[A:%.*]], float [[A]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
481; CHECK-NEXT:    ret float [[RET]]
482;
483  %ret = call float @llvm.experimental.constrained.fsub.f32(float %a, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore")
484  ret float %ret
485}
486
487define float @fsub_nnan_x_x_defaultenv(float %a) #0 {
488; CHECK-LABEL: @fsub_nnan_x_x_defaultenv(
489; CHECK-NEXT:    ret float 0.000000e+00
490;
491  %ret = call nnan float @llvm.experimental.constrained.fsub.f32(float %a, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore")
492  ret float %ret
493}
494
495; Missing nnan: must not fire.
496define float @fsub_x_x_ebmaytrap(float %a) #0 {
497; CHECK-LABEL: @fsub_x_x_ebmaytrap(
498; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[A:%.*]], float [[A]], metadata !"round.tonearest", metadata !"fpexcept.maytrap")
499; CHECK-NEXT:    ret float [[RET]]
500;
501  %ret = call float @llvm.experimental.constrained.fsub.f32(float %a, float %a, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
502  ret float %ret
503}
504
505; TODO: This will fold if we allow non-default floating point environments.
506define float @fsub_nnan_x_x_ebmaytrap(float %a) #0 {
507; CHECK-LABEL: @fsub_nnan_x_x_ebmaytrap(
508; CHECK-NEXT:    [[RET:%.*]] = call nnan float @llvm.experimental.constrained.fsub.f32(float [[A:%.*]], float [[A]], metadata !"round.tonearest", metadata !"fpexcept.maytrap")
509; CHECK-NEXT:    ret float [[RET]]
510;
511  %ret = call nnan float @llvm.experimental.constrained.fsub.f32(float %a, float %a, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
512  ret float %ret
513}
514
515; Missing nnan: must not fire.
516define float @fsub_x_x_ebstrict(float %a) #0 {
517; CHECK-LABEL: @fsub_x_x_ebstrict(
518; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[A:%.*]], float [[A]], metadata !"round.tonearest", metadata !"fpexcept.strict")
519; CHECK-NEXT:    ret float [[RET]]
520;
521  %ret = call float @llvm.experimental.constrained.fsub.f32(float %a, float %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
522  ret float %ret
523}
524
525; TODO: This will fold if we allow non-default floating point environments.
526; The instruction is expected to remain, but the result isn't used.
527define float @fsub_nnan_x_x_ebstrict(float %a) #0 {
528; CHECK-LABEL: @fsub_nnan_x_x_ebstrict(
529; CHECK-NEXT:    [[RET:%.*]] = call nnan float @llvm.experimental.constrained.fsub.f32(float [[A:%.*]], float [[A]], metadata !"round.tonearest", metadata !"fpexcept.strict")
530; CHECK-NEXT:    ret float [[RET]]
531;
532  %ret = call nnan float @llvm.experimental.constrained.fsub.f32(float %a, float %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
533  ret float %ret
534}
535
536;
537; Y - (Y - X) --> X
538;
539
540; Missing nsz and reassoc: must not fire
541define float @fsub_fsub_y_x_x_defaultenv(float %x, float %y) #0 {
542; CHECK-LABEL: @fsub_fsub_y_x_x_defaultenv(
543; CHECK-NEXT:    [[INNER:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
544; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y]], float [[INNER]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
545; CHECK-NEXT:    ret float [[RET]]
546;
547  %inner = call float @llvm.experimental.constrained.fsub.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore")
548  %ret = call float @llvm.experimental.constrained.fsub.f32(float %y, float %inner, metadata !"round.tonearest", metadata !"fpexcept.ignore")
549  ret float %ret
550}
551
552; TODO: Need constrained intrinsic support in m_c_FAdd() and m_FSub to fire.
553define float @fsub_fsub_fmf_y_x_x_defaultenv(float %x, float %y) #0 {
554; CHECK-LABEL: @fsub_fsub_fmf_y_x_x_defaultenv(
555; CHECK-NEXT:    [[INNER:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
556; CHECK-NEXT:    [[RET:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[Y]], float [[INNER]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
557; CHECK-NEXT:    ret float [[RET]]
558;
559  %inner = call float @llvm.experimental.constrained.fsub.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore")
560  %ret = call nsz reassoc float @llvm.experimental.constrained.fsub.f32(float %y, float %inner, metadata !"round.tonearest", metadata !"fpexcept.ignore")
561  ret float %ret
562}
563
564; TODO: Consider how alternate rounding modes can break these transforms.
565
566; The "fpexcept.maytrap" instruction must _not_ be folded into the
567; "fpexcept.ignore" instruction. This must not fire.
568define float @fsub_fsub_fmf_y_x_x_ebmaytrap_defaultenv(float %x, float %y) #0 {
569; CHECK-LABEL: @fsub_fsub_fmf_y_x_x_ebmaytrap_defaultenv(
570; CHECK-NEXT:    [[INNER:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.maytrap")
571; CHECK-NEXT:    [[RET:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[Y]], float [[INNER]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
572; CHECK-NEXT:    ret float [[RET]]
573;
574  %inner = call float @llvm.experimental.constrained.fsub.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
575  %ret = call nsz reassoc float @llvm.experimental.constrained.fsub.f32(float %y, float %inner, metadata !"round.tonearest", metadata !"fpexcept.ignore")
576  ret float %ret
577}
578
579; Missing nsz and reassoc: must not fire
580define float @fsub_fsub_y_x_x_ebmaytrap(float %x, float %y) #0 {
581; CHECK-LABEL: @fsub_fsub_y_x_x_ebmaytrap(
582; CHECK-NEXT:    [[INNER:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.maytrap")
583; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y]], float [[INNER]], metadata !"round.tonearest", metadata !"fpexcept.maytrap")
584; CHECK-NEXT:    ret float [[RET]]
585;
586  %inner = call float @llvm.experimental.constrained.fsub.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
587  %ret = call float @llvm.experimental.constrained.fsub.f32(float %y, float %inner, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
588  ret float %ret
589}
590
591; TODO: Need constrained intrinsic support in m_c_FAdd() and m_FSub to fire.
592define float @fsub_fsub_fmf_y_x_x_ebmaytrap(float %x, float %y) #0 {
593; CHECK-LABEL: @fsub_fsub_fmf_y_x_x_ebmaytrap(
594; CHECK-NEXT:    [[INNER:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.maytrap")
595; CHECK-NEXT:    [[RET:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[Y]], float [[INNER]], metadata !"round.tonearest", metadata !"fpexcept.maytrap")
596; CHECK-NEXT:    ret float [[RET]]
597;
598  %inner = call float @llvm.experimental.constrained.fsub.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
599  %ret = call nsz reassoc float @llvm.experimental.constrained.fsub.f32(float %y, float %inner, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
600  ret float %ret
601}
602
603; Missing nsz and reassoc: must not fire
604define float @fsub_fsub_y_x_x_ebstrict(float %x, float %y) #0 {
605; CHECK-LABEL: @fsub_fsub_y_x_x_ebstrict(
606; CHECK-NEXT:    [[INNER:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.strict")
607; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y]], float [[INNER]], metadata !"round.tonearest", metadata !"fpexcept.strict")
608; CHECK-NEXT:    ret float [[RET]]
609;
610  %inner = call float @llvm.experimental.constrained.fsub.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.strict")
611  %ret = call float @llvm.experimental.constrained.fsub.f32(float %y, float %inner, metadata !"round.tonearest", metadata !"fpexcept.strict")
612  ret float %ret
613}
614
615; TODO: Need constrained intrinsic support in m_c_FAdd() and m_FSub to fire.
616define float @fsub_fsub_fmf_y_x_x_ebstrict(float %x, float %y) #0 {
617; CHECK-LABEL: @fsub_fsub_fmf_y_x_x_ebstrict(
618; CHECK-NEXT:    [[INNER:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.strict")
619; CHECK-NEXT:    [[RET:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[Y]], float [[INNER]], metadata !"round.tonearest", metadata !"fpexcept.strict")
620; CHECK-NEXT:    ret float [[RET]]
621;
622  %inner = call float @llvm.experimental.constrained.fsub.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.strict")
623  %ret = call nsz reassoc float @llvm.experimental.constrained.fsub.f32(float %y, float %inner, metadata !"round.tonearest", metadata !"fpexcept.strict")
624  ret float %ret
625}
626
627;
628; (X + Y) - Y --> X
629; TODO: Missing IR matcher support means these won't fire.
630;
631
632; Missing nsz and reassoc: must not fire
633define float @fadd_fsub_x_y_y_defaultenv(float %x, float %y) #0 {
634; CHECK-LABEL: @fadd_fsub_x_y_y_defaultenv(
635; CHECK-NEXT:    [[INNER:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X:%.*]], float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
636; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[INNER]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
637; CHECK-NEXT:    ret float [[RET]]
638;
639  %inner = call float @llvm.experimental.constrained.fadd.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore")
640  %ret = call float @llvm.experimental.constrained.fsub.f32(float %inner, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore")
641  ret float %ret
642}
643
644; TODO: Need constrained intrinsic support in m_c_FAdd() and m_FSub to fire.
645define float @fadd_fsub_fmf_x_y_y_defaultenv(float %x, float %y) #0 {
646; CHECK-LABEL: @fadd_fsub_fmf_x_y_y_defaultenv(
647; CHECK-NEXT:    [[INNER:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X:%.*]], float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
648; CHECK-NEXT:    [[RET:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[INNER]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
649; CHECK-NEXT:    ret float [[RET]]
650;
651  %inner = call float @llvm.experimental.constrained.fadd.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore")
652  %ret = call nsz reassoc float @llvm.experimental.constrained.fsub.f32(float %inner, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore")
653  ret float %ret
654}
655
656; The "fpexcept.maytrap" instruction must _not_ be folded into the
657; "fpexcept.ignore" instruction. This must not fire.
658define float @fadd_fsub_fmf_x_y_y_ebmaytrap_defaultenv(float %x, float %y) #0 {
659; CHECK-LABEL: @fadd_fsub_fmf_x_y_y_ebmaytrap_defaultenv(
660; CHECK-NEXT:    [[INNER:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X:%.*]], float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.maytrap")
661; CHECK-NEXT:    [[RET:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[INNER]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
662; CHECK-NEXT:    ret float [[RET]]
663;
664  %inner = call float @llvm.experimental.constrained.fadd.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
665  %ret = call nsz reassoc float @llvm.experimental.constrained.fsub.f32(float %inner, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore")
666  ret float %ret
667}
668
669; Missing nsz and reassoc: must not fire
670define float @fadd_fsub_x_y_y_ebmaytrap(float %x, float %y) #0 {
671; CHECK-LABEL: @fadd_fsub_x_y_y_ebmaytrap(
672; CHECK-NEXT:    [[INNER:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X:%.*]], float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.maytrap")
673; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[INNER]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.maytrap")
674; CHECK-NEXT:    ret float [[RET]]
675;
676  %inner = call float @llvm.experimental.constrained.fadd.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
677  %ret = call float @llvm.experimental.constrained.fsub.f32(float %inner, float %y, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
678  ret float %ret
679}
680
681; TODO: Need constrained intrinsic support in m_c_FAdd() and m_FSub to fire.
682define float @fadd_fsub_fmf_x_y_y_ebmaytrap(float %x, float %y) #0 {
683; CHECK-LABEL: @fadd_fsub_fmf_x_y_y_ebmaytrap(
684; CHECK-NEXT:    [[INNER:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X:%.*]], float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.maytrap")
685; CHECK-NEXT:    [[RET:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[INNER]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.maytrap")
686; CHECK-NEXT:    ret float [[RET]]
687;
688  %inner = call float @llvm.experimental.constrained.fadd.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
689  %ret = call nsz reassoc float @llvm.experimental.constrained.fsub.f32(float %inner, float %y, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
690  ret float %ret
691}
692
693; Missing nsz and reassoc: must not fire
694define float @fadd_fsub_x_y_y_ebstrict(float %x, float %y) #0 {
695; CHECK-LABEL: @fadd_fsub_x_y_y_ebstrict(
696; CHECK-NEXT:    [[INNER:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X:%.*]], float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.strict")
697; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[INNER]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.strict")
698; CHECK-NEXT:    ret float [[RET]]
699;
700  %inner = call float @llvm.experimental.constrained.fadd.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.strict")
701  %ret = call float @llvm.experimental.constrained.fsub.f32(float %inner, float %y, metadata !"round.tonearest", metadata !"fpexcept.strict")
702  ret float %ret
703}
704
705; TODO: Need constrained intrinsic support in m_c_FAdd() and m_FSub to fire.
706define float @fadd_fsub_fmf_x_y_y_ebstrict(float %x, float %y) #0 {
707; CHECK-LABEL: @fadd_fsub_fmf_x_y_y_ebstrict(
708; CHECK-NEXT:    [[INNER:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X:%.*]], float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.strict")
709; CHECK-NEXT:    [[RET:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[INNER]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.strict")
710; CHECK-NEXT:    ret float [[RET]]
711;
712  %inner = call float @llvm.experimental.constrained.fadd.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.strict")
713  %ret = call nsz reassoc float @llvm.experimental.constrained.fsub.f32(float %inner, float %y, metadata !"round.tonearest", metadata !"fpexcept.strict")
714  ret float %ret
715}
716
717declare float @llvm.fabs.f32(float)
718declare <2 x float> @llvm.fabs.v2f32(<2 x float>)
719
720declare float @llvm.experimental.constrained.fadd.f32(float, float, metadata, metadata)
721declare float @llvm.experimental.constrained.fsub.f32(float, float, metadata, metadata)
722
723declare float @llvm.experimental.constrained.sitofp.f32.i32(i32, metadata, metadata)
724
725attributes #0 = { strictfp }
726