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 --filetype=obj --disassemble --args -O2 \ | 4 ; RUN: %p2i -i %s --filetype=obj --disassemble --args -O2 \ |
5 ; RUN: | FileCheck %s | 5 ; RUN: -allow-externally-defined-symbols | FileCheck %s |
6 ; RUN: %p2i -i %s --filetype=obj --disassemble --args -O2 \ | 6 ; RUN: %p2i -i %s --filetype=obj --disassemble --args -O2 \ |
7 ; RUN: | FileCheck --check-prefix=O2 %s | 7 ; RUN: -allow-externally-defined-symbols | FileCheck --check-prefix=O2 %s |
8 ; RUN: %p2i -i %s --filetype=obj --disassemble --args -Om1 \ | 8 ; RUN: %p2i -i %s --filetype=obj --disassemble --args -Om1 \ |
9 ; RUN: | FileCheck %s | 9 ; RUN: -allow-externally-defined-symbols | FileCheck %s |
10 | 10 |
11 ; RUN: %if --need=allow_dump --need=target_ARM32 --command %p2i --filetype=asm \ | 11 ; RUN: %if --need=allow_dump --need=target_ARM32 --command %p2i --filetype=asm \ |
12 ; RUN: --target arm32 -i %s --args -O2 --skip-unimplemented \ | 12 ; RUN: --target arm32 -i %s --args -O2 --skip-unimplemented \ |
| 13 ; RUN: -allow-externally-defined-symbols \ |
13 ; RUN: | %if --need=allow_dump --need=target_ARM32 --command FileCheck %s \ | 14 ; RUN: | %if --need=allow_dump --need=target_ARM32 --command FileCheck %s \ |
14 ; RUN: --check-prefix=ARM32 | 15 ; RUN: --check-prefix=ARM32 |
15 | 16 |
16 ; RUN: %if --need=allow_dump --need=target_ARM32 --command %p2i --filetype=asm \ | 17 ; RUN: %if --need=allow_dump --need=target_ARM32 --command %p2i --filetype=asm \ |
17 ; RUN: --target arm32 -i %s --args -O2 --skip-unimplemented \ | 18 ; RUN: --target arm32 -i %s --args -O2 --skip-unimplemented \ |
| 19 ; RUN: -allow-externally-defined-symbols \ |
18 ; RUN: | %if --need=allow_dump --need=target_ARM32 --command FileCheck %s \ | 20 ; RUN: | %if --need=allow_dump --need=target_ARM32 --command FileCheck %s \ |
19 ; RUN: --check-prefix=ARM32O2 | 21 ; RUN: --check-prefix=ARM32O2 |
20 | 22 |
21 ; RUN: %if --need=allow_dump --need=target_ARM32 --command %p2i --filetype=asm \ | 23 ; RUN: %if --need=allow_dump --need=target_ARM32 --command %p2i --filetype=asm \ |
22 ; RUN: --target arm32 -i %s --args -Om1 --skip-unimplemented \ | 24 ; RUN: --target arm32 -i %s --args -Om1 --skip-unimplemented \ |
| 25 ; RUN: -allow-externally-defined-symbols \ |
23 ; RUN: | %if --need=allow_dump --need=target_ARM32 --command FileCheck %s \ | 26 ; RUN: | %if --need=allow_dump --need=target_ARM32 --command FileCheck %s \ |
24 ; RUN: --check-prefix=ARM32 | 27 ; RUN: --check-prefix=ARM32 |
25 | 28 |
26 declare i8 @llvm.nacl.atomic.load.i8(i8*, i32) | 29 declare i8 @llvm.nacl.atomic.load.i8(i8*, i32) |
27 declare i16 @llvm.nacl.atomic.load.i16(i16*, i32) | 30 declare i16 @llvm.nacl.atomic.load.i16(i16*, i32) |
28 declare i32 @llvm.nacl.atomic.load.i32(i32*, i32) | 31 declare i32 @llvm.nacl.atomic.load.i32(i32*, i32) |
29 declare i64 @llvm.nacl.atomic.load.i64(i64*, i32) | 32 declare i64 @llvm.nacl.atomic.load.i64(i64*, i32) |
30 declare void @llvm.nacl.atomic.store.i8(i8, i8*, i32) | 33 declare void @llvm.nacl.atomic.store.i8(i8, i8*, i32) |
31 declare void @llvm.nacl.atomic.store.i16(i16, i16*, i32) | 34 declare void @llvm.nacl.atomic.store.i16(i16, i16*, i32) |
32 declare void @llvm.nacl.atomic.store.i32(i32, i32*, i32) | 35 declare void @llvm.nacl.atomic.store.i32(i32, i32*, i32) |
(...skipping 18 matching lines...) Expand all Loading... |
51 ; NOTE: The LLC equivalent for 16-bit atomic operations are expanded | 54 ; NOTE: The LLC equivalent for 16-bit atomic operations are expanded |
52 ; as 32-bit operations. For Subzero, assume that real 16-bit operations | 55 ; as 32-bit operations. For Subzero, assume that real 16-bit operations |
53 ; will be usable (the validator will be fixed): | 56 ; will be usable (the validator will be fixed): |
54 ; https://code.google.com/p/nativeclient/issues/detail?id=2981 | 57 ; https://code.google.com/p/nativeclient/issues/detail?id=2981 |
55 | 58 |
56 ;;; Load | 59 ;;; Load |
57 | 60 |
58 ; x86 guarantees load/store to be atomic if naturally aligned. | 61 ; x86 guarantees load/store to be atomic if naturally aligned. |
59 ; The PNaCl IR requires all atomic accesses to be naturally aligned. | 62 ; The PNaCl IR requires all atomic accesses to be naturally aligned. |
60 | 63 |
61 define i32 @test_atomic_load_8(i32 %iptr) { | 64 define internal i32 @test_atomic_load_8(i32 %iptr) { |
62 entry: | 65 entry: |
63 %ptr = inttoptr i32 %iptr to i8* | 66 %ptr = inttoptr i32 %iptr to i8* |
64 ; parameter value "6" is for the sequential consistency memory order. | 67 ; parameter value "6" is for the sequential consistency memory order. |
65 %i = call i8 @llvm.nacl.atomic.load.i8(i8* %ptr, i32 6) | 68 %i = call i8 @llvm.nacl.atomic.load.i8(i8* %ptr, i32 6) |
66 %i2 = sub i8 %i, 0 | 69 %i2 = sub i8 %i, 0 |
67 %r = zext i8 %i2 to i32 | 70 %r = zext i8 %i2 to i32 |
68 ret i32 %r | 71 ret i32 %r |
69 } | 72 } |
70 ; CHECK-LABEL: test_atomic_load_8 | 73 ; CHECK-LABEL: test_atomic_load_8 |
71 ; CHECK: mov {{.*}},DWORD | 74 ; CHECK: mov {{.*}},DWORD |
72 ; CHECK: mov {{.*}},BYTE | 75 ; CHECK: mov {{.*}},BYTE |
73 ; ARM32-LABEL: test_atomic_load_8 | 76 ; ARM32-LABEL: test_atomic_load_8 |
74 ; ARM32: ldrb r{{[0-9]+}}, [r{{[0-9]+}} | 77 ; ARM32: ldrb r{{[0-9]+}}, [r{{[0-9]+}} |
75 ; ARM32: dmb | 78 ; ARM32: dmb |
76 | 79 |
77 define i32 @test_atomic_load_16(i32 %iptr) { | 80 define internal i32 @test_atomic_load_16(i32 %iptr) { |
78 entry: | 81 entry: |
79 %ptr = inttoptr i32 %iptr to i16* | 82 %ptr = inttoptr i32 %iptr to i16* |
80 %i = call i16 @llvm.nacl.atomic.load.i16(i16* %ptr, i32 6) | 83 %i = call i16 @llvm.nacl.atomic.load.i16(i16* %ptr, i32 6) |
81 %i2 = sub i16 %i, 0 | 84 %i2 = sub i16 %i, 0 |
82 %r = zext i16 %i2 to i32 | 85 %r = zext i16 %i2 to i32 |
83 ret i32 %r | 86 ret i32 %r |
84 } | 87 } |
85 ; CHECK-LABEL: test_atomic_load_16 | 88 ; CHECK-LABEL: test_atomic_load_16 |
86 ; CHECK: mov {{.*}},DWORD | 89 ; CHECK: mov {{.*}},DWORD |
87 ; CHECK: mov {{.*}},WORD | 90 ; CHECK: mov {{.*}},WORD |
88 ; ARM32-LABEL: test_atomic_load_16 | 91 ; ARM32-LABEL: test_atomic_load_16 |
89 ; ARM32: ldrh r{{[0-9]+}}, [r{{[0-9]+}} | 92 ; ARM32: ldrh r{{[0-9]+}}, [r{{[0-9]+}} |
90 ; ARM32: dmb | 93 ; ARM32: dmb |
91 | 94 |
92 define i32 @test_atomic_load_32(i32 %iptr) { | 95 define internal i32 @test_atomic_load_32(i32 %iptr) { |
93 entry: | 96 entry: |
94 %ptr = inttoptr i32 %iptr to i32* | 97 %ptr = inttoptr i32 %iptr to i32* |
95 %r = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6) | 98 %r = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6) |
96 ret i32 %r | 99 ret i32 %r |
97 } | 100 } |
98 ; CHECK-LABEL: test_atomic_load_32 | 101 ; CHECK-LABEL: test_atomic_load_32 |
99 ; CHECK: mov {{.*}},DWORD | 102 ; CHECK: mov {{.*}},DWORD |
100 ; CHECK: mov {{.*}},DWORD | 103 ; CHECK: mov {{.*}},DWORD |
101 ; ARM32-LABEL: test_atomic_load_32 | 104 ; ARM32-LABEL: test_atomic_load_32 |
102 ; ARM32: ldr r{{[0-9]+}}, [r{{[0-9]+}} | 105 ; ARM32: ldr r{{[0-9]+}}, [r{{[0-9]+}} |
103 ; ARM32: dmb | 106 ; ARM32: dmb |
104 | 107 |
105 define i64 @test_atomic_load_64(i32 %iptr) { | 108 define internal i64 @test_atomic_load_64(i32 %iptr) { |
106 entry: | 109 entry: |
107 %ptr = inttoptr i32 %iptr to i64* | 110 %ptr = inttoptr i32 %iptr to i64* |
108 %r = call i64 @llvm.nacl.atomic.load.i64(i64* %ptr, i32 6) | 111 %r = call i64 @llvm.nacl.atomic.load.i64(i64* %ptr, i32 6) |
109 ret i64 %r | 112 ret i64 %r |
110 } | 113 } |
111 ; CHECK-LABEL: test_atomic_load_64 | 114 ; CHECK-LABEL: test_atomic_load_64 |
112 ; CHECK: movq x{{.*}},QWORD | 115 ; CHECK: movq x{{.*}},QWORD |
113 ; CHECK: movq QWORD {{.*}},x{{.*}} | 116 ; CHECK: movq QWORD {{.*}},x{{.*}} |
114 ; ARM32-LABEL: test_atomic_load_64 | 117 ; ARM32-LABEL: test_atomic_load_64 |
115 ; ARM32: ldrexd r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}} | 118 ; ARM32: ldrexd r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}} |
116 ; ARM32: dmb | 119 ; ARM32: dmb |
117 | 120 |
118 define i32 @test_atomic_load_32_with_arith(i32 %iptr) { | 121 define internal i32 @test_atomic_load_32_with_arith(i32 %iptr) { |
119 entry: | 122 entry: |
120 br label %next | 123 br label %next |
121 | 124 |
122 next: | 125 next: |
123 %ptr = inttoptr i32 %iptr to i32* | 126 %ptr = inttoptr i32 %iptr to i32* |
124 %r = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6) | 127 %r = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6) |
125 %r2 = sub i32 32, %r | 128 %r2 = sub i32 32, %r |
126 ret i32 %r2 | 129 ret i32 %r2 |
127 } | 130 } |
128 ; CHECK-LABEL: test_atomic_load_32_with_arith | 131 ; CHECK-LABEL: test_atomic_load_32_with_arith |
129 ; CHECK: mov {{.*}},DWORD | 132 ; CHECK: mov {{.*}},DWORD |
130 ; The next instruction may be a separate load or folded into an add. | 133 ; The next instruction may be a separate load or folded into an add. |
131 ; | 134 ; |
132 ; In O2 mode, we know that the load and sub are going to be fused. | 135 ; In O2 mode, we know that the load and sub are going to be fused. |
133 ; O2-LABEL: test_atomic_load_32_with_arith | 136 ; O2-LABEL: test_atomic_load_32_with_arith |
134 ; O2: mov {{.*}},DWORD | 137 ; O2: mov {{.*}},DWORD |
135 ; O2: sub {{.*}},DWORD | 138 ; O2: sub {{.*}},DWORD |
136 ; ARM32-LABEL: test_atomic_load_32_with_arith | 139 ; ARM32-LABEL: test_atomic_load_32_with_arith |
137 ; ARM32: ldr r{{[0-9]+}}, [r{{[0-9]+}} | 140 ; ARM32: ldr r{{[0-9]+}}, [r{{[0-9]+}} |
138 ; ARM32: dmb | 141 ; ARM32: dmb |
139 | 142 |
140 define i32 @test_atomic_load_32_ignored(i32 %iptr) { | 143 define internal i32 @test_atomic_load_32_ignored(i32 %iptr) { |
141 entry: | 144 entry: |
142 %ptr = inttoptr i32 %iptr to i32* | 145 %ptr = inttoptr i32 %iptr to i32* |
143 %ignored = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6) | 146 %ignored = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6) |
144 ret i32 0 | 147 ret i32 0 |
145 } | 148 } |
146 ; CHECK-LABEL: test_atomic_load_32_ignored | 149 ; CHECK-LABEL: test_atomic_load_32_ignored |
147 ; CHECK: mov {{.*}},DWORD | 150 ; CHECK: mov {{.*}},DWORD |
148 ; CHECK: mov {{.*}},DWORD | 151 ; CHECK: mov {{.*}},DWORD |
149 ; O2-LABEL: test_atomic_load_32_ignored | 152 ; O2-LABEL: test_atomic_load_32_ignored |
150 ; O2: mov {{.*}},DWORD | 153 ; O2: mov {{.*}},DWORD |
151 ; O2: mov {{.*}},DWORD | 154 ; O2: mov {{.*}},DWORD |
152 ; ARM32-LABEL: test_atomic_load_32_ignored | 155 ; ARM32-LABEL: test_atomic_load_32_ignored |
153 ; ARM32: ldr r{{[0-9]+}}, [r{{[0-9]+}} | 156 ; ARM32: ldr r{{[0-9]+}}, [r{{[0-9]+}} |
154 ; ARM32: dmb | 157 ; ARM32: dmb |
155 | 158 |
156 define i64 @test_atomic_load_64_ignored(i32 %iptr) { | 159 define internal i64 @test_atomic_load_64_ignored(i32 %iptr) { |
157 entry: | 160 entry: |
158 %ptr = inttoptr i32 %iptr to i64* | 161 %ptr = inttoptr i32 %iptr to i64* |
159 %ignored = call i64 @llvm.nacl.atomic.load.i64(i64* %ptr, i32 6) | 162 %ignored = call i64 @llvm.nacl.atomic.load.i64(i64* %ptr, i32 6) |
160 ret i64 0 | 163 ret i64 0 |
161 } | 164 } |
162 ; CHECK-LABEL: test_atomic_load_64_ignored | 165 ; CHECK-LABEL: test_atomic_load_64_ignored |
163 ; CHECK: movq x{{.*}},QWORD | 166 ; CHECK: movq x{{.*}},QWORD |
164 ; CHECK: movq QWORD {{.*}},x{{.*}} | 167 ; CHECK: movq QWORD {{.*}},x{{.*}} |
165 ; ARM32-LABEL: test_atomic_load_64_ignored | 168 ; ARM32-LABEL: test_atomic_load_64_ignored |
166 ; ARM32: ldrexd r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}} | 169 ; ARM32: ldrexd r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}} |
167 ; ARM32: dmb | 170 ; ARM32: dmb |
168 | 171 |
169 ;;; Store | 172 ;;; Store |
170 | 173 |
171 define void @test_atomic_store_8(i32 %iptr, i32 %v) { | 174 define internal void @test_atomic_store_8(i32 %iptr, i32 %v) { |
172 entry: | 175 entry: |
173 %truncv = trunc i32 %v to i8 | 176 %truncv = trunc i32 %v to i8 |
174 %ptr = inttoptr i32 %iptr to i8* | 177 %ptr = inttoptr i32 %iptr to i8* |
175 call void @llvm.nacl.atomic.store.i8(i8 %truncv, i8* %ptr, i32 6) | 178 call void @llvm.nacl.atomic.store.i8(i8 %truncv, i8* %ptr, i32 6) |
176 ret void | 179 ret void |
177 } | 180 } |
178 ; CHECK-LABEL: test_atomic_store_8 | 181 ; CHECK-LABEL: test_atomic_store_8 |
179 ; CHECK: mov BYTE | 182 ; CHECK: mov BYTE |
180 ; CHECK: mfence | 183 ; CHECK: mfence |
181 ; ARM32-LABEL: test_atomic_store_8 | 184 ; ARM32-LABEL: test_atomic_store_8 |
182 ; ARM32: dmb | 185 ; ARM32: dmb |
183 ; ARM32: strb r{{[0-9]+}}, [r{{[0-9]+}} | 186 ; ARM32: strb r{{[0-9]+}}, [r{{[0-9]+}} |
184 ; ARM32: dmb | 187 ; ARM32: dmb |
185 | 188 |
186 define void @test_atomic_store_16(i32 %iptr, i32 %v) { | 189 define internal void @test_atomic_store_16(i32 %iptr, i32 %v) { |
187 entry: | 190 entry: |
188 %truncv = trunc i32 %v to i16 | 191 %truncv = trunc i32 %v to i16 |
189 %ptr = inttoptr i32 %iptr to i16* | 192 %ptr = inttoptr i32 %iptr to i16* |
190 call void @llvm.nacl.atomic.store.i16(i16 %truncv, i16* %ptr, i32 6) | 193 call void @llvm.nacl.atomic.store.i16(i16 %truncv, i16* %ptr, i32 6) |
191 ret void | 194 ret void |
192 } | 195 } |
193 ; CHECK-LABEL: test_atomic_store_16 | 196 ; CHECK-LABEL: test_atomic_store_16 |
194 ; CHECK: mov WORD | 197 ; CHECK: mov WORD |
195 ; CHECK: mfence | 198 ; CHECK: mfence |
196 ; ARM32-LABEL: test_atomic_store_16 | 199 ; ARM32-LABEL: test_atomic_store_16 |
197 ; ARM32: dmb | 200 ; ARM32: dmb |
198 ; ARM32: strh r{{[0-9]+}}, [r{{[0-9]+}} | 201 ; ARM32: strh r{{[0-9]+}}, [r{{[0-9]+}} |
199 ; ARM32: dmb | 202 ; ARM32: dmb |
200 | 203 |
201 define void @test_atomic_store_32(i32 %iptr, i32 %v) { | 204 define internal void @test_atomic_store_32(i32 %iptr, i32 %v) { |
202 entry: | 205 entry: |
203 %ptr = inttoptr i32 %iptr to i32* | 206 %ptr = inttoptr i32 %iptr to i32* |
204 call void @llvm.nacl.atomic.store.i32(i32 %v, i32* %ptr, i32 6) | 207 call void @llvm.nacl.atomic.store.i32(i32 %v, i32* %ptr, i32 6) |
205 ret void | 208 ret void |
206 } | 209 } |
207 ; CHECK-LABEL: test_atomic_store_32 | 210 ; CHECK-LABEL: test_atomic_store_32 |
208 ; CHECK: mov DWORD | 211 ; CHECK: mov DWORD |
209 ; CHECK: mfence | 212 ; CHECK: mfence |
210 ; ARM32-LABEL: test_atomic_store_32 | 213 ; ARM32-LABEL: test_atomic_store_32 |
211 ; ARM32: dmb | 214 ; ARM32: dmb |
212 ; ARM32: str r{{[0-9]+}}, [r{{[0-9]+}} | 215 ; ARM32: str r{{[0-9]+}}, [r{{[0-9]+}} |
213 ; ARM32: dmb | 216 ; ARM32: dmb |
214 | 217 |
215 define void @test_atomic_store_64(i32 %iptr, i64 %v) { | 218 define internal void @test_atomic_store_64(i32 %iptr, i64 %v) { |
216 entry: | 219 entry: |
217 %ptr = inttoptr i32 %iptr to i64* | 220 %ptr = inttoptr i32 %iptr to i64* |
218 call void @llvm.nacl.atomic.store.i64(i64 %v, i64* %ptr, i32 6) | 221 call void @llvm.nacl.atomic.store.i64(i64 %v, i64* %ptr, i32 6) |
219 ret void | 222 ret void |
220 } | 223 } |
221 ; CHECK-LABEL: test_atomic_store_64 | 224 ; CHECK-LABEL: test_atomic_store_64 |
222 ; CHECK: movq x{{.*}},QWORD | 225 ; CHECK: movq x{{.*}},QWORD |
223 ; CHECK: movq QWORD {{.*}},x{{.*}} | 226 ; CHECK: movq QWORD {{.*}},x{{.*}} |
224 ; CHECK: mfence | 227 ; CHECK: mfence |
225 ; ARM32-LABEL: test_atomic_store_64 | 228 ; ARM32-LABEL: test_atomic_store_64 |
226 ; ARM32: dmb | 229 ; ARM32: dmb |
227 ; ARM32: ldrexd r{{[0-9]+}}, r{{[0-9]+}}, [[MEM:.*]] | 230 ; ARM32: ldrexd r{{[0-9]+}}, r{{[0-9]+}}, [[MEM:.*]] |
228 ; ARM32: strexd [[S:r[0-9]+]], r{{[0-9]+}}, r{{[0-9]+}}, [[MEM]] | 231 ; ARM32: strexd [[S:r[0-9]+]], r{{[0-9]+}}, r{{[0-9]+}}, [[MEM]] |
229 ; ARM32: cmp [[S]], #0 | 232 ; ARM32: cmp [[S]], #0 |
230 ; ARM32: bne | 233 ; ARM32: bne |
231 ; ARM32: dmb | 234 ; ARM32: dmb |
232 | 235 |
233 define void @test_atomic_store_64_const(i32 %iptr) { | 236 define internal void @test_atomic_store_64_const(i32 %iptr) { |
234 entry: | 237 entry: |
235 %ptr = inttoptr i32 %iptr to i64* | 238 %ptr = inttoptr i32 %iptr to i64* |
236 call void @llvm.nacl.atomic.store.i64(i64 12345678901234, i64* %ptr, i32 6) | 239 call void @llvm.nacl.atomic.store.i64(i64 12345678901234, i64* %ptr, i32 6) |
237 ret void | 240 ret void |
238 } | 241 } |
239 ; CHECK-LABEL: test_atomic_store_64_const | 242 ; CHECK-LABEL: test_atomic_store_64_const |
240 ; CHECK: mov {{.*}},0x73ce2ff2 | 243 ; CHECK: mov {{.*}},0x73ce2ff2 |
241 ; CHECK: mov {{.*}},0xb3a | 244 ; CHECK: mov {{.*}},0xb3a |
242 ; CHECK: movq x{{.*}},QWORD | 245 ; CHECK: movq x{{.*}},QWORD |
243 ; CHECK: movq QWORD {{.*}},x{{.*}} | 246 ; CHECK: movq QWORD {{.*}},x{{.*}} |
244 ; CHECK: mfence | 247 ; CHECK: mfence |
245 ; ARM32-LABEL: test_atomic_store_64_const | 248 ; ARM32-LABEL: test_atomic_store_64_const |
246 ; ARM32: dmb | 249 ; ARM32: dmb |
247 ; ARM32: movw [[T0:r[0-9]+]], #12274 | 250 ; ARM32: movw [[T0:r[0-9]+]], #12274 |
248 ; ARM32: movt [[T0]], #29646 | 251 ; ARM32: movt [[T0]], #29646 |
249 ; ARM32: movw r{{[0-9]+}}, #2874 | 252 ; ARM32: movw r{{[0-9]+}}, #2874 |
250 ; ARM32: .L[[RETRY:.*]]: | 253 ; ARM32: .L[[RETRY:.*]]: |
251 ; ARM32: ldrexd r{{[0-9]+}}, r{{[0-9]+}}, [[MEM:.*]] | 254 ; ARM32: ldrexd r{{[0-9]+}}, r{{[0-9]+}}, [[MEM:.*]] |
252 ; ARM32: strexd [[S:r[0-9]+]], r{{[0-9]+}}, r{{[0-9]+}}, [[MEM]] | 255 ; ARM32: strexd [[S:r[0-9]+]], r{{[0-9]+}}, r{{[0-9]+}}, [[MEM]] |
253 ; ARM32: cmp [[S]], #0 | 256 ; ARM32: cmp [[S]], #0 |
254 ; ARM32: bne .L[[RETRY]] | 257 ; ARM32: bne .L[[RETRY]] |
255 ; ARM32: dmb | 258 ; ARM32: dmb |
256 | 259 |
257 ;;; RMW | 260 ;;; RMW |
258 | 261 |
259 ;; add | 262 ;; add |
260 | 263 |
261 define i32 @test_atomic_rmw_add_8(i32 %iptr, i32 %v) { | 264 define internal i32 @test_atomic_rmw_add_8(i32 %iptr, i32 %v) { |
262 entry: | 265 entry: |
263 %trunc = trunc i32 %v to i8 | 266 %trunc = trunc i32 %v to i8 |
264 %ptr = inttoptr i32 %iptr to i8* | 267 %ptr = inttoptr i32 %iptr to i8* |
265 ; "1" is an atomic add, and "6" is sequential consistency. | 268 ; "1" is an atomic add, and "6" is sequential consistency. |
266 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 1, i8* %ptr, i8 %trunc, i32 6) | 269 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 1, i8* %ptr, i8 %trunc, i32 6) |
267 %a_ext = zext i8 %a to i32 | 270 %a_ext = zext i8 %a to i32 |
268 ret i32 %a_ext | 271 ret i32 %a_ext |
269 } | 272 } |
270 ; CHECK-LABEL: test_atomic_rmw_add_8 | 273 ; CHECK-LABEL: test_atomic_rmw_add_8 |
271 ; CHECK: lock xadd BYTE {{.*}},[[REG:.*]] | 274 ; CHECK: lock xadd BYTE {{.*}},[[REG:.*]] |
272 ; CHECK: {{mov|movzx}} {{.*}},[[REG]] | 275 ; CHECK: {{mov|movzx}} {{.*}},[[REG]] |
273 ; ARM32-LABEL: test_atomic_rmw_add_8 | 276 ; ARM32-LABEL: test_atomic_rmw_add_8 |
274 ; ARM32: dmb | 277 ; ARM32: dmb |
275 ; ARM32: ldrexb | 278 ; ARM32: ldrexb |
276 ; ARM32: add | 279 ; ARM32: add |
277 ; ARM32: strexb | 280 ; ARM32: strexb |
278 ; ARM32: bne | 281 ; ARM32: bne |
279 ; ARM32: dmb | 282 ; ARM32: dmb |
280 | 283 |
281 define i32 @test_atomic_rmw_add_16(i32 %iptr, i32 %v) { | 284 define internal i32 @test_atomic_rmw_add_16(i32 %iptr, i32 %v) { |
282 entry: | 285 entry: |
283 %trunc = trunc i32 %v to i16 | 286 %trunc = trunc i32 %v to i16 |
284 %ptr = inttoptr i32 %iptr to i16* | 287 %ptr = inttoptr i32 %iptr to i16* |
285 %a = call i16 @llvm.nacl.atomic.rmw.i16(i32 1, i16* %ptr, i16 %trunc, i32 6) | 288 %a = call i16 @llvm.nacl.atomic.rmw.i16(i32 1, i16* %ptr, i16 %trunc, i32 6) |
286 %a_ext = zext i16 %a to i32 | 289 %a_ext = zext i16 %a to i32 |
287 ret i32 %a_ext | 290 ret i32 %a_ext |
288 } | 291 } |
289 ; CHECK-LABEL: test_atomic_rmw_add_16 | 292 ; CHECK-LABEL: test_atomic_rmw_add_16 |
290 ; CHECK: lock xadd WORD {{.*}},[[REG:.*]] | 293 ; CHECK: lock xadd WORD {{.*}},[[REG:.*]] |
291 ; CHECK: {{mov|movzx}} {{.*}},[[REG]] | 294 ; CHECK: {{mov|movzx}} {{.*}},[[REG]] |
292 ; ARM32-LABEL: test_atomic_rmw_add_16 | 295 ; ARM32-LABEL: test_atomic_rmw_add_16 |
293 ; ARM32: dmb | 296 ; ARM32: dmb |
294 ; ARM32: ldrexh | 297 ; ARM32: ldrexh |
295 ; ARM32: add | 298 ; ARM32: add |
296 ; ARM32: strexh | 299 ; ARM32: strexh |
297 ; ARM32: bne | 300 ; ARM32: bne |
298 ; ARM32: dmb | 301 ; ARM32: dmb |
299 | 302 |
300 define i32 @test_atomic_rmw_add_32(i32 %iptr, i32 %v) { | 303 define internal i32 @test_atomic_rmw_add_32(i32 %iptr, i32 %v) { |
301 entry: | 304 entry: |
302 %ptr = inttoptr i32 %iptr to i32* | 305 %ptr = inttoptr i32 %iptr to i32* |
303 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 1, i32* %ptr, i32 %v, i32 6) | 306 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 1, i32* %ptr, i32 %v, i32 6) |
304 ret i32 %a | 307 ret i32 %a |
305 } | 308 } |
306 ; CHECK-LABEL: test_atomic_rmw_add_32 | 309 ; CHECK-LABEL: test_atomic_rmw_add_32 |
307 ; CHECK: lock xadd DWORD {{.*}},[[REG:.*]] | 310 ; CHECK: lock xadd DWORD {{.*}},[[REG:.*]] |
308 ; CHECK: mov {{.*}},[[REG]] | 311 ; CHECK: mov {{.*}},[[REG]] |
309 ; ARM32-LABEL: test_atomic_rmw_add_32 | 312 ; ARM32-LABEL: test_atomic_rmw_add_32 |
310 ; ARM32: dmb | 313 ; ARM32: dmb |
311 ; ARM32: ldrex | 314 ; ARM32: ldrex |
312 ; ARM32: add | 315 ; ARM32: add |
313 ; ARM32: strex | 316 ; ARM32: strex |
314 ; ARM32: bne | 317 ; ARM32: bne |
315 ; ARM32: dmb | 318 ; ARM32: dmb |
316 | 319 |
317 define i64 @test_atomic_rmw_add_64(i32 %iptr, i64 %v) { | 320 define internal i64 @test_atomic_rmw_add_64(i32 %iptr, i64 %v) { |
318 entry: | 321 entry: |
319 %ptr = inttoptr i32 %iptr to i64* | 322 %ptr = inttoptr i32 %iptr to i64* |
320 %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 1, i64* %ptr, i64 %v, i32 6) | 323 %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 1, i64* %ptr, i64 %v, i32 6) |
321 ret i64 %a | 324 ret i64 %a |
322 } | 325 } |
323 ; CHECK-LABEL: test_atomic_rmw_add_64 | 326 ; CHECK-LABEL: test_atomic_rmw_add_64 |
324 ; CHECK: push ebx | 327 ; CHECK: push ebx |
325 ; CHECK: mov eax,DWORD PTR [{{.*}}] | 328 ; CHECK: mov eax,DWORD PTR [{{.*}}] |
326 ; CHECK: mov edx,DWORD PTR [{{.*}}+0x4] | 329 ; CHECK: mov edx,DWORD PTR [{{.*}}+0x4] |
327 ; CHECK: [[LABEL:[^ ]*]]: {{.*}} mov ebx,eax | 330 ; CHECK: [[LABEL:[^ ]*]]: {{.*}} mov ebx,eax |
(...skipping 10 matching lines...) Expand all Loading... |
338 ; ARM32-LABEL: test_atomic_rmw_add_64 | 341 ; ARM32-LABEL: test_atomic_rmw_add_64 |
339 ; ARM32: dmb | 342 ; ARM32: dmb |
340 ; ARM32: ldrexd r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}}] | 343 ; ARM32: ldrexd r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}}] |
341 ; ARM32: adds | 344 ; ARM32: adds |
342 ; ARM32-NEXT: adc | 345 ; ARM32-NEXT: adc |
343 ; ARM32: strexd r{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}}] | 346 ; ARM32: strexd r{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}}] |
344 ; ARM32: bne | 347 ; ARM32: bne |
345 ; ARM32: dmb | 348 ; ARM32: dmb |
346 | 349 |
347 ; Same test as above, but with a global address to test FakeUse issues. | 350 ; Same test as above, but with a global address to test FakeUse issues. |
348 define i64 @test_atomic_rmw_add_64_global(i64 %v) { | 351 define internal i64 @test_atomic_rmw_add_64_global(i64 %v) { |
349 entry: | 352 entry: |
350 %ptr = bitcast [8 x i8]* @Global64 to i64* | 353 %ptr = bitcast [8 x i8]* @Global64 to i64* |
351 %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 1, i64* %ptr, i64 %v, i32 6) | 354 %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 1, i64* %ptr, i64 %v, i32 6) |
352 ret i64 %a | 355 ret i64 %a |
353 } | 356 } |
354 ; CHECK-LABEL: test_atomic_rmw_add_64_global | 357 ; CHECK-LABEL: test_atomic_rmw_add_64_global |
355 ; ARM32-LABEL: test_atomic_rmw_add_64_global | 358 ; ARM32-LABEL: test_atomic_rmw_add_64_global |
356 ; ARM32: dmb | 359 ; ARM32: dmb |
357 ; ARM32: ldrexd r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}}] | 360 ; ARM32: ldrexd r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}}] |
358 ; ARM32: adds | 361 ; ARM32: adds |
359 ; ARM32-NEXT: adc | 362 ; ARM32-NEXT: adc |
360 ; ARM32: strexd r{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}}] | 363 ; ARM32: strexd r{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}}] |
361 ; ARM32: bne | 364 ; ARM32: bne |
362 ; ARM32: dmb | 365 ; ARM32: dmb |
363 | 366 |
364 ; Test with some more register pressure. When we have an alloca, ebp is | 367 ; Test with some more register pressure. When we have an alloca, ebp is |
365 ; used to manage the stack frame, so it cannot be used as a register either. | 368 ; used to manage the stack frame, so it cannot be used as a register either. |
366 declare void @use_ptr(i32 %iptr) | 369 declare void @use_ptr(i32 %iptr) |
367 | 370 |
368 define i64 @test_atomic_rmw_add_64_alloca(i32 %iptr, i64 %v) { | 371 define internal i64 @test_atomic_rmw_add_64_alloca(i32 %iptr, i64 %v) { |
369 entry: | 372 entry: |
370 br label %eblock ; Disable alloca optimization | 373 br label %eblock ; Disable alloca optimization |
371 eblock: | 374 eblock: |
372 %alloca_ptr = alloca i8, i32 16, align 16 | 375 %alloca_ptr = alloca i8, i32 16, align 16 |
373 %ptr = inttoptr i32 %iptr to i64* | 376 %ptr = inttoptr i32 %iptr to i64* |
374 %old = call i64 @llvm.nacl.atomic.rmw.i64(i32 1, i64* %ptr, i64 %v, i32 6) | 377 %old = call i64 @llvm.nacl.atomic.rmw.i64(i32 1, i64* %ptr, i64 %v, i32 6) |
375 store i8 0, i8* %alloca_ptr, align 1 | 378 store i8 0, i8* %alloca_ptr, align 1 |
376 store i8 1, i8* %alloca_ptr, align 1 | 379 store i8 1, i8* %alloca_ptr, align 1 |
377 store i8 2, i8* %alloca_ptr, align 1 | 380 store i8 2, i8* %alloca_ptr, align 1 |
378 store i8 3, i8* %alloca_ptr, align 1 | 381 store i8 3, i8* %alloca_ptr, align 1 |
(...skipping 16 matching lines...) Expand all Loading... |
395 ; CHECK: call {{.*}} R_{{.*}} use_ptr | 398 ; CHECK: call {{.*}} R_{{.*}} use_ptr |
396 ; ARM32-LABEL: test_atomic_rmw_add_64_alloca | 399 ; ARM32-LABEL: test_atomic_rmw_add_64_alloca |
397 ; ARM32: dmb | 400 ; ARM32: dmb |
398 ; ARM32: ldrexd r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}}] | 401 ; ARM32: ldrexd r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}}] |
399 ; ARM32: adds | 402 ; ARM32: adds |
400 ; ARM32-NEXT: adc | 403 ; ARM32-NEXT: adc |
401 ; ARM32: strexd r{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}}] | 404 ; ARM32: strexd r{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}}] |
402 ; ARM32: bne | 405 ; ARM32: bne |
403 ; ARM32: dmb | 406 ; ARM32: dmb |
404 | 407 |
405 define i32 @test_atomic_rmw_add_32_ignored(i32 %iptr, i32 %v) { | 408 define internal i32 @test_atomic_rmw_add_32_ignored(i32 %iptr, i32 %v) { |
406 entry: | 409 entry: |
407 %ptr = inttoptr i32 %iptr to i32* | 410 %ptr = inttoptr i32 %iptr to i32* |
408 %ignored = call i32 @llvm.nacl.atomic.rmw.i32(i32 1, i32* %ptr, i32 %v, i32 6) | 411 %ignored = call i32 @llvm.nacl.atomic.rmw.i32(i32 1, i32* %ptr, i32 %v, i32 6) |
409 ret i32 %v | 412 ret i32 %v |
410 } | 413 } |
411 ; Technically this could use "lock add" instead of "lock xadd", if liveness | 414 ; Technically this could use "lock add" instead of "lock xadd", if liveness |
412 ; tells us that the destination variable is dead. | 415 ; tells us that the destination variable is dead. |
413 ; CHECK-LABEL: test_atomic_rmw_add_32_ignored | 416 ; CHECK-LABEL: test_atomic_rmw_add_32_ignored |
414 ; CHECK: lock xadd DWORD {{.*}},[[REG:.*]] | 417 ; CHECK: lock xadd DWORD {{.*}},[[REG:.*]] |
415 ; ARM32-LABEL: test_atomic_rmw_add_32_ignored | 418 ; ARM32-LABEL: test_atomic_rmw_add_32_ignored |
416 ; ARM32: dmb | 419 ; ARM32: dmb |
417 ; ARM32: ldrex | 420 ; ARM32: ldrex |
418 ; ARM32: add | 421 ; ARM32: add |
419 ; ARM32: strex | 422 ; ARM32: strex |
420 ; ARM32: bne | 423 ; ARM32: bne |
421 ; ARM32: dmb | 424 ; ARM32: dmb |
422 | 425 |
423 ; Atomic RMW 64 needs to be expanded into its own loop. | 426 ; Atomic RMW 64 needs to be expanded into its own loop. |
424 ; Make sure that works w/ non-trivial function bodies. | 427 ; Make sure that works w/ non-trivial function bodies. |
425 define i64 @test_atomic_rmw_add_64_loop(i32 %iptr, i64 %v) { | 428 define internal i64 @test_atomic_rmw_add_64_loop(i32 %iptr, i64 %v) { |
426 entry: | 429 entry: |
427 %x = icmp ult i64 %v, 100 | 430 %x = icmp ult i64 %v, 100 |
428 br i1 %x, label %err, label %loop | 431 br i1 %x, label %err, label %loop |
429 | 432 |
430 loop: | 433 loop: |
431 %v_next = phi i64 [ %v, %entry ], [ %next, %loop ] | 434 %v_next = phi i64 [ %v, %entry ], [ %next, %loop ] |
432 %ptr = inttoptr i32 %iptr to i64* | 435 %ptr = inttoptr i32 %iptr to i64* |
433 %next = call i64 @llvm.nacl.atomic.rmw.i64(i32 1, i64* %ptr, i64 %v_next, i32
6) | 436 %next = call i64 @llvm.nacl.atomic.rmw.i64(i32 1, i64* %ptr, i64 %v_next, i32
6) |
434 %success = icmp eq i64 %next, 100 | 437 %success = icmp eq i64 %next, 100 |
435 br i1 %success, label %done, label %loop | 438 br i1 %success, label %done, label %loop |
(...skipping 19 matching lines...) Expand all Loading... |
455 ; ARM32: ldrexd r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}}] | 458 ; ARM32: ldrexd r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}}] |
456 ; ARM32: adds | 459 ; ARM32: adds |
457 ; ARM32-NEXT: adc | 460 ; ARM32-NEXT: adc |
458 ; ARM32: strexd r{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}}] | 461 ; ARM32: strexd r{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}}] |
459 ; ARM32: bne | 462 ; ARM32: bne |
460 ; ARM32: dmb | 463 ; ARM32: dmb |
461 ; ARM32: b | 464 ; ARM32: b |
462 | 465 |
463 ;; sub | 466 ;; sub |
464 | 467 |
465 define i32 @test_atomic_rmw_sub_8(i32 %iptr, i32 %v) { | 468 define internal i32 @test_atomic_rmw_sub_8(i32 %iptr, i32 %v) { |
466 entry: | 469 entry: |
467 %trunc = trunc i32 %v to i8 | 470 %trunc = trunc i32 %v to i8 |
468 %ptr = inttoptr i32 %iptr to i8* | 471 %ptr = inttoptr i32 %iptr to i8* |
469 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 2, i8* %ptr, i8 %trunc, i32 6) | 472 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 2, i8* %ptr, i8 %trunc, i32 6) |
470 %a_ext = zext i8 %a to i32 | 473 %a_ext = zext i8 %a to i32 |
471 ret i32 %a_ext | 474 ret i32 %a_ext |
472 } | 475 } |
473 ; CHECK-LABEL: test_atomic_rmw_sub_8 | 476 ; CHECK-LABEL: test_atomic_rmw_sub_8 |
474 ; CHECK: neg [[REG:.*]] | 477 ; CHECK: neg [[REG:.*]] |
475 ; CHECK: lock xadd BYTE {{.*}},[[REG]] | 478 ; CHECK: lock xadd BYTE {{.*}},[[REG]] |
476 ; CHECK: {{mov|movzx}} {{.*}},[[REG]] | 479 ; CHECK: {{mov|movzx}} {{.*}},[[REG]] |
477 ; ARM32-LABEL: test_atomic_rmw_sub_8 | 480 ; ARM32-LABEL: test_atomic_rmw_sub_8 |
478 ; ARM32: dmb | 481 ; ARM32: dmb |
479 ; ARM32: ldrexb | 482 ; ARM32: ldrexb |
480 ; ARM32: sub | 483 ; ARM32: sub |
481 ; ARM32: strexb | 484 ; ARM32: strexb |
482 ; ARM32: bne | 485 ; ARM32: bne |
483 ; ARM32: dmb | 486 ; ARM32: dmb |
484 | 487 |
485 define i32 @test_atomic_rmw_sub_16(i32 %iptr, i32 %v) { | 488 define internal i32 @test_atomic_rmw_sub_16(i32 %iptr, i32 %v) { |
486 entry: | 489 entry: |
487 %trunc = trunc i32 %v to i16 | 490 %trunc = trunc i32 %v to i16 |
488 %ptr = inttoptr i32 %iptr to i16* | 491 %ptr = inttoptr i32 %iptr to i16* |
489 %a = call i16 @llvm.nacl.atomic.rmw.i16(i32 2, i16* %ptr, i16 %trunc, i32 6) | 492 %a = call i16 @llvm.nacl.atomic.rmw.i16(i32 2, i16* %ptr, i16 %trunc, i32 6) |
490 %a_ext = zext i16 %a to i32 | 493 %a_ext = zext i16 %a to i32 |
491 ret i32 %a_ext | 494 ret i32 %a_ext |
492 } | 495 } |
493 ; CHECK-LABEL: test_atomic_rmw_sub_16 | 496 ; CHECK-LABEL: test_atomic_rmw_sub_16 |
494 ; CHECK: neg [[REG:.*]] | 497 ; CHECK: neg [[REG:.*]] |
495 ; CHECK: lock xadd WORD {{.*}},[[REG]] | 498 ; CHECK: lock xadd WORD {{.*}},[[REG]] |
496 ; CHECK: {{mov|movzx}} {{.*}},[[REG]] | 499 ; CHECK: {{mov|movzx}} {{.*}},[[REG]] |
497 ; ARM32-LABEL: test_atomic_rmw_sub_16 | 500 ; ARM32-LABEL: test_atomic_rmw_sub_16 |
498 ; ARM32: dmb | 501 ; ARM32: dmb |
499 ; ARM32: ldrexh | 502 ; ARM32: ldrexh |
500 ; ARM32: sub | 503 ; ARM32: sub |
501 ; ARM32: strexh | 504 ; ARM32: strexh |
502 ; ARM32: bne | 505 ; ARM32: bne |
503 ; ARM32: dmb | 506 ; ARM32: dmb |
504 | 507 |
505 define i32 @test_atomic_rmw_sub_32(i32 %iptr, i32 %v) { | 508 define internal i32 @test_atomic_rmw_sub_32(i32 %iptr, i32 %v) { |
506 entry: | 509 entry: |
507 %ptr = inttoptr i32 %iptr to i32* | 510 %ptr = inttoptr i32 %iptr to i32* |
508 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 2, i32* %ptr, i32 %v, i32 6) | 511 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 2, i32* %ptr, i32 %v, i32 6) |
509 ret i32 %a | 512 ret i32 %a |
510 } | 513 } |
511 ; CHECK-LABEL: test_atomic_rmw_sub_32 | 514 ; CHECK-LABEL: test_atomic_rmw_sub_32 |
512 ; CHECK: neg [[REG:.*]] | 515 ; CHECK: neg [[REG:.*]] |
513 ; CHECK: lock xadd DWORD {{.*}},[[REG]] | 516 ; CHECK: lock xadd DWORD {{.*}},[[REG]] |
514 ; CHECK: mov {{.*}},[[REG]] | 517 ; CHECK: mov {{.*}},[[REG]] |
515 ; ARM32-LABEL: test_atomic_rmw_sub_32 | 518 ; ARM32-LABEL: test_atomic_rmw_sub_32 |
516 ; ARM32: dmb | 519 ; ARM32: dmb |
517 ; ARM32: ldrex | 520 ; ARM32: ldrex |
518 ; ARM32: sub | 521 ; ARM32: sub |
519 ; ARM32: strex | 522 ; ARM32: strex |
520 ; ARM32: bne | 523 ; ARM32: bne |
521 ; ARM32: dmb | 524 ; ARM32: dmb |
522 | 525 |
523 define i64 @test_atomic_rmw_sub_64(i32 %iptr, i64 %v) { | 526 define internal i64 @test_atomic_rmw_sub_64(i32 %iptr, i64 %v) { |
524 entry: | 527 entry: |
525 %ptr = inttoptr i32 %iptr to i64* | 528 %ptr = inttoptr i32 %iptr to i64* |
526 %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 2, i64* %ptr, i64 %v, i32 6) | 529 %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 2, i64* %ptr, i64 %v, i32 6) |
527 ret i64 %a | 530 ret i64 %a |
528 } | 531 } |
529 ; CHECK-LABEL: test_atomic_rmw_sub_64 | 532 ; CHECK-LABEL: test_atomic_rmw_sub_64 |
530 ; CHECK: push ebx | 533 ; CHECK: push ebx |
531 ; CHECK: mov eax,DWORD PTR [{{.*}}] | 534 ; CHECK: mov eax,DWORD PTR [{{.*}}] |
532 ; CHECK: mov edx,DWORD PTR [{{.*}}+0x4] | 535 ; CHECK: mov edx,DWORD PTR [{{.*}}+0x4] |
533 ; CHECK: [[LABEL:[^ ]*]]: {{.*}} mov ebx,eax | 536 ; CHECK: [[LABEL:[^ ]*]]: {{.*}} mov ebx,eax |
534 ; CHECK: sub ebx,{{.*e.[^x]}} | 537 ; CHECK: sub ebx,{{.*e.[^x]}} |
535 ; CHECK: mov ecx,edx | 538 ; CHECK: mov ecx,edx |
536 ; CHECK: sbb ecx,{{.*e.[^x]}} | 539 ; CHECK: sbb ecx,{{.*e.[^x]}} |
537 ; CHECK: lock cmpxchg8b QWORD PTR [e{{.[^x]}} | 540 ; CHECK: lock cmpxchg8b QWORD PTR [e{{.[^x]}} |
538 ; CHECK: jne [[LABEL]] | 541 ; CHECK: jne [[LABEL]] |
539 ; ARM32-LABEL: test_atomic_rmw_sub_64 | 542 ; ARM32-LABEL: test_atomic_rmw_sub_64 |
540 ; ARM32: dmb | 543 ; ARM32: dmb |
541 ; ARM32: ldrexd r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}}] | 544 ; ARM32: ldrexd r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}}] |
542 ; ARM32: subs | 545 ; ARM32: subs |
543 ; ARM32-NEXT: sbc | 546 ; ARM32-NEXT: sbc |
544 ; ARM32: strexd r{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}}] | 547 ; ARM32: strexd r{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}}] |
545 ; ARM32: bne | 548 ; ARM32: bne |
546 ; ARM32: dmb | 549 ; ARM32: dmb |
547 | 550 |
548 define i32 @test_atomic_rmw_sub_32_ignored(i32 %iptr, i32 %v) { | 551 define internal i32 @test_atomic_rmw_sub_32_ignored(i32 %iptr, i32 %v) { |
549 entry: | 552 entry: |
550 %ptr = inttoptr i32 %iptr to i32* | 553 %ptr = inttoptr i32 %iptr to i32* |
551 %ignored = call i32 @llvm.nacl.atomic.rmw.i32(i32 2, i32* %ptr, i32 %v, i32 6) | 554 %ignored = call i32 @llvm.nacl.atomic.rmw.i32(i32 2, i32* %ptr, i32 %v, i32 6) |
552 ret i32 %v | 555 ret i32 %v |
553 } | 556 } |
554 ; Could use "lock sub" instead of "neg; lock xadd" | 557 ; Could use "lock sub" instead of "neg; lock xadd" |
555 ; CHECK-LABEL: test_atomic_rmw_sub_32_ignored | 558 ; CHECK-LABEL: test_atomic_rmw_sub_32_ignored |
556 ; CHECK: neg [[REG:.*]] | 559 ; CHECK: neg [[REG:.*]] |
557 ; CHECK: lock xadd DWORD {{.*}},[[REG]] | 560 ; CHECK: lock xadd DWORD {{.*}},[[REG]] |
558 ; ARM32-LABEL: test_atomic_rmw_sub_32_ignored | 561 ; ARM32-LABEL: test_atomic_rmw_sub_32_ignored |
559 ; ARM32: dmb | 562 ; ARM32: dmb |
560 ; ARM32: ldrex | 563 ; ARM32: ldrex |
561 ; ARM32: sub | 564 ; ARM32: sub |
562 ; ARM32: strex | 565 ; ARM32: strex |
563 ; ARM32: bne | 566 ; ARM32: bne |
564 ; ARM32: dmb | 567 ; ARM32: dmb |
565 | 568 |
566 ;; or | 569 ;; or |
567 | 570 |
568 define i32 @test_atomic_rmw_or_8(i32 %iptr, i32 %v) { | 571 define internal i32 @test_atomic_rmw_or_8(i32 %iptr, i32 %v) { |
569 entry: | 572 entry: |
570 %trunc = trunc i32 %v to i8 | 573 %trunc = trunc i32 %v to i8 |
571 %ptr = inttoptr i32 %iptr to i8* | 574 %ptr = inttoptr i32 %iptr to i8* |
572 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 3, i8* %ptr, i8 %trunc, i32 6) | 575 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 3, i8* %ptr, i8 %trunc, i32 6) |
573 %a_ext = zext i8 %a to i32 | 576 %a_ext = zext i8 %a to i32 |
574 ret i32 %a_ext | 577 ret i32 %a_ext |
575 } | 578 } |
576 ; CHECK-LABEL: test_atomic_rmw_or_8 | 579 ; CHECK-LABEL: test_atomic_rmw_or_8 |
577 ; CHECK: mov al,BYTE PTR | 580 ; CHECK: mov al,BYTE PTR |
578 ; Dest cannot be eax here, because eax is used for the old value. Also want | 581 ; Dest cannot be eax here, because eax is used for the old value. Also want |
579 ; to make sure that cmpxchg's source is the same register. | 582 ; to make sure that cmpxchg's source is the same register. |
580 ; CHECK: or [[REG:[^a].]] | 583 ; CHECK: or [[REG:[^a].]] |
581 ; CHECK: lock cmpxchg BYTE PTR [e{{[^a].}}],[[REG]] | 584 ; CHECK: lock cmpxchg BYTE PTR [e{{[^a].}}],[[REG]] |
582 ; CHECK: jne | 585 ; CHECK: jne |
583 ; ARM32-LABEL: test_atomic_rmw_or_8 | 586 ; ARM32-LABEL: test_atomic_rmw_or_8 |
584 ; ARM32: dmb | 587 ; ARM32: dmb |
585 ; ARM32: ldrexb | 588 ; ARM32: ldrexb |
586 ; ARM32: orr | 589 ; ARM32: orr |
587 ; ARM32: strexb | 590 ; ARM32: strexb |
588 ; ARM32: bne | 591 ; ARM32: bne |
589 ; ARM32: dmb | 592 ; ARM32: dmb |
590 | 593 |
591 ; Same test as above, but with a global address to test FakeUse issues. | 594 ; Same test as above, but with a global address to test FakeUse issues. |
592 define i32 @test_atomic_rmw_or_8_global(i32 %v) { | 595 define internal i32 @test_atomic_rmw_or_8_global(i32 %v) { |
593 entry: | 596 entry: |
594 %trunc = trunc i32 %v to i8 | 597 %trunc = trunc i32 %v to i8 |
595 %ptr = bitcast [1 x i8]* @Global8 to i8* | 598 %ptr = bitcast [1 x i8]* @Global8 to i8* |
596 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 3, i8* %ptr, i8 %trunc, i32 6) | 599 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 3, i8* %ptr, i8 %trunc, i32 6) |
597 %a_ext = zext i8 %a to i32 | 600 %a_ext = zext i8 %a to i32 |
598 ret i32 %a_ext | 601 ret i32 %a_ext |
599 } | 602 } |
600 ; CHECK-LABEL: test_atomic_rmw_or_8_global | 603 ; CHECK-LABEL: test_atomic_rmw_or_8_global |
601 ; ARM32-LABEL: test_atomic_rmw_or_8_global | 604 ; ARM32-LABEL: test_atomic_rmw_or_8_global |
602 ; ARM32: movw [[PTR:r[0-9]+]], #:lower16:Global8 | 605 ; ARM32: movw [[PTR:r[0-9]+]], #:lower16:Global8 |
603 ; ARM32: movt [[PTR]], #:upper16:Global8 | 606 ; ARM32: movt [[PTR]], #:upper16:Global8 |
604 ; ARM32: dmb | 607 ; ARM32: dmb |
605 ; ARM32: ldrexb r{{[0-9]+}}, {{[[]}}[[PTR]]{{[]]}} | 608 ; ARM32: ldrexb r{{[0-9]+}}, {{[[]}}[[PTR]]{{[]]}} |
606 ; ARM32: orr | 609 ; ARM32: orr |
607 ; ARM32: strexb | 610 ; ARM32: strexb |
608 ; ARM32: bne | 611 ; ARM32: bne |
609 ; ARM32: dmb | 612 ; ARM32: dmb |
610 | 613 |
611 define i32 @test_atomic_rmw_or_16(i32 %iptr, i32 %v) { | 614 define internal i32 @test_atomic_rmw_or_16(i32 %iptr, i32 %v) { |
612 entry: | 615 entry: |
613 %trunc = trunc i32 %v to i16 | 616 %trunc = trunc i32 %v to i16 |
614 %ptr = inttoptr i32 %iptr to i16* | 617 %ptr = inttoptr i32 %iptr to i16* |
615 %a = call i16 @llvm.nacl.atomic.rmw.i16(i32 3, i16* %ptr, i16 %trunc, i32 6) | 618 %a = call i16 @llvm.nacl.atomic.rmw.i16(i32 3, i16* %ptr, i16 %trunc, i32 6) |
616 %a_ext = zext i16 %a to i32 | 619 %a_ext = zext i16 %a to i32 |
617 ret i32 %a_ext | 620 ret i32 %a_ext |
618 } | 621 } |
619 ; CHECK-LABEL: test_atomic_rmw_or_16 | 622 ; CHECK-LABEL: test_atomic_rmw_or_16 |
620 ; CHECK: mov ax,WORD PTR | 623 ; CHECK: mov ax,WORD PTR |
621 ; CHECK: or [[REG:[^a].]] | 624 ; CHECK: or [[REG:[^a].]] |
622 ; CHECK: lock cmpxchg WORD PTR [e{{[^a].}}],[[REG]] | 625 ; CHECK: lock cmpxchg WORD PTR [e{{[^a].}}],[[REG]] |
623 ; CHECK: jne | 626 ; CHECK: jne |
624 ; ARM32-LABEL: test_atomic_rmw_or_16 | 627 ; ARM32-LABEL: test_atomic_rmw_or_16 |
625 ; ARM32: dmb | 628 ; ARM32: dmb |
626 ; ARM32: ldrexh | 629 ; ARM32: ldrexh |
627 ; ARM32: orr | 630 ; ARM32: orr |
628 ; ARM32: strexh | 631 ; ARM32: strexh |
629 ; ARM32: bne | 632 ; ARM32: bne |
630 ; ARM32: dmb | 633 ; ARM32: dmb |
631 | 634 |
632 ; Same test as above, but with a global address to test FakeUse issues. | 635 ; Same test as above, but with a global address to test FakeUse issues. |
633 define i32 @test_atomic_rmw_or_16_global(i32 %v) { | 636 define internal i32 @test_atomic_rmw_or_16_global(i32 %v) { |
634 entry: | 637 entry: |
635 %trunc = trunc i32 %v to i16 | 638 %trunc = trunc i32 %v to i16 |
636 %ptr = bitcast [2 x i8]* @Global16 to i16* | 639 %ptr = bitcast [2 x i8]* @Global16 to i16* |
637 %a = call i16 @llvm.nacl.atomic.rmw.i16(i32 3, i16* %ptr, i16 %trunc, i32 6) | 640 %a = call i16 @llvm.nacl.atomic.rmw.i16(i32 3, i16* %ptr, i16 %trunc, i32 6) |
638 %a_ext = zext i16 %a to i32 | 641 %a_ext = zext i16 %a to i32 |
639 ret i32 %a_ext | 642 ret i32 %a_ext |
640 } | 643 } |
641 ; CHECK-LABEL: test_atomic_rmw_or_16_global | 644 ; CHECK-LABEL: test_atomic_rmw_or_16_global |
642 ; ARM32-LABEL: test_atomic_rmw_or_16_global | 645 ; ARM32-LABEL: test_atomic_rmw_or_16_global |
643 ; ARM32: movw [[PTR:r[0-9]+]], #:lower16:Global16 | 646 ; ARM32: movw [[PTR:r[0-9]+]], #:lower16:Global16 |
644 ; ARM32: movt [[PTR]], #:upper16:Global16 | 647 ; ARM32: movt [[PTR]], #:upper16:Global16 |
645 ; ARM32: dmb | 648 ; ARM32: dmb |
646 ; ARM32: ldrexh r{{[0-9]+}}, {{[[]}}[[PTR]]{{[]]}} | 649 ; ARM32: ldrexh r{{[0-9]+}}, {{[[]}}[[PTR]]{{[]]}} |
647 ; ARM32: orr | 650 ; ARM32: orr |
648 ; ARM32: strexh | 651 ; ARM32: strexh |
649 ; ARM32: bne | 652 ; ARM32: bne |
650 ; ARM32: dmb | 653 ; ARM32: dmb |
651 | 654 |
652 define i32 @test_atomic_rmw_or_32(i32 %iptr, i32 %v) { | 655 define internal i32 @test_atomic_rmw_or_32(i32 %iptr, i32 %v) { |
653 entry: | 656 entry: |
654 %ptr = inttoptr i32 %iptr to i32* | 657 %ptr = inttoptr i32 %iptr to i32* |
655 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 3, i32* %ptr, i32 %v, i32 6) | 658 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 3, i32* %ptr, i32 %v, i32 6) |
656 ret i32 %a | 659 ret i32 %a |
657 } | 660 } |
658 ; CHECK-LABEL: test_atomic_rmw_or_32 | 661 ; CHECK-LABEL: test_atomic_rmw_or_32 |
659 ; CHECK: mov eax,DWORD PTR | 662 ; CHECK: mov eax,DWORD PTR |
660 ; CHECK: or [[REG:e[^a].]] | 663 ; CHECK: or [[REG:e[^a].]] |
661 ; CHECK: lock cmpxchg DWORD PTR [e{{[^a].}}],[[REG]] | 664 ; CHECK: lock cmpxchg DWORD PTR [e{{[^a].}}],[[REG]] |
662 ; CHECK: jne | 665 ; CHECK: jne |
663 ; ARM32-LABEL: test_atomic_rmw_or_32 | 666 ; ARM32-LABEL: test_atomic_rmw_or_32 |
664 ; ARM32: dmb | 667 ; ARM32: dmb |
665 ; ARM32: ldrex | 668 ; ARM32: ldrex |
666 ; ARM32: orr | 669 ; ARM32: orr |
667 ; ARM32: strex | 670 ; ARM32: strex |
668 ; ARM32: bne | 671 ; ARM32: bne |
669 ; ARM32: dmb | 672 ; ARM32: dmb |
670 | 673 |
671 ; Same test as above, but with a global address to test FakeUse issues. | 674 ; Same test as above, but with a global address to test FakeUse issues. |
672 define i32 @test_atomic_rmw_or_32_global(i32 %v) { | 675 define internal i32 @test_atomic_rmw_or_32_global(i32 %v) { |
673 entry: | 676 entry: |
674 %ptr = bitcast [4 x i8]* @Global32 to i32* | 677 %ptr = bitcast [4 x i8]* @Global32 to i32* |
675 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 3, i32* %ptr, i32 %v, i32 6) | 678 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 3, i32* %ptr, i32 %v, i32 6) |
676 ret i32 %a | 679 ret i32 %a |
677 } | 680 } |
678 ; CHECK-LABEL: test_atomic_rmw_or_32_global | 681 ; CHECK-LABEL: test_atomic_rmw_or_32_global |
679 ; ARM32-LABEL: test_atomic_rmw_or_32_global | 682 ; ARM32-LABEL: test_atomic_rmw_or_32_global |
680 ; ARM32: movw [[PTR:r[0-9]+]], #:lower16:Global32 | 683 ; ARM32: movw [[PTR:r[0-9]+]], #:lower16:Global32 |
681 ; ARM32: movt [[PTR]], #:upper16:Global32 | 684 ; ARM32: movt [[PTR]], #:upper16:Global32 |
682 ; ARM32: dmb | 685 ; ARM32: dmb |
683 ; ARM32: ldrex r{{[0-9]+}}, {{[[]}}[[PTR]]{{[]]}} | 686 ; ARM32: ldrex r{{[0-9]+}}, {{[[]}}[[PTR]]{{[]]}} |
684 ; ARM32: orr | 687 ; ARM32: orr |
685 ; ARM32: strex | 688 ; ARM32: strex |
686 ; ARM32: bne | 689 ; ARM32: bne |
687 ; ARM32: dmb | 690 ; ARM32: dmb |
688 | 691 |
689 define i64 @test_atomic_rmw_or_64(i32 %iptr, i64 %v) { | 692 define internal i64 @test_atomic_rmw_or_64(i32 %iptr, i64 %v) { |
690 entry: | 693 entry: |
691 %ptr = inttoptr i32 %iptr to i64* | 694 %ptr = inttoptr i32 %iptr to i64* |
692 %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 3, i64* %ptr, i64 %v, i32 6) | 695 %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 3, i64* %ptr, i64 %v, i32 6) |
693 ret i64 %a | 696 ret i64 %a |
694 } | 697 } |
695 ; CHECK-LABEL: test_atomic_rmw_or_64 | 698 ; CHECK-LABEL: test_atomic_rmw_or_64 |
696 ; CHECK: push ebx | 699 ; CHECK: push ebx |
697 ; CHECK: mov eax,DWORD PTR [{{.*}}] | 700 ; CHECK: mov eax,DWORD PTR [{{.*}}] |
698 ; CHECK: mov edx,DWORD PTR [{{.*}}+0x4] | 701 ; CHECK: mov edx,DWORD PTR [{{.*}}+0x4] |
699 ; CHECK: [[LABEL:[^ ]*]]: {{.*}} mov ebx,eax | 702 ; CHECK: [[LABEL:[^ ]*]]: {{.*}} mov ebx,eax |
700 ; CHECK: or ebx,{{.*e.[^x]}} | 703 ; CHECK: or ebx,{{.*e.[^x]}} |
701 ; CHECK: mov ecx,edx | 704 ; CHECK: mov ecx,edx |
702 ; CHECK: or ecx,{{.*e.[^x]}} | 705 ; CHECK: or ecx,{{.*e.[^x]}} |
703 ; CHECK: lock cmpxchg8b QWORD PTR [e{{.[^x]}} | 706 ; CHECK: lock cmpxchg8b QWORD PTR [e{{.[^x]}} |
704 ; CHECK: jne [[LABEL]] | 707 ; CHECK: jne [[LABEL]] |
705 ; ARM32-LABEL: test_atomic_rmw_or_64 | 708 ; ARM32-LABEL: test_atomic_rmw_or_64 |
706 ; ARM32: dmb | 709 ; ARM32: dmb |
707 ; ARM32: ldrexd r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}}] | 710 ; ARM32: ldrexd r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}}] |
708 ; ARM32: orr | 711 ; ARM32: orr |
709 ; ARM32-NEXT: orr | 712 ; ARM32-NEXT: orr |
710 ; ARM32: strexd r{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}}] | 713 ; ARM32: strexd r{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}}] |
711 ; ARM32: bne | 714 ; ARM32: bne |
712 ; ARM32: dmb | 715 ; ARM32: dmb |
713 | 716 |
714 define i32 @test_atomic_rmw_or_32_ignored(i32 %iptr, i32 %v) { | 717 define internal i32 @test_atomic_rmw_or_32_ignored(i32 %iptr, i32 %v) { |
715 entry: | 718 entry: |
716 %ptr = inttoptr i32 %iptr to i32* | 719 %ptr = inttoptr i32 %iptr to i32* |
717 %ignored = call i32 @llvm.nacl.atomic.rmw.i32(i32 3, i32* %ptr, i32 %v, i32 6) | 720 %ignored = call i32 @llvm.nacl.atomic.rmw.i32(i32 3, i32* %ptr, i32 %v, i32 6) |
718 ret i32 %v | 721 ret i32 %v |
719 } | 722 } |
720 ; CHECK-LABEL: test_atomic_rmw_or_32_ignored | 723 ; CHECK-LABEL: test_atomic_rmw_or_32_ignored |
721 ; Could just "lock or", if we inspect the liveness information first. | 724 ; Could just "lock or", if we inspect the liveness information first. |
722 ; Would also need a way to introduce "lock"'edness to binary | 725 ; Would also need a way to introduce "lock"'edness to binary |
723 ; operators without introducing overhead on the more common binary ops. | 726 ; operators without introducing overhead on the more common binary ops. |
724 ; CHECK: mov eax,DWORD PTR | 727 ; CHECK: mov eax,DWORD PTR |
725 ; CHECK: or [[REG:e[^a].]] | 728 ; CHECK: or [[REG:e[^a].]] |
726 ; CHECK: lock cmpxchg DWORD PTR [e{{[^a].}}],[[REG]] | 729 ; CHECK: lock cmpxchg DWORD PTR [e{{[^a].}}],[[REG]] |
727 ; CHECK: jne | 730 ; CHECK: jne |
728 ; ARM32-LABEL: test_atomic_rmw_or_32_ignored | 731 ; ARM32-LABEL: test_atomic_rmw_or_32_ignored |
729 ; ARM32: dmb | 732 ; ARM32: dmb |
730 ; ARM32: ldrex | 733 ; ARM32: ldrex |
731 ; ARM32: orr | 734 ; ARM32: orr |
732 ; ARM32: strex | 735 ; ARM32: strex |
733 ; ARM32: bne | 736 ; ARM32: bne |
734 ; ARM32: dmb | 737 ; ARM32: dmb |
735 | 738 |
736 ;; and | 739 ;; and |
737 | 740 |
738 define i32 @test_atomic_rmw_and_8(i32 %iptr, i32 %v) { | 741 define internal i32 @test_atomic_rmw_and_8(i32 %iptr, i32 %v) { |
739 entry: | 742 entry: |
740 %trunc = trunc i32 %v to i8 | 743 %trunc = trunc i32 %v to i8 |
741 %ptr = inttoptr i32 %iptr to i8* | 744 %ptr = inttoptr i32 %iptr to i8* |
742 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 4, i8* %ptr, i8 %trunc, i32 6) | 745 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 4, i8* %ptr, i8 %trunc, i32 6) |
743 %a_ext = zext i8 %a to i32 | 746 %a_ext = zext i8 %a to i32 |
744 ret i32 %a_ext | 747 ret i32 %a_ext |
745 } | 748 } |
746 ; CHECK-LABEL: test_atomic_rmw_and_8 | 749 ; CHECK-LABEL: test_atomic_rmw_and_8 |
747 ; CHECK: mov al,BYTE PTR | 750 ; CHECK: mov al,BYTE PTR |
748 ; CHECK: and [[REG:[^a].]] | 751 ; CHECK: and [[REG:[^a].]] |
749 ; CHECK: lock cmpxchg BYTE PTR [e{{[^a].}}],[[REG]] | 752 ; CHECK: lock cmpxchg BYTE PTR [e{{[^a].}}],[[REG]] |
750 ; CHECK: jne | 753 ; CHECK: jne |
751 ; ARM32-LABEL: test_atomic_rmw_and_8 | 754 ; ARM32-LABEL: test_atomic_rmw_and_8 |
752 ; ARM32: dmb | 755 ; ARM32: dmb |
753 ; ARM32: ldrexb | 756 ; ARM32: ldrexb |
754 ; ARM32: and | 757 ; ARM32: and |
755 ; ARM32: strexb | 758 ; ARM32: strexb |
756 ; ARM32: bne | 759 ; ARM32: bne |
757 ; ARM32: dmb | 760 ; ARM32: dmb |
758 | 761 |
759 define i32 @test_atomic_rmw_and_16(i32 %iptr, i32 %v) { | 762 define internal i32 @test_atomic_rmw_and_16(i32 %iptr, i32 %v) { |
760 entry: | 763 entry: |
761 %trunc = trunc i32 %v to i16 | 764 %trunc = trunc i32 %v to i16 |
762 %ptr = inttoptr i32 %iptr to i16* | 765 %ptr = inttoptr i32 %iptr to i16* |
763 %a = call i16 @llvm.nacl.atomic.rmw.i16(i32 4, i16* %ptr, i16 %trunc, i32 6) | 766 %a = call i16 @llvm.nacl.atomic.rmw.i16(i32 4, i16* %ptr, i16 %trunc, i32 6) |
764 %a_ext = zext i16 %a to i32 | 767 %a_ext = zext i16 %a to i32 |
765 ret i32 %a_ext | 768 ret i32 %a_ext |
766 } | 769 } |
767 ; CHECK-LABEL: test_atomic_rmw_and_16 | 770 ; CHECK-LABEL: test_atomic_rmw_and_16 |
768 ; CHECK: mov ax,WORD PTR | 771 ; CHECK: mov ax,WORD PTR |
769 ; CHECK: and | 772 ; CHECK: and |
770 ; CHECK: lock cmpxchg WORD PTR [e{{[^a].}}] | 773 ; CHECK: lock cmpxchg WORD PTR [e{{[^a].}}] |
771 ; CHECK: jne | 774 ; CHECK: jne |
772 ; ARM32-LABEL: test_atomic_rmw_and_16 | 775 ; ARM32-LABEL: test_atomic_rmw_and_16 |
773 ; ARM32: dmb | 776 ; ARM32: dmb |
774 ; ARM32: ldrexh | 777 ; ARM32: ldrexh |
775 ; ARM32: and | 778 ; ARM32: and |
776 ; ARM32: strexh | 779 ; ARM32: strexh |
777 ; ARM32: bne | 780 ; ARM32: bne |
778 ; ARM32: dmb | 781 ; ARM32: dmb |
779 | 782 |
780 define i32 @test_atomic_rmw_and_32(i32 %iptr, i32 %v) { | 783 define internal i32 @test_atomic_rmw_and_32(i32 %iptr, i32 %v) { |
781 entry: | 784 entry: |
782 %ptr = inttoptr i32 %iptr to i32* | 785 %ptr = inttoptr i32 %iptr to i32* |
783 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 4, i32* %ptr, i32 %v, i32 6) | 786 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 4, i32* %ptr, i32 %v, i32 6) |
784 ret i32 %a | 787 ret i32 %a |
785 } | 788 } |
786 ; CHECK-LABEL: test_atomic_rmw_and_32 | 789 ; CHECK-LABEL: test_atomic_rmw_and_32 |
787 ; CHECK: mov eax,DWORD PTR | 790 ; CHECK: mov eax,DWORD PTR |
788 ; CHECK: and | 791 ; CHECK: and |
789 ; CHECK: lock cmpxchg DWORD PTR [e{{[^a].}}] | 792 ; CHECK: lock cmpxchg DWORD PTR [e{{[^a].}}] |
790 ; CHECK: jne | 793 ; CHECK: jne |
791 ; ARM32-LABEL: test_atomic_rmw_and_32 | 794 ; ARM32-LABEL: test_atomic_rmw_and_32 |
792 ; ARM32: dmb | 795 ; ARM32: dmb |
793 ; ARM32: ldrex | 796 ; ARM32: ldrex |
794 ; ARM32: and | 797 ; ARM32: and |
795 ; ARM32: strex | 798 ; ARM32: strex |
796 ; ARM32: bne | 799 ; ARM32: bne |
797 ; ARM32: dmb | 800 ; ARM32: dmb |
798 | 801 |
799 define i64 @test_atomic_rmw_and_64(i32 %iptr, i64 %v) { | 802 define internal i64 @test_atomic_rmw_and_64(i32 %iptr, i64 %v) { |
800 entry: | 803 entry: |
801 %ptr = inttoptr i32 %iptr to i64* | 804 %ptr = inttoptr i32 %iptr to i64* |
802 %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 4, i64* %ptr, i64 %v, i32 6) | 805 %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 4, i64* %ptr, i64 %v, i32 6) |
803 ret i64 %a | 806 ret i64 %a |
804 } | 807 } |
805 ; CHECK-LABEL: test_atomic_rmw_and_64 | 808 ; CHECK-LABEL: test_atomic_rmw_and_64 |
806 ; CHECK: push ebx | 809 ; CHECK: push ebx |
807 ; CHECK: mov eax,DWORD PTR [{{.*}}] | 810 ; CHECK: mov eax,DWORD PTR [{{.*}}] |
808 ; CHECK: mov edx,DWORD PTR [{{.*}}+0x4] | 811 ; CHECK: mov edx,DWORD PTR [{{.*}}+0x4] |
809 ; CHECK: [[LABEL:[^ ]*]]: {{.*}} mov ebx,eax | 812 ; CHECK: [[LABEL:[^ ]*]]: {{.*}} mov ebx,eax |
810 ; CHECK: and ebx,{{.*e.[^x]}} | 813 ; CHECK: and ebx,{{.*e.[^x]}} |
811 ; CHECK: mov ecx,edx | 814 ; CHECK: mov ecx,edx |
812 ; CHECK: and ecx,{{.*e.[^x]}} | 815 ; CHECK: and ecx,{{.*e.[^x]}} |
813 ; CHECK: lock cmpxchg8b QWORD PTR [e{{.[^x]}} | 816 ; CHECK: lock cmpxchg8b QWORD PTR [e{{.[^x]}} |
814 ; CHECK: jne [[LABEL]] | 817 ; CHECK: jne [[LABEL]] |
815 ; ARM32-LABEL: test_atomic_rmw_and_64 | 818 ; ARM32-LABEL: test_atomic_rmw_and_64 |
816 ; ARM32: dmb | 819 ; ARM32: dmb |
817 ; ARM32: ldrexd r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}}] | 820 ; ARM32: ldrexd r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}}] |
818 ; ARM32: and | 821 ; ARM32: and |
819 ; ARM32-NEXT: and | 822 ; ARM32-NEXT: and |
820 ; ARM32: strexd r{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}}] | 823 ; ARM32: strexd r{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}}] |
821 ; ARM32: bne | 824 ; ARM32: bne |
822 ; ARM32: dmb | 825 ; ARM32: dmb |
823 | 826 |
824 define i32 @test_atomic_rmw_and_32_ignored(i32 %iptr, i32 %v) { | 827 define internal i32 @test_atomic_rmw_and_32_ignored(i32 %iptr, i32 %v) { |
825 entry: | 828 entry: |
826 %ptr = inttoptr i32 %iptr to i32* | 829 %ptr = inttoptr i32 %iptr to i32* |
827 %ignored = call i32 @llvm.nacl.atomic.rmw.i32(i32 4, i32* %ptr, i32 %v, i32 6) | 830 %ignored = call i32 @llvm.nacl.atomic.rmw.i32(i32 4, i32* %ptr, i32 %v, i32 6) |
828 ret i32 %v | 831 ret i32 %v |
829 } | 832 } |
830 ; CHECK-LABEL: test_atomic_rmw_and_32_ignored | 833 ; CHECK-LABEL: test_atomic_rmw_and_32_ignored |
831 ; Could just "lock and" | 834 ; Could just "lock and" |
832 ; CHECK: mov eax,DWORD PTR | 835 ; CHECK: mov eax,DWORD PTR |
833 ; CHECK: and | 836 ; CHECK: and |
834 ; CHECK: lock cmpxchg DWORD PTR [e{{[^a].}}] | 837 ; CHECK: lock cmpxchg DWORD PTR [e{{[^a].}}] |
835 ; CHECK: jne | 838 ; CHECK: jne |
836 ; ARM32-LABEL: test_atomic_rmw_and_32_ignored | 839 ; ARM32-LABEL: test_atomic_rmw_and_32_ignored |
837 ; ARM32: dmb | 840 ; ARM32: dmb |
838 ; ARM32: ldrex | 841 ; ARM32: ldrex |
839 ; ARM32: and | 842 ; ARM32: and |
840 ; ARM32: strex | 843 ; ARM32: strex |
841 ; ARM32: bne | 844 ; ARM32: bne |
842 ; ARM32: dmb | 845 ; ARM32: dmb |
843 | 846 |
844 ;; xor | 847 ;; xor |
845 | 848 |
846 define i32 @test_atomic_rmw_xor_8(i32 %iptr, i32 %v) { | 849 define internal i32 @test_atomic_rmw_xor_8(i32 %iptr, i32 %v) { |
847 entry: | 850 entry: |
848 %trunc = trunc i32 %v to i8 | 851 %trunc = trunc i32 %v to i8 |
849 %ptr = inttoptr i32 %iptr to i8* | 852 %ptr = inttoptr i32 %iptr to i8* |
850 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 5, i8* %ptr, i8 %trunc, i32 6) | 853 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 5, i8* %ptr, i8 %trunc, i32 6) |
851 %a_ext = zext i8 %a to i32 | 854 %a_ext = zext i8 %a to i32 |
852 ret i32 %a_ext | 855 ret i32 %a_ext |
853 } | 856 } |
854 ; CHECK-LABEL: test_atomic_rmw_xor_8 | 857 ; CHECK-LABEL: test_atomic_rmw_xor_8 |
855 ; CHECK: mov al,BYTE PTR | 858 ; CHECK: mov al,BYTE PTR |
856 ; CHECK: xor [[REG:[^a].]] | 859 ; CHECK: xor [[REG:[^a].]] |
857 ; CHECK: lock cmpxchg BYTE PTR [e{{[^a].}}],[[REG]] | 860 ; CHECK: lock cmpxchg BYTE PTR [e{{[^a].}}],[[REG]] |
858 ; CHECK: jne | 861 ; CHECK: jne |
859 ; ARM32-LABEL: test_atomic_rmw_xor_8 | 862 ; ARM32-LABEL: test_atomic_rmw_xor_8 |
860 ; ARM32: dmb | 863 ; ARM32: dmb |
861 ; ARM32: ldrexb | 864 ; ARM32: ldrexb |
862 ; ARM32: eor | 865 ; ARM32: eor |
863 ; ARM32: strexb | 866 ; ARM32: strexb |
864 ; ARM32: bne | 867 ; ARM32: bne |
865 ; ARM32: dmb | 868 ; ARM32: dmb |
866 | 869 |
867 define i32 @test_atomic_rmw_xor_16(i32 %iptr, i32 %v) { | 870 define internal i32 @test_atomic_rmw_xor_16(i32 %iptr, i32 %v) { |
868 entry: | 871 entry: |
869 %trunc = trunc i32 %v to i16 | 872 %trunc = trunc i32 %v to i16 |
870 %ptr = inttoptr i32 %iptr to i16* | 873 %ptr = inttoptr i32 %iptr to i16* |
871 %a = call i16 @llvm.nacl.atomic.rmw.i16(i32 5, i16* %ptr, i16 %trunc, i32 6) | 874 %a = call i16 @llvm.nacl.atomic.rmw.i16(i32 5, i16* %ptr, i16 %trunc, i32 6) |
872 %a_ext = zext i16 %a to i32 | 875 %a_ext = zext i16 %a to i32 |
873 ret i32 %a_ext | 876 ret i32 %a_ext |
874 } | 877 } |
875 ; CHECK-LABEL: test_atomic_rmw_xor_16 | 878 ; CHECK-LABEL: test_atomic_rmw_xor_16 |
876 ; CHECK: mov ax,WORD PTR | 879 ; CHECK: mov ax,WORD PTR |
877 ; CHECK: xor | 880 ; CHECK: xor |
878 ; CHECK: lock cmpxchg WORD PTR [e{{[^a].}}] | 881 ; CHECK: lock cmpxchg WORD PTR [e{{[^a].}}] |
879 ; CHECK: jne | 882 ; CHECK: jne |
880 ; ARM32-LABEL: test_atomic_rmw_xor_16 | 883 ; ARM32-LABEL: test_atomic_rmw_xor_16 |
881 ; ARM32: dmb | 884 ; ARM32: dmb |
882 ; ARM32: ldrexh | 885 ; ARM32: ldrexh |
883 ; ARM32: eor | 886 ; ARM32: eor |
884 ; ARM32: strexh | 887 ; ARM32: strexh |
885 ; ARM32: bne | 888 ; ARM32: bne |
886 ; ARM32: dmb | 889 ; ARM32: dmb |
887 | 890 |
888 define i32 @test_atomic_rmw_xor_32(i32 %iptr, i32 %v) { | 891 define internal i32 @test_atomic_rmw_xor_32(i32 %iptr, i32 %v) { |
889 entry: | 892 entry: |
890 %ptr = inttoptr i32 %iptr to i32* | 893 %ptr = inttoptr i32 %iptr to i32* |
891 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 5, i32* %ptr, i32 %v, i32 6) | 894 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 5, i32* %ptr, i32 %v, i32 6) |
892 ret i32 %a | 895 ret i32 %a |
893 } | 896 } |
894 ; CHECK-LABEL: test_atomic_rmw_xor_32 | 897 ; CHECK-LABEL: test_atomic_rmw_xor_32 |
895 ; CHECK: mov eax,DWORD PTR | 898 ; CHECK: mov eax,DWORD PTR |
896 ; CHECK: xor | 899 ; CHECK: xor |
897 ; CHECK: lock cmpxchg DWORD PTR [e{{[^a].}}] | 900 ; CHECK: lock cmpxchg DWORD PTR [e{{[^a].}}] |
898 ; CHECK: jne | 901 ; CHECK: jne |
899 ; ARM32-LABEL: test_atomic_rmw_xor_32 | 902 ; ARM32-LABEL: test_atomic_rmw_xor_32 |
900 ; ARM32: dmb | 903 ; ARM32: dmb |
901 ; ARM32: ldrex | 904 ; ARM32: ldrex |
902 ; ARM32: eor | 905 ; ARM32: eor |
903 ; ARM32: strex | 906 ; ARM32: strex |
904 ; ARM32: bne | 907 ; ARM32: bne |
905 ; ARM32: dmb | 908 ; ARM32: dmb |
906 | 909 |
907 define i64 @test_atomic_rmw_xor_64(i32 %iptr, i64 %v) { | 910 define internal i64 @test_atomic_rmw_xor_64(i32 %iptr, i64 %v) { |
908 entry: | 911 entry: |
909 %ptr = inttoptr i32 %iptr to i64* | 912 %ptr = inttoptr i32 %iptr to i64* |
910 %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 5, i64* %ptr, i64 %v, i32 6) | 913 %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 5, i64* %ptr, i64 %v, i32 6) |
911 ret i64 %a | 914 ret i64 %a |
912 } | 915 } |
913 ; CHECK-LABEL: test_atomic_rmw_xor_64 | 916 ; CHECK-LABEL: test_atomic_rmw_xor_64 |
914 ; CHECK: push ebx | 917 ; CHECK: push ebx |
915 ; CHECK: mov eax,DWORD PTR [{{.*}}] | 918 ; CHECK: mov eax,DWORD PTR [{{.*}}] |
916 ; CHECK: mov edx,DWORD PTR [{{.*}}+0x4] | 919 ; CHECK: mov edx,DWORD PTR [{{.*}}+0x4] |
917 ; CHECK: mov ebx,eax | 920 ; CHECK: mov ebx,eax |
918 ; CHECK: or ebx,{{.*e.[^x]}} | 921 ; CHECK: or ebx,{{.*e.[^x]}} |
919 ; CHECK: mov ecx,edx | 922 ; CHECK: mov ecx,edx |
920 ; CHECK: or ecx,{{.*e.[^x]}} | 923 ; CHECK: or ecx,{{.*e.[^x]}} |
921 ; CHECK: lock cmpxchg8b QWORD PTR [e{{.[^x]}} | 924 ; CHECK: lock cmpxchg8b QWORD PTR [e{{.[^x]}} |
922 ; CHECK: jne | 925 ; CHECK: jne |
923 ; ARM32-LABEL: test_atomic_rmw_xor_64 | 926 ; ARM32-LABEL: test_atomic_rmw_xor_64 |
924 ; ARM32: dmb | 927 ; ARM32: dmb |
925 ; ARM32: ldrexd r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}}] | 928 ; ARM32: ldrexd r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}}] |
926 ; ARM32: eor | 929 ; ARM32: eor |
927 ; ARM32-NEXT: eor | 930 ; ARM32-NEXT: eor |
928 ; ARM32: strexd r{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}}] | 931 ; ARM32: strexd r{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}, [r{{[0-9]+}}] |
929 ; ARM32: bne | 932 ; ARM32: bne |
930 ; ARM32: dmb | 933 ; ARM32: dmb |
931 | 934 |
932 define i32 @test_atomic_rmw_xor_32_ignored(i32 %iptr, i32 %v) { | 935 define internal i32 @test_atomic_rmw_xor_32_ignored(i32 %iptr, i32 %v) { |
933 entry: | 936 entry: |
934 %ptr = inttoptr i32 %iptr to i32* | 937 %ptr = inttoptr i32 %iptr to i32* |
935 %ignored = call i32 @llvm.nacl.atomic.rmw.i32(i32 5, i32* %ptr, i32 %v, i32 6) | 938 %ignored = call i32 @llvm.nacl.atomic.rmw.i32(i32 5, i32* %ptr, i32 %v, i32 6) |
936 ret i32 %v | 939 ret i32 %v |
937 } | 940 } |
938 ; CHECK-LABEL: test_atomic_rmw_xor_32_ignored | 941 ; CHECK-LABEL: test_atomic_rmw_xor_32_ignored |
939 ; CHECK: mov eax,DWORD PTR | 942 ; CHECK: mov eax,DWORD PTR |
940 ; CHECK: xor | 943 ; CHECK: xor |
941 ; CHECK: lock cmpxchg DWORD PTR [e{{[^a].}}] | 944 ; CHECK: lock cmpxchg DWORD PTR [e{{[^a].}}] |
942 ; CHECK: jne | 945 ; CHECK: jne |
943 ; ARM32-LABEL: test_atomic_rmw_xor_32_ignored | 946 ; ARM32-LABEL: test_atomic_rmw_xor_32_ignored |
944 ; ARM32: dmb | 947 ; ARM32: dmb |
945 ; ARM32: ldrex | 948 ; ARM32: ldrex |
946 ; ARM32: eor | 949 ; ARM32: eor |
947 ; ARM32: strex | 950 ; ARM32: strex |
948 ; ARM32: bne | 951 ; ARM32: bne |
949 ; ARM32: dmb | 952 ; ARM32: dmb |
950 | 953 |
951 ;; exchange | 954 ;; exchange |
952 | 955 |
953 define i32 @test_atomic_rmw_xchg_8(i32 %iptr, i32 %v) { | 956 define internal i32 @test_atomic_rmw_xchg_8(i32 %iptr, i32 %v) { |
954 entry: | 957 entry: |
955 %trunc = trunc i32 %v to i8 | 958 %trunc = trunc i32 %v to i8 |
956 %ptr = inttoptr i32 %iptr to i8* | 959 %ptr = inttoptr i32 %iptr to i8* |
957 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 6, i8* %ptr, i8 %trunc, i32 6) | 960 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 6, i8* %ptr, i8 %trunc, i32 6) |
958 %a_ext = zext i8 %a to i32 | 961 %a_ext = zext i8 %a to i32 |
959 ret i32 %a_ext | 962 ret i32 %a_ext |
960 } | 963 } |
961 ; CHECK-LABEL: test_atomic_rmw_xchg_8 | 964 ; CHECK-LABEL: test_atomic_rmw_xchg_8 |
962 ; CHECK: xchg BYTE PTR {{.*}},[[REG:.*]] | 965 ; CHECK: xchg BYTE PTR {{.*}},[[REG:.*]] |
963 ; ARM32-LABEL: test_atomic_rmw_xchg_8 | 966 ; ARM32-LABEL: test_atomic_rmw_xchg_8 |
964 ; ARM32: dmb | 967 ; ARM32: dmb |
965 ; ARM32: ldrexb | 968 ; ARM32: ldrexb |
966 ; ARM32: strexb | 969 ; ARM32: strexb |
967 ; ARM32: cmp | 970 ; ARM32: cmp |
968 ; ARM32: bne | 971 ; ARM32: bne |
969 ; ARM32: dmb | 972 ; ARM32: dmb |
970 | 973 |
971 define i32 @test_atomic_rmw_xchg_16(i32 %iptr, i32 %v) { | 974 define internal i32 @test_atomic_rmw_xchg_16(i32 %iptr, i32 %v) { |
972 entry: | 975 entry: |
973 %trunc = trunc i32 %v to i16 | 976 %trunc = trunc i32 %v to i16 |
974 %ptr = inttoptr i32 %iptr to i16* | 977 %ptr = inttoptr i32 %iptr to i16* |
975 %a = call i16 @llvm.nacl.atomic.rmw.i16(i32 6, i16* %ptr, i16 %trunc, i32 6) | 978 %a = call i16 @llvm.nacl.atomic.rmw.i16(i32 6, i16* %ptr, i16 %trunc, i32 6) |
976 %a_ext = zext i16 %a to i32 | 979 %a_ext = zext i16 %a to i32 |
977 ret i32 %a_ext | 980 ret i32 %a_ext |
978 } | 981 } |
979 ; CHECK-LABEL: test_atomic_rmw_xchg_16 | 982 ; CHECK-LABEL: test_atomic_rmw_xchg_16 |
980 ; CHECK: xchg WORD PTR {{.*}},[[REG:.*]] | 983 ; CHECK: xchg WORD PTR {{.*}},[[REG:.*]] |
981 ; ARM32-LABEL: test_atomic_rmw_xchg_16 | 984 ; ARM32-LABEL: test_atomic_rmw_xchg_16 |
982 ; ARM32: dmb | 985 ; ARM32: dmb |
983 ; ARM32: ldrexh | 986 ; ARM32: ldrexh |
984 ; ARM32: strexh | 987 ; ARM32: strexh |
985 ; ARM32: cmp | 988 ; ARM32: cmp |
986 ; ARM32: bne | 989 ; ARM32: bne |
987 ; ARM32: dmb | 990 ; ARM32: dmb |
988 | 991 |
989 define i32 @test_atomic_rmw_xchg_32(i32 %iptr, i32 %v) { | 992 define internal i32 @test_atomic_rmw_xchg_32(i32 %iptr, i32 %v) { |
990 entry: | 993 entry: |
991 %ptr = inttoptr i32 %iptr to i32* | 994 %ptr = inttoptr i32 %iptr to i32* |
992 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 6, i32* %ptr, i32 %v, i32 6) | 995 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 6, i32* %ptr, i32 %v, i32 6) |
993 ret i32 %a | 996 ret i32 %a |
994 } | 997 } |
995 ; CHECK-LABEL: test_atomic_rmw_xchg_32 | 998 ; CHECK-LABEL: test_atomic_rmw_xchg_32 |
996 ; CHECK: xchg DWORD PTR {{.*}},[[REG:.*]] | 999 ; CHECK: xchg DWORD PTR {{.*}},[[REG:.*]] |
997 ; ARM32-LABEL: test_atomic_rmw_xchg_32 | 1000 ; ARM32-LABEL: test_atomic_rmw_xchg_32 |
998 ; ARM32: dmb | 1001 ; ARM32: dmb |
999 ; ARM32: ldrex | 1002 ; ARM32: ldrex |
1000 ; ARM32: strex | 1003 ; ARM32: strex |
1001 ; ARM32: cmp | 1004 ; ARM32: cmp |
1002 ; ARM32: bne | 1005 ; ARM32: bne |
1003 ; ARM32: dmb | 1006 ; ARM32: dmb |
1004 | 1007 |
1005 define i64 @test_atomic_rmw_xchg_64(i32 %iptr, i64 %v) { | 1008 define internal i64 @test_atomic_rmw_xchg_64(i32 %iptr, i64 %v) { |
1006 entry: | 1009 entry: |
1007 %ptr = inttoptr i32 %iptr to i64* | 1010 %ptr = inttoptr i32 %iptr to i64* |
1008 %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 6, i64* %ptr, i64 %v, i32 6) | 1011 %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 6, i64* %ptr, i64 %v, i32 6) |
1009 ret i64 %a | 1012 ret i64 %a |
1010 } | 1013 } |
1011 ; CHECK-LABEL: test_atomic_rmw_xchg_64 | 1014 ; CHECK-LABEL: test_atomic_rmw_xchg_64 |
1012 ; CHECK: push ebx | 1015 ; CHECK: push ebx |
1013 ; CHECK-DAG: mov edx | 1016 ; CHECK-DAG: mov edx |
1014 ; CHECK-DAG: mov eax | 1017 ; CHECK-DAG: mov eax |
1015 ; CHECK-DAG: mov ecx | 1018 ; CHECK-DAG: mov ecx |
1016 ; CHECK-DAG: mov ebx | 1019 ; CHECK-DAG: mov ebx |
1017 ; CHECK: lock cmpxchg8b QWORD PTR [{{e.[^x]}} | 1020 ; CHECK: lock cmpxchg8b QWORD PTR [{{e.[^x]}} |
1018 ; CHECK: jne | 1021 ; CHECK: jne |
1019 ; ARM32-LABEL: test_atomic_rmw_xchg_64 | 1022 ; ARM32-LABEL: test_atomic_rmw_xchg_64 |
1020 ; ARM32: dmb | 1023 ; ARM32: dmb |
1021 ; ARM32: ldrexd r{{[0-9]+}}, r{{[0-9]+}}, {{[[]}}[[PTR:r[0-9]+]]{{[]]}} | 1024 ; ARM32: ldrexd r{{[0-9]+}}, r{{[0-9]+}}, {{[[]}}[[PTR:r[0-9]+]]{{[]]}} |
1022 ; ARM32: strexd r{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}, {{[[]}}[[PTR]]{{[]]}} | 1025 ; ARM32: strexd r{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}, {{[[]}}[[PTR]]{{[]]}} |
1023 ; ARM32: cmp | 1026 ; ARM32: cmp |
1024 ; ARM32: bne | 1027 ; ARM32: bne |
1025 ; ARM32: dmb | 1028 ; ARM32: dmb |
1026 | 1029 |
1027 define i32 @test_atomic_rmw_xchg_32_ignored(i32 %iptr, i32 %v) { | 1030 define internal i32 @test_atomic_rmw_xchg_32_ignored(i32 %iptr, i32 %v) { |
1028 entry: | 1031 entry: |
1029 %ptr = inttoptr i32 %iptr to i32* | 1032 %ptr = inttoptr i32 %iptr to i32* |
1030 %ignored = call i32 @llvm.nacl.atomic.rmw.i32(i32 6, i32* %ptr, i32 %v, i32 6) | 1033 %ignored = call i32 @llvm.nacl.atomic.rmw.i32(i32 6, i32* %ptr, i32 %v, i32 6) |
1031 ret i32 %v | 1034 ret i32 %v |
1032 } | 1035 } |
1033 ; In this case, ignoring the return value doesn't help. The xchg is | 1036 ; In this case, ignoring the return value doesn't help. The xchg is |
1034 ; used to do an atomic store. | 1037 ; used to do an atomic store. |
1035 ; CHECK-LABEL: test_atomic_rmw_xchg_32_ignored | 1038 ; CHECK-LABEL: test_atomic_rmw_xchg_32_ignored |
1036 ; CHECK: xchg DWORD PTR {{.*}},[[REG:.*]] | 1039 ; CHECK: xchg DWORD PTR {{.*}},[[REG:.*]] |
1037 ; ARM32-LABEL: test_atomic_rmw_xchg_32_ignored | 1040 ; ARM32-LABEL: test_atomic_rmw_xchg_32_ignored |
1038 ; ARM32: dmb | 1041 ; ARM32: dmb |
1039 ; ARM32: ldrex | 1042 ; ARM32: ldrex |
1040 ; ARM32: strex | 1043 ; ARM32: strex |
1041 ; ARM32: cmp | 1044 ; ARM32: cmp |
1042 ; ARM32: bne | 1045 ; ARM32: bne |
1043 ; ARM32: dmb | 1046 ; ARM32: dmb |
1044 | 1047 |
1045 ;;;; Cmpxchg | 1048 ;;;; Cmpxchg |
1046 | 1049 |
1047 define i32 @test_atomic_cmpxchg_8(i32 %iptr, i32 %expected, i32 %desired) { | 1050 define internal i32 @test_atomic_cmpxchg_8(i32 %iptr, i32 %expected, |
| 1051 i32 %desired) { |
1048 entry: | 1052 entry: |
1049 %trunc_exp = trunc i32 %expected to i8 | 1053 %trunc_exp = trunc i32 %expected to i8 |
1050 %trunc_des = trunc i32 %desired to i8 | 1054 %trunc_des = trunc i32 %desired to i8 |
1051 %ptr = inttoptr i32 %iptr to i8* | 1055 %ptr = inttoptr i32 %iptr to i8* |
1052 %old = call i8 @llvm.nacl.atomic.cmpxchg.i8(i8* %ptr, i8 %trunc_exp, | 1056 %old = call i8 @llvm.nacl.atomic.cmpxchg.i8(i8* %ptr, i8 %trunc_exp, |
1053 i8 %trunc_des, i32 6, i32 6) | 1057 i8 %trunc_des, i32 6, i32 6) |
1054 %old_ext = zext i8 %old to i32 | 1058 %old_ext = zext i8 %old to i32 |
1055 ret i32 %old_ext | 1059 ret i32 %old_ext |
1056 } | 1060 } |
1057 ; CHECK-LABEL: test_atomic_cmpxchg_8 | 1061 ; CHECK-LABEL: test_atomic_cmpxchg_8 |
1058 ; CHECK: mov eax,{{.*}} | 1062 ; CHECK: mov eax,{{.*}} |
1059 ; Need to check that eax isn't used as the address register or the desired. | 1063 ; Need to check that eax isn't used as the address register or the desired. |
1060 ; since it is already used as the *expected* register. | 1064 ; since it is already used as the *expected* register. |
1061 ; CHECK: lock cmpxchg BYTE PTR [e{{[^a].}}],{{[^a]}}l | 1065 ; CHECK: lock cmpxchg BYTE PTR [e{{[^a].}}],{{[^a]}}l |
1062 ; ARM32-LABEL: test_atomic_cmpxchg_8 | 1066 ; ARM32-LABEL: test_atomic_cmpxchg_8 |
1063 ; ARM32: dmb | 1067 ; ARM32: dmb |
1064 ; ARM32: ldrexb | 1068 ; ARM32: ldrexb |
1065 ; ARM32: cmp | 1069 ; ARM32: cmp |
1066 ; ARM32: strexbeq | 1070 ; ARM32: strexbeq |
1067 ; ARM32: {{str|mov}}ne | 1071 ; ARM32: {{str|mov}}ne |
1068 ; ARM32: cmpeq | 1072 ; ARM32: cmpeq |
1069 ; ARM32: bne | 1073 ; ARM32: bne |
1070 ; ARM32: dmb | 1074 ; ARM32: dmb |
1071 | 1075 |
1072 define i32 @test_atomic_cmpxchg_16(i32 %iptr, i32 %expected, i32 %desired) { | 1076 define internal i32 @test_atomic_cmpxchg_16(i32 %iptr, i32 %expected, |
| 1077 i32 %desired) { |
1073 entry: | 1078 entry: |
1074 %trunc_exp = trunc i32 %expected to i16 | 1079 %trunc_exp = trunc i32 %expected to i16 |
1075 %trunc_des = trunc i32 %desired to i16 | 1080 %trunc_des = trunc i32 %desired to i16 |
1076 %ptr = inttoptr i32 %iptr to i16* | 1081 %ptr = inttoptr i32 %iptr to i16* |
1077 %old = call i16 @llvm.nacl.atomic.cmpxchg.i16(i16* %ptr, i16 %trunc_exp, | 1082 %old = call i16 @llvm.nacl.atomic.cmpxchg.i16(i16* %ptr, i16 %trunc_exp, |
1078 i16 %trunc_des, i32 6, i32 6) | 1083 i16 %trunc_des, i32 6, i32 6) |
1079 %old_ext = zext i16 %old to i32 | 1084 %old_ext = zext i16 %old to i32 |
1080 ret i32 %old_ext | 1085 ret i32 %old_ext |
1081 } | 1086 } |
1082 ; CHECK-LABEL: test_atomic_cmpxchg_16 | 1087 ; CHECK-LABEL: test_atomic_cmpxchg_16 |
1083 ; CHECK: mov eax,{{.*}} | 1088 ; CHECK: mov eax,{{.*}} |
1084 ; CHECK: lock cmpxchg WORD PTR [e{{[^a].}}],{{[^a]}}x | 1089 ; CHECK: lock cmpxchg WORD PTR [e{{[^a].}}],{{[^a]}}x |
1085 ; ARM32-LABEL: test_atomic_cmpxchg_16 | 1090 ; ARM32-LABEL: test_atomic_cmpxchg_16 |
1086 ; ARM32: dmb | 1091 ; ARM32: dmb |
1087 ; ARM32: ldrexh | 1092 ; ARM32: ldrexh |
1088 ; ARM32: cmp | 1093 ; ARM32: cmp |
1089 ; ARM32: strexheq | 1094 ; ARM32: strexheq |
1090 ; ARM32: {{str|mov}}ne | 1095 ; ARM32: {{str|mov}}ne |
1091 ; ARM32: cmpeq | 1096 ; ARM32: cmpeq |
1092 ; ARM32: bne | 1097 ; ARM32: bne |
1093 ; ARM32: dmb | 1098 ; ARM32: dmb |
1094 | 1099 |
1095 define i32 @test_atomic_cmpxchg_32(i32 %iptr, i32 %expected, i32 %desired) { | 1100 define internal i32 @test_atomic_cmpxchg_32(i32 %iptr, i32 %expected, |
| 1101 i32 %desired) { |
1096 entry: | 1102 entry: |
1097 %ptr = inttoptr i32 %iptr to i32* | 1103 %ptr = inttoptr i32 %iptr to i32* |
1098 %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %expected, | 1104 %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %expected, |
1099 i32 %desired, i32 6, i32 6) | 1105 i32 %desired, i32 6, i32 6) |
1100 ret i32 %old | 1106 ret i32 %old |
1101 } | 1107 } |
1102 ; CHECK-LABEL: test_atomic_cmpxchg_32 | 1108 ; CHECK-LABEL: test_atomic_cmpxchg_32 |
1103 ; CHECK: mov eax,{{.*}} | 1109 ; CHECK: mov eax,{{.*}} |
1104 ; CHECK: lock cmpxchg DWORD PTR [e{{[^a].}}],e{{[^a]}} | 1110 ; CHECK: lock cmpxchg DWORD PTR [e{{[^a].}}],e{{[^a]}} |
1105 ; ARM32-LABEL: test_atomic_cmpxchg_32 | 1111 ; ARM32-LABEL: test_atomic_cmpxchg_32 |
1106 ; ARM32: dmb | 1112 ; ARM32: dmb |
1107 ; ARM32: ldrex | 1113 ; ARM32: ldrex |
1108 ; ARM32: cmp | 1114 ; ARM32: cmp |
1109 ; ARM32: strexeq | 1115 ; ARM32: strexeq |
1110 ; ARM32: {{str|mov}}ne | 1116 ; ARM32: {{str|mov}}ne |
1111 ; ARM32: cmpeq | 1117 ; ARM32: cmpeq |
1112 ; ARM32: bne | 1118 ; ARM32: bne |
1113 ; ARM32: dmb | 1119 ; ARM32: dmb |
1114 | 1120 |
1115 define i64 @test_atomic_cmpxchg_64(i32 %iptr, i64 %expected, i64 %desired) { | 1121 define internal i64 @test_atomic_cmpxchg_64(i32 %iptr, i64 %expected, |
| 1122 i64 %desired) { |
1116 entry: | 1123 entry: |
1117 %ptr = inttoptr i32 %iptr to i64* | 1124 %ptr = inttoptr i32 %iptr to i64* |
1118 %old = call i64 @llvm.nacl.atomic.cmpxchg.i64(i64* %ptr, i64 %expected, | 1125 %old = call i64 @llvm.nacl.atomic.cmpxchg.i64(i64* %ptr, i64 %expected, |
1119 i64 %desired, i32 6, i32 6) | 1126 i64 %desired, i32 6, i32 6) |
1120 ret i64 %old | 1127 ret i64 %old |
1121 } | 1128 } |
1122 ; CHECK-LABEL: test_atomic_cmpxchg_64 | 1129 ; CHECK-LABEL: test_atomic_cmpxchg_64 |
1123 ; CHECK: push ebx | 1130 ; CHECK: push ebx |
1124 ; CHECK-DAG: mov edx | 1131 ; CHECK-DAG: mov edx |
1125 ; CHECK-DAG: mov eax | 1132 ; CHECK-DAG: mov eax |
1126 ; CHECK-DAG: mov ecx | 1133 ; CHECK-DAG: mov ecx |
1127 ; CHECK-DAG: mov ebx | 1134 ; CHECK-DAG: mov ebx |
1128 ; CHECK: lock cmpxchg8b QWORD PTR [e{{.[^x]}}+0x0] | 1135 ; CHECK: lock cmpxchg8b QWORD PTR [e{{.[^x]}}+0x0] |
1129 ; edx and eax are already the return registers, so they don't actually | 1136 ; edx and eax are already the return registers, so they don't actually |
1130 ; need to be reshuffled via movs. The next test stores the result | 1137 ; need to be reshuffled via movs. The next test stores the result |
1131 ; somewhere, so in that case they do need to be mov'ed. | 1138 ; somewhere, so in that case they do need to be mov'ed. |
1132 ; ARM32-LABEL: test_atomic_cmpxchg_64 | 1139 ; ARM32-LABEL: test_atomic_cmpxchg_64 |
1133 ; ARM32: dmb | 1140 ; ARM32: dmb |
1134 ; ARM32: ldrexd r{{[0-9]+}}, r{{[0-9]+}}, {{[[]}}[[PTR:r[0-9]+]]{{[]]}} | 1141 ; ARM32: ldrexd r{{[0-9]+}}, r{{[0-9]+}}, {{[[]}}[[PTR:r[0-9]+]]{{[]]}} |
1135 ; ARM32: cmp | 1142 ; ARM32: cmp |
1136 ; ARM32-NEXT: cmpeq | 1143 ; ARM32-NEXT: cmpeq |
1137 ; ARM32: strexdeq r{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}, {{[[]}}[[PTR]]{{[]]}} | 1144 ; ARM32: strexdeq r{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}, {{[[]}}[[PTR]]{{[]]}} |
1138 ; ARM32: {{str|mov}}ne | 1145 ; ARM32: {{str|mov}}ne |
1139 ; ARM32: {{str|mov}}ne | 1146 ; ARM32: {{str|mov}}ne |
1140 ; ARM32: cmpeq | 1147 ; ARM32: cmpeq |
1141 ; ARM32: bne | 1148 ; ARM32: bne |
1142 ; ARM32: dmb | 1149 ; ARM32: dmb |
1143 | 1150 |
1144 define i64 @test_atomic_cmpxchg_64_undef(i32 %iptr, i64 %desired) { | 1151 define internal i64 @test_atomic_cmpxchg_64_undef(i32 %iptr, i64 %desired) { |
1145 entry: | 1152 entry: |
1146 %ptr = inttoptr i32 %iptr to i64* | 1153 %ptr = inttoptr i32 %iptr to i64* |
1147 %old = call i64 @llvm.nacl.atomic.cmpxchg.i64(i64* %ptr, i64 undef, | 1154 %old = call i64 @llvm.nacl.atomic.cmpxchg.i64(i64* %ptr, i64 undef, |
1148 i64 %desired, i32 6, i32 6) | 1155 i64 %desired, i32 6, i32 6) |
1149 ret i64 %old | 1156 ret i64 %old |
1150 } | 1157 } |
1151 ; CHECK-LABEL: test_atomic_cmpxchg_64_undef | 1158 ; CHECK-LABEL: test_atomic_cmpxchg_64_undef |
1152 ; CHECK: lock cmpxchg8b QWORD PTR [e{{.[^x]}}+0x0] | 1159 ; CHECK: lock cmpxchg8b QWORD PTR [e{{.[^x]}}+0x0] |
1153 ; ARM32-LABEL: test_atomic_cmpxchg_64_undef | 1160 ; ARM32-LABEL: test_atomic_cmpxchg_64_undef |
1154 ; ARM32: mov r{{[0-9]+}}, #0 | 1161 ; ARM32: mov r{{[0-9]+}}, #0 |
1155 ; ARM32: mov r{{[0-9]+}}, #0 | 1162 ; ARM32: mov r{{[0-9]+}}, #0 |
1156 ; ARM32: dmb | 1163 ; ARM32: dmb |
1157 ; ARM32: ldrexd r{{[0-9]+}}, r{{[0-9]+}}, {{[[]}}[[PTR:r[0-9]+]]{{[]]}} | 1164 ; ARM32: ldrexd r{{[0-9]+}}, r{{[0-9]+}}, {{[[]}}[[PTR:r[0-9]+]]{{[]]}} |
1158 ; ARM32: cmp | 1165 ; ARM32: cmp |
1159 ; ARM32-NEXT: cmpeq | 1166 ; ARM32-NEXT: cmpeq |
1160 ; ARM32: strexdeq r{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}, {{[[]}}[[PTR]]{{[]]}} | 1167 ; ARM32: strexdeq r{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}, {{[[]}}[[PTR]]{{[]]}} |
1161 ; ARM32: {{str|mov}}ne | 1168 ; ARM32: {{str|mov}}ne |
1162 ; ARM32: {{str|mov}}ne | 1169 ; ARM32: {{str|mov}}ne |
1163 ; ARM32: cmpeq | 1170 ; ARM32: cmpeq |
1164 ; ARM32: bne | 1171 ; ARM32: bne |
1165 ; ARM32: dmb | 1172 ; ARM32: dmb |
1166 | 1173 |
1167 ; Test a case where %old really does need to be copied out of edx:eax. | 1174 ; Test a case where %old really does need to be copied out of edx:eax. |
1168 define void @test_atomic_cmpxchg_64_store(i32 %ret_iptr, i32 %iptr, i64 %expecte
d, i64 %desired) { | 1175 define internal void @test_atomic_cmpxchg_64_store( |
| 1176 i32 %ret_iptr, i32 %iptr, i64 %expected, i64 %desired) { |
1169 entry: | 1177 entry: |
1170 %ptr = inttoptr i32 %iptr to i64* | 1178 %ptr = inttoptr i32 %iptr to i64* |
1171 %old = call i64 @llvm.nacl.atomic.cmpxchg.i64(i64* %ptr, i64 %expected, | 1179 %old = call i64 @llvm.nacl.atomic.cmpxchg.i64(i64* %ptr, i64 %expected, |
1172 i64 %desired, i32 6, i32 6) | 1180 i64 %desired, i32 6, i32 6) |
1173 %__6 = inttoptr i32 %ret_iptr to i64* | 1181 %__6 = inttoptr i32 %ret_iptr to i64* |
1174 store i64 %old, i64* %__6, align 1 | 1182 store i64 %old, i64* %__6, align 1 |
1175 ret void | 1183 ret void |
1176 } | 1184 } |
1177 ; CHECK-LABEL: test_atomic_cmpxchg_64_store | 1185 ; CHECK-LABEL: test_atomic_cmpxchg_64_store |
1178 ; CHECK: push ebx | 1186 ; CHECK: push ebx |
(...skipping 13 matching lines...) Expand all Loading... |
1192 ; ARM32: {{str|mov}}ne | 1200 ; ARM32: {{str|mov}}ne |
1193 ; ARM32: {{str|mov}}ne | 1201 ; ARM32: {{str|mov}}ne |
1194 ; ARM32: cmpeq | 1202 ; ARM32: cmpeq |
1195 ; ARM32: bne | 1203 ; ARM32: bne |
1196 ; ARM32: dmb | 1204 ; ARM32: dmb |
1197 ; ARM32: str | 1205 ; ARM32: str |
1198 ; ARM32: str | 1206 ; ARM32: str |
1199 | 1207 |
1200 ; Test with some more register pressure. When we have an alloca, ebp is | 1208 ; Test with some more register pressure. When we have an alloca, ebp is |
1201 ; used to manage the stack frame, so it cannot be used as a register either. | 1209 ; used to manage the stack frame, so it cannot be used as a register either. |
1202 define i64 @test_atomic_cmpxchg_64_alloca(i32 %iptr, i64 %expected, i64 %desired
) { | 1210 define internal i64 @test_atomic_cmpxchg_64_alloca(i32 %iptr, i64 %expected, |
| 1211 i64 %desired) { |
1203 entry: | 1212 entry: |
1204 br label %eblock ; Disable alloca optimization | 1213 br label %eblock ; Disable alloca optimization |
1205 eblock: | 1214 eblock: |
1206 %alloca_ptr = alloca i8, i32 16, align 16 | 1215 %alloca_ptr = alloca i8, i32 16, align 16 |
1207 %ptr = inttoptr i32 %iptr to i64* | 1216 %ptr = inttoptr i32 %iptr to i64* |
1208 %old = call i64 @llvm.nacl.atomic.cmpxchg.i64(i64* %ptr, i64 %expected, | 1217 %old = call i64 @llvm.nacl.atomic.cmpxchg.i64(i64* %ptr, i64 %expected, |
1209 i64 %desired, i32 6, i32 6) | 1218 i64 %desired, i32 6, i32 6) |
1210 store i8 0, i8* %alloca_ptr, align 1 | 1219 store i8 0, i8* %alloca_ptr, align 1 |
1211 store i8 1, i8* %alloca_ptr, align 1 | 1220 store i8 1, i8* %alloca_ptr, align 1 |
1212 store i8 2, i8* %alloca_ptr, align 1 | 1221 store i8 2, i8* %alloca_ptr, align 1 |
(...skipping 20 matching lines...) Expand all Loading... |
1233 ; ARM32: ldrexd r{{[0-9]+}}, r{{[0-9]+}}, {{[[]}}[[PTR:r[0-9]+]]{{[]]}} | 1242 ; ARM32: ldrexd r{{[0-9]+}}, r{{[0-9]+}}, {{[[]}}[[PTR:r[0-9]+]]{{[]]}} |
1234 ; ARM32: cmp | 1243 ; ARM32: cmp |
1235 ; ARM32-NEXT: cmpeq | 1244 ; ARM32-NEXT: cmpeq |
1236 ; ARM32: strexdeq r{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}, {{[[]}}[[PTR]]{{[]]}} | 1245 ; ARM32: strexdeq r{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}, {{[[]}}[[PTR]]{{[]]}} |
1237 ; ARM32: {{str|mov}}ne | 1246 ; ARM32: {{str|mov}}ne |
1238 ; ARM32: {{str|mov}}ne | 1247 ; ARM32: {{str|mov}}ne |
1239 ; ARM32: cmpeq | 1248 ; ARM32: cmpeq |
1240 ; ARM32: bne | 1249 ; ARM32: bne |
1241 ; ARM32: dmb | 1250 ; ARM32: dmb |
1242 | 1251 |
1243 define i32 @test_atomic_cmpxchg_32_ignored(i32 %iptr, i32 %expected, i32 %desire
d) { | 1252 define internal i32 @test_atomic_cmpxchg_32_ignored(i32 %iptr, i32 %expected, |
| 1253 i32 %desired) { |
1244 entry: | 1254 entry: |
1245 %ptr = inttoptr i32 %iptr to i32* | 1255 %ptr = inttoptr i32 %iptr to i32* |
1246 %ignored = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %expected, | 1256 %ignored = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %expected, |
1247 i32 %desired, i32 6, i32 6) | 1257 i32 %desired, i32 6, i32 6) |
1248 ret i32 0 | 1258 ret i32 0 |
1249 } | 1259 } |
1250 ; CHECK-LABEL: test_atomic_cmpxchg_32_ignored | 1260 ; CHECK-LABEL: test_atomic_cmpxchg_32_ignored |
1251 ; CHECK: mov eax,{{.*}} | 1261 ; CHECK: mov eax,{{.*}} |
1252 ; CHECK: lock cmpxchg DWORD PTR [e{{[^a].}}] | 1262 ; CHECK: lock cmpxchg DWORD PTR [e{{[^a].}}] |
1253 ; ARM32-LABEL: test_atomic_cmpxchg_32_ignored | 1263 ; ARM32-LABEL: test_atomic_cmpxchg_32_ignored |
1254 ; ARM32: dmb | 1264 ; ARM32: dmb |
1255 ; ARM32: ldrex | 1265 ; ARM32: ldrex |
1256 ; ARM32: cmp | 1266 ; ARM32: cmp |
1257 ; ARM32: strexeq | 1267 ; ARM32: strexeq |
1258 ; ARM32: {{str|mov}}ne | 1268 ; ARM32: {{str|mov}}ne |
1259 ; ARM32: cmpeq | 1269 ; ARM32: cmpeq |
1260 ; ARM32: bne | 1270 ; ARM32: bne |
1261 ; ARM32: dmb | 1271 ; ARM32: dmb |
1262 | 1272 |
1263 define i64 @test_atomic_cmpxchg_64_ignored(i32 %iptr, i64 %expected, i64 %desire
d) { | 1273 define internal i64 @test_atomic_cmpxchg_64_ignored(i32 %iptr, i64 %expected, |
| 1274 i64 %desired) { |
1264 entry: | 1275 entry: |
1265 %ptr = inttoptr i32 %iptr to i64* | 1276 %ptr = inttoptr i32 %iptr to i64* |
1266 %ignored = call i64 @llvm.nacl.atomic.cmpxchg.i64(i64* %ptr, i64 %expected, | 1277 %ignored = call i64 @llvm.nacl.atomic.cmpxchg.i64(i64* %ptr, i64 %expected, |
1267 i64 %desired, i32 6, i32 6) | 1278 i64 %desired, i32 6, i32 6) |
1268 ret i64 0 | 1279 ret i64 0 |
1269 } | 1280 } |
1270 ; CHECK-LABEL: test_atomic_cmpxchg_64_ignored | 1281 ; CHECK-LABEL: test_atomic_cmpxchg_64_ignored |
1271 ; CHECK: push ebx | 1282 ; CHECK: push ebx |
1272 ; CHECK-DAG: mov edx | 1283 ; CHECK-DAG: mov edx |
1273 ; CHECK-DAG: mov eax | 1284 ; CHECK-DAG: mov eax |
1274 ; CHECK-DAG: mov ecx | 1285 ; CHECK-DAG: mov ecx |
1275 ; CHECK-DAG: mov ebx | 1286 ; CHECK-DAG: mov ebx |
1276 ; CHECK: lock cmpxchg8b QWORD PTR [e{{.[^x]}}+0x0] | 1287 ; CHECK: lock cmpxchg8b QWORD PTR [e{{.[^x]}}+0x0] |
1277 ; ARM32-LABEL: test_atomic_cmpxchg_64_ignored | 1288 ; ARM32-LABEL: test_atomic_cmpxchg_64_ignored |
1278 ; ARM32: dmb | 1289 ; ARM32: dmb |
1279 ; ARM32: ldrexd [[R0:r[0-9]+]], [[R1:r[0-9]+]], {{[[]}}[[PTR:r[0-9]+]]{{[]]}} | 1290 ; ARM32: ldrexd [[R0:r[0-9]+]], [[R1:r[0-9]+]], {{[[]}}[[PTR:r[0-9]+]]{{[]]}} |
1280 ; ARM32: cmp | 1291 ; ARM32: cmp |
1281 ; ARM32-NEXT: cmpeq | 1292 ; ARM32-NEXT: cmpeq |
1282 ; ARM32: strexdeq r{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}, {{[[]}}[[PTR]]{{[]]}} | 1293 ; ARM32: strexdeq r{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}, {{[[]}}[[PTR]]{{[]]}} |
1283 ; ARM32O2-NOT: {{str|mov}}ne [[R0]] | 1294 ; ARM32O2-NOT: {{str|mov}}ne [[R0]] |
1284 ; ARM32O2-NOT: {{str|mov}}ne [[R1]] | 1295 ; ARM32O2-NOT: {{str|mov}}ne [[R1]] |
1285 ; ARM32: cmpeq | 1296 ; ARM32: cmpeq |
1286 ; ARM32: bne | 1297 ; ARM32: bne |
1287 ; ARM32: dmb | 1298 ; ARM32: dmb |
1288 | 1299 |
1289 ;;;; Fence and is-lock-free. | 1300 ;;;; Fence and is-lock-free. |
1290 | 1301 |
1291 define void @test_atomic_fence() { | 1302 define internal void @test_atomic_fence() { |
1292 entry: | 1303 entry: |
1293 call void @llvm.nacl.atomic.fence(i32 6) | 1304 call void @llvm.nacl.atomic.fence(i32 6) |
1294 ret void | 1305 ret void |
1295 } | 1306 } |
1296 ; CHECK-LABEL: test_atomic_fence | 1307 ; CHECK-LABEL: test_atomic_fence |
1297 ; CHECK: mfence | 1308 ; CHECK: mfence |
1298 ; ARM32-LABEL: test_atomic_fence | 1309 ; ARM32-LABEL: test_atomic_fence |
1299 ; ARM32: dmb sy | 1310 ; ARM32: dmb sy |
1300 | 1311 |
1301 define void @test_atomic_fence_all() { | 1312 define internal void @test_atomic_fence_all() { |
1302 entry: | 1313 entry: |
1303 call void @llvm.nacl.atomic.fence.all() | 1314 call void @llvm.nacl.atomic.fence.all() |
1304 ret void | 1315 ret void |
1305 } | 1316 } |
1306 ; CHECK-LABEL: test_atomic_fence_all | 1317 ; CHECK-LABEL: test_atomic_fence_all |
1307 ; CHECK: mfence | 1318 ; CHECK: mfence |
1308 ; ARM32-LABEL: test_atomic_fence_all | 1319 ; ARM32-LABEL: test_atomic_fence_all |
1309 ; ARM32: dmb sy | 1320 ; ARM32: dmb sy |
1310 | 1321 |
1311 define i32 @test_atomic_is_lock_free(i32 %iptr) { | 1322 define internal i32 @test_atomic_is_lock_free(i32 %iptr) { |
1312 entry: | 1323 entry: |
1313 %ptr = inttoptr i32 %iptr to i8* | 1324 %ptr = inttoptr i32 %iptr to i8* |
1314 %i = call i1 @llvm.nacl.atomic.is.lock.free(i32 4, i8* %ptr) | 1325 %i = call i1 @llvm.nacl.atomic.is.lock.free(i32 4, i8* %ptr) |
1315 %r = zext i1 %i to i32 | 1326 %r = zext i1 %i to i32 |
1316 ret i32 %r | 1327 ret i32 %r |
1317 } | 1328 } |
1318 ; CHECK-LABEL: test_atomic_is_lock_free | 1329 ; CHECK-LABEL: test_atomic_is_lock_free |
1319 ; CHECK: mov {{.*}},0x1 | 1330 ; CHECK: mov {{.*}},0x1 |
1320 ; ARM32-LABEL: test_atomic_is_lock_free | 1331 ; ARM32-LABEL: test_atomic_is_lock_free |
1321 ; ARM32: movw {{.*}}, #1 | 1332 ; ARM32: movw {{.*}}, #1 |
1322 | 1333 |
1323 define i32 @test_not_lock_free(i32 %iptr) { | 1334 define internal i32 @test_not_lock_free(i32 %iptr) { |
1324 entry: | 1335 entry: |
1325 %ptr = inttoptr i32 %iptr to i8* | 1336 %ptr = inttoptr i32 %iptr to i8* |
1326 %i = call i1 @llvm.nacl.atomic.is.lock.free(i32 7, i8* %ptr) | 1337 %i = call i1 @llvm.nacl.atomic.is.lock.free(i32 7, i8* %ptr) |
1327 %r = zext i1 %i to i32 | 1338 %r = zext i1 %i to i32 |
1328 ret i32 %r | 1339 ret i32 %r |
1329 } | 1340 } |
1330 ; CHECK-LABEL: test_not_lock_free | 1341 ; CHECK-LABEL: test_not_lock_free |
1331 ; CHECK: mov {{.*}},0x0 | 1342 ; CHECK: mov {{.*}},0x0 |
1332 ; ARM32-LABEL: test_not_lock_free | 1343 ; ARM32-LABEL: test_not_lock_free |
1333 ; ARM32: mov {{.*}}, #0 | 1344 ; ARM32: mov {{.*}}, #0 |
1334 | 1345 |
1335 define i32 @test_atomic_is_lock_free_ignored(i32 %iptr) { | 1346 define internal i32 @test_atomic_is_lock_free_ignored(i32 %iptr) { |
1336 entry: | 1347 entry: |
1337 %ptr = inttoptr i32 %iptr to i8* | 1348 %ptr = inttoptr i32 %iptr to i8* |
1338 %ignored = call i1 @llvm.nacl.atomic.is.lock.free(i32 4, i8* %ptr) | 1349 %ignored = call i1 @llvm.nacl.atomic.is.lock.free(i32 4, i8* %ptr) |
1339 ret i32 0 | 1350 ret i32 0 |
1340 } | 1351 } |
1341 ; CHECK-LABEL: test_atomic_is_lock_free_ignored | 1352 ; CHECK-LABEL: test_atomic_is_lock_free_ignored |
1342 ; CHECK: mov {{.*}},0x0 | 1353 ; CHECK: mov {{.*}},0x0 |
1343 ; This can get optimized out, because it's side-effect-free. | 1354 ; This can get optimized out, because it's side-effect-free. |
1344 ; O2-LABEL: test_atomic_is_lock_free_ignored | 1355 ; O2-LABEL: test_atomic_is_lock_free_ignored |
1345 ; O2-NOT: mov {{.*}}, 1 | 1356 ; O2-NOT: mov {{.*}}, 1 |
1346 ; O2: mov {{.*}},0x0 | 1357 ; O2: mov {{.*}},0x0 |
1347 ; ARM32O2-LABEL: test_atomic_is_lock_free_ignored | 1358 ; ARM32O2-LABEL: test_atomic_is_lock_free_ignored |
1348 ; ARM32O2-NOT: mov {{.*}}, #1 | 1359 ; ARM32O2-NOT: mov {{.*}}, #1 |
1349 ; ARM32O2: mov {{.*}}, #0 | 1360 ; ARM32O2: mov {{.*}}, #0 |
1350 | 1361 |
1351 ; TODO(jvoung): at some point we can take advantage of the | 1362 ; TODO(jvoung): at some point we can take advantage of the |
1352 ; fact that nacl.atomic.is.lock.free will resolve to a constant | 1363 ; fact that nacl.atomic.is.lock.free will resolve to a constant |
1353 ; (which adds DCE opportunities). Once we optimize, the test expectations | 1364 ; (which adds DCE opportunities). Once we optimize, the test expectations |
1354 ; for this case should change. | 1365 ; for this case should change. |
1355 define i32 @test_atomic_is_lock_free_can_dce(i32 %iptr, i32 %x, i32 %y) { | 1366 define internal i32 @test_atomic_is_lock_free_can_dce(i32 %iptr, i32 %x, |
| 1367 i32 %y) { |
1356 entry: | 1368 entry: |
1357 %ptr = inttoptr i32 %iptr to i8* | 1369 %ptr = inttoptr i32 %iptr to i8* |
1358 %i = call i1 @llvm.nacl.atomic.is.lock.free(i32 4, i8* %ptr) | 1370 %i = call i1 @llvm.nacl.atomic.is.lock.free(i32 4, i8* %ptr) |
1359 %i_ext = zext i1 %i to i32 | 1371 %i_ext = zext i1 %i to i32 |
1360 %cmp = icmp eq i32 %i_ext, 1 | 1372 %cmp = icmp eq i32 %i_ext, 1 |
1361 br i1 %cmp, label %lock_free, label %not_lock_free | 1373 br i1 %cmp, label %lock_free, label %not_lock_free |
1362 lock_free: | 1374 lock_free: |
1363 ret i32 %i_ext | 1375 ret i32 %i_ext |
1364 | 1376 |
1365 not_lock_free: | 1377 not_lock_free: |
1366 %z = add i32 %x, %y | 1378 %z = add i32 %x, %y |
1367 ret i32 %z | 1379 ret i32 %z |
1368 } | 1380 } |
1369 ; CHECK-LABEL: test_atomic_is_lock_free_can_dce | 1381 ; CHECK-LABEL: test_atomic_is_lock_free_can_dce |
1370 ; CHECK: mov {{.*}},0x1 | 1382 ; CHECK: mov {{.*}},0x1 |
1371 ; CHECK: ret | 1383 ; CHECK: ret |
1372 ; CHECK: add | 1384 ; CHECK: add |
1373 ; CHECK: ret | 1385 ; CHECK: ret |
1374 | 1386 |
1375 ; Test the liveness / register allocation properties of the xadd instruction. | 1387 ; Test the liveness / register allocation properties of the xadd instruction. |
1376 ; Make sure we model that the Src register is modified and therefore it can't | 1388 ; Make sure we model that the Src register is modified and therefore it can't |
1377 ; share a register with an overlapping live range, even if the result of the | 1389 ; share a register with an overlapping live range, even if the result of the |
1378 ; xadd instruction is unused. | 1390 ; xadd instruction is unused. |
1379 define void @test_xadd_regalloc() { | 1391 define internal void @test_xadd_regalloc() { |
1380 entry: | 1392 entry: |
1381 br label %body | 1393 br label %body |
1382 body: | 1394 body: |
1383 %i = phi i32 [ 1, %entry ], [ %i_plus_1, %body ] | 1395 %i = phi i32 [ 1, %entry ], [ %i_plus_1, %body ] |
1384 %g = bitcast [4 x i8]* @Global32 to i32* | 1396 %g = bitcast [4 x i8]* @Global32 to i32* |
1385 %unused = call i32 @llvm.nacl.atomic.rmw.i32(i32 1, i32* %g, i32 %i, i32 6) | 1397 %unused = call i32 @llvm.nacl.atomic.rmw.i32(i32 1, i32* %g, i32 %i, i32 6) |
1386 %i_plus_1 = add i32 %i, 1 | 1398 %i_plus_1 = add i32 %i, 1 |
1387 %cmp = icmp eq i32 %i_plus_1, 1001 | 1399 %cmp = icmp eq i32 %i_plus_1, 1001 |
1388 br i1 %cmp, label %done, label %body | 1400 br i1 %cmp, label %done, label %body |
1389 done: | 1401 done: |
1390 ret void | 1402 ret void |
1391 } | 1403 } |
1392 ; O2-LABEL: test_xadd_regalloc | 1404 ; O2-LABEL: test_xadd_regalloc |
1393 ;;; Some register will be used in the xadd instruction. | 1405 ;;; Some register will be used in the xadd instruction. |
1394 ; O2: lock xadd DWORD PTR {{.*}},[[REG:e..]] | 1406 ; O2: lock xadd DWORD PTR {{.*}},[[REG:e..]] |
1395 ;;; Make sure that register isn't used again, e.g. as the induction variable. | 1407 ;;; Make sure that register isn't used again, e.g. as the induction variable. |
1396 ; O2-NOT: [[REG]] | 1408 ; O2-NOT: [[REG]] |
1397 ; O2: ret | 1409 ; O2: ret |
1398 | 1410 |
1399 ; Do the same test for the xchg instruction instead of xadd. | 1411 ; Do the same test for the xchg instruction instead of xadd. |
1400 define void @test_xchg_regalloc() { | 1412 define internal void @test_xchg_regalloc() { |
1401 entry: | 1413 entry: |
1402 br label %body | 1414 br label %body |
1403 body: | 1415 body: |
1404 %i = phi i32 [ 1, %entry ], [ %i_plus_1, %body ] | 1416 %i = phi i32 [ 1, %entry ], [ %i_plus_1, %body ] |
1405 %g = bitcast [4 x i8]* @Global32 to i32* | 1417 %g = bitcast [4 x i8]* @Global32 to i32* |
1406 %unused = call i32 @llvm.nacl.atomic.rmw.i32(i32 6, i32* %g, i32 %i, i32 6) | 1418 %unused = call i32 @llvm.nacl.atomic.rmw.i32(i32 6, i32* %g, i32 %i, i32 6) |
1407 %i_plus_1 = add i32 %i, 1 | 1419 %i_plus_1 = add i32 %i, 1 |
1408 %cmp = icmp eq i32 %i_plus_1, 1001 | 1420 %cmp = icmp eq i32 %i_plus_1, 1001 |
1409 br i1 %cmp, label %done, label %body | 1421 br i1 %cmp, label %done, label %body |
1410 done: | 1422 done: |
1411 ret void | 1423 ret void |
1412 } | 1424 } |
1413 ; O2-LABEL: test_xchg_regalloc | 1425 ; O2-LABEL: test_xchg_regalloc |
1414 ;;; Some register will be used in the xchg instruction. | 1426 ;;; Some register will be used in the xchg instruction. |
1415 ; O2: xchg DWORD PTR {{.*}},[[REG:e..]] | 1427 ; O2: xchg DWORD PTR {{.*}},[[REG:e..]] |
1416 ;;; Make sure that register isn't used again, e.g. as the induction variable. | 1428 ;;; Make sure that register isn't used again, e.g. as the induction variable. |
1417 ; O2-NOT: [[REG]] | 1429 ; O2-NOT: [[REG]] |
1418 ; O2: ret | 1430 ; O2: ret |
1419 | 1431 |
1420 ; Same test for cmpxchg. | 1432 ; Same test for cmpxchg. |
1421 define void @test_cmpxchg_regalloc() { | 1433 define internal void @test_cmpxchg_regalloc() { |
1422 entry: | 1434 entry: |
1423 br label %body | 1435 br label %body |
1424 body: | 1436 body: |
1425 %i = phi i32 [ 1, %entry ], [ %i_plus_1, %body ] | 1437 %i = phi i32 [ 1, %entry ], [ %i_plus_1, %body ] |
1426 %g = bitcast [4 x i8]* @Global32 to i32* | 1438 %g = bitcast [4 x i8]* @Global32 to i32* |
1427 %unused = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %g, i32 %i, i32 %i, i32
6, i32 6) | 1439 %unused = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %g, i32 %i, i32 %i, i32
6, i32 6) |
1428 %i_plus_1 = add i32 %i, 1 | 1440 %i_plus_1 = add i32 %i, 1 |
1429 %cmp = icmp eq i32 %i_plus_1, 1001 | 1441 %cmp = icmp eq i32 %i_plus_1, 1001 |
1430 br i1 %cmp, label %done, label %body | 1442 br i1 %cmp, label %done, label %body |
1431 done: | 1443 done: |
1432 ret void | 1444 ret void |
1433 } | 1445 } |
1434 ; O2-LABEL: test_cmpxchg_regalloc | 1446 ; O2-LABEL: test_cmpxchg_regalloc |
1435 ;;; eax and some other register will be used in the cmpxchg instruction. | 1447 ;;; eax and some other register will be used in the cmpxchg instruction. |
1436 ; O2: lock cmpxchg DWORD PTR {{.*}},[[REG:e..]] | 1448 ; O2: lock cmpxchg DWORD PTR {{.*}},[[REG:e..]] |
1437 ;;; Make sure eax isn't used again, e.g. as the induction variable. | 1449 ;;; Make sure eax isn't used again, e.g. as the induction variable. |
1438 ; O2-NOT: eax | 1450 ; O2-NOT: eax |
1439 ; O2: ret | 1451 ; O2: ret |
1440 | 1452 |
1441 ; Same test for cmpxchg8b. | 1453 ; Same test for cmpxchg8b. |
1442 define void @test_cmpxchg8b_regalloc() { | 1454 define internal void @test_cmpxchg8b_regalloc() { |
1443 entry: | 1455 entry: |
1444 br label %body | 1456 br label %body |
1445 body: | 1457 body: |
1446 %i = phi i32 [ 1, %entry ], [ %i_plus_1, %body ] | 1458 %i = phi i32 [ 1, %entry ], [ %i_plus_1, %body ] |
1447 %g = bitcast [8 x i8]* @Global64 to i64* | 1459 %g = bitcast [8 x i8]* @Global64 to i64* |
1448 %i_64 = zext i32 %i to i64 | 1460 %i_64 = zext i32 %i to i64 |
1449 %unused = call i64 @llvm.nacl.atomic.cmpxchg.i64(i64* %g, i64 %i_64, i64 %i_64
, i32 6, i32 6) | 1461 %unused = call i64 @llvm.nacl.atomic.cmpxchg.i64(i64* %g, i64 %i_64, i64 %i_64
, i32 6, i32 6) |
1450 %i_plus_1 = add i32 %i, 1 | 1462 %i_plus_1 = add i32 %i, 1 |
1451 %cmp = icmp eq i32 %i_plus_1, 1001 | 1463 %cmp = icmp eq i32 %i_plus_1, 1001 |
1452 br i1 %cmp, label %done, label %body | 1464 br i1 %cmp, label %done, label %body |
1453 done: | 1465 done: |
1454 ret void | 1466 ret void |
1455 } | 1467 } |
1456 ; O2-LABEL: test_cmpxchg8b_regalloc | 1468 ; O2-LABEL: test_cmpxchg8b_regalloc |
1457 ;;; eax and some other register will be used in the cmpxchg instruction. | 1469 ;;; eax and some other register will be used in the cmpxchg instruction. |
1458 ; O2: lock cmpxchg8b QWORD PTR | 1470 ; O2: lock cmpxchg8b QWORD PTR |
1459 ;;; Make sure eax/ecx/edx/ebx aren't used again, e.g. as the induction variable. | 1471 ;;; Make sure eax/ecx/edx/ebx aren't used again, e.g. as the induction variable. |
1460 ; O2-NOT: {{eax|ecx|edx|ebx}} | 1472 ; O2-NOT: {{eax|ecx|edx|ebx}} |
1461 ; O2: pop ebx | 1473 ; O2: pop ebx |
OLD | NEW |