1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -passes=instsimplify -S | FileCheck %s
3
4; fneg (fsub -0.0, X) ==> X
5define float @fsub_-0_x(float %a) #0 {
6; CHECK-LABEL: @fsub_-0_x(
7; CHECK-NEXT:    [[T1:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0:[0-9]+]]
8; CHECK-NEXT:    [[RET:%.*]] = fneg float [[T1]]
9; CHECK-NEXT:    ret float [[RET]]
10;
11  %t1 = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
12  %ret = fneg float %t1
13  ret float %ret
14}
15
16define <2 x float> @fsub_-0_x_vec(<2 x float> %a) #0 {
17; CHECK-LABEL: @fsub_-0_x_vec(
18; CHECK-NEXT:    [[T1:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float -0.000000e+00, float -0.000000e+00>, <2 x float> [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
19; CHECK-NEXT:    [[RET:%.*]] = fneg <2 x float> [[T1]]
20; CHECK-NEXT:    ret <2 x float> [[RET]]
21;
22  %t1 = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float><float -0.0, float -0.0>, <2 x float> %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
23  %ret = fneg <2 x float> %t1
24  ret <2 x float> %ret
25}
26
27define <2 x float> @fsub_-0_x_vec_undef_elts(<2 x float> %a) #0 {
28; CHECK-LABEL: @fsub_-0_x_vec_undef_elts(
29; CHECK-NEXT:    [[T1:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float -0.000000e+00, float undef>, <2 x float> [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
30; CHECK-NEXT:    [[RET:%.*]] = fneg <2 x float> [[T1]]
31; CHECK-NEXT:    ret <2 x float> [[RET]]
32;
33  %t1 = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float><float -0.0, float undef>, <2 x float> %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
34  %ret = fneg <2 x float> %t1
35  ret <2 x float> %ret
36}
37
38define <2 x float> @fsub_negzero_vec_undef_elts(<2 x float> %x) #0 {
39; CHECK-LABEL: @fsub_negzero_vec_undef_elts(
40; CHECK-NEXT:    [[R:%.*]] = call nsz <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float undef, float -0.000000e+00>, <2 x float> [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
41; CHECK-NEXT:    ret <2 x float> [[R]]
42;
43  %r = call nsz <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float><float undef, float -0.0>, <2 x float> %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
44  ret <2 x float> %r
45}
46
47; fsub -0.0, (fsub -0.0, X) ==> X
48define float @fsub_-0_-0_x(float %a) #0 {
49; CHECK-LABEL: @fsub_-0_-0_x(
50; CHECK-NEXT:    [[T1:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
51; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[T1]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
52; CHECK-NEXT:    ret float [[RET]]
53;
54  %t1 = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
55  %ret = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
56  ret float %ret
57}
58
59; fsub -0.0, (fneg X) ==> X
60define float @fneg_x(float %a) #0 {
61; CHECK-LABEL: @fneg_x(
62; CHECK-NEXT:    ret float [[A:%.*]]
63;
64  %t1 = fneg float %a
65  %ret = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
66  ret float %ret
67}
68
69define <2 x float> @fsub_-0_-0_x_vec(<2 x float> %a) #0 {
70; CHECK-LABEL: @fsub_-0_-0_x_vec(
71; CHECK-NEXT:    [[T1:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float -0.000000e+00, float -0.000000e+00>, <2 x float> [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
72; CHECK-NEXT:    [[RET:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float -0.000000e+00, float -0.000000e+00>, <2 x float> [[T1]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
73; CHECK-NEXT:    ret <2 x float> [[RET]]
74;
75  %t1 = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float><float -0.0, float -0.0>, <2 x float> %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
76  %ret = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float><float -0.0, float -0.0>, <2 x float> %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
77  ret <2 x float> %ret
78}
79
80define <2 x float> @fneg_x_vec(<2 x float> %a) #0 {
81; CHECK-LABEL: @fneg_x_vec(
82; CHECK-NEXT:    ret <2 x float> [[A:%.*]]
83;
84  %t1 = fneg <2 x float> %a
85  %ret = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float><float -0.0, float -0.0>, <2 x float> %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
86  ret <2 x float> %ret
87}
88
89define <2 x float> @fsub_-0_-0_x_vec_undef_elts(<2 x float> %a) #0 {
90; CHECK-LABEL: @fsub_-0_-0_x_vec_undef_elts(
91; CHECK-NEXT:    [[T1:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float undef, float -0.000000e+00>, <2 x float> [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
92; CHECK-NEXT:    [[RET:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float -0.000000e+00, float undef>, <2 x float> [[T1]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
93; CHECK-NEXT:    ret <2 x float> [[RET]]
94;
95  %t1 = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float><float undef, float -0.0>, <2 x float> %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
96  %ret = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float><float -0.0, float undef>, <2 x float> %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
97  ret <2 x float> %ret
98}
99
100define <2 x float> @fneg_x_vec_undef_elts(<2 x float> %a) #0 {
101; CHECK-LABEL: @fneg_x_vec_undef_elts(
102; CHECK-NEXT:    ret <2 x float> [[A:%.*]]
103;
104  %t1 = fneg <2 x float> %a
105  %ret = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float><float -0.0, float undef>, <2 x float> %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
106  ret <2 x float> %ret
107}
108
109; fsub -0.0, (fsub 0.0, X) != X
110define float @fsub_-0_0_x(float %a) #0 {
111; CHECK-LABEL: @fsub_-0_0_x(
112; CHECK-NEXT:    [[T1:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
113; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[T1]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
114; CHECK-NEXT:    ret float [[RET]]
115;
116  %t1 = call float @llvm.experimental.constrained.fsub.f32(float 0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
117  %ret = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
118  ret float %ret
119}
120
121; fsub 0.0, (fsub -0.0, X) != X
122define float @fsub_0_-0_x(float %a) #0 {
123; CHECK-LABEL: @fsub_0_-0_x(
124; CHECK-NEXT:    [[T1:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
125; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[T1]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
126; CHECK-NEXT:    ret float [[RET]]
127;
128  %t1 = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
129  %ret = call float @llvm.experimental.constrained.fsub.f32(float 0.0, float %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
130  ret float %ret
131}
132
133; fsub X, 0 ==> X
134define float @fsub_x_0(float %x) #0 {
135; CHECK-LABEL: @fsub_x_0(
136; CHECK-NEXT:    ret float [[X:%.*]]
137;
138  %r = call float @llvm.experimental.constrained.fsub.f32(float %x, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
139  ret float %r
140}
141
142define <2 x float> @fsub_x_0_vec_undef(<2 x float> %x) #0 {
143; CHECK-LABEL: @fsub_x_0_vec_undef(
144; CHECK-NEXT:    ret <2 x float> [[X:%.*]]
145;
146  %r = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> %x, <2 x float><float undef, float 0.0>, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
147  ret <2 x float> %r
148}
149
150; fadd X, -0 ==> X
151define float @fadd_x_n0(float %a) #0 {
152; CHECK-LABEL: @fadd_x_n0(
153; CHECK-NEXT:    ret float [[A:%.*]]
154;
155  %ret = call float @llvm.experimental.constrained.fadd.f32(float %a, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
156  ret float %ret
157}
158
159define <2 x float> @fadd_x_n0_vec_undef_elt(<2 x float> %a) #0 {
160; CHECK-LABEL: @fadd_x_n0_vec_undef_elt(
161; CHECK-NEXT:    ret <2 x float> [[A:%.*]]
162;
163  %ret = call <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> %a, <2 x float> <float -0.0, float undef>, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
164  ret <2 x float> %ret
165}
166
167; fadd X, 0 ==> X
168define float @fadd_x_p0(float %a) #0 {
169; CHECK-LABEL: @fadd_x_p0(
170; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[A:%.*]], float 0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
171; CHECK-NEXT:    ret float [[RET]]
172;
173  %ret = call float @llvm.experimental.constrained.fadd.f32(float %a, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
174  ret float %ret
175}
176
177define <2 x float> @fadd_x_p0_vec_undef_elt(<2 x float> %a) #0 {
178; CHECK-LABEL: @fadd_x_p0_vec_undef_elt(
179; CHECK-NEXT:    [[RET:%.*]] = call <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> [[A:%.*]], <2 x float> <float 0.000000e+00, float undef>, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
180; CHECK-NEXT:    ret <2 x float> [[RET]]
181;
182  %ret = call <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> %a, <2 x float> <float 0.0, float undef>, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
183  ret <2 x float> %ret
184}
185
186; fmul X, 1.0 ==> X
187define double @fmul_X_1(double %a) #0 {
188; CHECK-LABEL: @fmul_X_1(
189; CHECK-NEXT:    ret double [[A:%.*]]
190;
191  %b = call double @llvm.experimental.constrained.fmul.f64(double 1.0, double %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
192  ret double %b
193}
194
195; Originally PR2642
196define <4 x float> @fmul_X_1_vec(<4 x float> %x) {
197; CHECK-LABEL: @fmul_X_1_vec(
198; CHECK-NEXT:    ret <4 x float> [[X:%.*]]
199;
200  %m = call <4 x float> @llvm.experimental.constrained.fmul.v4f32(<4 x float> %x, <4 x float> <float 1.0, float 1.0, float 1.0, float 1.0>, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
201  ret <4 x float> %m
202}
203
204; fdiv X, 1.0 ==> X
205define float @fdiv_x_1(float %a) #0 {
206; CHECK-LABEL: @fdiv_x_1(
207; CHECK-NEXT:    ret float [[A:%.*]]
208;
209  %ret = call float @llvm.experimental.constrained.fdiv.f32(float %a, float 1.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
210
211  ret float %ret
212}
213
214
215; The fabs can't be eliminated because llvm.experimental.constrained.sqrt.f32 may return -0 or NaN with
216; an arbitrary sign bit.
217define float @fabs_sqrt(float %a) #0 {
218; CHECK-LABEL: @fabs_sqrt(
219; CHECK-NEXT:    [[SQRT:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
220; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SQRT]])
221; CHECK-NEXT:    ret float [[FABS]]
222;
223  %sqrt = call float @llvm.experimental.constrained.sqrt.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
224  %fabs = call float @llvm.fabs.f32(float %sqrt)
225  ret float %fabs
226}
227
228; The fabs can't be eliminated because the nnan sqrt may still return -0.
229define float @fabs_sqrt_nnan(float %a) #0 {
230; CHECK-LABEL: @fabs_sqrt_nnan(
231; CHECK-NEXT:    [[SQRT:%.*]] = call nnan float @llvm.experimental.constrained.sqrt.f32(float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
232; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SQRT]])
233; CHECK-NEXT:    ret float [[FABS]]
234;
235  %sqrt = call nnan float @llvm.experimental.constrained.sqrt.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
236  %fabs = call float @llvm.fabs.f32(float %sqrt)
237  ret float %fabs
238}
239
240; The fabs can't be eliminated because the nsz sqrt may still return NaN.
241define float @fabs_sqrt_nsz(float %a) #0 {
242; CHECK-LABEL: @fabs_sqrt_nsz(
243; CHECK-NEXT:    [[SQRT:%.*]] = call nsz float @llvm.experimental.constrained.sqrt.f32(float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
244; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SQRT]])
245; CHECK-NEXT:    ret float [[FABS]]
246;
247  %sqrt = call nsz float @llvm.experimental.constrained.sqrt.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
248  %fabs = call float @llvm.fabs.f32(float %sqrt)
249  ret float %fabs
250}
251
252; The fabs can be eliminated because we're nsz and nnan.
253define float @fabs_sqrt_nnan_nsz(float %a) #0 {
254; CHECK-LABEL: @fabs_sqrt_nnan_nsz(
255; CHECK-NEXT:    [[SQRT:%.*]] = call nnan nsz float @llvm.experimental.constrained.sqrt.f32(float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
256; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SQRT]])
257; CHECK-NEXT:    ret float [[FABS]]
258;
259  %sqrt = call nnan nsz float @llvm.experimental.constrained.sqrt.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
260  %fabs = call float @llvm.fabs.f32(float %sqrt)
261  ret float %fabs
262}
263
264; The second fabs can be eliminated because the operand to sqrt cannot be -0.
265define float @fabs_sqrt_nnan_fabs(float %a) #0 {
266; CHECK-LABEL: @fabs_sqrt_nnan_fabs(
267; CHECK-NEXT:    [[B:%.*]] = call float @llvm.fabs.f32(float [[A:%.*]])
268; CHECK-NEXT:    [[SQRT:%.*]] = call nnan float @llvm.experimental.constrained.sqrt.f32(float [[B]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
269; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SQRT]])
270; CHECK-NEXT:    ret float [[FABS]]
271;
272  %b = call float @llvm.fabs.f32(float %a)
273  %sqrt = call nnan float @llvm.experimental.constrained.sqrt.f32(float %b, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
274  %fabs = call float @llvm.fabs.f32(float %sqrt)
275  ret float %fabs
276}
277
278; Y - (Y - X) --> X
279
280define float @fsub_fsub_common_op(float %x, float %y) #0 {
281; CHECK-LABEL: @fsub_fsub_common_op(
282; CHECK-NEXT:    [[S:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
283; CHECK-NEXT:    [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[Y]], float [[S]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
284; CHECK-NEXT:    ret float [[R]]
285;
286  %s = call float @llvm.experimental.constrained.fsub.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
287  %r = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float %y, float %s, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
288  ret float %r
289}
290
291define <2 x float> @fsub_fsub_common_op_vec(<2 x float> %x, <2 x float> %y) #0 {
292; CHECK-LABEL: @fsub_fsub_common_op_vec(
293; CHECK-NEXT:    [[S:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> [[Y:%.*]], <2 x float> [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
294; CHECK-NEXT:    [[R:%.*]] = call reassoc nsz <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> [[Y]], <2 x float> [[S]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
295; CHECK-NEXT:    ret <2 x float> [[R]]
296;
297  %s = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> %y, <2 x float> %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
298  %r = call reassoc nsz <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> %y, <2 x float> %s, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
299  ret <2 x float> %r
300}
301
302; Negative test - fsub is not commutative.
303; Y - (X - Y) --> (Y - X) + Y (canonicalized)
304
305define float @fsub_fsub_wrong_common_op(float %x, float %y) #0 {
306; CHECK-LABEL: @fsub_fsub_wrong_common_op(
307; CHECK-NEXT:    [[S:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[X:%.*]], float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
308; CHECK-NEXT:    [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[Y]], float [[S]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
309; CHECK-NEXT:    ret float [[R]]
310;
311  %s = call float @llvm.experimental.constrained.fsub.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
312  %r = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float %y, float %s, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
313  ret float %r
314}
315
316; Negative test - negated operand needed.
317; (Y - X) - Y --> -X
318
319define float @fsub_fsub_common_op_wrong_commute(float %x, float %y) #0 {
320; CHECK-LABEL: @fsub_fsub_common_op_wrong_commute(
321; CHECK-NEXT:    [[S:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
322; CHECK-NEXT:    [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[S]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
323; CHECK-NEXT:    ret float [[R]]
324;
325  %s = call float @llvm.experimental.constrained.fsub.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
326  %r = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float %s, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
327  ret float %r
328}
329
330; Negative test - fsub is not commutative.
331; (X - Y) - Y --> ?
332
333define float @fsub_fsub_wrong_common_op_wrong_commute(float %x, float %y) #0 {
334; CHECK-LABEL: @fsub_fsub_wrong_common_op_wrong_commute(
335; CHECK-NEXT:    [[S:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[X:%.*]], float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
336; CHECK-NEXT:    [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[S]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
337; CHECK-NEXT:    ret float [[R]]
338;
339  %s = call float @llvm.experimental.constrained.fsub.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
340  %r = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float %s, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
341  ret float %r
342}
343
344; (Y + X) - Y --> X
345
346define float @fadd_fsub_common_op(float %x, float %y) #0 {
347; CHECK-LABEL: @fadd_fsub_common_op(
348; CHECK-NEXT:    [[A:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
349; CHECK-NEXT:    [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[A]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
350; CHECK-NEXT:    ret float [[R]]
351;
352  %a = call float @llvm.experimental.constrained.fadd.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
353  %r = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float %a, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
354  ret float %r
355}
356
357; (X + Y) - Y --> X
358
359define <2 x float> @fadd_fsub_common_op_commute_vec(<2 x float> %x, <2 x float> %y) #0 {
360; CHECK-LABEL: @fadd_fsub_common_op_commute_vec(
361; CHECK-NEXT:    [[A:%.*]] = call <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> [[X:%.*]], <2 x float> [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
362; CHECK-NEXT:    [[R:%.*]] = call reassoc nsz <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> [[A]], <2 x float> [[Y]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
363; CHECK-NEXT:    ret <2 x float> [[R]]
364;
365  %a = call <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> %x, <2 x float> %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
366  %r = call reassoc nsz <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> %a, <2 x float> %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
367  ret <2 x float> %r
368}
369
370; Negative test - negated operand needed.
371; Y - (Y + X) --> -X
372
373define float @fadd_fsub_common_op_wrong_commute(float %x, float %y) #0 {
374; CHECK-LABEL: @fadd_fsub_common_op_wrong_commute(
375; CHECK-NEXT:    [[A:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
376; CHECK-NEXT:    [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[Y]], float [[A]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
377; CHECK-NEXT:    ret float [[R]]
378;
379  %a = call float @llvm.experimental.constrained.fadd.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
380  %r = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float %y, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
381  ret float %r
382}
383
384; Negative test - negated operand needed.
385; Y - (X + Y) --> -X
386
387define float @fadd_fsub_common_op_wrong_commute_commute(float %x, float %y) #0 {
388; CHECK-LABEL: @fadd_fsub_common_op_wrong_commute_commute(
389; CHECK-NEXT:    [[A:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X:%.*]], float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
390; CHECK-NEXT:    [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[Y]], float [[A]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
391; CHECK-NEXT:    ret float [[R]]
392;
393  %a = call float @llvm.experimental.constrained.fadd.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
394  %r = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float %y, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
395  ret float %r
396}
397
398; Y + (X - Y) --> X
399
400define <2 x float> @fsub_fadd_common_op_vec(<2 x float> %x, <2 x float> %y) #0 {
401; CHECK-LABEL: @fsub_fadd_common_op_vec(
402; CHECK-NEXT:    [[S:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> [[X:%.*]], <2 x float> [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
403; CHECK-NEXT:    [[R:%.*]] = call reassoc nsz <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> [[Y]], <2 x float> [[S]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
404; CHECK-NEXT:    ret <2 x float> [[R]]
405;
406  %s = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> %x, <2 x float> %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
407  %r = call reassoc nsz <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> %y, <2 x float> %s, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
408  ret <2 x float> %r
409}
410
411; (X - Y) + Y --> X
412
413define float @fsub_fadd_common_op_commute(float %x, float %y) #0 {
414; CHECK-LABEL: @fsub_fadd_common_op_commute(
415; CHECK-NEXT:    [[S:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[X:%.*]], float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
416; CHECK-NEXT:    [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fadd.f32(float [[S]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
417; CHECK-NEXT:    ret float [[R]]
418;
419  %s = call float @llvm.experimental.constrained.fsub.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
420  %r = call reassoc nsz float @llvm.experimental.constrained.fadd.f32(float %s, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
421  ret float %r
422}
423
424; Negative test.
425; Y + (Y - X) --> ?
426
427define float @fsub_fadd_common_op_wrong_commute(float %x, float %y) #0 {
428; CHECK-LABEL: @fsub_fadd_common_op_wrong_commute(
429; CHECK-NEXT:    [[S:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
430; CHECK-NEXT:    [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fadd.f32(float [[Y]], float [[S]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
431; CHECK-NEXT:    ret float [[R]]
432;
433  %s = call float @llvm.experimental.constrained.fsub.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
434  %r = call reassoc nsz float @llvm.experimental.constrained.fadd.f32(float %y, float %s, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
435  ret float %r
436}
437
438; Negative test.
439; (Y - X) + Y --> ?
440
441define float @fsub_fadd_common_op_wrong_commute_commute(float %x, float %y) #0 {
442; CHECK-LABEL: @fsub_fadd_common_op_wrong_commute_commute(
443; CHECK-NEXT:    [[S:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
444; CHECK-NEXT:    [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fadd.f32(float [[S]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
445; CHECK-NEXT:    ret float [[R]]
446;
447  %s = call float @llvm.experimental.constrained.fsub.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
448  %r = call reassoc nsz float @llvm.experimental.constrained.fadd.f32(float %s, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
449  ret float %r
450}
451
452; Originally PR46627 - https://bugs.llvm.org/show_bug.cgi?id=46627
453
454define float @maxnum_with_poszero_op(float %a) #0 {
455; CHECK-LABEL: @maxnum_with_poszero_op(
456; CHECK-NEXT:    [[MAX:%.*]] = call float @llvm.experimental.constrained.maxnum.f32(float [[A:%.*]], float 0.000000e+00, metadata !"fpexcept.ignore") #[[ATTR0]]
457; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float [[MAX]])
458; CHECK-NEXT:    ret float [[FABS]]
459;
460  %max = call float @llvm.experimental.constrained.maxnum.f32(float %a, float 0.0, metadata !"fpexcept.ignore") #0
461  %fabs = call float @llvm.fabs.f32(float %max)
462  ret float %fabs
463}
464
465define float @maxnum_with_poszero_op_commute(float %a) #0 {
466; CHECK-LABEL: @maxnum_with_poszero_op_commute(
467; CHECK-NEXT:    [[SQRT:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
468; CHECK-NEXT:    [[MAX:%.*]] = call float @llvm.experimental.constrained.maxnum.f32(float 0.000000e+00, float [[SQRT]], metadata !"fpexcept.ignore") #[[ATTR0]]
469; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float [[MAX]])
470; CHECK-NEXT:    ret float [[FABS]]
471;
472  %sqrt = call float @llvm.experimental.constrained.sqrt.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
473  %max = call float @llvm.experimental.constrained.maxnum.f32(float 0.0, float %sqrt, metadata !"fpexcept.ignore") #0
474  %fabs = call float @llvm.fabs.f32(float %max)
475  ret float %fabs
476}
477
478define float @maxnum_with_negzero_op(float %a) #0 {
479; CHECK-LABEL: @maxnum_with_negzero_op(
480; CHECK-NEXT:    [[NNAN:%.*]] = call nnan float @llvm.experimental.constrained.sqrt.f32(float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
481; CHECK-NEXT:    [[FABSA:%.*]] = call float @llvm.fabs.f32(float [[NNAN]])
482; CHECK-NEXT:    [[MAX:%.*]] = call float @llvm.experimental.constrained.maxnum.f32(float -0.000000e+00, float [[FABSA]], metadata !"fpexcept.ignore") #[[ATTR0]]
483; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float [[MAX]])
484; CHECK-NEXT:    ret float [[FABS]]
485;
486  %nnan = call nnan float @llvm.experimental.constrained.sqrt.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
487  %fabsa = call float @llvm.fabs.f32(float %nnan)
488  %max = call float @llvm.experimental.constrained.maxnum.f32(float -0.0, float %fabsa, metadata !"fpexcept.ignore") #0
489  %fabs = call float @llvm.fabs.f32(float %max)
490  ret float %fabs
491}
492
493define float @maxnum_with_negzero_op_commute(float %a) #0 {
494; CHECK-LABEL: @maxnum_with_negzero_op_commute(
495; CHECK-NEXT:    [[NNAN:%.*]] = call nnan float @llvm.experimental.constrained.sqrt.f32(float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
496; CHECK-NEXT:    [[FABSA:%.*]] = call float @llvm.fabs.f32(float [[NNAN]])
497; CHECK-NEXT:    [[MAX:%.*]] = call float @llvm.experimental.constrained.maxnum.f32(float [[FABSA]], float -0.000000e+00, metadata !"fpexcept.ignore") #[[ATTR0]]
498; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float [[MAX]])
499; CHECK-NEXT:    ret float [[FABS]]
500;
501  %nnan = call nnan float @llvm.experimental.constrained.sqrt.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
502  %fabsa = call float @llvm.fabs.f32(float %nnan)
503  %max = call float @llvm.experimental.constrained.maxnum.f32(float %fabsa, float -0.0, metadata !"fpexcept.ignore") #0
504  %fabs = call float @llvm.fabs.f32(float %max)
505  ret float %fabs
506}
507
508; If an operand is strictly greater than 0.0, we know the sign of the result of maxnum.
509
510define float @maxnum_with_pos_one_op(float %a) #0 {
511; CHECK-LABEL: @maxnum_with_pos_one_op(
512; CHECK-NEXT:    [[MAX:%.*]] = call float @llvm.experimental.constrained.maxnum.f32(float [[A:%.*]], float 1.000000e+00, metadata !"fpexcept.ignore") #[[ATTR0]]
513; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float [[MAX]])
514; CHECK-NEXT:    ret float [[FABS]]
515;
516  %max = call float @llvm.experimental.constrained.maxnum.f32(float %a, float 1.0, metadata !"fpexcept.ignore") #0
517  %fabs = call float @llvm.fabs.f32(float %max)
518  ret float %fabs
519}
520
521declare float @llvm.fabs.f32(float)
522declare <2 x float> @llvm.fabs.v2f32(<2 x float>)
523
524declare float @llvm.experimental.constrained.fadd.f32(float, float, metadata, metadata) #0
525declare <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float>, <2 x float>, metadata, metadata) #0
526
527declare float @llvm.experimental.constrained.fsub.f32(float, float, metadata, metadata) #0
528declare <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float>, <2 x float>, metadata, metadata) #0
529
530declare double @llvm.experimental.constrained.fmul.f64(double, double, metadata, metadata) #0
531declare <4 x float> @llvm.experimental.constrained.fmul.v4f32(<4 x float>, <4 x float>, metadata, metadata) #0
532
533declare float @llvm.experimental.constrained.fdiv.f32(float, float, metadata, metadata) #0
534
535declare float @llvm.experimental.constrained.maxnum.f32(float, float, metadata) #0
536declare float @llvm.experimental.constrained.sqrt.f32(float, metadata, metadata) #0
537
538attributes #0 = { strictfp }
539