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