• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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: select_complicated
321define i16 @select_complicated(double %v1, double %v2, i16 %a, i16 %b) {
322; CHECK: ldr [[REG:d[0-9]+]],
323; CHECK: fcmp d0, d2
324; CHECK-NEXT: fmov d2, #13.00000000
325; CHECK-NEXT: fccmp d1, d2, #4, ne
326; CHECK-NEXT: fccmp d0, d1, #1, ne
327; CHECK-NEXT: fccmp d0, d1, #4, vc
328; CEHCK-NEXT: csel w0, w0, w1, eq
329  %1 = fcmp one double %v1, %v2
330  %2 = fcmp oeq double %v2, 13.0
331  %3 = fcmp oeq double %v1, 42.0
332  %or0 = or i1 %2, %3
333  %or1 = or i1 %1, %or0
334  %sel = select i1 %or1, i16 %a, i16 %b
335  ret i16 %sel
336}
337
338; CHECK-LABEL: gccbug
339define i64 @gccbug(i64 %x0, i64 %x1) {
340; CHECK: cmp x0, #2
341; CHECK-NEXT: ccmp x0, #4, #4, ne
342; CHECK-NEXT: ccmp x1, #0, #0, eq
343; CHECK-NEXT: orr w[[REGNUM:[0-9]+]], wzr, #0x1
344; CHECK-NEXT: cinc x0, x[[REGNUM]], eq
345; CHECK-NEXT: ret
346  %cmp0 = icmp eq i64 %x1, 0
347  %cmp1 = icmp eq i64 %x0, 2
348  %cmp2 = icmp eq i64 %x0, 4
349
350  %or = or i1 %cmp2, %cmp1
351  %and = and i1 %or, %cmp0
352
353  %sel = select i1 %and, i64 2, i64 1
354  ret i64 %sel
355}
356
357; CHECK-LABEL: select_ororand
358define i32 @select_ororand(i32 %w0, i32 %w1, i32 %w2, i32 %w3) {
359; CHECK: cmp w3, #4
360; CHECK-NEXT: ccmp w2, #2, #0, gt
361; CHECK-NEXT: ccmp w1, #13, #2, ge
362; CHECK-NEXT: ccmp w0, #0, #4, ls
363; CHECK-NEXT: csel w0, w3, wzr, eq
364; CHECK-NEXT: ret
365  %c0 = icmp eq i32 %w0, 0
366  %c1 = icmp ugt i32 %w1, 13
367  %c2 = icmp slt i32 %w2, 2
368  %c4 = icmp sgt i32 %w3, 4
369  %or = or i1 %c0, %c1
370  %and = and i1 %c2, %c4
371  %or1 = or i1 %or, %and
372  %sel = select i1 %or1, i32 %w3, i32 0
373  ret i32 %sel
374}
375
376; CHECK-LABEL: select_andor
377define i32 @select_andor(i32 %v1, i32 %v2, i32 %v3) {
378; CHECK: cmp w1, w2
379; CHECK-NEXT: ccmp w0, #0, #4, lt
380; CHECK-NEXT: ccmp w0, w1, #0, eq
381; CHECK-NEXT: csel w0, w0, w1, eq
382; CHECK-NEXT: ret
383  %c0 = icmp eq i32 %v1, %v2
384  %c1 = icmp sge i32 %v2, %v3
385  %c2 = icmp eq i32 %v1, 0
386  %or = or i1 %c2, %c1
387  %and = and i1 %or, %c0
388  %sel = select i1 %and, i32 %v1, i32 %v2
389  ret i32 %sel
390}
391
392; CHECK-LABEL: select_noccmp1
393define i64 @select_noccmp1(i64 %v1, i64 %v2, i64 %v3, i64 %r) {
394; CHECK: cmp x0, #0
395; CHECK-NEXT: cset [[REG0:w[0-9]+]], lt
396; CHECK-NEXT: cmp x0, #13
397; CHECK-NOT: ccmp
398; CHECK-NEXT: cset [[REG1:w[0-9]+]], gt
399; CHECK-NEXT: cmp x2, #2
400; CHECK-NEXT: cset [[REG2:w[0-9]+]], lt
401; CHECK-NEXT: cmp x2, #4
402; CHECK-NEXT: cset [[REG3:w[0-9]+]], gt
403; CHECK-NEXT: and [[REG4:w[0-9]+]], [[REG0]], [[REG1]]
404; CHECK-NEXT: and [[REG5:w[0-9]+]], [[REG2]], [[REG3]]
405; CHECK-NEXT: orr [[REG6:w[0-9]+]], [[REG4]], [[REG5]]
406; CHECK-NEXT: cmp [[REG6]], #0
407; CHECK-NEXT: csel x0, xzr, x3, ne
408; CHECK-NEXT: ret
409  %c0 = icmp slt i64 %v1, 0
410  %c1 = icmp sgt i64 %v1, 13
411  %c2 = icmp slt i64 %v3, 2
412  %c4 = icmp sgt i64 %v3, 4
413  %and0 = and i1 %c0, %c1
414  %and1 = and i1 %c2, %c4
415  %or = or i1 %and0, %and1
416  %sel = select i1 %or, i64 0, i64 %r
417  ret i64 %sel
418}
419
420@g = global i32 0
421
422; Should not use ccmp if we have to compute the or expression in an integer
423; register anyway because of other users.
424; CHECK-LABEL: select_noccmp2
425define i64 @select_noccmp2(i64 %v1, i64 %v2, i64 %v3, i64 %r) {
426; CHECK: cmp x0, #0
427; CHECK-NEXT: cset [[REG0:w[0-9]+]], lt
428; CHECK-NOT: ccmp
429; CHECK-NEXT: cmp x0, #13
430; CHECK-NEXT: cset [[REG1:w[0-9]+]], gt
431; CHECK-NEXT: orr [[REG2:w[0-9]+]], [[REG0]], [[REG1]]
432; CHECK-NEXT: cmp [[REG2]], #0
433; CHECK-NEXT: csel x0, xzr, x3, ne
434; CHECK-NEXT: sbfx [[REG3:w[0-9]+]], [[REG2]], #0, #1
435; CHECK-NEXT: adrp x[[REGN4:[0-9]+]], _g@PAGE
436; CHECK-NEXT: str [[REG3]], [x[[REGN4]], _g@PAGEOFF]
437; CHECK-NEXT: ret
438  %c0 = icmp slt i64 %v1, 0
439  %c1 = icmp sgt i64 %v1, 13
440  %or = or i1 %c0, %c1
441  %sel = select i1 %or, i64 0, i64 %r
442  %ext = sext i1 %or to i32
443  store volatile i32 %ext, i32* @g
444  ret i64 %sel
445}
446