1; RUN: llc < %s -mcpu=cyclone -verify-machineinstrs -aarch64-ccmp -aarch64-stress-ccmp | FileCheck %s
2target triple = "arm64-apple-ios"
3
4; CHECK: single_same
5; CHECK: cmp w0, #5
6; CHECK-NEXT: ccmp w1, #17, #4, ne
7; CHECK-NEXT: b.ne
8; CHECK: %if.then
9; CHECK: bl _foo
10; CHECK: %if.end
11define i32 @single_same(i32 %a, i32 %b) nounwind ssp {
12entry:
13  %cmp = icmp eq i32 %a, 5
14  %cmp1 = icmp eq i32 %b, 17
15  %or.cond = or i1 %cmp, %cmp1
16  br i1 %or.cond, label %if.then, label %if.end
17
18if.then:
19  %call = tail call i32 @foo() nounwind
20  br label %if.end
21
22if.end:
23  ret i32 7
24}
25
26; Different condition codes for the two compares.
27; CHECK: single_different
28; CHECK: cmp w0, #6
29; CHECK-NEXT: ccmp w1, #17, #0, ge
30; CHECK-NEXT: b.eq
31; CHECK: %if.then
32; CHECK: bl _foo
33; CHECK: %if.end
34define i32 @single_different(i32 %a, i32 %b) nounwind ssp {
35entry:
36  %cmp = icmp sle i32 %a, 5
37  %cmp1 = icmp ne i32 %b, 17
38  %or.cond = or i1 %cmp, %cmp1
39  br i1 %or.cond, label %if.then, label %if.end
40
41if.then:
42  %call = tail call i32 @foo() nounwind
43  br label %if.end
44
45if.end:
46  ret i32 7
47}
48
49; Second block clobbers the flags, can't convert (easily).
50; CHECK: single_flagclobber
51; CHECK: cmp
52; CHECK: b.eq
53; CHECK: cmp
54; CHECK: b.gt
55define i32 @single_flagclobber(i32 %a, i32 %b) nounwind ssp {
56entry:
57  %cmp = icmp eq i32 %a, 5
58  br i1 %cmp, label %if.then, label %lor.lhs.false
59
60lor.lhs.false:                                    ; preds = %entry
61  %cmp1 = icmp slt i32 %b, 7
62  %mul = shl nsw i32 %b, 1
63  %add = add nsw i32 %b, 1
64  %cond = select i1 %cmp1, i32 %mul, i32 %add
65  %cmp2 = icmp slt i32 %cond, 17
66  br i1 %cmp2, label %if.then, label %if.end
67
68if.then:                                          ; preds = %lor.lhs.false, %entry
69  %call = tail call i32 @foo() nounwind
70  br label %if.end
71
72if.end:                                           ; preds = %if.then, %lor.lhs.false
73  ret i32 7
74}
75
76; Second block clobbers the flags and ends with a tbz terminator.
77; CHECK: single_flagclobber_tbz
78; CHECK: cmp
79; CHECK: b.eq
80; CHECK: cmp
81; CHECK: tbz
82define i32 @single_flagclobber_tbz(i32 %a, i32 %b) nounwind ssp {
83entry:
84  %cmp = icmp eq i32 %a, 5
85  br i1 %cmp, label %if.then, label %lor.lhs.false
86
87lor.lhs.false:                                    ; preds = %entry
88  %cmp1 = icmp slt i32 %b, 7
89  %mul = shl nsw i32 %b, 1
90  %add = add nsw i32 %b, 1
91  %cond = select i1 %cmp1, i32 %mul, i32 %add
92  %and = and i32 %cond, 8
93  %cmp2 = icmp ne i32 %and, 0
94  br i1 %cmp2, label %if.then, label %if.end
95
96if.then:                                          ; preds = %lor.lhs.false, %entry
97  %call = tail call i32 @foo() nounwind
98  br label %if.end
99
100if.end:                                           ; preds = %if.then, %lor.lhs.false
101  ret i32 7
102}
103
104; Speculatively execute division by zero.
105; The sdiv/udiv instructions do not trap when the divisor is zero, so they are
106; safe to speculate.
107; CHECK-LABEL: speculate_division:
108; CHECK: cmp w0, #1
109; CHECK: sdiv [[DIVRES:w[0-9]+]], w1, w0
110; CHECK: ccmp [[DIVRES]], #16, #0, ge
111; CHECK: b.gt [[BLOCK:LBB[0-9_]+]]
112; CHECK: bl _foo
113; CHECK: [[BLOCK]]:
114; CHECK: orr w0, wzr, #0x7
115define i32 @speculate_division(i32 %a, i32 %b) nounwind ssp {
116entry:
117  %cmp = icmp sgt i32 %a, 0
118  br i1 %cmp, label %land.lhs.true, label %if.end
119
120land.lhs.true:
121  %div = sdiv i32 %b, %a
122  %cmp1 = icmp slt i32 %div, 17
123  br i1 %cmp1, label %if.then, label %if.end
124
125if.then:
126  %call = tail call i32 @foo() nounwind
127  br label %if.end
128
129if.end:
130  ret i32 7
131}
132
133; Floating point compare.
134; CHECK: single_fcmp
135; CHECK: cmp
136; CHECK-NOT: b.
137; CHECK: fccmp {{.*}}, #8, ge
138; CHECK: b.lt
139define i32 @single_fcmp(i32 %a, float %b) nounwind ssp {
140entry:
141  %cmp = icmp sgt i32 %a, 0
142  br i1 %cmp, label %land.lhs.true, label %if.end
143
144land.lhs.true:
145  %conv = sitofp i32 %a to float
146  %div = fdiv float %b, %conv
147  %cmp1 = fcmp oge float %div, 1.700000e+01
148  br i1 %cmp1, label %if.then, label %if.end
149
150if.then:
151  %call = tail call i32 @foo() nounwind
152  br label %if.end
153
154if.end:
155  ret i32 7
156}
157
158; Chain multiple compares.
159; CHECK: multi_different
160; CHECK: cmp
161; CHECK: ccmp
162; CHECK: ccmp
163; CHECK: b.
164define void @multi_different(i32 %a, i32 %b, i32 %c) nounwind ssp {
165entry:
166  %cmp = icmp sgt i32 %a, %b
167  br i1 %cmp, label %land.lhs.true, label %if.end
168
169land.lhs.true:
170  %div = sdiv i32 %b, %a
171  %cmp1 = icmp eq i32 %div, 5
172  %cmp4 = icmp sgt i32 %div, %c
173  %or.cond = and i1 %cmp1, %cmp4
174  br i1 %or.cond, label %if.then, label %if.end
175
176if.then:
177  %call = tail call i32 @foo() nounwind
178  br label %if.end
179
180if.end:
181  ret void
182}
183
184; Convert a cbz in the head block.
185; CHECK: cbz_head
186; CHECK: cmp w0, #0
187; CHECK: ccmp
188define i32 @cbz_head(i32 %a, i32 %b) nounwind ssp {
189entry:
190  %cmp = icmp eq i32 %a, 0
191  %cmp1 = icmp ne i32 %b, 17
192  %or.cond = or i1 %cmp, %cmp1
193  br i1 %or.cond, label %if.then, label %if.end
194
195if.then:
196  %call = tail call i32 @foo() nounwind
197  br label %if.end
198
199if.end:
200  ret i32 7
201}
202
203; Check that the immediate operand is in range. The ccmp instruction encodes a
204; smaller range of immediates than subs/adds.
205; The ccmp immediates must be in the range 0-31.
206; CHECK: immediate_range
207; CHECK-NOT: ccmp
208define i32 @immediate_range(i32 %a, i32 %b) nounwind ssp {
209entry:
210  %cmp = icmp eq i32 %a, 5
211  %cmp1 = icmp eq i32 %b, 32
212  %or.cond = or i1 %cmp, %cmp1
213  br i1 %or.cond, label %if.then, label %if.end
214
215if.then:
216  %call = tail call i32 @foo() nounwind
217  br label %if.end
218
219if.end:
220  ret i32 7
221}
222
223; Convert a cbz in the second block.
224; CHECK: cbz_second
225; CHECK: cmp w0, #0
226; CHECK: ccmp w1, #0, #0, ne
227; CHECK: b.eq
228define i32 @cbz_second(i32 %a, i32 %b) nounwind ssp {
229entry:
230  %cmp = icmp eq i32 %a, 0
231  %cmp1 = icmp ne i32 %b, 0
232  %or.cond = or i1 %cmp, %cmp1
233  br i1 %or.cond, label %if.then, label %if.end
234
235if.then:
236  %call = tail call i32 @foo() nounwind
237  br label %if.end
238
239if.end:
240  ret i32 7
241}
242
243; Convert a cbnz in the second block.
244; CHECK: cbnz_second
245; CHECK: cmp w0, #0
246; CHECK: ccmp w1, #0, #4, ne
247; CHECK: b.ne
248define i32 @cbnz_second(i32 %a, i32 %b) nounwind ssp {
249entry:
250  %cmp = icmp eq i32 %a, 0
251  %cmp1 = icmp eq i32 %b, 0
252  %or.cond = or i1 %cmp, %cmp1
253  br i1 %or.cond, label %if.then, label %if.end
254
255if.then:
256  %call = tail call i32 @foo() nounwind
257  br label %if.end
258
259if.end:
260  ret i32 7
261}
262declare i32 @foo()
263
264%str1 = type { %str2 }
265%str2 = type { [24 x i8], i8*, i32, %str1*, i32, [4 x i8], %str1*, %str1*, %str1*, %str1*, %str1*, %str1*, %str1*, %str1*, %str1*, i8*, i8, i8*, %str1*, i8* }
266
267; Test case distilled from 126.gcc.
268; The phi in sw.bb.i.i gets multiple operands for the %entry predecessor.
269; CHECK: build_modify_expr
270define void @build_modify_expr() nounwind ssp {
271entry:
272  switch i32 undef, label %sw.bb.i.i [
273    i32 69, label %if.end85
274    i32 70, label %if.end85
275    i32 71, label %if.end85
276    i32 72, label %if.end85
277    i32 73, label %if.end85
278    i32 105, label %if.end85
279    i32 106, label %if.end85
280  ]
281
282if.end85:
283  ret void
284
285sw.bb.i.i:
286  %ref.tr.i.i = phi %str1* [ %0, %sw.bb.i.i ], [ undef, %entry ]
287  %operands.i.i = getelementptr inbounds %str1, %str1* %ref.tr.i.i, i64 0, i32 0, i32 2
288  %arrayidx.i.i = bitcast i32* %operands.i.i to %str1**
289  %0 = load %str1*, %str1** %arrayidx.i.i, align 8
290  %code1.i.i.phi.trans.insert = getelementptr inbounds %str1, %str1* %0, i64 0, i32 0, i32 0, i64 16
291  br label %sw.bb.i.i
292}
293
294; CHECK-LABEL: select_and
295define i64 @select_and(i32 %w0, i32 %w1, i64 %x2, i64 %x3) {
296; CHECK: cmp w1, #5
297; CHECK-NEXT: ccmp w0, w1, #0, ne
298; CHECK-NEXT: csel x0, x2, x3, lt
299; CHECK-NEXT: ret
300  %1 = icmp slt i32 %w0, %w1
301  %2 = icmp ne i32 5, %w1
302  %3 = and i1 %1, %2
303  %sel = select i1 %3, i64 %x2, i64 %x3
304  ret i64 %sel
305}
306
307; CHECK-LABEL: select_or
308define i64 @select_or(i32 %w0, i32 %w1, i64 %x2, i64 %x3) {
309; CHECK: cmp w1, #5
310; CHECK-NEXT: ccmp w0, w1, #8, eq
311; CHECK-NEXT: csel x0, x2, x3, lt
312; CHECK-NEXT: ret
313  %1 = icmp slt i32 %w0, %w1
314  %2 = icmp ne i32 5, %w1
315  %3 = or i1 %1, %2
316  %sel = select i1 %3, i64 %x2, i64 %x3
317  ret i64 %sel
318}
319
320; CHECK-LABEL: gccbug
321define i64 @gccbug(i64 %x0, i64 %x1) {
322; CHECK: cmp x0, #2
323; CHECK-NEXT: ccmp x0, #4, #4, ne
324; CHECK-NEXT: ccmp x1, #0, #0, eq
325; CHECK-NEXT: orr w[[REGNUM:[0-9]+]], wzr, #0x1
326; CHECK-NEXT: cinc x0, x[[REGNUM]], eq
327; CHECK-NEXT: ret
328  %cmp0 = icmp eq i64 %x1, 0
329  %cmp1 = icmp eq i64 %x0, 2
330  %cmp2 = icmp eq i64 %x0, 4
331
332  %or = or i1 %cmp2, %cmp1
333  %and = and i1 %or, %cmp0
334
335  %sel = select i1 %and, i64 2, i64 1
336  ret i64 %sel
337}
338
339; CHECK-LABEL: select_ororand
340define i32 @select_ororand(i32 %w0, i32 %w1, i32 %w2, i32 %w3) {
341; CHECK: cmp w3, #4
342; CHECK-NEXT: ccmp w2, #2, #0, gt
343; CHECK-NEXT: ccmp w1, #13, #2, ge
344; CHECK-NEXT: ccmp w0, #0, #4, ls
345; CHECK-NEXT: csel w0, w3, wzr, eq
346; CHECK-NEXT: ret
347  %c0 = icmp eq i32 %w0, 0
348  %c1 = icmp ugt i32 %w1, 13
349  %c2 = icmp slt i32 %w2, 2
350  %c4 = icmp sgt i32 %w3, 4
351  %or = or i1 %c0, %c1
352  %and = and i1 %c2, %c4
353  %or1 = or i1 %or, %and
354  %sel = select i1 %or1, i32 %w3, i32 0
355  ret i32 %sel
356}
357
358; CHECK-LABEL: select_andor
359define i32 @select_andor(i32 %v1, i32 %v2, i32 %v3) {
360; CHECK: cmp w1, w2
361; CHECK-NEXT: ccmp w0, #0, #4, lt
362; CHECK-NEXT: ccmp w0, w1, #0, eq
363; CHECK-NEXT: csel w0, w0, w1, eq
364; CHECK-NEXT: ret
365  %c0 = icmp eq i32 %v1, %v2
366  %c1 = icmp sge i32 %v2, %v3
367  %c2 = icmp eq i32 %v1, 0
368  %or = or i1 %c2, %c1
369  %and = and i1 %or, %c0
370  %sel = select i1 %and, i32 %v1, i32 %v2
371  ret i32 %sel
372}
373
374; CHECK-LABEL: select_noccmp1
375define i64 @select_noccmp1(i64 %v1, i64 %v2, i64 %v3, i64 %r) {
376; CHECK: cmp x0, #0
377; CHECK-NEXT: cset [[REG0:w[0-9]+]], lt
378; CHECK-NEXT: cmp x0, #13
379; CHECK-NOT: ccmp
380; CHECK-NEXT: cset [[REG1:w[0-9]+]], gt
381; CHECK-NEXT: cmp x2, #2
382; CHECK-NEXT: cset [[REG2:w[0-9]+]], lt
383; CHECK-NEXT: cmp x2, #4
384; CHECK-NEXT: cset [[REG3:w[0-9]+]], gt
385; CHECK-NEXT: and [[REG4:w[0-9]+]], [[REG0]], [[REG1]]
386; CHECK-NEXT: and [[REG5:w[0-9]+]], [[REG2]], [[REG3]]
387; CHECK-NEXT: orr [[REG6:w[0-9]+]], [[REG4]], [[REG5]]
388; CHECK-NEXT: cmp [[REG6]], #0
389; CHECK-NEXT: csel x0, xzr, x3, ne
390; CHECK-NEXT: ret
391  %c0 = icmp slt i64 %v1, 0
392  %c1 = icmp sgt i64 %v1, 13
393  %c2 = icmp slt i64 %v3, 2
394  %c4 = icmp sgt i64 %v3, 4
395  %and0 = and i1 %c0, %c1
396  %and1 = and i1 %c2, %c4
397  %or = or i1 %and0, %and1
398  %sel = select i1 %or, i64 0, i64 %r
399  ret i64 %sel
400}
401
402@g = global i32 0
403
404; Should not use ccmp if we have to compute the or expression in an integer
405; register anyway because of other users.
406; CHECK-LABEL: select_noccmp2
407define i64 @select_noccmp2(i64 %v1, i64 %v2, i64 %v3, i64 %r) {
408; CHECK: cmp x0, #0
409; CHECK-NEXT: cset [[REG0:w[0-9]+]], lt
410; CHECK-NOT: ccmp
411; CHECK-NEXT: cmp x0, #13
412; CHECK-NEXT: cset [[REG1:w[0-9]+]], gt
413; CHECK-NEXT: orr [[REG2:w[0-9]+]], [[REG0]], [[REG1]]
414; CHECK-NEXT: cmp [[REG2]], #0
415; CHECK-NEXT: csel x0, xzr, x3, ne
416; CHECK-NEXT: sbfx [[REG3:w[0-9]+]], [[REG2]], #0, #1
417; CHECK-NEXT: adrp x[[REGN4:[0-9]+]], _g@PAGE
418; CHECK-NEXT: str [[REG3]], [x[[REGN4]], _g@PAGEOFF]
419; CHECK-NEXT: ret
420  %c0 = icmp slt i64 %v1, 0
421  %c1 = icmp sgt i64 %v1, 13
422  %or = or i1 %c0, %c1
423  %sel = select i1 %or, i64 0, i64 %r
424  %ext = sext i1 %or to i32
425  store volatile i32 %ext, i32* @g
426  ret i64 %sel
427}
428
429; The following is not possible to implement with a single cmp;ccmp;csel
430; sequence.
431; CHECK-LABEL: select_noccmp3
432define i32 @select_noccmp3(i32 %v0, i32 %v1, i32 %v2) {
433  %c0 = icmp slt i32 %v0, 0
434  %c1 = icmp sgt i32 %v0, 13
435  %c2 = icmp slt i32 %v0, 22
436  %c3 = icmp sgt i32 %v0, 44
437  %c4 = icmp eq i32 %v0, 99
438  %c5 = icmp eq i32 %v0, 77
439  %or0 = or i1 %c0, %c1
440  %or1 = or i1 %c2, %c3
441  %and0 = and i1 %or0, %or1
442  %or2 = or i1 %c4, %c5
443  %and1 = and i1 %and0, %or2
444  %sel = select i1 %and1, i32 %v1, i32 %v2
445  ret i32 %sel
446}
447
448; Test the IR CCs that expand to two cond codes.
449
450; CHECK-LABEL: select_and_olt_one:
451; CHECK-LABEL: ; BB#0:
452; CHECK-NEXT: fcmp d0, d1
453; CHECK-NEXT: fccmp d2, d3, #4, mi
454; CHECK-NEXT: fccmp d2, d3, #1, ne
455; CHECK-NEXT: csel w0, w0, w1, vc
456; CHECK-NEXT: ret
457define i32 @select_and_olt_one(double %v0, double %v1, double %v2, double %v3, i32 %a, i32 %b) #0 {
458  %c0 = fcmp olt double %v0, %v1
459  %c1 = fcmp one double %v2, %v3
460  %cr = and i1 %c1, %c0
461  %sel = select i1 %cr, i32 %a, i32 %b
462  ret i32 %sel
463}
464
465; CHECK-LABEL: select_and_one_olt:
466; CHECK-LABEL: ; BB#0:
467; CHECK-NEXT: fcmp d0, d1
468; CHECK-NEXT: fccmp d0, d1, #1, ne
469; CHECK-NEXT: fccmp d2, d3, #0, vc
470; CHECK-NEXT: csel w0, w0, w1, mi
471; CHECK-NEXT: ret
472define i32 @select_and_one_olt(double %v0, double %v1, double %v2, double %v3, i32 %a, i32 %b) #0 {
473  %c0 = fcmp one double %v0, %v1
474  %c1 = fcmp olt double %v2, %v3
475  %cr = and i1 %c1, %c0
476  %sel = select i1 %cr, i32 %a, i32 %b
477  ret i32 %sel
478}
479
480; CHECK-LABEL: select_and_olt_ueq:
481; CHECK-LABEL: ; BB#0:
482; CHECK-NEXT: fcmp d0, d1
483; CHECK-NEXT: fccmp d2, d3, #0, mi
484; CHECK-NEXT: fccmp d2, d3, #8, le
485; CHECK-NEXT: csel w0, w0, w1, pl
486; CHECK-NEXT: ret
487define i32 @select_and_olt_ueq(double %v0, double %v1, double %v2, double %v3, i32 %a, i32 %b) #0 {
488  %c0 = fcmp olt double %v0, %v1
489  %c1 = fcmp ueq double %v2, %v3
490  %cr = and i1 %c1, %c0
491  %sel = select i1 %cr, i32 %a, i32 %b
492  ret i32 %sel
493}
494
495; CHECK-LABEL: select_and_ueq_olt:
496; CHECK-LABEL: ; BB#0:
497; CHECK-NEXT: fcmp d0, d1
498; CHECK-NEXT: fccmp d0, d1, #8, le
499; CHECK-NEXT: fccmp d2, d3, #0, pl
500; CHECK-NEXT: csel w0, w0, w1, mi
501; CHECK-NEXT: ret
502define i32 @select_and_ueq_olt(double %v0, double %v1, double %v2, double %v3, i32 %a, i32 %b) #0 {
503  %c0 = fcmp ueq double %v0, %v1
504  %c1 = fcmp olt double %v2, %v3
505  %cr = and i1 %c1, %c0
506  %sel = select i1 %cr, i32 %a, i32 %b
507  ret i32 %sel
508}
509
510; CHECK-LABEL: select_or_olt_one:
511; CHECK-LABEL: ; BB#0:
512; CHECK-NEXT: fcmp d0, d1
513; CHECK-NEXT: fccmp d2, d3, #0, pl
514; CHECK-NEXT: fccmp d2, d3, #8, le
515; CHECK-NEXT: csel w0, w0, w1, mi
516; CHECK-NEXT: ret
517define i32 @select_or_olt_one(double %v0, double %v1, double %v2, double %v3, i32 %a, i32 %b) #0 {
518  %c0 = fcmp olt double %v0, %v1
519  %c1 = fcmp one double %v2, %v3
520  %cr = or i1 %c1, %c0
521  %sel = select i1 %cr, i32 %a, i32 %b
522  ret i32 %sel
523}
524
525; CHECK-LABEL: select_or_one_olt:
526; CHECK-LABEL: ; BB#0:
527; CHECK-NEXT: fcmp d0, d1
528; CHECK-NEXT: fccmp d0, d1, #1, ne
529; CHECK-NEXT: fccmp d2, d3, #8, vs
530; CHECK-NEXT: csel w0, w0, w1, mi
531; CHECK-NEXT: ret
532define i32 @select_or_one_olt(double %v0, double %v1, double %v2, double %v3, i32 %a, i32 %b) #0 {
533  %c0 = fcmp one double %v0, %v1
534  %c1 = fcmp olt double %v2, %v3
535  %cr = or i1 %c1, %c0
536  %sel = select i1 %cr, i32 %a, i32 %b
537  ret i32 %sel
538}
539
540; CHECK-LABEL: select_or_olt_ueq:
541; CHECK-LABEL: ; BB#0:
542; CHECK-NEXT: fcmp d0, d1
543; CHECK-NEXT: fccmp d2, d3, #4, pl
544; CHECK-NEXT: fccmp d2, d3, #1, ne
545; CHECK-NEXT: csel w0, w0, w1, vs
546; CHECK-NEXT: ret
547define i32 @select_or_olt_ueq(double %v0, double %v1, double %v2, double %v3, i32 %a, i32 %b) #0 {
548  %c0 = fcmp olt double %v0, %v1
549  %c1 = fcmp ueq double %v2, %v3
550  %cr = or i1 %c1, %c0
551  %sel = select i1 %cr, i32 %a, i32 %b
552  ret i32 %sel
553}
554
555; CHECK-LABEL: select_or_ueq_olt:
556; CHECK-LABEL: ; BB#0:
557; CHECK-NEXT: fcmp d0, d1
558; CHECK-NEXT: fccmp d0, d1, #8, le
559; CHECK-NEXT: fccmp d2, d3, #8, mi
560; CHECK-NEXT: csel w0, w0, w1, mi
561; CHECK-NEXT: ret
562define i32 @select_or_ueq_olt(double %v0, double %v1, double %v2, double %v3, i32 %a, i32 %b) #0 {
563  %c0 = fcmp ueq double %v0, %v1
564  %c1 = fcmp olt double %v2, %v3
565  %cr = or i1 %c1, %c0
566  %sel = select i1 %cr, i32 %a, i32 %b
567  ret i32 %sel
568}
569
570; CHECK-LABEL: select_or_olt_ogt_ueq:
571; CHECK-LABEL: ; BB#0:
572; CHECK-NEXT: fcmp d0, d1
573; CHECK-NEXT: fccmp d2, d3, #0, pl
574; CHECK-NEXT: fccmp d4, d5, #4, le
575; CHECK-NEXT: fccmp d4, d5, #1, ne
576; CHECK-NEXT: csel w0, w0, w1, vs
577; CHECK-NEXT: ret
578define i32 @select_or_olt_ogt_ueq(double %v0, double %v1, double %v2, double %v3, double %v4, double %v5, i32 %a, i32 %b) #0 {
579  %c0 = fcmp olt double %v0, %v1
580  %c1 = fcmp ogt double %v2, %v3
581  %c2 = fcmp ueq double %v4, %v5
582  %c3 = or i1 %c1, %c0
583  %cr = or i1 %c2, %c3
584  %sel = select i1 %cr, i32 %a, i32 %b
585  ret i32 %sel
586}
587
588; CHECK-LABEL: select_or_olt_ueq_ogt:
589; CHECK-LABEL: ; BB#0:
590; CHECK-NEXT: fcmp d0, d1
591; CHECK-NEXT: fccmp d2, d3, #4, pl
592; CHECK-NEXT: fccmp d2, d3, #1, ne
593; CHECK-NEXT: fccmp d4, d5, #0, vc
594; CHECK-NEXT: csel w0, w0, w1, gt
595; CHECK-NEXT: ret
596define i32 @select_or_olt_ueq_ogt(double %v0, double %v1, double %v2, double %v3, double %v4, double %v5, i32 %a, i32 %b) #0 {
597  %c0 = fcmp olt double %v0, %v1
598  %c1 = fcmp ueq double %v2, %v3
599  %c2 = fcmp ogt double %v4, %v5
600  %c3 = or i1 %c1, %c0
601  %cr = or i1 %c2, %c3
602  %sel = select i1 %cr, i32 %a, i32 %b
603  ret i32 %sel
604}
605
606; Verify that we correctly promote f16.
607
608; CHECK-LABEL: half_select_and_olt_oge:
609; CHECK-LABEL: ; BB#0:
610; CHECK-DAG:  fcvt [[S0:s[0-9]+]], h0
611; CHECK-DAG:  fcvt [[S1:s[0-9]+]], h1
612; CHECK-NEXT: fcmp [[S0]], [[S1]]
613; CHECK-DAG:  fcvt [[S2:s[0-9]+]], h2
614; CHECK-DAG:  fcvt [[S3:s[0-9]+]], h3
615; CHECK-NEXT: fccmp [[S2]], [[S3]], #8, mi
616; CHECK-NEXT: csel w0, w0, w1, ge
617; CHECK-NEXT: ret
618define i32 @half_select_and_olt_oge(half %v0, half %v1, half %v2, half %v3, i32 %a, i32 %b) #0 {
619  %c0 = fcmp olt half %v0, %v1
620  %c1 = fcmp oge half %v2, %v3
621  %cr = and i1 %c1, %c0
622  %sel = select i1 %cr, i32 %a, i32 %b
623  ret i32 %sel
624}
625
626; CHECK-LABEL: half_select_and_olt_one:
627; CHECK-LABEL: ; BB#0:
628; CHECK-DAG:  fcvt [[S0:s[0-9]+]], h0
629; CHECK-DAG:  fcvt [[S1:s[0-9]+]], h1
630; CHECK-NEXT: fcmp [[S0]], [[S1]]
631; CHECK-DAG:  fcvt [[S2:s[0-9]+]], h2
632; CHECK-DAG:  fcvt [[S3:s[0-9]+]], h3
633; CHECK-NEXT: fccmp [[S2]], [[S3]], #4, mi
634; CHECK-NEXT: fccmp [[S2]], [[S3]], #1, ne
635; CHECK-NEXT: csel w0, w0, w1, vc
636; CHECK-NEXT: ret
637define i32 @half_select_and_olt_one(half %v0, half %v1, half %v2, half %v3, i32 %a, i32 %b) #0 {
638  %c0 = fcmp olt half %v0, %v1
639  %c1 = fcmp one half %v2, %v3
640  %cr = and i1 %c1, %c0
641  %sel = select i1 %cr, i32 %a, i32 %b
642  ret i32 %sel
643}
644
645; Also verify that we don't try to generate f128 FCCMPs, using RT calls instead.
646
647; CHECK-LABEL: f128_select_and_olt_oge:
648; CHECK: bl ___lttf2
649; CHECK: bl ___getf2
650define i32 @f128_select_and_olt_oge(fp128 %v0, fp128 %v1, fp128 %v2, fp128 %v3, i32 %a, i32 %b) #0 {
651  %c0 = fcmp olt fp128 %v0, %v1
652  %c1 = fcmp oge fp128 %v2, %v3
653  %cr = and i1 %c1, %c0
654  %sel = select i1 %cr, i32 %a, i32 %b
655  ret i32 %sel
656}
657
658attributes #0 = { nounwind }
659