xref: /llvm-project/llvm/test/Transforms/InstSimplify/floating-point-arithmetic-strictfp.ll (revision 38fffa630ee80163dc65e759392ad29798905679)
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")
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")
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> splat (float -0.000000e+00), <2 x float> [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
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")
23  %ret = fneg <2 x float> %t1
24  ret <2 x float> %ret
25}
26
27define <2 x float> @fsub_-0_x_vec_poison_elts(<2 x float> %a) #0 {
28; CHECK-LABEL: @fsub_-0_x_vec_poison_elts(
29; CHECK-NEXT:    [[T1:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float -0.000000e+00, float poison>, <2 x float> [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
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 poison>, <2 x float> %a, metadata !"round.tonearest", metadata !"fpexcept.ignore")
34  %ret = fneg <2 x float> %t1
35  ret <2 x float> %ret
36}
37
38define <2 x float> @fsub_negzero_vec_poison_elts(<2 x float> %x) #0 {
39; CHECK-LABEL: @fsub_negzero_vec_poison_elts(
40; CHECK-NEXT:    [[R:%.*]] = call nsz <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float poison, float -0.000000e+00>, <2 x float> [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
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 poison, float -0.0>, <2 x float> %x, metadata !"round.tonearest", metadata !"fpexcept.ignore")
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")
51; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[T1]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
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")
55  %ret = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore")
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")
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> splat (float -0.000000e+00), <2 x float> [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
72; CHECK-NEXT:    [[RET:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> splat (float -0.000000e+00), <2 x float> [[T1]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
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")
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")
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")
86  ret <2 x float> %ret
87}
88
89define <2 x float> @fsub_-0_-0_x_vec_poison_elts(<2 x float> %a) #0 {
90; CHECK-LABEL: @fsub_-0_-0_x_vec_poison_elts(
91; CHECK-NEXT:    [[T1:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float poison, float -0.000000e+00>, <2 x float> [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
92; CHECK-NEXT:    [[RET:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float -0.000000e+00, float poison>, <2 x float> [[T1]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
93; CHECK-NEXT:    ret <2 x float> [[RET]]
94;
95  %t1 = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float><float poison, float -0.0>, <2 x float> %a, metadata !"round.tonearest", metadata !"fpexcept.ignore")
96  %ret = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float><float -0.0, float poison>, <2 x float> %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore")
97  ret <2 x float> %ret
98}
99
100define <2 x float> @fneg_x_vec_poison_elts(<2 x float> %a) #0 {
101; CHECK-LABEL: @fneg_x_vec_poison_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 poison>, <2 x float> %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore")
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")
113; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[T1]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
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")
117  %ret = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore")
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")
125; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[T1]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
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")
129  %ret = call float @llvm.experimental.constrained.fsub.f32(float 0.0, float %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore")
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")
139  ret float %r
140}
141
142define <2 x float> @fsub_x_0_vec_poison(<2 x float> %x) #0 {
143; CHECK-LABEL: @fsub_x_0_vec_poison(
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 poison, float 0.0>, metadata !"round.tonearest", metadata !"fpexcept.ignore")
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")
156  ret float %ret
157}
158
159define <2 x float> @fadd_x_n0_vec_poison_elt(<2 x float> %a) #0 {
160; CHECK-LABEL: @fadd_x_n0_vec_poison_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 poison>, metadata !"round.tonearest", metadata !"fpexcept.ignore")
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")
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")
174  ret float %ret
175}
176
177define <2 x float> @fadd_x_p0_vec_poison_elt(<2 x float> %a) #0 {
178; CHECK-LABEL: @fadd_x_p0_vec_poison_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 poison>, metadata !"round.tonearest", metadata !"fpexcept.ignore")
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 poison>, metadata !"round.tonearest", metadata !"fpexcept.ignore")
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")
192  ret double %b
193}
194
195; Originally PR2642
196define <4 x float> @fmul_X_1_vec(<4 x float> %x) #0 {
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")
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")
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")
220; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SQRT]]) #[[ATTR0:[0-9]+]]
221; CHECK-NEXT:    ret float [[FABS]]
222;
223  %sqrt = call float @llvm.experimental.constrained.sqrt.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore")
224  %fabs = call float @llvm.fabs.f32(float %sqrt) #0
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")
232; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SQRT]]) #[[ATTR0]]
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")
236  %fabs = call float @llvm.fabs.f32(float %sqrt) #0
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")
244; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SQRT]]) #[[ATTR0]]
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")
248  %fabs = call float @llvm.fabs.f32(float %sqrt) #0
249  ret float %fabs
250}
251
252define float @fabs_sqrt_nnan_nsz(float %a) #0 {
253; CHECK-LABEL: @fabs_sqrt_nnan_nsz(
254; CHECK-NEXT:    [[SQRT:%.*]] = call nnan nsz float @llvm.experimental.constrained.sqrt.f32(float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
255; CHECK-NEXT:    ret float [[SQRT]]
256;
257  %sqrt = call nnan nsz float @llvm.experimental.constrained.sqrt.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore")
258  %fabs = call float @llvm.fabs.f32(float %sqrt) #0
259  ret float %fabs
260}
261
262define float @fabs_sqrt_nnan_fabs(float %a) #0 {
263; CHECK-LABEL: @fabs_sqrt_nnan_fabs(
264; CHECK-NEXT:    [[B:%.*]] = call float @llvm.fabs.f32(float [[A:%.*]]) #[[ATTR0]]
265; CHECK-NEXT:    [[SQRT:%.*]] = call nnan float @llvm.experimental.constrained.sqrt.f32(float [[B]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
266; CHECK-NEXT:    ret float [[SQRT]]
267;
268  %b = call float @llvm.fabs.f32(float %a) #0
269  %sqrt = call nnan float @llvm.experimental.constrained.sqrt.f32(float %b, metadata !"round.tonearest", metadata !"fpexcept.ignore")
270  %fabs = call float @llvm.fabs.f32(float %sqrt) #0
271  ret float %fabs
272}
273
274; Y - (Y - X) --> X
275
276define float @fsub_fsub_common_op(float %x, float %y) #0 {
277; CHECK-LABEL: @fsub_fsub_common_op(
278; CHECK-NEXT:    [[S:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
279; CHECK-NEXT:    [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[Y]], float [[S]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
280; CHECK-NEXT:    ret float [[R]]
281;
282  %s = call float @llvm.experimental.constrained.fsub.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore")
283  %r = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float %y, float %s, metadata !"round.tonearest", metadata !"fpexcept.ignore")
284  ret float %r
285}
286
287define <2 x float> @fsub_fsub_common_op_vec(<2 x float> %x, <2 x float> %y) #0 {
288; CHECK-LABEL: @fsub_fsub_common_op_vec(
289; 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")
290; 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")
291; CHECK-NEXT:    ret <2 x float> [[R]]
292;
293  %s = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> %y, <2 x float> %x, metadata !"round.tonearest", metadata !"fpexcept.ignore")
294  %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")
295  ret <2 x float> %r
296}
297
298; Negative test - fsub is not commutative.
299; Y - (X - Y) --> (Y - X) + Y (canonicalized)
300
301define float @fsub_fsub_wrong_common_op(float %x, float %y) #0 {
302; CHECK-LABEL: @fsub_fsub_wrong_common_op(
303; CHECK-NEXT:    [[S:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[X:%.*]], float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
304; CHECK-NEXT:    [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[Y]], float [[S]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
305; CHECK-NEXT:    ret float [[R]]
306;
307  %s = call float @llvm.experimental.constrained.fsub.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore")
308  %r = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float %y, float %s, metadata !"round.tonearest", metadata !"fpexcept.ignore")
309  ret float %r
310}
311
312; Negative test - negated operand needed.
313; (Y - X) - Y --> -X
314
315define float @fsub_fsub_common_op_wrong_commute(float %x, float %y) #0 {
316; CHECK-LABEL: @fsub_fsub_common_op_wrong_commute(
317; CHECK-NEXT:    [[S:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
318; CHECK-NEXT:    [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[S]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
319; CHECK-NEXT:    ret float [[R]]
320;
321  %s = call float @llvm.experimental.constrained.fsub.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore")
322  %r = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float %s, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore")
323  ret float %r
324}
325
326; Negative test - fsub is not commutative.
327; (X - Y) - Y --> ?
328
329define float @fsub_fsub_wrong_common_op_wrong_commute(float %x, float %y) #0 {
330; CHECK-LABEL: @fsub_fsub_wrong_common_op_wrong_commute(
331; CHECK-NEXT:    [[S:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[X:%.*]], float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
332; CHECK-NEXT:    [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[S]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
333; CHECK-NEXT:    ret float [[R]]
334;
335  %s = call float @llvm.experimental.constrained.fsub.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore")
336  %r = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float %s, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore")
337  ret float %r
338}
339
340; (Y + X) - Y --> X
341
342define float @fadd_fsub_common_op(float %x, float %y) #0 {
343; CHECK-LABEL: @fadd_fsub_common_op(
344; CHECK-NEXT:    [[A:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
345; CHECK-NEXT:    [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[A]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
346; CHECK-NEXT:    ret float [[R]]
347;
348  %a = call float @llvm.experimental.constrained.fadd.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore")
349  %r = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float %a, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore")
350  ret float %r
351}
352
353; (X + Y) - Y --> X
354
355define <2 x float> @fadd_fsub_common_op_commute_vec(<2 x float> %x, <2 x float> %y) #0 {
356; CHECK-LABEL: @fadd_fsub_common_op_commute_vec(
357; 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")
358; 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")
359; CHECK-NEXT:    ret <2 x float> [[R]]
360;
361  %a = call <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> %x, <2 x float> %y, metadata !"round.tonearest", metadata !"fpexcept.ignore")
362  %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")
363  ret <2 x float> %r
364}
365
366; Negative test - negated operand needed.
367; Y - (Y + X) --> -X
368
369define float @fadd_fsub_common_op_wrong_commute(float %x, float %y) #0 {
370; CHECK-LABEL: @fadd_fsub_common_op_wrong_commute(
371; CHECK-NEXT:    [[A:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
372; CHECK-NEXT:    [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[Y]], float [[A]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
373; CHECK-NEXT:    ret float [[R]]
374;
375  %a = call float @llvm.experimental.constrained.fadd.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore")
376  %r = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float %y, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore")
377  ret float %r
378}
379
380; Negative test - negated operand needed.
381; Y - (X + Y) --> -X
382
383define float @fadd_fsub_common_op_wrong_commute_commute(float %x, float %y) #0 {
384; CHECK-LABEL: @fadd_fsub_common_op_wrong_commute_commute(
385; CHECK-NEXT:    [[A:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X:%.*]], float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
386; CHECK-NEXT:    [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[Y]], float [[A]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
387; CHECK-NEXT:    ret float [[R]]
388;
389  %a = call float @llvm.experimental.constrained.fadd.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore")
390  %r = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float %y, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore")
391  ret float %r
392}
393
394; Y + (X - Y) --> X
395
396define <2 x float> @fsub_fadd_common_op_vec(<2 x float> %x, <2 x float> %y) #0 {
397; CHECK-LABEL: @fsub_fadd_common_op_vec(
398; 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")
399; 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")
400; CHECK-NEXT:    ret <2 x float> [[R]]
401;
402  %s = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> %x, <2 x float> %y, metadata !"round.tonearest", metadata !"fpexcept.ignore")
403  %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")
404  ret <2 x float> %r
405}
406
407; (X - Y) + Y --> X
408
409define float @fsub_fadd_common_op_commute(float %x, float %y) #0 {
410; CHECK-LABEL: @fsub_fadd_common_op_commute(
411; CHECK-NEXT:    [[S:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[X:%.*]], float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
412; CHECK-NEXT:    [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fadd.f32(float [[S]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
413; CHECK-NEXT:    ret float [[R]]
414;
415  %s = call float @llvm.experimental.constrained.fsub.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore")
416  %r = call reassoc nsz float @llvm.experimental.constrained.fadd.f32(float %s, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore")
417  ret float %r
418}
419
420; Negative test.
421; Y + (Y - X) --> ?
422
423define float @fsub_fadd_common_op_wrong_commute(float %x, float %y) #0 {
424; CHECK-LABEL: @fsub_fadd_common_op_wrong_commute(
425; CHECK-NEXT:    [[S:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
426; CHECK-NEXT:    [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fadd.f32(float [[Y]], float [[S]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
427; CHECK-NEXT:    ret float [[R]]
428;
429  %s = call float @llvm.experimental.constrained.fsub.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore")
430  %r = call reassoc nsz float @llvm.experimental.constrained.fadd.f32(float %y, float %s, metadata !"round.tonearest", metadata !"fpexcept.ignore")
431  ret float %r
432}
433
434; Negative test.
435; (Y - X) + Y --> ?
436
437define float @fsub_fadd_common_op_wrong_commute_commute(float %x, float %y) #0 {
438; CHECK-LABEL: @fsub_fadd_common_op_wrong_commute_commute(
439; CHECK-NEXT:    [[S:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
440; CHECK-NEXT:    [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fadd.f32(float [[S]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
441; CHECK-NEXT:    ret float [[R]]
442;
443  %s = call float @llvm.experimental.constrained.fsub.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore")
444  %r = call reassoc nsz float @llvm.experimental.constrained.fadd.f32(float %s, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore")
445  ret float %r
446}
447
448; Originally PR46627 - https://bugs.llvm.org/show_bug.cgi?id=46627
449
450define float @maxnum_with_poszero_op(float %a) #0 {
451; CHECK-LABEL: @maxnum_with_poszero_op(
452; CHECK-NEXT:    [[MAX:%.*]] = call float @llvm.experimental.constrained.maxnum.f32(float [[A:%.*]], float 0.000000e+00, metadata !"fpexcept.ignore")
453; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float [[MAX]]) #[[ATTR0]]
454; CHECK-NEXT:    ret float [[FABS]]
455;
456  %max = call float @llvm.experimental.constrained.maxnum.f32(float %a, float 0.0, metadata !"fpexcept.ignore")
457  %fabs = call float @llvm.fabs.f32(float %max) #0
458  ret float %fabs
459}
460
461define float @maxnum_with_poszero_op_commute(float %a) #0 {
462; CHECK-LABEL: @maxnum_with_poszero_op_commute(
463; CHECK-NEXT:    [[SQRT:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
464; CHECK-NEXT:    [[MAX:%.*]] = call float @llvm.experimental.constrained.maxnum.f32(float 0.000000e+00, float [[SQRT]], metadata !"fpexcept.ignore")
465; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float [[MAX]]) #[[ATTR0]]
466; CHECK-NEXT:    ret float [[FABS]]
467;
468  %sqrt = call float @llvm.experimental.constrained.sqrt.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore")
469  %max = call float @llvm.experimental.constrained.maxnum.f32(float 0.0, float %sqrt, metadata !"fpexcept.ignore")
470  %fabs = call float @llvm.fabs.f32(float %max) #0
471  ret float %fabs
472}
473
474define float @maxnum_with_negzero_op(float %a) #0 {
475; CHECK-LABEL: @maxnum_with_negzero_op(
476; CHECK-NEXT:    [[NNAN:%.*]] = call nnan float @llvm.experimental.constrained.sqrt.f32(float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
477; CHECK-NEXT:    [[FABSA:%.*]] = call float @llvm.fabs.f32(float [[NNAN]]) #[[ATTR0]]
478; CHECK-NEXT:    [[MAX:%.*]] = call float @llvm.experimental.constrained.maxnum.f32(float -0.000000e+00, float [[FABSA]], metadata !"fpexcept.ignore")
479; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float [[MAX]]) #[[ATTR0]]
480; CHECK-NEXT:    ret float [[FABS]]
481;
482  %nnan = call nnan float @llvm.experimental.constrained.sqrt.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore")
483  %fabsa = call float @llvm.fabs.f32(float %nnan) #0
484  %max = call float @llvm.experimental.constrained.maxnum.f32(float -0.0, float %fabsa, metadata !"fpexcept.ignore")
485  %fabs = call float @llvm.fabs.f32(float %max) #0
486  ret float %fabs
487}
488
489define float @maxnum_with_negzero_op_commute(float %a) #0 {
490; CHECK-LABEL: @maxnum_with_negzero_op_commute(
491; CHECK-NEXT:    [[NNAN:%.*]] = call nnan float @llvm.experimental.constrained.sqrt.f32(float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
492; CHECK-NEXT:    [[FABSA:%.*]] = call float @llvm.fabs.f32(float [[NNAN]]) #[[ATTR0]]
493; CHECK-NEXT:    [[MAX:%.*]] = call float @llvm.experimental.constrained.maxnum.f32(float [[FABSA]], float -0.000000e+00, metadata !"fpexcept.ignore")
494; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float [[MAX]]) #[[ATTR0]]
495; CHECK-NEXT:    ret float [[FABS]]
496;
497  %nnan = call nnan float @llvm.experimental.constrained.sqrt.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore")
498  %fabsa = call float @llvm.fabs.f32(float %nnan) #0
499  %max = call float @llvm.experimental.constrained.maxnum.f32(float %fabsa, float -0.0, metadata !"fpexcept.ignore")
500  %fabs = call float @llvm.fabs.f32(float %max) #0
501  ret float %fabs
502}
503
504; If an operand is strictly greater than 0.0, we know the sign of the result of maxnum.
505
506define float @maxnum_with_pos_one_op(float %a) #0 {
507; CHECK-LABEL: @maxnum_with_pos_one_op(
508; CHECK-NEXT:    [[MAX:%.*]] = call float @llvm.experimental.constrained.maxnum.f32(float [[A:%.*]], float 1.000000e+00, metadata !"fpexcept.ignore")
509; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float [[MAX]]) #[[ATTR0]]
510; CHECK-NEXT:    ret float [[FABS]]
511;
512  %max = call float @llvm.experimental.constrained.maxnum.f32(float %a, float 1.0, metadata !"fpexcept.ignore")
513  %fabs = call float @llvm.fabs.f32(float %max) #0
514  ret float %fabs
515}
516
517declare float @llvm.fabs.f32(float)
518declare <2 x float> @llvm.fabs.v2f32(<2 x float>)
519
520declare float @llvm.experimental.constrained.fadd.f32(float, float, metadata, metadata)
521declare <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float>, <2 x float>, metadata, metadata)
522
523declare float @llvm.experimental.constrained.fsub.f32(float, float, metadata, metadata)
524declare <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float>, <2 x float>, metadata, metadata)
525
526declare double @llvm.experimental.constrained.fmul.f64(double, double, metadata, metadata)
527declare <4 x float> @llvm.experimental.constrained.fmul.v4f32(<4 x float>, <4 x float>, metadata, metadata)
528
529declare float @llvm.experimental.constrained.fdiv.f32(float, float, metadata, metadata)
530
531declare float @llvm.experimental.constrained.maxnum.f32(float, float, metadata)
532declare float @llvm.experimental.constrained.sqrt.f32(float, metadata, metadata)
533
534attributes #0 = { strictfp }
535