OLD | NEW |
1 ; This tests each of the supported NaCl atomic instructions for every | 1 ; This tests each of the supported NaCl atomic instructions for every |
2 ; size allowed. | 2 ; size allowed. |
3 | 3 |
4 ; RUN: %p2i -i %s --args -O2 --verbose none \ | 4 ; RUN: %p2i -i %s --assemble --disassemble --args -O2 --verbose none \ |
5 ; RUN: | llvm-mc -triple=i686-none-nacl -filetype=obj \ | |
6 ; RUN: | llvm-objdump -d --symbolize -x86-asm-syntax=intel - \ | |
7 ; RUN: | FileCheck %s | 5 ; RUN: | FileCheck %s |
8 ; RUN: %p2i -i %s --args -O2 --verbose none \ | 6 ; RUN: %p2i -i %s --assemble --disassemble --args -O2 --verbose none \ |
9 ; RUN: | llvm-mc -triple=i686-none-nacl -filetype=obj \ | |
10 ; RUN: | llvm-objdump -d --symbolize -x86-asm-syntax=intel - \ | |
11 ; RUN: | FileCheck --check-prefix=CHECKO2 %s | 7 ; RUN: | FileCheck --check-prefix=CHECKO2 %s |
12 ; RUN: %p2i -i %s --args -Om1 --verbose none \ | 8 ; RUN: %p2i -i %s --assemble --disassemble --args -Om1 --verbose none \ |
13 ; RUN: | llvm-mc -triple=i686-none-nacl -filetype=obj \ | |
14 ; RUN: | llvm-objdump -d --symbolize -x86-asm-syntax=intel - \ | |
15 ; RUN: | FileCheck %s | 9 ; RUN: | FileCheck %s |
16 | 10 |
17 declare i8 @llvm.nacl.atomic.load.i8(i8*, i32) | 11 declare i8 @llvm.nacl.atomic.load.i8(i8*, i32) |
18 declare i16 @llvm.nacl.atomic.load.i16(i16*, i32) | 12 declare i16 @llvm.nacl.atomic.load.i16(i16*, i32) |
19 declare i32 @llvm.nacl.atomic.load.i32(i32*, i32) | 13 declare i32 @llvm.nacl.atomic.load.i32(i32*, i32) |
20 declare i64 @llvm.nacl.atomic.load.i64(i64*, i32) | 14 declare i64 @llvm.nacl.atomic.load.i64(i64*, i32) |
21 declare void @llvm.nacl.atomic.store.i8(i8, i8*, i32) | 15 declare void @llvm.nacl.atomic.store.i8(i8, i8*, i32) |
22 declare void @llvm.nacl.atomic.store.i16(i16, i16*, i32) | 16 declare void @llvm.nacl.atomic.store.i16(i16, i16*, i32) |
23 declare void @llvm.nacl.atomic.store.i32(i32, i32*, i32) | 17 declare void @llvm.nacl.atomic.store.i32(i32, i32*, i32) |
24 declare void @llvm.nacl.atomic.store.i64(i64, i64*, i32) | 18 declare void @llvm.nacl.atomic.store.i64(i64, i64*, i32) |
(...skipping 21 matching lines...) Expand all Loading... |
46 | 40 |
47 define i32 @test_atomic_load_8(i32 %iptr) { | 41 define i32 @test_atomic_load_8(i32 %iptr) { |
48 entry: | 42 entry: |
49 %ptr = inttoptr i32 %iptr to i8* | 43 %ptr = inttoptr i32 %iptr to i8* |
50 ; parameter value "6" is for the sequential consistency memory order. | 44 ; parameter value "6" is for the sequential consistency memory order. |
51 %i = call i8 @llvm.nacl.atomic.load.i8(i8* %ptr, i32 6) | 45 %i = call i8 @llvm.nacl.atomic.load.i8(i8* %ptr, i32 6) |
52 %r = zext i8 %i to i32 | 46 %r = zext i8 %i to i32 |
53 ret i32 %r | 47 ret i32 %r |
54 } | 48 } |
55 ; CHECK-LABEL: test_atomic_load_8 | 49 ; CHECK-LABEL: test_atomic_load_8 |
56 ; CHECK: mov {{.*}}, dword | 50 ; CHECK: mov {{.*}},DWORD |
57 ; CHECK: mov {{.*}}, byte | 51 ; CHECK: mov {{.*}},byte |
58 | 52 |
59 define i32 @test_atomic_load_16(i32 %iptr) { | 53 define i32 @test_atomic_load_16(i32 %iptr) { |
60 entry: | 54 entry: |
61 %ptr = inttoptr i32 %iptr to i16* | 55 %ptr = inttoptr i32 %iptr to i16* |
62 %i = call i16 @llvm.nacl.atomic.load.i16(i16* %ptr, i32 6) | 56 %i = call i16 @llvm.nacl.atomic.load.i16(i16* %ptr, i32 6) |
63 %r = zext i16 %i to i32 | 57 %r = zext i16 %i to i32 |
64 ret i32 %r | 58 ret i32 %r |
65 } | 59 } |
66 ; CHECK-LABEL: test_atomic_load_16 | 60 ; CHECK-LABEL: test_atomic_load_16 |
67 ; CHECK: mov {{.*}}, dword | 61 ; CHECK: mov {{.*}},DWORD |
68 ; CHECK: mov {{.*}}, word | 62 ; CHECK: mov {{.*}},word |
69 | 63 |
70 define i32 @test_atomic_load_32(i32 %iptr) { | 64 define i32 @test_atomic_load_32(i32 %iptr) { |
71 entry: | 65 entry: |
72 %ptr = inttoptr i32 %iptr to i32* | 66 %ptr = inttoptr i32 %iptr to i32* |
73 %r = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6) | 67 %r = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6) |
74 ret i32 %r | 68 ret i32 %r |
75 } | 69 } |
76 ; CHECK-LABEL: test_atomic_load_32 | 70 ; CHECK-LABEL: test_atomic_load_32 |
77 ; CHECK: mov {{.*}}, dword | 71 ; CHECK: mov {{.*}},DWORD |
78 ; CHECK: mov {{.*}}, dword | 72 ; CHECK: mov {{.*}},DWORD |
79 | 73 |
80 define i64 @test_atomic_load_64(i32 %iptr) { | 74 define i64 @test_atomic_load_64(i32 %iptr) { |
81 entry: | 75 entry: |
82 %ptr = inttoptr i32 %iptr to i64* | 76 %ptr = inttoptr i32 %iptr to i64* |
83 %r = call i64 @llvm.nacl.atomic.load.i64(i64* %ptr, i32 6) | 77 %r = call i64 @llvm.nacl.atomic.load.i64(i64* %ptr, i32 6) |
84 ret i64 %r | 78 ret i64 %r |
85 } | 79 } |
86 ; CHECK-LABEL: test_atomic_load_64 | 80 ; CHECK-LABEL: test_atomic_load_64 |
87 ; CHECK: movq x{{.*}}, qword | 81 ; CHECK: movq x{{.*}},QWORD |
88 ; CHECK: movq qword {{.*}}, x{{.*}} | 82 ; CHECK: movq QWORD {{.*}},x{{.*}} |
89 | 83 |
90 define i32 @test_atomic_load_32_with_arith(i32 %iptr) { | 84 define i32 @test_atomic_load_32_with_arith(i32 %iptr) { |
91 entry: | 85 entry: |
92 br label %next | 86 br label %next |
93 | 87 |
94 next: | 88 next: |
95 %ptr = inttoptr i32 %iptr to i32* | 89 %ptr = inttoptr i32 %iptr to i32* |
96 %r = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6) | 90 %r = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6) |
97 %r2 = add i32 %r, 32 | 91 %r2 = add i32 %r, 32 |
98 ret i32 %r2 | 92 ret i32 %r2 |
99 } | 93 } |
100 ; CHECK-LABEL: test_atomic_load_32_with_arith | 94 ; CHECK-LABEL: test_atomic_load_32_with_arith |
101 ; CHECK: mov {{.*}}, dword | 95 ; CHECK: mov {{.*}},DWORD |
102 ; The next instruction may be a separate load or folded into an add. | 96 ; The next instruction may be a separate load or folded into an add. |
103 ; | 97 ; |
104 ; In O2 mode, we know that the load and add are going to be fused. | 98 ; In O2 mode, we know that the load and add are going to be fused. |
105 ; CHECKO2-LABEL: test_atomic_load_32_with_arith | 99 ; CHECKO2-LABEL: test_atomic_load_32_with_arith |
106 ; CHECKO2: mov {{.*}}, dword | 100 ; CHECKO2: mov {{.*}}, DWORD |
107 ; CHECKO2: add {{.*}}, dword | 101 ; CHECKO2: add {{.*}}, DWORD |
108 | 102 |
109 define i32 @test_atomic_load_32_ignored(i32 %iptr) { | 103 define i32 @test_atomic_load_32_ignored(i32 %iptr) { |
110 entry: | 104 entry: |
111 %ptr = inttoptr i32 %iptr to i32* | 105 %ptr = inttoptr i32 %iptr to i32* |
112 %ignored = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6) | 106 %ignored = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6) |
113 ret i32 0 | 107 ret i32 0 |
114 } | 108 } |
115 ; CHECK-LABEL: test_atomic_load_32_ignored | 109 ; CHECK-LABEL: test_atomic_load_32_ignored |
116 ; CHECK: mov {{.*}}, dword | 110 ; CHECK: mov {{.*}},DWORD |
117 ; CHECK: mov {{.*}}, dword | 111 ; CHECK: mov {{.*}},DWORD |
118 ; CHECKO2-LABEL: test_atomic_load_32_ignored | 112 ; CHECKO2-LABEL: test_atomic_load_32_ignored |
119 ; CHECKO2: mov {{.*}}, dword | 113 ; CHECKO2: mov {{.*}}, DWORD |
120 ; CHECKO2: mov {{.*}}, dword | 114 ; CHECKO2: mov {{.*}}, DWORD |
121 | 115 |
122 define i64 @test_atomic_load_64_ignored(i32 %iptr) { | 116 define i64 @test_atomic_load_64_ignored(i32 %iptr) { |
123 entry: | 117 entry: |
124 %ptr = inttoptr i32 %iptr to i64* | 118 %ptr = inttoptr i32 %iptr to i64* |
125 %ignored = call i64 @llvm.nacl.atomic.load.i64(i64* %ptr, i32 6) | 119 %ignored = call i64 @llvm.nacl.atomic.load.i64(i64* %ptr, i32 6) |
126 ret i64 0 | 120 ret i64 0 |
127 } | 121 } |
128 ; CHECK-LABEL: test_atomic_load_64_ignored | 122 ; CHECK-LABEL: test_atomic_load_64_ignored |
129 ; CHECK: movq x{{.*}}, qword | 123 ; CHECK: movq x{{.*}},QWORD |
130 ; CHECK: movq qword {{.*}}, x{{.*}} | 124 ; CHECK: movq QWORD {{.*}},x{{.*}} |
131 | 125 |
132 ;;; Store | 126 ;;; Store |
133 | 127 |
134 define void @test_atomic_store_8(i32 %iptr, i32 %v) { | 128 define void @test_atomic_store_8(i32 %iptr, i32 %v) { |
135 entry: | 129 entry: |
136 %truncv = trunc i32 %v to i8 | 130 %truncv = trunc i32 %v to i8 |
137 %ptr = inttoptr i32 %iptr to i8* | 131 %ptr = inttoptr i32 %iptr to i8* |
138 call void @llvm.nacl.atomic.store.i8(i8 %truncv, i8* %ptr, i32 6) | 132 call void @llvm.nacl.atomic.store.i8(i8 %truncv, i8* %ptr, i32 6) |
139 ret void | 133 ret void |
140 } | 134 } |
(...skipping 12 matching lines...) Expand all Loading... |
153 ; CHECK: mov word | 147 ; CHECK: mov word |
154 ; CHECK: mfence | 148 ; CHECK: mfence |
155 | 149 |
156 define void @test_atomic_store_32(i32 %iptr, i32 %v) { | 150 define void @test_atomic_store_32(i32 %iptr, i32 %v) { |
157 entry: | 151 entry: |
158 %ptr = inttoptr i32 %iptr to i32* | 152 %ptr = inttoptr i32 %iptr to i32* |
159 call void @llvm.nacl.atomic.store.i32(i32 %v, i32* %ptr, i32 6) | 153 call void @llvm.nacl.atomic.store.i32(i32 %v, i32* %ptr, i32 6) |
160 ret void | 154 ret void |
161 } | 155 } |
162 ; CHECK-LABEL: test_atomic_store_32 | 156 ; CHECK-LABEL: test_atomic_store_32 |
163 ; CHECK: mov dword | 157 ; CHECK: mov DWORD |
164 ; CHECK: mfence | 158 ; CHECK: mfence |
165 | 159 |
166 define void @test_atomic_store_64(i32 %iptr, i64 %v) { | 160 define void @test_atomic_store_64(i32 %iptr, i64 %v) { |
167 entry: | 161 entry: |
168 %ptr = inttoptr i32 %iptr to i64* | 162 %ptr = inttoptr i32 %iptr to i64* |
169 call void @llvm.nacl.atomic.store.i64(i64 %v, i64* %ptr, i32 6) | 163 call void @llvm.nacl.atomic.store.i64(i64 %v, i64* %ptr, i32 6) |
170 ret void | 164 ret void |
171 } | 165 } |
172 ; CHECK-LABEL: test_atomic_store_64 | 166 ; CHECK-LABEL: test_atomic_store_64 |
173 ; CHECK: movq x{{.*}}, qword | 167 ; CHECK: movq x{{.*}},QWORD |
174 ; CHECK: movq qword {{.*}}, x{{.*}} | 168 ; CHECK: movq QWORD {{.*}},x{{.*}} |
175 ; CHECK: mfence | 169 ; CHECK: mfence |
176 | 170 |
177 define void @test_atomic_store_64_const(i32 %iptr) { | 171 define void @test_atomic_store_64_const(i32 %iptr) { |
178 entry: | 172 entry: |
179 %ptr = inttoptr i32 %iptr to i64* | 173 %ptr = inttoptr i32 %iptr to i64* |
180 call void @llvm.nacl.atomic.store.i64(i64 12345678901234, i64* %ptr, i32 6) | 174 call void @llvm.nacl.atomic.store.i64(i64 12345678901234, i64* %ptr, i32 6) |
181 ret void | 175 ret void |
182 } | 176 } |
183 ; CHECK-LABEL: test_atomic_store_64_const | 177 ; CHECK-LABEL: test_atomic_store_64_const |
184 ; CHECK: mov {{.*}}, 1942892530 | 178 ; CHECK: mov {{.*}},0x73ce2ff2 |
185 ; CHECK: mov {{.*}}, 2874 | 179 ; CHECK: mov {{.*}},0xb3a |
186 ; CHECK: movq x{{.*}}, qword | 180 ; CHECK: movq x{{.*}},QWORD |
187 ; CHECK: movq qword {{.*}}, x{{.*}} | 181 ; CHECK: movq QWORD {{.*}},x{{.*}} |
188 ; CHECK: mfence | 182 ; CHECK: mfence |
189 | 183 |
190 | 184 |
191 ;;; RMW | 185 ;;; RMW |
192 | 186 |
193 ;; add | 187 ;; add |
194 | 188 |
195 define i32 @test_atomic_rmw_add_8(i32 %iptr, i32 %v) { | 189 define i32 @test_atomic_rmw_add_8(i32 %iptr, i32 %v) { |
196 entry: | 190 entry: |
197 %trunc = trunc i32 %v to i8 | 191 %trunc = trunc i32 %v to i8 |
198 %ptr = inttoptr i32 %iptr to i8* | 192 %ptr = inttoptr i32 %iptr to i8* |
199 ; "1" is an atomic add, and "6" is sequential consistency. | 193 ; "1" is an atomic add, and "6" is sequential consistency. |
200 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 1, i8* %ptr, i8 %trunc, i32 6) | 194 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 1, i8* %ptr, i8 %trunc, i32 6) |
201 %a_ext = zext i8 %a to i32 | 195 %a_ext = zext i8 %a to i32 |
202 ret i32 %a_ext | 196 ret i32 %a_ext |
203 } | 197 } |
204 ; CHECK-LABEL: test_atomic_rmw_add_8 | 198 ; CHECK-LABEL: test_atomic_rmw_add_8 |
205 ; CHECK: lock | 199 ; CHECK: lock |
206 ; CHECK-NEXT: xadd byte {{.*}}, [[REG:.*]] | 200 ; CHECK-NEXT: xadd byte {{.*}},[[REG:.*]] |
207 ; CHECK: {{mov|movzx}} {{.*}}, [[REG]] | 201 ; CHECK: {{mov|movzx}} {{.*}},[[REG]] |
208 | 202 |
209 define i32 @test_atomic_rmw_add_16(i32 %iptr, i32 %v) { | 203 define i32 @test_atomic_rmw_add_16(i32 %iptr, i32 %v) { |
210 entry: | 204 entry: |
211 %trunc = trunc i32 %v to i16 | 205 %trunc = trunc i32 %v to i16 |
212 %ptr = inttoptr i32 %iptr to i16* | 206 %ptr = inttoptr i32 %iptr to i16* |
213 %a = call i16 @llvm.nacl.atomic.rmw.i16(i32 1, i16* %ptr, i16 %trunc, i32 6) | 207 %a = call i16 @llvm.nacl.atomic.rmw.i16(i32 1, i16* %ptr, i16 %trunc, i32 6) |
214 %a_ext = zext i16 %a to i32 | 208 %a_ext = zext i16 %a to i32 |
215 ret i32 %a_ext | 209 ret i32 %a_ext |
216 } | 210 } |
217 ; CHECK-LABEL: test_atomic_rmw_add_16 | 211 ; CHECK-LABEL: test_atomic_rmw_add_16 |
218 ; CHECK: lock | 212 ; CHECK: lock |
219 ; CHECK-NEXT: xadd word {{.*}}, [[REG:.*]] | 213 ; CHECK-NEXT: xadd word {{.*}},[[REG:.*]] |
220 ; CHECK: {{mov|movzx}} {{.*}}, [[REG]] | 214 ; CHECK: {{mov|movzx}} {{.*}},[[REG]] |
221 | 215 |
222 define i32 @test_atomic_rmw_add_32(i32 %iptr, i32 %v) { | 216 define i32 @test_atomic_rmw_add_32(i32 %iptr, i32 %v) { |
223 entry: | 217 entry: |
224 %ptr = inttoptr i32 %iptr to i32* | 218 %ptr = inttoptr i32 %iptr to i32* |
225 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 1, i32* %ptr, i32 %v, i32 6) | 219 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 1, i32* %ptr, i32 %v, i32 6) |
226 ret i32 %a | 220 ret i32 %a |
227 } | 221 } |
228 ; CHECK-LABEL: test_atomic_rmw_add_32 | 222 ; CHECK-LABEL: test_atomic_rmw_add_32 |
229 ; CHECK: lock | 223 ; CHECK: lock |
230 ; CHECK-NEXT: xadd dword {{.*}}, [[REG:.*]] | 224 ; CHECK-NEXT: xadd DWORD {{.*}},[[REG:.*]] |
231 ; CHECK: mov {{.*}}, [[REG]] | 225 ; CHECK: mov {{.*}},[[REG]] |
232 | 226 |
233 define i64 @test_atomic_rmw_add_64(i32 %iptr, i64 %v) { | 227 define i64 @test_atomic_rmw_add_64(i32 %iptr, i64 %v) { |
234 entry: | 228 entry: |
235 %ptr = inttoptr i32 %iptr to i64* | 229 %ptr = inttoptr i32 %iptr to i64* |
236 %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 1, i64* %ptr, i64 %v, i32 6) | 230 %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 1, i64* %ptr, i64 %v, i32 6) |
237 ret i64 %a | 231 ret i64 %a |
238 } | 232 } |
239 ; CHECK-LABEL: test_atomic_rmw_add_64 | 233 ; CHECK-LABEL: test_atomic_rmw_add_64 |
240 ; CHECK: push ebx | 234 ; CHECK: push ebx |
241 ; CHECK: mov eax, dword ptr [{{.*}}] | 235 ; CHECK: mov eax,DWORD PTR [{{.*}}] |
242 ; CHECK: mov edx, dword ptr [{{.*}} + 4] | 236 ; CHECK: mov edx,DWORD PTR [{{.*}}+0x4] |
243 ; CHECK: mov ebx, eax | 237 ; CHECK: mov ebx,eax |
244 ; RHS of add cannot be any of the e[abcd]x regs because they are | 238 ; RHS of add cannot be any of the e[abcd]x regs because they are |
245 ; clobbered in the loop, and the RHS needs to be remain live. | 239 ; clobbered in the loop, and the RHS needs to be remain live. |
246 ; CHECK: add ebx, {{.*e.[^x]}} | 240 ; CHECK: add ebx,{{.*e.[^x]}} |
247 ; CHECK: mov ecx, edx | 241 ; CHECK: mov ecx,edx |
248 ; CHECK: adc ecx, {{.*e.[^x]}} | 242 ; CHECK: adc ecx, {{.*e.[^x]}} |
249 ; Ptr cannot be eax, ebx, ecx, or edx (used up for the expected and desired). | 243 ; Ptr cannot be eax, ebx, ecx, or edx (used up for the expected and desired). |
250 ; It can be esi, edi, or ebp though, for example (so we need to be careful | 244 ; It can be esi, edi, or ebp though, for example (so we need to be careful |
251 ; about rejecting eb* and ed*.) | 245 ; about rejecting eb* and ed*.) |
252 ; CHECK: lock | 246 ; CHECK: lock |
253 ; CHECK-NEXT: cmpxchg8b qword ptr [e{{.[^x]}}] | 247 ; CHECK-NEXT: cmpxchg8b QWORD PTR [e{{.[^x]}}] |
254 ; CHECK: jne -{{[0-9]}} | 248 ; CHECK: jne-{{[0-9]}} |
255 | 249 |
256 ; Test with some more register pressure. When we have an alloca, ebp is | 250 ; Test with some more register pressure. When we have an alloca, ebp is |
257 ; used to manage the stack frame, so it cannot be used as a register either. | 251 ; used to manage the stack frame, so it cannot be used as a register either. |
258 define void @use_ptr(i32 %iptr) { | 252 define void @use_ptr(i32 %iptr) { |
259 entry: | 253 entry: |
260 ret void | 254 ret void |
261 } | 255 } |
262 | 256 |
263 define i64 @test_atomic_rmw_add_64_alloca(i32 %iptr, i64 %v) { | 257 define i64 @test_atomic_rmw_add_64_alloca(i32 %iptr, i64 %v) { |
264 entry: | 258 entry: |
(...skipping 13 matching lines...) Expand all Loading... |
278 ; CHECK-DAG: mov edx | 272 ; CHECK-DAG: mov edx |
279 ; CHECK-DAG: mov eax | 273 ; CHECK-DAG: mov eax |
280 ; CHECK-DAG: mov ecx | 274 ; CHECK-DAG: mov ecx |
281 ; CHECK-DAG: mov ebx | 275 ; CHECK-DAG: mov ebx |
282 ; Ptr cannot be eax, ebx, ecx, or edx (used up for the expected and desired). | 276 ; Ptr cannot be eax, ebx, ecx, or edx (used up for the expected and desired). |
283 ; It also cannot be ebp since we use that for alloca. Also make sure it's | 277 ; It also cannot be ebp since we use that for alloca. Also make sure it's |
284 ; not esp, since that's the stack pointer and mucking with it will break | 278 ; not esp, since that's the stack pointer and mucking with it will break |
285 ; the later use_ptr function call. | 279 ; the later use_ptr function call. |
286 ; That pretty much leaves esi, or edi as the only viable registers. | 280 ; That pretty much leaves esi, or edi as the only viable registers. |
287 ; CHECK: lock | 281 ; CHECK: lock |
288 ; CHECK-NEXT: cmpxchg8b qword ptr [e{{[ds]}}i] | 282 ; CHECK-NEXT: cmpxchg8b QWORD PTR [e{{[ds]}}i] |
289 ; CHECK: call use_ptr | 283 ; CHECK: call {{.*}} R_{{.*}} use_ptr |
290 | 284 |
291 define i32 @test_atomic_rmw_add_32_ignored(i32 %iptr, i32 %v) { | 285 define i32 @test_atomic_rmw_add_32_ignored(i32 %iptr, i32 %v) { |
292 entry: | 286 entry: |
293 %ptr = inttoptr i32 %iptr to i32* | 287 %ptr = inttoptr i32 %iptr to i32* |
294 %ignored = call i32 @llvm.nacl.atomic.rmw.i32(i32 1, i32* %ptr, i32 %v, i32 6) | 288 %ignored = call i32 @llvm.nacl.atomic.rmw.i32(i32 1, i32* %ptr, i32 %v, i32 6) |
295 ret i32 %v | 289 ret i32 %v |
296 } | 290 } |
297 ; Technically this could use "lock add" instead of "lock xadd", if liveness | 291 ; Technically this could use "lock add" instead of "lock xadd", if liveness |
298 ; tells us that the destination variable is dead. | 292 ; tells us that the destination variable is dead. |
299 ; CHECK-LABEL: test_atomic_rmw_add_32_ignored | 293 ; CHECK-LABEL: test_atomic_rmw_add_32_ignored |
300 ; CHECK: lock | 294 ; CHECK: lock |
301 ; CHECK-NEXT: xadd dword {{.*}}, [[REG:.*]] | 295 ; CHECK-NEXT: xadd DWORD {{.*}},[[REG:.*]] |
302 | 296 |
303 ; Atomic RMW 64 needs to be expanded into its own loop. | 297 ; Atomic RMW 64 needs to be expanded into its own loop. |
304 ; Make sure that works w/ non-trivial function bodies. | 298 ; Make sure that works w/ non-trivial function bodies. |
305 define i64 @test_atomic_rmw_add_64_loop(i32 %iptr, i64 %v) { | 299 define i64 @test_atomic_rmw_add_64_loop(i32 %iptr, i64 %v) { |
306 entry: | 300 entry: |
307 %x = icmp ult i64 %v, 100 | 301 %x = icmp ult i64 %v, 100 |
308 br i1 %x, label %err, label %loop | 302 br i1 %x, label %err, label %loop |
309 | 303 |
310 loop: | 304 loop: |
311 %v_next = phi i64 [ %v, %entry ], [ %next, %loop ] | 305 %v_next = phi i64 [ %v, %entry ], [ %next, %loop ] |
312 %ptr = inttoptr i32 %iptr to i64* | 306 %ptr = inttoptr i32 %iptr to i64* |
313 %next = call i64 @llvm.nacl.atomic.rmw.i64(i32 1, i64* %ptr, i64 %v_next, i32
6) | 307 %next = call i64 @llvm.nacl.atomic.rmw.i64(i32 1, i64* %ptr, i64 %v_next, i32
6) |
314 %success = icmp eq i64 %next, 100 | 308 %success = icmp eq i64 %next, 100 |
315 br i1 %success, label %done, label %loop | 309 br i1 %success, label %done, label %loop |
316 | 310 |
317 done: | 311 done: |
318 ret i64 %next | 312 ret i64 %next |
319 | 313 |
320 err: | 314 err: |
321 ret i64 0 | 315 ret i64 0 |
322 } | 316 } |
323 ; CHECK-LABEL: test_atomic_rmw_add_64_loop | 317 ; CHECK-LABEL: test_atomic_rmw_add_64_loop |
324 ; CHECK: push ebx | 318 ; CHECK: push ebx |
325 ; CHECK: mov eax, dword ptr [{{.*}}] | 319 ; CHECK: mov eax,DWORD PTR [{{.*}}] |
326 ; CHECK: mov edx, dword ptr [{{.*}} + 4] | 320 ; CHECK: mov edx,DWORD PTR [{{.*}}+0x4] |
327 ; CHECK: mov ebx, eax | 321 ; CHECK: mov ebx,eax |
328 ; CHECK: add ebx, {{.*e.[^x]}} | 322 ; CHECK: add ebx,{{.*e.[^x]}} |
329 ; CHECK: mov ecx, edx | 323 ; CHECK: mov ecx,edx |
330 ; CHECK: adc ecx, {{.*e.[^x]}} | 324 ; CHECK: adc ecx, {{.*e.[^x]}} |
331 ; CHECK: lock | 325 ; CHECK: lock |
332 ; CHECK-NEXT: cmpxchg8b qword ptr [e{{.[^x]}}] | 326 ; CHECK-NEXT: cmpxchg8b QWORD PTR [e{{.[^x]}}] |
333 ; CHECK: jne -{{[0-9]}} | 327 ; CHECK: jne-{{[0-9]}} |
334 | 328 |
335 ;; sub | 329 ;; sub |
336 | 330 |
337 define i32 @test_atomic_rmw_sub_8(i32 %iptr, i32 %v) { | 331 define i32 @test_atomic_rmw_sub_8(i32 %iptr, i32 %v) { |
338 entry: | 332 entry: |
339 %trunc = trunc i32 %v to i8 | 333 %trunc = trunc i32 %v to i8 |
340 %ptr = inttoptr i32 %iptr to i8* | 334 %ptr = inttoptr i32 %iptr to i8* |
341 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 2, i8* %ptr, i8 %trunc, i32 6) | 335 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 2, i8* %ptr, i8 %trunc, i32 6) |
342 %a_ext = zext i8 %a to i32 | 336 %a_ext = zext i8 %a to i32 |
343 ret i32 %a_ext | 337 ret i32 %a_ext |
344 } | 338 } |
345 ; CHECK-LABEL: test_atomic_rmw_sub_8 | 339 ; CHECK-LABEL: test_atomic_rmw_sub_8 |
346 ; CHECK: neg [[REG:.*]] | 340 ; CHECK: neg [[REG:.*]] |
347 ; CHECK: lock | 341 ; CHECK: lock |
348 ; CHECK-NEXT: xadd byte {{.*}}, [[REG]] | 342 ; CHECK-NEXT: xadd byte {{.*}},[[REG]] |
349 ; CHECK: {{mov|movzx}} {{.*}}, [[REG]] | 343 ; CHECK: {{mov|movzx}} {{.*}},[[REG]] |
350 | 344 |
351 define i32 @test_atomic_rmw_sub_16(i32 %iptr, i32 %v) { | 345 define i32 @test_atomic_rmw_sub_16(i32 %iptr, i32 %v) { |
352 entry: | 346 entry: |
353 %trunc = trunc i32 %v to i16 | 347 %trunc = trunc i32 %v to i16 |
354 %ptr = inttoptr i32 %iptr to i16* | 348 %ptr = inttoptr i32 %iptr to i16* |
355 %a = call i16 @llvm.nacl.atomic.rmw.i16(i32 2, i16* %ptr, i16 %trunc, i32 6) | 349 %a = call i16 @llvm.nacl.atomic.rmw.i16(i32 2, i16* %ptr, i16 %trunc, i32 6) |
356 %a_ext = zext i16 %a to i32 | 350 %a_ext = zext i16 %a to i32 |
357 ret i32 %a_ext | 351 ret i32 %a_ext |
358 } | 352 } |
359 ; CHECK-LABEL: test_atomic_rmw_sub_16 | 353 ; CHECK-LABEL: test_atomic_rmw_sub_16 |
360 ; CHECK: neg [[REG:.*]] | 354 ; CHECK: neg [[REG:.*]] |
361 ; CHECK: lock | 355 ; CHECK: lock |
362 ; CHECK-NEXT: xadd word {{.*}}, [[REG]] | 356 ; CHECK-NEXT: xadd word {{.*}},[[REG]] |
363 ; CHECK: {{mov|movzx}} {{.*}}, [[REG]] | 357 ; CHECK: {{mov|movzx}} {{.*}},[[REG]] |
364 | 358 |
365 define i32 @test_atomic_rmw_sub_32(i32 %iptr, i32 %v) { | 359 define i32 @test_atomic_rmw_sub_32(i32 %iptr, i32 %v) { |
366 entry: | 360 entry: |
367 %ptr = inttoptr i32 %iptr to i32* | 361 %ptr = inttoptr i32 %iptr to i32* |
368 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 2, i32* %ptr, i32 %v, i32 6) | 362 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 2, i32* %ptr, i32 %v, i32 6) |
369 ret i32 %a | 363 ret i32 %a |
370 } | 364 } |
371 ; CHECK-LABEL: test_atomic_rmw_sub_32 | 365 ; CHECK-LABEL: test_atomic_rmw_sub_32 |
372 ; CHECK: neg [[REG:.*]] | 366 ; CHECK: neg [[REG:.*]] |
373 ; CHECK: lock | 367 ; CHECK: lock |
374 ; CHECK-NEXT: xadd dword {{.*}}, [[REG]] | 368 ; CHECK-NEXT: xadd DWORD {{.*}},[[REG]] |
375 ; CHECK: mov {{.*}}, [[REG]] | 369 ; CHECK: mov {{.*}},[[REG]] |
376 | 370 |
377 define i64 @test_atomic_rmw_sub_64(i32 %iptr, i64 %v) { | 371 define i64 @test_atomic_rmw_sub_64(i32 %iptr, i64 %v) { |
378 entry: | 372 entry: |
379 %ptr = inttoptr i32 %iptr to i64* | 373 %ptr = inttoptr i32 %iptr to i64* |
380 %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 2, i64* %ptr, i64 %v, i32 6) | 374 %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 2, i64* %ptr, i64 %v, i32 6) |
381 ret i64 %a | 375 ret i64 %a |
382 } | 376 } |
383 ; CHECK-LABEL: test_atomic_rmw_sub_64 | 377 ; CHECK-LABEL: test_atomic_rmw_sub_64 |
384 ; CHECK: push ebx | 378 ; CHECK: push ebx |
385 ; CHECK: mov eax, dword ptr [{{.*}}] | 379 ; CHECK: mov eax,DWORD PTR [{{.*}}] |
386 ; CHECK: mov edx, dword ptr [{{.*}} + 4] | 380 ; CHECK: mov edx,DWORD PTR [{{.*}}+0x4] |
387 ; CHECK: mov ebx, eax | 381 ; CHECK: mov ebx,eax |
388 ; CHECK: sub ebx, {{.*e.[^x]}} | 382 ; CHECK: sub ebx, {{.*e.[^x]}} |
389 ; CHECK: mov ecx, edx | 383 ; CHECK: mov ecx,edx |
390 ; CHECK: sbb ecx, {{.*e.[^x]}} | 384 ; CHECK: sbb ecx, {{.*e.[^x]}} |
391 ; CHECK: lock | 385 ; CHECK: lock |
392 ; CHECK-NEXT: cmpxchg8b qword ptr [e{{.[^x]}}] | 386 ; CHECK-NEXT: cmpxchg8b QWORD PTR [e{{.[^x]}}] |
393 ; CHECK: jne -{{[0-9]}} | 387 ; CHECK: jne-{{[0-9]}} |
394 | 388 |
395 | 389 |
396 define i32 @test_atomic_rmw_sub_32_ignored(i32 %iptr, i32 %v) { | 390 define i32 @test_atomic_rmw_sub_32_ignored(i32 %iptr, i32 %v) { |
397 entry: | 391 entry: |
398 %ptr = inttoptr i32 %iptr to i32* | 392 %ptr = inttoptr i32 %iptr to i32* |
399 %ignored = call i32 @llvm.nacl.atomic.rmw.i32(i32 2, i32* %ptr, i32 %v, i32 6) | 393 %ignored = call i32 @llvm.nacl.atomic.rmw.i32(i32 2, i32* %ptr, i32 %v, i32 6) |
400 ret i32 %v | 394 ret i32 %v |
401 } | 395 } |
402 ; Could use "lock sub" instead of "neg; lock xadd" | 396 ; Could use "lock sub" instead of "neg; lock xadd" |
403 ; CHECK-LABEL: test_atomic_rmw_sub_32_ignored | 397 ; CHECK-LABEL: test_atomic_rmw_sub_32_ignored |
404 ; CHECK: neg [[REG:.*]] | 398 ; CHECK: neg [[REG:.*]] |
405 ; CHECK: lock | 399 ; CHECK: lock |
406 ; CHECK-NEXT: xadd dword {{.*}}, [[REG]] | 400 ; CHECK-NEXT: xadd DWORD {{.*}},[[REG]] |
407 | 401 |
408 ;; or | 402 ;; or |
409 | 403 |
410 define i32 @test_atomic_rmw_or_8(i32 %iptr, i32 %v) { | 404 define i32 @test_atomic_rmw_or_8(i32 %iptr, i32 %v) { |
411 entry: | 405 entry: |
412 %trunc = trunc i32 %v to i8 | 406 %trunc = trunc i32 %v to i8 |
413 %ptr = inttoptr i32 %iptr to i8* | 407 %ptr = inttoptr i32 %iptr to i8* |
414 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 3, i8* %ptr, i8 %trunc, i32 6) | 408 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 3, i8* %ptr, i8 %trunc, i32 6) |
415 %a_ext = zext i8 %a to i32 | 409 %a_ext = zext i8 %a to i32 |
416 ret i32 %a_ext | 410 ret i32 %a_ext |
417 } | 411 } |
418 ; CHECK-LABEL: test_atomic_rmw_or_8 | 412 ; CHECK-LABEL: test_atomic_rmw_or_8 |
419 ; CHECK: mov al, byte ptr | 413 ; CHECK: mov al,BYTE PTR |
420 ; Dest cannot be eax here, because eax is used for the old value. Also want | 414 ; Dest cannot be eax here, because eax is used for the old value. Also want |
421 ; to make sure that cmpxchg's source is the same register. | 415 ; to make sure that cmpxchg's source is the same register. |
422 ; CHECK: or [[REG:[^a].]] | 416 ; CHECK: or [[REG:[^a].]] |
423 ; CHECK: lock | 417 ; CHECK: lock |
424 ; CHECK-NEXT: cmpxchg byte ptr [e{{[^a].}}], [[REG]] | 418 ; CHECK-NEXT: cmpxchg BYTE PTR [e{{[^a].}}], [[REG]] |
425 ; CHECK: jne -{{[0-9]}} | 419 ; CHECK: jne-{{[0-9]}} |
426 | 420 |
427 define i32 @test_atomic_rmw_or_16(i32 %iptr, i32 %v) { | 421 define i32 @test_atomic_rmw_or_16(i32 %iptr, i32 %v) { |
428 entry: | 422 entry: |
429 %trunc = trunc i32 %v to i16 | 423 %trunc = trunc i32 %v to i16 |
430 %ptr = inttoptr i32 %iptr to i16* | 424 %ptr = inttoptr i32 %iptr to i16* |
431 %a = call i16 @llvm.nacl.atomic.rmw.i16(i32 3, i16* %ptr, i16 %trunc, i32 6) | 425 %a = call i16 @llvm.nacl.atomic.rmw.i16(i32 3, i16* %ptr, i16 %trunc, i32 6) |
432 %a_ext = zext i16 %a to i32 | 426 %a_ext = zext i16 %a to i32 |
433 ret i32 %a_ext | 427 ret i32 %a_ext |
434 } | 428 } |
435 ; CHECK-LABEL: test_atomic_rmw_or_16 | 429 ; CHECK-LABEL: test_atomic_rmw_or_16 |
436 ; CHECK: mov ax, word ptr | 430 ; CHECK: mov ax,WORD PTR |
437 ; CHECK: or [[REG:[^a].]] | 431 ; CHECK: or [[REG:[^a].]] |
438 ; CHECK: lock | 432 ; CHECK: lock |
439 ; CHECK-NEXT: cmpxchg word ptr [e{{[^a].}}], [[REG]] | 433 ; CHECK-NEXT: cmpxchg WORD PTR [e{{[^a].}}], [[REG]] |
440 ; CHECK: jne -{{[0-9]}} | 434 ; CHECK: jne-{{[0-9]}} |
441 | 435 |
442 define i32 @test_atomic_rmw_or_32(i32 %iptr, i32 %v) { | 436 define i32 @test_atomic_rmw_or_32(i32 %iptr, i32 %v) { |
443 entry: | 437 entry: |
444 %ptr = inttoptr i32 %iptr to i32* | 438 %ptr = inttoptr i32 %iptr to i32* |
445 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 3, i32* %ptr, i32 %v, i32 6) | 439 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 3, i32* %ptr, i32 %v, i32 6) |
446 ret i32 %a | 440 ret i32 %a |
447 } | 441 } |
448 ; CHECK-LABEL: test_atomic_rmw_or_32 | 442 ; CHECK-LABEL: test_atomic_rmw_or_32 |
449 ; CHECK: mov eax, dword ptr | 443 ; CHECK: mov eax,DWORD PTR |
450 ; CHECK: or [[REG:e[^a].]] | 444 ; CHECK: or [[REG:e[^a].]] |
451 ; CHECK: lock | 445 ; CHECK: lock |
452 ; CHECK-NEXT: cmpxchg dword ptr [e{{[^a].}}], [[REG]] | 446 ; CHECK-NEXT: cmpxchg DWORD PTR [e{{[^a].}}], [[REG]] |
453 ; CHECK: jne -{{[0-9]}} | 447 ; CHECK: jne-{{[0-9]}} |
454 | 448 |
455 define i64 @test_atomic_rmw_or_64(i32 %iptr, i64 %v) { | 449 define i64 @test_atomic_rmw_or_64(i32 %iptr, i64 %v) { |
456 entry: | 450 entry: |
457 %ptr = inttoptr i32 %iptr to i64* | 451 %ptr = inttoptr i32 %iptr to i64* |
458 %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 3, i64* %ptr, i64 %v, i32 6) | 452 %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 3, i64* %ptr, i64 %v, i32 6) |
459 ret i64 %a | 453 ret i64 %a |
460 } | 454 } |
461 ; CHECK-LABEL: test_atomic_rmw_or_64 | 455 ; CHECK-LABEL: test_atomic_rmw_or_64 |
462 ; CHECK: push ebx | 456 ; CHECK: push ebx |
463 ; CHECK: mov eax, dword ptr [{{.*}}] | 457 ; CHECK: mov eax,DWORD PTR [{{.*}}] |
464 ; CHECK: mov edx, dword ptr [{{.*}} + 4] | 458 ; CHECK: mov edx,DWORD PTR [{{.*}}+0x4] |
465 ; CHECK: mov ebx, eax | 459 ; CHECK: mov ebx,eax |
466 ; CHECK: or ebx, {{.*e.[^x]}} | 460 ; CHECK: or ebx, {{.*e.[^x]}} |
467 ; CHECK: mov ecx, edx | 461 ; CHECK: mov ecx,edx |
468 ; CHECK: or ecx, {{.*e.[^x]}} | 462 ; CHECK: or ecx, {{.*e.[^x]}} |
469 ; CHECK: lock | 463 ; CHECK: lock |
470 ; CHECK-NEXT: cmpxchg8b qword ptr [e{{.[^x]}}] | 464 ; CHECK-NEXT: cmpxchg8b QWORD PTR [e{{.[^x]}}] |
471 ; CHECK: jne -{{[0-9]}} | 465 ; CHECK: jne-{{[0-9]}} |
472 | 466 |
473 define i32 @test_atomic_rmw_or_32_ignored(i32 %iptr, i32 %v) { | 467 define i32 @test_atomic_rmw_or_32_ignored(i32 %iptr, i32 %v) { |
474 entry: | 468 entry: |
475 %ptr = inttoptr i32 %iptr to i32* | 469 %ptr = inttoptr i32 %iptr to i32* |
476 %ignored = call i32 @llvm.nacl.atomic.rmw.i32(i32 3, i32* %ptr, i32 %v, i32 6) | 470 %ignored = call i32 @llvm.nacl.atomic.rmw.i32(i32 3, i32* %ptr, i32 %v, i32 6) |
477 ret i32 %v | 471 ret i32 %v |
478 } | 472 } |
479 ; CHECK-LABEL: test_atomic_rmw_or_32_ignored | 473 ; CHECK-LABEL: test_atomic_rmw_or_32_ignored |
480 ; Could just "lock or", if we inspect the liveness information first. | 474 ; Could just "lock or", if we inspect the liveness information first. |
481 ; Would also need a way to introduce "lock"'edness to binary | 475 ; Would also need a way to introduce "lock"'edness to binary |
482 ; operators without introducing overhead on the more common binary ops. | 476 ; operators without introducing overhead on the more common binary ops. |
483 ; CHECK: mov eax, dword ptr | 477 ; CHECK: mov eax,DWORD PTR |
484 ; CHECK: or [[REG:e[^a].]] | 478 ; CHECK: or [[REG:e[^a].]] |
485 ; CHECK: lock | 479 ; CHECK: lock |
486 ; CHECK-NEXT: cmpxchg dword ptr [e{{[^a].}}], [[REG]] | 480 ; CHECK-NEXT: cmpxchg DWORD PTR [e{{[^a].}}], [[REG]] |
487 ; CHECK: jne -{{[0-9]}} | 481 ; CHECK: jne-{{[0-9]}} |
488 | 482 |
489 ;; and | 483 ;; and |
490 | 484 |
491 define i32 @test_atomic_rmw_and_8(i32 %iptr, i32 %v) { | 485 define i32 @test_atomic_rmw_and_8(i32 %iptr, i32 %v) { |
492 entry: | 486 entry: |
493 %trunc = trunc i32 %v to i8 | 487 %trunc = trunc i32 %v to i8 |
494 %ptr = inttoptr i32 %iptr to i8* | 488 %ptr = inttoptr i32 %iptr to i8* |
495 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 4, i8* %ptr, i8 %trunc, i32 6) | 489 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 4, i8* %ptr, i8 %trunc, i32 6) |
496 %a_ext = zext i8 %a to i32 | 490 %a_ext = zext i8 %a to i32 |
497 ret i32 %a_ext | 491 ret i32 %a_ext |
498 } | 492 } |
499 ; CHECK-LABEL: test_atomic_rmw_and_8 | 493 ; CHECK-LABEL: test_atomic_rmw_and_8 |
500 ; CHECK: mov al, byte ptr | 494 ; CHECK: mov al,BYTE PTR |
501 ; CHECK: and [[REG:[^a].]] | 495 ; CHECK: and [[REG:[^a].]] |
502 ; CHECK: lock | 496 ; CHECK: lock |
503 ; CHECK-NEXT: cmpxchg byte ptr [e{{[^a].}}], [[REG]] | 497 ; CHECK-NEXT: cmpxchg BYTE PTR [e{{[^a].}}], [[REG]] |
504 ; CHECK: jne -{{[0-9]}} | 498 ; CHECK: jne-{{[0-9]}} |
505 | 499 |
506 define i32 @test_atomic_rmw_and_16(i32 %iptr, i32 %v) { | 500 define i32 @test_atomic_rmw_and_16(i32 %iptr, i32 %v) { |
507 entry: | 501 entry: |
508 %trunc = trunc i32 %v to i16 | 502 %trunc = trunc i32 %v to i16 |
509 %ptr = inttoptr i32 %iptr to i16* | 503 %ptr = inttoptr i32 %iptr to i16* |
510 %a = call i16 @llvm.nacl.atomic.rmw.i16(i32 4, i16* %ptr, i16 %trunc, i32 6) | 504 %a = call i16 @llvm.nacl.atomic.rmw.i16(i32 4, i16* %ptr, i16 %trunc, i32 6) |
511 %a_ext = zext i16 %a to i32 | 505 %a_ext = zext i16 %a to i32 |
512 ret i32 %a_ext | 506 ret i32 %a_ext |
513 } | 507 } |
514 ; CHECK-LABEL: test_atomic_rmw_and_16 | 508 ; CHECK-LABEL: test_atomic_rmw_and_16 |
515 ; CHECK: mov ax, word ptr | 509 ; CHECK: mov ax,WORD PTR |
516 ; CHECK: and | 510 ; CHECK: and |
517 ; CHECK: lock | 511 ; CHECK: lock |
518 ; CHECK-NEXT: cmpxchg word ptr [e{{[^a].}}] | 512 ; CHECK-NEXT: cmpxchg WORD PTR [e{{[^a].}}] |
519 ; CHECK: jne -{{[0-9]}} | 513 ; CHECK: jne-{{[0-9]}} |
520 | 514 |
521 define i32 @test_atomic_rmw_and_32(i32 %iptr, i32 %v) { | 515 define i32 @test_atomic_rmw_and_32(i32 %iptr, i32 %v) { |
522 entry: | 516 entry: |
523 %ptr = inttoptr i32 %iptr to i32* | 517 %ptr = inttoptr i32 %iptr to i32* |
524 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 4, i32* %ptr, i32 %v, i32 6) | 518 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 4, i32* %ptr, i32 %v, i32 6) |
525 ret i32 %a | 519 ret i32 %a |
526 } | 520 } |
527 ; CHECK-LABEL: test_atomic_rmw_and_32 | 521 ; CHECK-LABEL: test_atomic_rmw_and_32 |
528 ; CHECK: mov eax, dword ptr | 522 ; CHECK: mov eax,DWORD PTR |
529 ; CHECK: and | 523 ; CHECK: and |
530 ; CHECK: lock | 524 ; CHECK: lock |
531 ; CHECK-NEXT: cmpxchg dword ptr [e{{[^a].}}] | 525 ; CHECK-NEXT: cmpxchg DWORD PTR [e{{[^a].}}] |
532 ; CHECK: jne -{{[0-9]}} | 526 ; CHECK: jne-{{[0-9]}} |
533 | 527 |
534 define i64 @test_atomic_rmw_and_64(i32 %iptr, i64 %v) { | 528 define i64 @test_atomic_rmw_and_64(i32 %iptr, i64 %v) { |
535 entry: | 529 entry: |
536 %ptr = inttoptr i32 %iptr to i64* | 530 %ptr = inttoptr i32 %iptr to i64* |
537 %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 4, i64* %ptr, i64 %v, i32 6) | 531 %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 4, i64* %ptr, i64 %v, i32 6) |
538 ret i64 %a | 532 ret i64 %a |
539 } | 533 } |
540 ; CHECK-LABEL: test_atomic_rmw_and_64 | 534 ; CHECK-LABEL: test_atomic_rmw_and_64 |
541 ; CHECK: push ebx | 535 ; CHECK: push ebx |
542 ; CHECK: mov eax, dword ptr [{{.*}}] | 536 ; CHECK: mov eax,DWORD PTR [{{.*}}] |
543 ; CHECK: mov edx, dword ptr [{{.*}} + 4] | 537 ; CHECK: mov edx,DWORD PTR [{{.*}}+0x4] |
544 ; CHECK: mov ebx, eax | 538 ; CHECK: mov ebx,eax |
545 ; CHECK: and ebx, {{.*e.[^x]}} | 539 ; CHECK: and ebx, {{.*e.[^x]}} |
546 ; CHECK: mov ecx, edx | 540 ; CHECK: mov ecx,edx |
547 ; CHECK: and ecx, {{.*e.[^x]}} | 541 ; CHECK: and ecx, {{.*e.[^x]}} |
548 ; CHECK: lock | 542 ; CHECK: lock |
549 ; CHECK-NEXT: cmpxchg8b qword ptr [e{{.[^x]}}] | 543 ; CHECK-NEXT: cmpxchg8b QWORD PTR [e{{.[^x]}}] |
550 ; CHECK: jne -{{[0-9]}} | 544 ; CHECK: jne-{{[0-9]}} |
551 | 545 |
552 define i32 @test_atomic_rmw_and_32_ignored(i32 %iptr, i32 %v) { | 546 define i32 @test_atomic_rmw_and_32_ignored(i32 %iptr, i32 %v) { |
553 entry: | 547 entry: |
554 %ptr = inttoptr i32 %iptr to i32* | 548 %ptr = inttoptr i32 %iptr to i32* |
555 %ignored = call i32 @llvm.nacl.atomic.rmw.i32(i32 4, i32* %ptr, i32 %v, i32 6) | 549 %ignored = call i32 @llvm.nacl.atomic.rmw.i32(i32 4, i32* %ptr, i32 %v, i32 6) |
556 ret i32 %v | 550 ret i32 %v |
557 } | 551 } |
558 ; CHECK-LABEL: test_atomic_rmw_and_32_ignored | 552 ; CHECK-LABEL: test_atomic_rmw_and_32_ignored |
559 ; Could just "lock and" | 553 ; Could just "lock and" |
560 ; CHECK: mov eax, dword ptr | 554 ; CHECK: mov eax,DWORD PTR |
561 ; CHECK: and | 555 ; CHECK: and |
562 ; CHECK: lock | 556 ; CHECK: lock |
563 ; CHECK-NEXT: cmpxchg dword ptr [e{{[^a].}}] | 557 ; CHECK-NEXT: cmpxchg DWORD PTR [e{{[^a].}}] |
564 ; CHECK: jne -{{[0-9]}} | 558 ; CHECK: jne-{{[0-9]}} |
565 | 559 |
566 ;; xor | 560 ;; xor |
567 | 561 |
568 define i32 @test_atomic_rmw_xor_8(i32 %iptr, i32 %v) { | 562 define i32 @test_atomic_rmw_xor_8(i32 %iptr, i32 %v) { |
569 entry: | 563 entry: |
570 %trunc = trunc i32 %v to i8 | 564 %trunc = trunc i32 %v to i8 |
571 %ptr = inttoptr i32 %iptr to i8* | 565 %ptr = inttoptr i32 %iptr to i8* |
572 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 5, i8* %ptr, i8 %trunc, i32 6) | 566 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 5, i8* %ptr, i8 %trunc, i32 6) |
573 %a_ext = zext i8 %a to i32 | 567 %a_ext = zext i8 %a to i32 |
574 ret i32 %a_ext | 568 ret i32 %a_ext |
575 } | 569 } |
576 ; CHECK-LABEL: test_atomic_rmw_xor_8 | 570 ; CHECK-LABEL: test_atomic_rmw_xor_8 |
577 ; CHECK: mov al, byte ptr | 571 ; CHECK: mov al,BYTE PTR |
578 ; CHECK: xor [[REG:[^a].]] | 572 ; CHECK: xor [[REG:[^a].]] |
579 ; CHECK: lock | 573 ; CHECK: lock |
580 ; CHECK-NEXT: cmpxchg byte ptr [e{{[^a].}}], [[REG]] | 574 ; CHECK-NEXT: cmpxchg BYTE PTR [e{{[^a].}}], [[REG]] |
581 ; CHECK: jne -{{[0-9]}} | 575 ; CHECK: jne-{{[0-9]}} |
582 | 576 |
583 define i32 @test_atomic_rmw_xor_16(i32 %iptr, i32 %v) { | 577 define i32 @test_atomic_rmw_xor_16(i32 %iptr, i32 %v) { |
584 entry: | 578 entry: |
585 %trunc = trunc i32 %v to i16 | 579 %trunc = trunc i32 %v to i16 |
586 %ptr = inttoptr i32 %iptr to i16* | 580 %ptr = inttoptr i32 %iptr to i16* |
587 %a = call i16 @llvm.nacl.atomic.rmw.i16(i32 5, i16* %ptr, i16 %trunc, i32 6) | 581 %a = call i16 @llvm.nacl.atomic.rmw.i16(i32 5, i16* %ptr, i16 %trunc, i32 6) |
588 %a_ext = zext i16 %a to i32 | 582 %a_ext = zext i16 %a to i32 |
589 ret i32 %a_ext | 583 ret i32 %a_ext |
590 } | 584 } |
591 ; CHECK-LABEL: test_atomic_rmw_xor_16 | 585 ; CHECK-LABEL: test_atomic_rmw_xor_16 |
592 ; CHECK: mov ax, word ptr | 586 ; CHECK: mov ax,WORD PTR |
593 ; CHECK: xor | 587 ; CHECK: xor |
594 ; CHECK: lock | 588 ; CHECK: lock |
595 ; CHECK-NEXT: cmpxchg word ptr [e{{[^a].}}] | 589 ; CHECK-NEXT: cmpxchg WORD PTR [e{{[^a].}}] |
596 ; CHECK: jne -{{[0-9]}} | 590 ; CHECK: jne-{{[0-9]}} |
597 | 591 |
598 | 592 |
599 define i32 @test_atomic_rmw_xor_32(i32 %iptr, i32 %v) { | 593 define i32 @test_atomic_rmw_xor_32(i32 %iptr, i32 %v) { |
600 entry: | 594 entry: |
601 %ptr = inttoptr i32 %iptr to i32* | 595 %ptr = inttoptr i32 %iptr to i32* |
602 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 5, i32* %ptr, i32 %v, i32 6) | 596 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 5, i32* %ptr, i32 %v, i32 6) |
603 ret i32 %a | 597 ret i32 %a |
604 } | 598 } |
605 ; CHECK-LABEL: test_atomic_rmw_xor_32 | 599 ; CHECK-LABEL: test_atomic_rmw_xor_32 |
606 ; CHECK: mov eax, dword ptr | 600 ; CHECK: mov eax,DWORD PTR |
607 ; CHECK: xor | 601 ; CHECK: xor |
608 ; CHECK: lock | 602 ; CHECK: lock |
609 ; CHECK-NEXT: cmpxchg dword ptr [e{{[^a].}}] | 603 ; CHECK-NEXT: cmpxchg DWORD PTR [e{{[^a].}}] |
610 ; CHECK: jne -{{[0-9]}} | 604 ; CHECK: jne-{{[0-9]}} |
611 | 605 |
612 define i64 @test_atomic_rmw_xor_64(i32 %iptr, i64 %v) { | 606 define i64 @test_atomic_rmw_xor_64(i32 %iptr, i64 %v) { |
613 entry: | 607 entry: |
614 %ptr = inttoptr i32 %iptr to i64* | 608 %ptr = inttoptr i32 %iptr to i64* |
615 %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 5, i64* %ptr, i64 %v, i32 6) | 609 %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 5, i64* %ptr, i64 %v, i32 6) |
616 ret i64 %a | 610 ret i64 %a |
617 } | 611 } |
618 ; CHECK-LABEL: test_atomic_rmw_xor_64 | 612 ; CHECK-LABEL: test_atomic_rmw_xor_64 |
619 ; CHECK: push ebx | 613 ; CHECK: push ebx |
620 ; CHECK: mov eax, dword ptr [{{.*}}] | 614 ; CHECK: mov eax,DWORD PTR [{{.*}}] |
621 ; CHECK: mov edx, dword ptr [{{.*}} + 4] | 615 ; CHECK: mov edx,DWORD PTR [{{.*}}+0x4] |
622 ; CHECK: mov ebx, eax | 616 ; CHECK: mov ebx,eax |
623 ; CHECK: or ebx, {{.*e.[^x]}} | 617 ; CHECK: or ebx, {{.*e.[^x]}} |
624 ; CHECK: mov ecx, edx | 618 ; CHECK: mov ecx,edx |
625 ; CHECK: or ecx, {{.*e.[^x]}} | 619 ; CHECK: or ecx, {{.*e.[^x]}} |
626 ; CHECK: lock | 620 ; CHECK: lock |
627 ; CHECK-NEXT: cmpxchg8b qword ptr [e{{.[^x]}}] | 621 ; CHECK-NEXT: cmpxchg8b QWORD PTR [e{{.[^x]}}] |
628 ; CHECK: jne -{{[0-9]}} | 622 ; CHECK: jne-{{[0-9]}} |
629 | 623 |
630 define i32 @test_atomic_rmw_xor_32_ignored(i32 %iptr, i32 %v) { | 624 define i32 @test_atomic_rmw_xor_32_ignored(i32 %iptr, i32 %v) { |
631 entry: | 625 entry: |
632 %ptr = inttoptr i32 %iptr to i32* | 626 %ptr = inttoptr i32 %iptr to i32* |
633 %ignored = call i32 @llvm.nacl.atomic.rmw.i32(i32 5, i32* %ptr, i32 %v, i32 6) | 627 %ignored = call i32 @llvm.nacl.atomic.rmw.i32(i32 5, i32* %ptr, i32 %v, i32 6) |
634 ret i32 %v | 628 ret i32 %v |
635 } | 629 } |
636 ; CHECK-LABEL: test_atomic_rmw_xor_32_ignored | 630 ; CHECK-LABEL: test_atomic_rmw_xor_32_ignored |
637 ; CHECK: mov eax, dword ptr | 631 ; CHECK: mov eax,DWORD PTR |
638 ; CHECK: xor | 632 ; CHECK: xor |
639 ; CHECK: lock | 633 ; CHECK: lock |
640 ; CHECK-NEXT: cmpxchg dword ptr [e{{[^a].}}] | 634 ; CHECK-NEXT: cmpxchg DWORD PTR [e{{[^a].}}] |
641 ; CHECK: jne -{{[0-9]}} | 635 ; CHECK: jne-{{[0-9]}} |
642 | 636 |
643 ;; exchange | 637 ;; exchange |
644 | 638 |
645 define i32 @test_atomic_rmw_xchg_8(i32 %iptr, i32 %v) { | 639 define i32 @test_atomic_rmw_xchg_8(i32 %iptr, i32 %v) { |
646 entry: | 640 entry: |
647 %trunc = trunc i32 %v to i8 | 641 %trunc = trunc i32 %v to i8 |
648 %ptr = inttoptr i32 %iptr to i8* | 642 %ptr = inttoptr i32 %iptr to i8* |
649 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 6, i8* %ptr, i8 %trunc, i32 6) | 643 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 6, i8* %ptr, i8 %trunc, i32 6) |
650 %a_ext = zext i8 %a to i32 | 644 %a_ext = zext i8 %a to i32 |
651 ret i32 %a_ext | 645 ret i32 %a_ext |
652 } | 646 } |
653 ; CHECK-LABEL: test_atomic_rmw_xchg_8 | 647 ; CHECK-LABEL: test_atomic_rmw_xchg_8 |
654 ; CHECK: xchg byte ptr {{.*}}, [[REG:.*]] | 648 ; CHECK: xchg BYTE PTR {{.*}}, [[REG:.*]] |
655 | 649 |
656 define i32 @test_atomic_rmw_xchg_16(i32 %iptr, i32 %v) { | 650 define i32 @test_atomic_rmw_xchg_16(i32 %iptr, i32 %v) { |
657 entry: | 651 entry: |
658 %trunc = trunc i32 %v to i16 | 652 %trunc = trunc i32 %v to i16 |
659 %ptr = inttoptr i32 %iptr to i16* | 653 %ptr = inttoptr i32 %iptr to i16* |
660 %a = call i16 @llvm.nacl.atomic.rmw.i16(i32 6, i16* %ptr, i16 %trunc, i32 6) | 654 %a = call i16 @llvm.nacl.atomic.rmw.i16(i32 6, i16* %ptr, i16 %trunc, i32 6) |
661 %a_ext = zext i16 %a to i32 | 655 %a_ext = zext i16 %a to i32 |
662 ret i32 %a_ext | 656 ret i32 %a_ext |
663 } | 657 } |
664 ; CHECK-LABEL: test_atomic_rmw_xchg_16 | 658 ; CHECK-LABEL: test_atomic_rmw_xchg_16 |
665 ; CHECK: xchg word ptr {{.*}}, [[REG:.*]] | 659 ; CHECK: xchg WORD PTR {{.*}}, [[REG:.*]] |
666 | 660 |
667 define i32 @test_atomic_rmw_xchg_32(i32 %iptr, i32 %v) { | 661 define i32 @test_atomic_rmw_xchg_32(i32 %iptr, i32 %v) { |
668 entry: | 662 entry: |
669 %ptr = inttoptr i32 %iptr to i32* | 663 %ptr = inttoptr i32 %iptr to i32* |
670 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 6, i32* %ptr, i32 %v, i32 6) | 664 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 6, i32* %ptr, i32 %v, i32 6) |
671 ret i32 %a | 665 ret i32 %a |
672 } | 666 } |
673 ; CHECK-LABEL: test_atomic_rmw_xchg_32 | 667 ; CHECK-LABEL: test_atomic_rmw_xchg_32 |
674 ; CHECK: xchg dword ptr {{.*}}, [[REG:.*]] | 668 ; CHECK: xchg DWORD PTR {{.*}}, [[REG:.*]] |
675 | 669 |
676 define i64 @test_atomic_rmw_xchg_64(i32 %iptr, i64 %v) { | 670 define i64 @test_atomic_rmw_xchg_64(i32 %iptr, i64 %v) { |
677 entry: | 671 entry: |
678 %ptr = inttoptr i32 %iptr to i64* | 672 %ptr = inttoptr i32 %iptr to i64* |
679 %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 6, i64* %ptr, i64 %v, i32 6) | 673 %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 6, i64* %ptr, i64 %v, i32 6) |
680 ret i64 %a | 674 ret i64 %a |
681 } | 675 } |
682 ; CHECK-LABEL: test_atomic_rmw_xchg_64 | 676 ; CHECK-LABEL: test_atomic_rmw_xchg_64 |
683 ; CHECK: push ebx | 677 ; CHECK: push ebx |
684 ; CHECK-DAG: mov edx | 678 ; CHECK-DAG: mov edx |
685 ; CHECK-DAG: mov eax | 679 ; CHECK-DAG: mov eax |
686 ; CHECK-DAG: mov ecx | 680 ; CHECK-DAG: mov ecx |
687 ; CHECK-DAG: mov ebx | 681 ; CHECK-DAG: mov ebx |
688 ; CHECK: lock | 682 ; CHECK: lock |
689 ; CHECK-NEXT: cmpxchg8b qword ptr [{{e.[^x]}}] | 683 ; CHECK-NEXT: cmpxchg8b QWORD PTR [{{e.[^x]}}] |
690 ; CHECK: jne -{{[0-9]}} | 684 ; CHECK: jne-{{[0-9]}} |
691 | 685 |
692 define i32 @test_atomic_rmw_xchg_32_ignored(i32 %iptr, i32 %v) { | 686 define i32 @test_atomic_rmw_xchg_32_ignored(i32 %iptr, i32 %v) { |
693 entry: | 687 entry: |
694 %ptr = inttoptr i32 %iptr to i32* | 688 %ptr = inttoptr i32 %iptr to i32* |
695 %ignored = call i32 @llvm.nacl.atomic.rmw.i32(i32 6, i32* %ptr, i32 %v, i32 6) | 689 %ignored = call i32 @llvm.nacl.atomic.rmw.i32(i32 6, i32* %ptr, i32 %v, i32 6) |
696 ret i32 %v | 690 ret i32 %v |
697 } | 691 } |
698 ; In this case, ignoring the return value doesn't help. The xchg is | 692 ; In this case, ignoring the return value doesn't help. The xchg is |
699 ; used to do an atomic store. | 693 ; used to do an atomic store. |
700 ; CHECK-LABEL: test_atomic_rmw_xchg_32_ignored | 694 ; CHECK-LABEL: test_atomic_rmw_xchg_32_ignored |
701 ; CHECK: xchg dword ptr {{.*}}, [[REG:.*]] | 695 ; CHECK: xchg DWORD PTR {{.*}}, [[REG:.*]] |
702 | 696 |
703 ;;;; Cmpxchg | 697 ;;;; Cmpxchg |
704 | 698 |
705 define i32 @test_atomic_cmpxchg_8(i32 %iptr, i32 %expected, i32 %desired) { | 699 define i32 @test_atomic_cmpxchg_8(i32 %iptr, i32 %expected, i32 %desired) { |
706 entry: | 700 entry: |
707 %trunc_exp = trunc i32 %expected to i8 | 701 %trunc_exp = trunc i32 %expected to i8 |
708 %trunc_des = trunc i32 %desired to i8 | 702 %trunc_des = trunc i32 %desired to i8 |
709 %ptr = inttoptr i32 %iptr to i8* | 703 %ptr = inttoptr i32 %iptr to i8* |
710 %old = call i8 @llvm.nacl.atomic.cmpxchg.i8(i8* %ptr, i8 %trunc_exp, | 704 %old = call i8 @llvm.nacl.atomic.cmpxchg.i8(i8* %ptr, i8 %trunc_exp, |
711 i8 %trunc_des, i32 6, i32 6) | 705 i8 %trunc_des, i32 6, i32 6) |
712 %old_ext = zext i8 %old to i32 | 706 %old_ext = zext i8 %old to i32 |
713 ret i32 %old_ext | 707 ret i32 %old_ext |
714 } | 708 } |
715 ; CHECK-LABEL: test_atomic_cmpxchg_8 | 709 ; CHECK-LABEL: test_atomic_cmpxchg_8 |
716 ; CHECK: mov eax, {{.*}} | 710 ; CHECK: mov eax,{{.*}} |
717 ; Need to check that eax isn't used as the address register or the desired. | 711 ; Need to check that eax isn't used as the address register or the desired. |
718 ; since it is already used as the *expected* register. | 712 ; since it is already used as the *expected* register. |
719 ; CHECK: lock | 713 ; CHECK: lock |
720 ; CHECK-NEXT: cmpxchg byte ptr [e{{[^a].}}], {{[^a]}}l | 714 ; CHECK-NEXT: cmpxchg BYTE PTR [e{{[^a].}}], {{[^a]}}l |
721 | 715 |
722 define i32 @test_atomic_cmpxchg_16(i32 %iptr, i32 %expected, i32 %desired) { | 716 define i32 @test_atomic_cmpxchg_16(i32 %iptr, i32 %expected, i32 %desired) { |
723 entry: | 717 entry: |
724 %trunc_exp = trunc i32 %expected to i16 | 718 %trunc_exp = trunc i32 %expected to i16 |
725 %trunc_des = trunc i32 %desired to i16 | 719 %trunc_des = trunc i32 %desired to i16 |
726 %ptr = inttoptr i32 %iptr to i16* | 720 %ptr = inttoptr i32 %iptr to i16* |
727 %old = call i16 @llvm.nacl.atomic.cmpxchg.i16(i16* %ptr, i16 %trunc_exp, | 721 %old = call i16 @llvm.nacl.atomic.cmpxchg.i16(i16* %ptr, i16 %trunc_exp, |
728 i16 %trunc_des, i32 6, i32 6) | 722 i16 %trunc_des, i32 6, i32 6) |
729 %old_ext = zext i16 %old to i32 | 723 %old_ext = zext i16 %old to i32 |
730 ret i32 %old_ext | 724 ret i32 %old_ext |
731 } | 725 } |
732 ; CHECK-LABEL: test_atomic_cmpxchg_16 | 726 ; CHECK-LABEL: test_atomic_cmpxchg_16 |
733 ; CHECK: mov eax, {{.*}} | 727 ; CHECK: mov eax,{{.*}} |
734 ; CHECK: lock | 728 ; CHECK: lock |
735 ; CHECK-NEXT: cmpxchg word ptr [e{{[^a].}}], {{[^a]}}x | 729 ; CHECK-NEXT: cmpxchg WORD PTR [e{{[^a].}}], {{[^a]}}x |
736 | 730 |
737 define i32 @test_atomic_cmpxchg_32(i32 %iptr, i32 %expected, i32 %desired) { | 731 define i32 @test_atomic_cmpxchg_32(i32 %iptr, i32 %expected, i32 %desired) { |
738 entry: | 732 entry: |
739 %ptr = inttoptr i32 %iptr to i32* | 733 %ptr = inttoptr i32 %iptr to i32* |
740 %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %expected, | 734 %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %expected, |
741 i32 %desired, i32 6, i32 6) | 735 i32 %desired, i32 6, i32 6) |
742 ret i32 %old | 736 ret i32 %old |
743 } | 737 } |
744 ; CHECK-LABEL: test_atomic_cmpxchg_32 | 738 ; CHECK-LABEL: test_atomic_cmpxchg_32 |
745 ; CHECK: mov eax, {{.*}} | 739 ; CHECK: mov eax,{{.*}} |
746 ; CHECK: lock | 740 ; CHECK: lock |
747 ; CHECK-NEXT: cmpxchg dword ptr [e{{[^a].}}], e{{[^a]}} | 741 ; CHECK-NEXT: cmpxchg DWORD PTR [e{{[^a].}}], e{{[^a]}} |
748 | 742 |
749 define i64 @test_atomic_cmpxchg_64(i32 %iptr, i64 %expected, i64 %desired) { | 743 define i64 @test_atomic_cmpxchg_64(i32 %iptr, i64 %expected, i64 %desired) { |
750 entry: | 744 entry: |
751 %ptr = inttoptr i32 %iptr to i64* | 745 %ptr = inttoptr i32 %iptr to i64* |
752 %old = call i64 @llvm.nacl.atomic.cmpxchg.i64(i64* %ptr, i64 %expected, | 746 %old = call i64 @llvm.nacl.atomic.cmpxchg.i64(i64* %ptr, i64 %expected, |
753 i64 %desired, i32 6, i32 6) | 747 i64 %desired, i32 6, i32 6) |
754 ret i64 %old | 748 ret i64 %old |
755 } | 749 } |
756 ; CHECK-LABEL: test_atomic_cmpxchg_64 | 750 ; CHECK-LABEL: test_atomic_cmpxchg_64 |
757 ; CHECK: push ebx | 751 ; CHECK: push ebx |
758 ; CHECK-DAG: mov edx | 752 ; CHECK-DAG: mov edx |
759 ; CHECK-DAG: mov eax | 753 ; CHECK-DAG: mov eax |
760 ; CHECK-DAG: mov ecx | 754 ; CHECK-DAG: mov ecx |
761 ; CHECK-DAG: mov ebx | 755 ; CHECK-DAG: mov ebx |
762 ; CHECK: lock | 756 ; CHECK: lock |
763 ; CHECK-NEXT: cmpxchg8b qword ptr [e{{.[^x]}}] | 757 ; CHECK-NEXT: cmpxchg8b QWORD PTR [e{{.[^x]}}] |
764 ; edx and eax are already the return registers, so they don't actually | 758 ; edx and eax are already the return registers, so they don't actually |
765 ; need to be reshuffled via movs. The next test stores the result | 759 ; need to be reshuffled via movs. The next test stores the result |
766 ; somewhere, so in that case they do need to be mov'ed. | 760 ; somewhere, so in that case they do need to be mov'ed. |
767 | 761 |
768 ; Test a case where %old really does need to be copied out of edx:eax. | 762 ; Test a case where %old really does need to be copied out of edx:eax. |
769 define void @test_atomic_cmpxchg_64_store(i32 %ret_iptr, i32 %iptr, i64 %expecte
d, i64 %desired) { | 763 define void @test_atomic_cmpxchg_64_store(i32 %ret_iptr, i32 %iptr, i64 %expecte
d, i64 %desired) { |
770 entry: | 764 entry: |
771 %ptr = inttoptr i32 %iptr to i64* | 765 %ptr = inttoptr i32 %iptr to i64* |
772 %old = call i64 @llvm.nacl.atomic.cmpxchg.i64(i64* %ptr, i64 %expected, | 766 %old = call i64 @llvm.nacl.atomic.cmpxchg.i64(i64* %ptr, i64 %expected, |
773 i64 %desired, i32 6, i32 6) | 767 i64 %desired, i32 6, i32 6) |
774 %__6 = inttoptr i32 %ret_iptr to i64* | 768 %__6 = inttoptr i32 %ret_iptr to i64* |
775 store i64 %old, i64* %__6, align 1 | 769 store i64 %old, i64* %__6, align 1 |
776 ret void | 770 ret void |
777 } | 771 } |
778 ; CHECK-LABEL: test_atomic_cmpxchg_64_store | 772 ; CHECK-LABEL: test_atomic_cmpxchg_64_store |
779 ; CHECK: push ebx | 773 ; CHECK: push ebx |
780 ; CHECK-DAG: mov edx | 774 ; CHECK-DAG: mov edx |
781 ; CHECK-DAG: mov eax | 775 ; CHECK-DAG: mov eax |
782 ; CHECK-DAG: mov ecx | 776 ; CHECK-DAG: mov ecx |
783 ; CHECK-DAG: mov ebx | 777 ; CHECK-DAG: mov ebx |
784 ; CHECK: lock | 778 ; CHECK: lock |
785 ; CHECK-NEXT: cmpxchg8b qword ptr [e{{.[^x]}}] | 779 ; CHECK-NEXT: cmpxchg8b QWORD PTR [e{{.[^x]}}] |
786 ; CHECK-DAG: mov {{.*}}, edx | 780 ; CHECK-DAG: mov {{.*}},edx |
787 ; CHECK-DAG: mov {{.*}}, eax | 781 ; CHECK-DAG: mov {{.*}},eax |
788 | 782 |
789 ; Test with some more register pressure. When we have an alloca, ebp is | 783 ; Test with some more register pressure. When we have an alloca, ebp is |
790 ; used to manage the stack frame, so it cannot be used as a register either. | 784 ; used to manage the stack frame, so it cannot be used as a register either. |
791 define i64 @test_atomic_cmpxchg_64_alloca(i32 %iptr, i64 %expected, i64 %desired
) { | 785 define i64 @test_atomic_cmpxchg_64_alloca(i32 %iptr, i64 %expected, i64 %desired
) { |
792 entry: | 786 entry: |
793 %alloca_ptr = alloca i8, i32 16, align 16 | 787 %alloca_ptr = alloca i8, i32 16, align 16 |
794 %ptr = inttoptr i32 %iptr to i64* | 788 %ptr = inttoptr i32 %iptr to i64* |
795 %old = call i64 @llvm.nacl.atomic.cmpxchg.i64(i64* %ptr, i64 %expected, | 789 %old = call i64 @llvm.nacl.atomic.cmpxchg.i64(i64* %ptr, i64 %expected, |
796 i64 %desired, i32 6, i32 6) | 790 i64 %desired, i32 6, i32 6) |
797 store i8 0, i8* %alloca_ptr, align 1 | 791 store i8 0, i8* %alloca_ptr, align 1 |
798 store i8 1, i8* %alloca_ptr, align 1 | 792 store i8 1, i8* %alloca_ptr, align 1 |
799 store i8 2, i8* %alloca_ptr, align 1 | 793 store i8 2, i8* %alloca_ptr, align 1 |
800 store i8 3, i8* %alloca_ptr, align 1 | 794 store i8 3, i8* %alloca_ptr, align 1 |
801 %__6 = ptrtoint i8* %alloca_ptr to i32 | 795 %__6 = ptrtoint i8* %alloca_ptr to i32 |
802 call void @use_ptr(i32 %__6) | 796 call void @use_ptr(i32 %__6) |
803 ret i64 %old | 797 ret i64 %old |
804 } | 798 } |
805 ; CHECK-LABEL: test_atomic_cmpxchg_64_alloca | 799 ; CHECK-LABEL: test_atomic_cmpxchg_64_alloca |
806 ; CHECK: push ebx | 800 ; CHECK: push ebx |
807 ; CHECK-DAG: mov edx | 801 ; CHECK-DAG: mov edx |
808 ; CHECK-DAG: mov eax | 802 ; CHECK-DAG: mov eax |
809 ; CHECK-DAG: mov ecx | 803 ; CHECK-DAG: mov ecx |
810 ; CHECK-DAG: mov ebx | 804 ; CHECK-DAG: mov ebx |
811 ; Ptr cannot be eax, ebx, ecx, or edx (used up for the expected and desired). | 805 ; Ptr cannot be eax, ebx, ecx, or edx (used up for the expected and desired). |
812 ; It also cannot be ebp since we use that for alloca. Also make sure it's | 806 ; It also cannot be ebp since we use that for alloca. Also make sure it's |
813 ; not esp, since that's the stack pointer and mucking with it will break | 807 ; not esp, since that's the stack pointer and mucking with it will break |
814 ; the later use_ptr function call. | 808 ; the later use_ptr function call. |
815 ; That pretty much leaves esi, or edi as the only viable registers. | 809 ; That pretty much leaves esi, or edi as the only viable registers. |
816 ; CHECK: lock | 810 ; CHECK: lock |
817 ; CHECK-NEXT: cmpxchg8b qword ptr [e{{[ds]}}i] | 811 ; CHECK-NEXT: cmpxchg8b QWORD PTR [e{{[ds]}}i] |
818 ; CHECK: call use_ptr | 812 ; CHECK: call {{.*}} R_{{.*}} use_ptr |
819 | 813 |
820 define i32 @test_atomic_cmpxchg_32_ignored(i32 %iptr, i32 %expected, i32 %desire
d) { | 814 define i32 @test_atomic_cmpxchg_32_ignored(i32 %iptr, i32 %expected, i32 %desire
d) { |
821 entry: | 815 entry: |
822 %ptr = inttoptr i32 %iptr to i32* | 816 %ptr = inttoptr i32 %iptr to i32* |
823 %ignored = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %expected, | 817 %ignored = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %expected, |
824 i32 %desired, i32 6, i32 6) | 818 i32 %desired, i32 6, i32 6) |
825 ret i32 0 | 819 ret i32 0 |
826 } | 820 } |
827 ; CHECK-LABEL: test_atomic_cmpxchg_32_ignored | 821 ; CHECK-LABEL: test_atomic_cmpxchg_32_ignored |
828 ; CHECK: mov eax, {{.*}} | 822 ; CHECK: mov eax,{{.*}} |
829 ; CHECK: lock | 823 ; CHECK: lock |
830 ; CHECK-NEXT: cmpxchg dword ptr [e{{[^a].}}] | 824 ; CHECK-NEXT: cmpxchg DWORD PTR [e{{[^a].}}] |
831 | 825 |
832 define i64 @test_atomic_cmpxchg_64_ignored(i32 %iptr, i64 %expected, i64 %desire
d) { | 826 define i64 @test_atomic_cmpxchg_64_ignored(i32 %iptr, i64 %expected, i64 %desire
d) { |
833 entry: | 827 entry: |
834 %ptr = inttoptr i32 %iptr to i64* | 828 %ptr = inttoptr i32 %iptr to i64* |
835 %ignored = call i64 @llvm.nacl.atomic.cmpxchg.i64(i64* %ptr, i64 %expected, | 829 %ignored = call i64 @llvm.nacl.atomic.cmpxchg.i64(i64* %ptr, i64 %expected, |
836 i64 %desired, i32 6, i32 6) | 830 i64 %desired, i32 6, i32 6) |
837 ret i64 0 | 831 ret i64 0 |
838 } | 832 } |
839 ; CHECK-LABEL: test_atomic_cmpxchg_64_ignored | 833 ; CHECK-LABEL: test_atomic_cmpxchg_64_ignored |
840 ; CHECK: push ebx | 834 ; CHECK: push ebx |
841 ; CHECK-DAG: mov edx | 835 ; CHECK-DAG: mov edx |
842 ; CHECK-DAG: mov eax | 836 ; CHECK-DAG: mov eax |
843 ; CHECK-DAG: mov ecx | 837 ; CHECK-DAG: mov ecx |
844 ; CHECK-DAG: mov ebx | 838 ; CHECK-DAG: mov ebx |
845 ; CHECK: lock | 839 ; CHECK: lock |
846 ; CHECK-NEXT: cmpxchg8b qword ptr [e{{.[^x]}}] | 840 ; CHECK-NEXT: cmpxchg8b QWORD PTR [e{{.[^x]}}] |
847 | 841 |
848 ;;;; Fence and is-lock-free. | 842 ;;;; Fence and is-lock-free. |
849 | 843 |
850 define void @test_atomic_fence() { | 844 define void @test_atomic_fence() { |
851 entry: | 845 entry: |
852 call void @llvm.nacl.atomic.fence(i32 6) | 846 call void @llvm.nacl.atomic.fence(i32 6) |
853 ret void | 847 ret void |
854 } | 848 } |
855 ; CHECK-LABEL: test_atomic_fence | 849 ; CHECK-LABEL: test_atomic_fence |
856 ; CHECK: mfence | 850 ; CHECK: mfence |
857 | 851 |
858 define void @test_atomic_fence_all() { | 852 define void @test_atomic_fence_all() { |
859 entry: | 853 entry: |
860 call void @llvm.nacl.atomic.fence.all() | 854 call void @llvm.nacl.atomic.fence.all() |
861 ret void | 855 ret void |
862 } | 856 } |
863 ; CHECK-LABEL: test_atomic_fence_all | 857 ; CHECK-LABEL: test_atomic_fence_all |
864 ; CHECK: mfence | 858 ; CHECK: mfence |
865 | 859 |
866 define i32 @test_atomic_is_lock_free(i32 %iptr) { | 860 define i32 @test_atomic_is_lock_free(i32 %iptr) { |
867 entry: | 861 entry: |
868 %ptr = inttoptr i32 %iptr to i8* | 862 %ptr = inttoptr i32 %iptr to i8* |
869 %i = call i1 @llvm.nacl.atomic.is.lock.free(i32 4, i8* %ptr) | 863 %i = call i1 @llvm.nacl.atomic.is.lock.free(i32 4, i8* %ptr) |
870 %r = zext i1 %i to i32 | 864 %r = zext i1 %i to i32 |
871 ret i32 %r | 865 ret i32 %r |
872 } | 866 } |
873 ; CHECK-LABEL: test_atomic_is_lock_free | 867 ; CHECK-LABEL: test_atomic_is_lock_free |
874 ; CHECK: mov {{.*}}, 1 | 868 ; CHECK: mov {{.*}},0x1 |
875 | 869 |
876 define i32 @test_not_lock_free(i32 %iptr) { | 870 define i32 @test_not_lock_free(i32 %iptr) { |
877 entry: | 871 entry: |
878 %ptr = inttoptr i32 %iptr to i8* | 872 %ptr = inttoptr i32 %iptr to i8* |
879 %i = call i1 @llvm.nacl.atomic.is.lock.free(i32 7, i8* %ptr) | 873 %i = call i1 @llvm.nacl.atomic.is.lock.free(i32 7, i8* %ptr) |
880 %r = zext i1 %i to i32 | 874 %r = zext i1 %i to i32 |
881 ret i32 %r | 875 ret i32 %r |
882 } | 876 } |
883 ; CHECK-LABEL: test_not_lock_free | 877 ; CHECK-LABEL: test_not_lock_free |
884 ; CHECK: mov {{.*}}, 0 | 878 ; CHECK: mov {{.*}},0x0 |
885 | 879 |
886 define i32 @test_atomic_is_lock_free_ignored(i32 %iptr) { | 880 define i32 @test_atomic_is_lock_free_ignored(i32 %iptr) { |
887 entry: | 881 entry: |
888 %ptr = inttoptr i32 %iptr to i8* | 882 %ptr = inttoptr i32 %iptr to i8* |
889 %ignored = call i1 @llvm.nacl.atomic.is.lock.free(i32 4, i8* %ptr) | 883 %ignored = call i1 @llvm.nacl.atomic.is.lock.free(i32 4, i8* %ptr) |
890 ret i32 0 | 884 ret i32 0 |
891 } | 885 } |
892 ; CHECK-LABEL: test_atomic_is_lock_free_ignored | 886 ; CHECK-LABEL: test_atomic_is_lock_free_ignored |
893 ; CHECK: mov {{.*}}, 0 | 887 ; CHECK: mov {{.*}},0x0 |
894 ; This can get optimized out, because it's side-effect-free. | 888 ; This can get optimized out, because it's side-effect-free. |
895 ; CHECKO2-LABEL: test_atomic_is_lock_free_ignored | 889 ; CHECKO2-LABEL: test_atomic_is_lock_free_ignored |
896 ; CHECKO2-NOT: mov {{.*}}, 1 | 890 ; CHECKO2-NOT: mov {{.*}}, 1 |
897 ; CHECKO2: mov {{.*}}, 0 | 891 ; CHECKO2: mov {{.*}}, 0 |
898 | 892 |
899 ; TODO(jvoung): at some point we can take advantage of the | 893 ; TODO(jvoung): at some point we can take advantage of the |
900 ; fact that nacl.atomic.is.lock.free will resolve to a constant | 894 ; fact that nacl.atomic.is.lock.free will resolve to a constant |
901 ; (which adds DCE opportunities). Once we optimize, the test expectations | 895 ; (which adds DCE opportunities). Once we optimize, the test expectations |
902 ; for this case should change. | 896 ; for this case should change. |
903 define i32 @test_atomic_is_lock_free_can_dce(i32 %iptr, i32 %x, i32 %y) { | 897 define i32 @test_atomic_is_lock_free_can_dce(i32 %iptr, i32 %x, i32 %y) { |
904 entry: | 898 entry: |
905 %ptr = inttoptr i32 %iptr to i8* | 899 %ptr = inttoptr i32 %iptr to i8* |
906 %i = call i1 @llvm.nacl.atomic.is.lock.free(i32 4, i8* %ptr) | 900 %i = call i1 @llvm.nacl.atomic.is.lock.free(i32 4, i8* %ptr) |
907 %i_ext = zext i1 %i to i32 | 901 %i_ext = zext i1 %i to i32 |
908 %cmp = icmp eq i32 %i_ext, 1 | 902 %cmp = icmp eq i32 %i_ext, 1 |
909 br i1 %cmp, label %lock_free, label %not_lock_free | 903 br i1 %cmp, label %lock_free, label %not_lock_free |
910 lock_free: | 904 lock_free: |
911 ret i32 %i_ext | 905 ret i32 %i_ext |
912 | 906 |
913 not_lock_free: | 907 not_lock_free: |
914 %z = add i32 %x, %y | 908 %z = add i32 %x, %y |
915 ret i32 %z | 909 ret i32 %z |
916 } | 910 } |
917 ; CHECK-LABEL: test_atomic_is_lock_free_can_dce | 911 ; CHECK-LABEL: test_atomic_is_lock_free_can_dce |
918 ; CHECK: mov {{.*}}, 1 | 912 ; CHECK: mov {{.*}},0x1 |
919 ; CHECK: ret | 913 ; CHECK: ret |
920 ; CHECK: add | 914 ; CHECK: add |
921 ; CHECK: ret | 915 ; CHECK: ret |
OLD | NEW |