1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2; RUN: llc < %s -mtriple=x86_64-unknown-unknown -verify-machineinstrs | FileCheck %s --check-prefix=X64
3; RUN: llc < %s -mtriple=i686-unknown-unknown -verify-machineinstrs | FileCheck %s --check-prefix=X86
4
5; Make sure that flags are properly preserved despite atomic optimizations.
6
7define i32 @atomic_and_flags_1(i8* %p, i32 %a, i32 %b) {
8; X64-LABEL: atomic_and_flags_1:
9; X64:       # %bb.0:
10; X64-NEXT:    cmpl %edx, %esi
11; X64-NEXT:    jne .LBB0_3
12; X64-NEXT:  # %bb.1: # %L1
13; X64-NEXT:    incb (%rdi)
14; X64-NEXT:    cmpl %edx, %esi
15; X64-NEXT:    jne .LBB0_2
16; X64-NEXT:  # %bb.4: # %L3
17; X64-NEXT:    movl $3, %eax
18; X64-NEXT:    retq
19; X64-NEXT:  .LBB0_3: # %L2
20; X64-NEXT:    movl $2, %eax
21; X64-NEXT:    retq
22; X64-NEXT:  .LBB0_2: # %L4
23; X64-NEXT:    movl $4, %eax
24; X64-NEXT:    retq
25;
26; X86-LABEL: atomic_and_flags_1:
27; X86:       # %bb.0:
28; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
29; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
30; X86-NEXT:    cmpl %eax, %ecx
31; X86-NEXT:    jne .LBB0_3
32; X86-NEXT:  # %bb.1: # %L1
33; X86-NEXT:    movl {{[0-9]+}}(%esp), %edx
34; X86-NEXT:    incb (%edx)
35; X86-NEXT:    cmpl %eax, %ecx
36; X86-NEXT:    jne .LBB0_2
37; X86-NEXT:  # %bb.4: # %L3
38; X86-NEXT:    movl $3, %eax
39; X86-NEXT:    retl
40; X86-NEXT:  .LBB0_3: # %L2
41; X86-NEXT:    movl $2, %eax
42; X86-NEXT:    retl
43; X86-NEXT:  .LBB0_2: # %L4
44; X86-NEXT:    movl $4, %eax
45; X86-NEXT:    retl
46  ; Generate flags value, and use it.
47  %cmp = icmp eq i32 %a, %b
48  br i1 %cmp, label %L1, label %L2
49
50L1:
51  ; The following pattern will get folded.
52  %1 = load atomic i8, i8* %p seq_cst, align 1
53  %2 = add i8 %1, 1 ; This forces the INC instruction to be generated.
54  store atomic i8 %2, i8* %p release, align 1
55
56  ; Use the comparison result again. We need to rematerialize the comparison
57  ; somehow. This test checks that cmpl gets emitted again, but any
58  ; rematerialization would work (the optimizer used to clobber the flags with
59  ; the add).
60  br i1 %cmp, label %L3, label %L4
61
62L2:
63  ret i32 2
64
65L3:
66  ret i32 3
67
68L4:
69  ret i32 4
70}
71
72; Same as above, but using 2 as immediate to avoid the INC instruction.
73define i32 @atomic_and_flags_2(i8* %p, i32 %a, i32 %b) {
74; X64-LABEL: atomic_and_flags_2:
75; X64:       # %bb.0:
76; X64-NEXT:    cmpl %edx, %esi
77; X64-NEXT:    jne .LBB1_3
78; X64-NEXT:  # %bb.1: # %L1
79; X64-NEXT:    addb $2, (%rdi)
80; X64-NEXT:    cmpl %edx, %esi
81; X64-NEXT:    jne .LBB1_2
82; X64-NEXT:  # %bb.4: # %L3
83; X64-NEXT:    movl $3, %eax
84; X64-NEXT:    retq
85; X64-NEXT:  .LBB1_3: # %L2
86; X64-NEXT:    movl $2, %eax
87; X64-NEXT:    retq
88; X64-NEXT:  .LBB1_2: # %L4
89; X64-NEXT:    movl $4, %eax
90; X64-NEXT:    retq
91;
92; X86-LABEL: atomic_and_flags_2:
93; X86:       # %bb.0:
94; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
95; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
96; X86-NEXT:    cmpl %eax, %ecx
97; X86-NEXT:    jne .LBB1_3
98; X86-NEXT:  # %bb.1: # %L1
99; X86-NEXT:    movl {{[0-9]+}}(%esp), %edx
100; X86-NEXT:    addb $2, (%edx)
101; X86-NEXT:    cmpl %eax, %ecx
102; X86-NEXT:    jne .LBB1_2
103; X86-NEXT:  # %bb.4: # %L3
104; X86-NEXT:    movl $3, %eax
105; X86-NEXT:    retl
106; X86-NEXT:  .LBB1_3: # %L2
107; X86-NEXT:    movl $2, %eax
108; X86-NEXT:    retl
109; X86-NEXT:  .LBB1_2: # %L4
110; X86-NEXT:    movl $4, %eax
111; X86-NEXT:    retl
112  %cmp = icmp eq i32 %a, %b
113  br i1 %cmp, label %L1, label %L2
114L1:
115  %1 = load atomic i8, i8* %p seq_cst, align 1
116  %2 = add i8 %1, 2
117  store atomic i8 %2, i8* %p release, align 1
118  br i1 %cmp, label %L3, label %L4
119L2:
120  ret i32 2
121L3:
122  ret i32 3
123L4:
124  ret i32 4
125}
126
127; FIXME: PR20841 - ensure we reuse the ZF flag from XADD for compares with zero.
128
129define zeroext i1 @xadd_cmp0_i64(i64* %x) nounwind {
130; X64-LABEL: xadd_cmp0_i64:
131; X64:       # %bb.0:
132; X64-NEXT:    movl $1, %eax
133; X64-NEXT:    lock xaddq %rax, (%rdi)
134; X64-NEXT:    testq %rax, %rax
135; X64-NEXT:    sete %al
136; X64-NEXT:    retq
137;
138; X86-LABEL: xadd_cmp0_i64:
139; X86:       # %bb.0:
140; X86-NEXT:    pushl %ebx
141; X86-NEXT:    pushl %esi
142; X86-NEXT:    movl {{[0-9]+}}(%esp), %esi
143; X86-NEXT:    movl (%esi), %eax
144; X86-NEXT:    movl 4(%esi), %edx
145; X86-NEXT:    .p2align 4, 0x90
146; X86-NEXT:  .LBB2_1: # %atomicrmw.start
147; X86-NEXT:    # =>This Inner Loop Header: Depth=1
148; X86-NEXT:    movl %eax, %ebx
149; X86-NEXT:    addl $1, %ebx
150; X86-NEXT:    movl %edx, %ecx
151; X86-NEXT:    adcl $0, %ecx
152; X86-NEXT:    lock cmpxchg8b (%esi)
153; X86-NEXT:    jne .LBB2_1
154; X86-NEXT:  # %bb.2: # %atomicrmw.end
155; X86-NEXT:    orl %edx, %eax
156; X86-NEXT:    sete %al
157; X86-NEXT:    popl %esi
158; X86-NEXT:    popl %ebx
159; X86-NEXT:    retl
160  %add = atomicrmw add i64* %x, i64 1 seq_cst
161  %cmp = icmp eq i64 %add, 0
162  ret i1 %cmp
163}
164
165define zeroext i1 @xadd_cmp0_i32(i32* %x) nounwind {
166; X64-LABEL: xadd_cmp0_i32:
167; X64:       # %bb.0:
168; X64-NEXT:    movl $1, %eax
169; X64-NEXT:    lock xaddl %eax, (%rdi)
170; X64-NEXT:    testl %eax, %eax
171; X64-NEXT:    setne %al
172; X64-NEXT:    retq
173;
174; X86-LABEL: xadd_cmp0_i32:
175; X86:       # %bb.0:
176; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
177; X86-NEXT:    movl $1, %ecx
178; X86-NEXT:    lock xaddl %ecx, (%eax)
179; X86-NEXT:    testl %ecx, %ecx
180; X86-NEXT:    setne %al
181; X86-NEXT:    retl
182  %add = atomicrmw add i32* %x, i32 1 seq_cst
183  %cmp = icmp ne i32 %add, 0
184  ret i1 %cmp
185}
186
187define zeroext i1 @xadd_cmp0_i16(i16* %x) nounwind {
188; X64-LABEL: xadd_cmp0_i16:
189; X64:       # %bb.0:
190; X64-NEXT:    movw $1, %ax
191; X64-NEXT:    lock xaddw %ax, (%rdi)
192; X64-NEXT:    testw %ax, %ax
193; X64-NEXT:    sete %al
194; X64-NEXT:    retq
195;
196; X86-LABEL: xadd_cmp0_i16:
197; X86:       # %bb.0:
198; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
199; X86-NEXT:    movw $1, %cx
200; X86-NEXT:    lock xaddw %cx, (%eax)
201; X86-NEXT:    testw %cx, %cx
202; X86-NEXT:    sete %al
203; X86-NEXT:    retl
204  %add = atomicrmw add i16* %x, i16 1 seq_cst
205  %cmp = icmp eq i16 %add, 0
206  ret i1 %cmp
207}
208
209define zeroext i1 @xadd_cmp0_i8(i8* %x) nounwind {
210; X64-LABEL: xadd_cmp0_i8:
211; X64:       # %bb.0:
212; X64-NEXT:    movb $1, %al
213; X64-NEXT:    lock xaddb %al, (%rdi)
214; X64-NEXT:    testb %al, %al
215; X64-NEXT:    setne %al
216; X64-NEXT:    retq
217;
218; X86-LABEL: xadd_cmp0_i8:
219; X86:       # %bb.0:
220; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
221; X86-NEXT:    movb $1, %cl
222; X86-NEXT:    lock xaddb %cl, (%eax)
223; X86-NEXT:    testb %cl, %cl
224; X86-NEXT:    setne %al
225; X86-NEXT:    retl
226  %add = atomicrmw add i8* %x, i8 1 seq_cst
227  %cmp = icmp ne i8 %add, 0
228  ret i1 %cmp
229}
230