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