1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2; RUN: llc < %s -mtriple=x86_64-- | FileCheck %s
3
4; CodeGenPrepare is expected to form overflow intrinsics to improve DAG/isel.
5
6define i1 @usubo_ult_i64(i64 %x, i64 %y, i64* %p) nounwind {
7; CHECK-LABEL: usubo_ult_i64:
8; CHECK:       # %bb.0:
9; CHECK-NEXT:    subq %rsi, %rdi
10; CHECK-NEXT:    setb %al
11; CHECK-NEXT:    movq %rdi, (%rdx)
12; CHECK-NEXT:    retq
13  %s = sub i64 %x, %y
14  store i64 %s, i64* %p
15  %ov = icmp ult i64 %x, %y
16  ret i1 %ov
17}
18
19; Verify insertion point for single-BB. Toggle predicate.
20
21define i1 @usubo_ugt_i32(i32 %x, i32 %y, i32* %p) nounwind {
22; CHECK-LABEL: usubo_ugt_i32:
23; CHECK:       # %bb.0:
24; CHECK-NEXT:    subl %esi, %edi
25; CHECK-NEXT:    setb %al
26; CHECK-NEXT:    movl %edi, (%rdx)
27; CHECK-NEXT:    retq
28  %ov = icmp ugt i32 %y, %x
29  %s = sub i32 %x, %y
30  store i32 %s, i32* %p
31  ret i1 %ov
32}
33
34; Constant operand should match.
35
36define i1 @usubo_ugt_constant_op0_i8(i8 %x, i8* %p) nounwind {
37; CHECK-LABEL: usubo_ugt_constant_op0_i8:
38; CHECK:       # %bb.0:
39; CHECK-NEXT:    movb $42, %cl
40; CHECK-NEXT:    subb %dil, %cl
41; CHECK-NEXT:    setb %al
42; CHECK-NEXT:    movb %cl, (%rsi)
43; CHECK-NEXT:    retq
44  %s = sub i8 42, %x
45  %ov = icmp ugt i8 %x, 42
46  store i8 %s, i8* %p
47  ret i1 %ov
48}
49
50; Compare with constant operand 0 is canonicalized by commuting, but verify match for non-canonical form.
51
52define i1 @usubo_ult_constant_op0_i16(i16 %x, i16* %p) nounwind {
53; CHECK-LABEL: usubo_ult_constant_op0_i16:
54; CHECK:       # %bb.0:
55; CHECK-NEXT:    movw $43, %cx
56; CHECK-NEXT:    subw %di, %cx
57; CHECK-NEXT:    setb %al
58; CHECK-NEXT:    movw %cx, (%rsi)
59; CHECK-NEXT:    retq
60  %s = sub i16 43, %x
61  %ov = icmp ult i16 43, %x
62  store i16 %s, i16* %p
63  ret i1 %ov
64}
65
66; Subtract with constant operand 1 is canonicalized to add.
67
68define i1 @usubo_ult_constant_op1_i16(i16 %x, i16* %p) nounwind {
69; CHECK-LABEL: usubo_ult_constant_op1_i16:
70; CHECK:       # %bb.0:
71; CHECK-NEXT:    subw $44, %di
72; CHECK-NEXT:    setb %al
73; CHECK-NEXT:    movw %di, (%rsi)
74; CHECK-NEXT:    retq
75  %s = add i16 %x, -44
76  %ov = icmp ult i16 %x, 44
77  store i16 %s, i16* %p
78  ret i1 %ov
79}
80
81define i1 @usubo_ugt_constant_op1_i8(i8 %x, i8* %p) nounwind {
82; CHECK-LABEL: usubo_ugt_constant_op1_i8:
83; CHECK:       # %bb.0:
84; CHECK-NEXT:    subb $45, %dil
85; CHECK-NEXT:    setb %al
86; CHECK-NEXT:    movb %dil, (%rsi)
87; CHECK-NEXT:    retq
88  %ov = icmp ugt i8 45, %x
89  %s = add i8 %x, -45
90  store i8 %s, i8* %p
91  ret i1 %ov
92}
93
94; Special-case: subtract 1 changes the compare predicate and constant.
95
96define i1 @usubo_eq_constant1_op1_i32(i32 %x, i32* %p) nounwind {
97; CHECK-LABEL: usubo_eq_constant1_op1_i32:
98; CHECK:       # %bb.0:
99; CHECK-NEXT:    subl $1, %edi
100; CHECK-NEXT:    setb %al
101; CHECK-NEXT:    movl %edi, (%rsi)
102; CHECK-NEXT:    retq
103  %s = add i32 %x, -1
104  %ov = icmp eq i32 %x, 0
105  store i32 %s, i32* %p
106  ret i1 %ov
107}
108
109; Special-case: subtract from 0 (negate) changes the compare predicate.
110
111define i1 @usubo_ne_constant0_op1_i32(i32 %x, i32* %p) {
112; CHECK-LABEL: usubo_ne_constant0_op1_i32:
113; CHECK:       # %bb.0:
114; CHECK-NEXT:    negl %edi
115; CHECK-NEXT:    setb %al
116; CHECK-NEXT:    movl %edi, (%rsi)
117; CHECK-NEXT:    retq
118  %s = sub i32 0, %x
119  %ov = icmp ne i32 %x, 0
120  store i32 %s, i32* %p
121  ret i1 %ov
122}
123
124; This used to verify insertion point for multi-BB, but now we just bail out.
125
126declare void @call(i1)
127
128define i1 @usubo_ult_sub_dominates_i64(i64 %x, i64 %y, i64* %p, i1 %cond) nounwind {
129; CHECK-LABEL: usubo_ult_sub_dominates_i64:
130; CHECK:       # %bb.0: # %entry
131; CHECK-NEXT:    testb $1, %cl
132; CHECK-NEXT:    je .LBB8_2
133; CHECK-NEXT:  # %bb.1: # %t
134; CHECK-NEXT:    movq %rdi, %rax
135; CHECK-NEXT:    subq %rsi, %rax
136; CHECK-NEXT:    movq %rax, (%rdx)
137; CHECK-NEXT:    testb $1, %cl
138; CHECK-NEXT:    je .LBB8_2
139; CHECK-NEXT:  # %bb.3: # %end
140; CHECK-NEXT:    cmpq %rsi, %rdi
141; CHECK-NEXT:    setb %al
142; CHECK-NEXT:    retq
143; CHECK-NEXT:  .LBB8_2: # %f
144; CHECK-NEXT:    movl %ecx, %eax
145; CHECK-NEXT:    retq
146entry:
147  br i1 %cond, label %t, label %f
148
149t:
150  %s = sub i64 %x, %y
151  store i64 %s, i64* %p
152  br i1 %cond, label %end, label %f
153
154f:
155  ret i1 %cond
156
157end:
158  %ov = icmp ult i64 %x, %y
159  ret i1 %ov
160}
161
162define i1 @usubo_ult_cmp_dominates_i64(i64 %x, i64 %y, i64* %p, i1 %cond) nounwind {
163; CHECK-LABEL: usubo_ult_cmp_dominates_i64:
164; CHECK:       # %bb.0: # %entry
165; CHECK-NEXT:    pushq %rbp
166; CHECK-NEXT:    pushq %r15
167; CHECK-NEXT:    pushq %r14
168; CHECK-NEXT:    pushq %rbx
169; CHECK-NEXT:    pushq %rax
170; CHECK-NEXT:    movl %ecx, %ebp
171; CHECK-NEXT:    testb $1, %bpl
172; CHECK-NEXT:    je .LBB9_2
173; CHECK-NEXT:  # %bb.1: # %t
174; CHECK-NEXT:    movq %rdx, %r14
175; CHECK-NEXT:    movq %rsi, %r15
176; CHECK-NEXT:    movq %rdi, %rbx
177; CHECK-NEXT:    xorl %edi, %edi
178; CHECK-NEXT:    cmpq %rsi, %rbx
179; CHECK-NEXT:    setb %dil
180; CHECK-NEXT:    callq call@PLT
181; CHECK-NEXT:    subq %r15, %rbx
182; CHECK-NEXT:    jae .LBB9_2
183; CHECK-NEXT:  # %bb.4: # %end
184; CHECK-NEXT:    setb %al
185; CHECK-NEXT:    movq %rbx, (%r14)
186; CHECK-NEXT:    jmp .LBB9_3
187; CHECK-NEXT:  .LBB9_2: # %f
188; CHECK-NEXT:    movl %ebp, %eax
189; CHECK-NEXT:  .LBB9_3: # %f
190; CHECK-NEXT:    addq $8, %rsp
191; CHECK-NEXT:    popq %rbx
192; CHECK-NEXT:    popq %r14
193; CHECK-NEXT:    popq %r15
194; CHECK-NEXT:    popq %rbp
195; CHECK-NEXT:    retq
196entry:
197  br i1 %cond, label %t, label %f
198
199t:
200  %ov = icmp ult i64 %x, %y
201  call void @call(i1 %ov)
202  br i1 %ov, label %end, label %f
203
204f:
205  ret i1 %cond
206
207end:
208  %s = sub i64 %x, %y
209  store i64 %s, i64* %p
210  ret i1 %ov
211}
212
213define void @PR41129(i64* %p64) {
214; CHECK-LABEL: PR41129:
215; CHECK:       # %bb.0: # %entry
216; CHECK-NEXT:    movq (%rdi), %rax
217; CHECK-NEXT:    testq %rax, %rax
218; CHECK-NEXT:    je .LBB10_2
219; CHECK-NEXT:  # %bb.1: # %false
220; CHECK-NEXT:    andl $7, %eax
221; CHECK-NEXT:    movq %rax, (%rdi)
222; CHECK-NEXT:    retq
223; CHECK-NEXT:  .LBB10_2: # %true
224; CHECK-NEXT:    decq %rax
225; CHECK-NEXT:    movq %rax, (%rdi)
226; CHECK-NEXT:    retq
227entry:
228  %key = load i64, i64* %p64, align 8
229  %cond17 = icmp eq i64 %key, 0
230  br i1 %cond17, label %true, label %false
231
232false:
233  %andval = and i64 %key, 7
234  store i64 %andval, i64* %p64
235  br label %exit
236
237true:
238  %svalue = add i64 %key, -1
239  store i64 %svalue, i64* %p64
240  br label %exit
241
242exit:
243  ret void
244}
245
246define i32 @PR42571(i32 %x, i32 %y) {
247; CHECK-LABEL: PR42571:
248; CHECK:       # %bb.0:
249; CHECK-NEXT:    # kill: def $edi killed $edi def $rdi
250; CHECK-NEXT:    leal -1(%rdi), %eax
251; CHECK-NEXT:    andl %edi, %eax
252; CHECK-NEXT:    cmpl $1, %edi
253; CHECK-NEXT:    cmovbl %esi, %eax
254; CHECK-NEXT:    retq
255  %tobool = icmp eq i32 %x, 0
256  %sub = add nsw i32 %x, -1
257  %and = and i32 %sub, %x
258  %cond = select i1 %tobool, i32 %y, i32 %and
259  ret i32 %cond
260}
261