1 ; RUN: llc -mtriple=armv8-none-linux-gnu -verify-machineinstrs < %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-LE --check-prefix=CHECK-ARM --check-prefix=CHECK-ARM-LE 2 ; RUN: llc -mtriple=armebv8-none-linux-gnu -verify-machineinstrs < %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-BE --check-prefix=CHECK-ARM --check-prefix=CHECK-ARM-BE 3 ; RUN: llc -mtriple=thumbv8-none-linux-gnu -verify-machineinstrs < %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-LE --check-prefix=CHECK-THUMB --check-prefix=CHECK-THUMB-LE 4 ; RUN: llc -mtriple=thumbebv8-none-linux-gnu -verify-machineinstrs < %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-BE --check-prefix=CHECK-THUMB --check-prefix=CHECK-THUMB-BE 5 6 @var8 = global i8 0 7 @var16 = global i16 0 8 @var32 = global i32 0 9 @var64 = global i64 0 10 11 define i8 @test_atomic_load_add_i8(i8 %offset) nounwind { 12 ; CHECK-LABEL: test_atomic_load_add_i8: 13 %old = atomicrmw add i8* @var8, i8 %offset seq_cst 14 ; CHECK-NOT: dmb 15 ; CHECK-NOT: mcr 16 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8 17 ; CHECK: movt r[[ADDR]], :upper16:var8 18 19 ; CHECK: .LBB{{[0-9]+}}_1: 20 ; CHECK: ldaexb r[[OLD:[0-9]+]], [r[[ADDR]]] 21 ; r0 below is a reasonable guess but could change: it certainly comes into the 22 ; function there. 23 ; CHECK-NEXT: add{{s?}} [[NEW:r[0-9]+]], r[[OLD]], r0 24 ; CHECK-NEXT: stlexb [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]] 25 ; CHECK-NEXT: cmp [[STATUS]], #0 26 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 27 ; CHECK-NOT: dmb 28 ; CHECK-NOT: mcr 29 30 ; CHECK: mov r0, r[[OLD]] 31 ret i8 %old 32 } 33 34 define i16 @test_atomic_load_add_i16(i16 %offset) nounwind { 35 ; CHECK-LABEL: test_atomic_load_add_i16: 36 %old = atomicrmw add i16* @var16, i16 %offset acquire 37 ; CHECK-NOT: dmb 38 ; CHECK-NOT: mcr 39 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16 40 ; CHECK: movt r[[ADDR]], :upper16:var16 41 42 ; CHECK: .LBB{{[0-9]+}}_1: 43 ; CHECK: ldaexh r[[OLD:[0-9]+]], [r[[ADDR]]] 44 ; r0 below is a reasonable guess but could change: it certainly comes into the 45 ; function there. 46 ; CHECK-NEXT: add{{s?}} [[NEW:r[0-9]+]], r[[OLD]], r0 47 ; CHECK-NEXT: strexh [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]] 48 ; CHECK-NEXT: cmp [[STATUS]], #0 49 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 50 ; CHECK-NOT: dmb 51 ; CHECK-NOT: mcr 52 53 ; CHECK: mov r0, r[[OLD]] 54 ret i16 %old 55 } 56 57 define i32 @test_atomic_load_add_i32(i32 %offset) nounwind { 58 ; CHECK-LABEL: test_atomic_load_add_i32: 59 %old = atomicrmw add i32* @var32, i32 %offset release 60 ; CHECK-NOT: dmb 61 ; CHECK-NOT: mcr 62 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32 63 ; CHECK: movt r[[ADDR]], :upper16:var32 64 65 ; CHECK: .LBB{{[0-9]+}}_1: 66 ; CHECK: ldrex r[[OLD:[0-9]+]], [r[[ADDR]]] 67 ; r0 below is a reasonable guess but could change: it certainly comes into the 68 ; function there. 69 ; CHECK-NEXT: add{{s?}} [[NEW:r[0-9]+]], r[[OLD]], r0 70 ; CHECK-NEXT: stlex [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]] 71 ; CHECK-NEXT: cmp [[STATUS]], #0 72 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 73 ; CHECK-NOT: dmb 74 ; CHECK-NOT: mcr 75 76 ; CHECK: mov r0, r[[OLD]] 77 ret i32 %old 78 } 79 80 define void @test_atomic_load_add_i64(i64 %offset) nounwind { 81 ; CHECK-LABEL: test_atomic_load_add_i64: 82 %old = atomicrmw add i64* @var64, i64 %offset monotonic 83 ; CHECK-NOT: dmb 84 ; CHECK-NOT: mcr 85 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64 86 ; CHECK: movt r[[ADDR]], :upper16:var64 87 88 ; CHECK: .LBB{{[0-9]+}}_1: 89 ; CHECK: ldrexd r[[OLD1:[0-9]+]], r[[OLD2:[0-9]+]], [r[[ADDR]]] 90 ; r0, r1 below is a reasonable guess but could change: it certainly comes into the 91 ; function there. 92 ; CHECK-LE-NEXT: adds{{(\.w)?}} [[NEW1:r[0-9]+|lr]], r[[OLD1]], r0 93 ; CHECK-LE-NEXT: adc{{(\.w)?}} [[NEW2:r[0-9]+]], r[[OLD2]], r1 94 ; CHECK-BE-NEXT: adds{{(\.w)?}} [[NEW2:r[0-9]+|lr]], r[[OLD2]], r1 95 ; CHECK-BE-NEXT: adc{{(\.w)?}} [[NEW1:r[0-9]+]], r[[OLD1]], r0 96 ; CHECK-NEXT: strexd [[STATUS:r[0-9]+]], [[NEW1]], [[NEW2]], [r[[ADDR]]] 97 ; CHECK-NEXT: cmp [[STATUS]], #0 98 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 99 ; CHECK-NOT: dmb 100 ; CHECK-NOT: mcr 101 102 ; CHECK: strd r[[OLD1]], r[[OLD2]], [r[[ADDR]]] 103 store i64 %old, i64* @var64 104 ret void 105 } 106 107 define i8 @test_atomic_load_sub_i8(i8 %offset) nounwind { 108 ; CHECK-LABEL: test_atomic_load_sub_i8: 109 %old = atomicrmw sub i8* @var8, i8 %offset monotonic 110 ; CHECK-NOT: dmb 111 ; CHECK-NOT: mcr 112 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8 113 ; CHECK: movt r[[ADDR]], :upper16:var8 114 115 ; CHECK: .LBB{{[0-9]+}}_1: 116 ; CHECK: ldrexb r[[OLD:[0-9]+]], [r[[ADDR]]] 117 ; r0 below is a reasonable guess but could change: it certainly comes into the 118 ; function there. 119 ; CHECK-NEXT: sub{{s?}} [[NEW:r[0-9]+]], r[[OLD]], r0 120 ; CHECK-NEXT: strexb [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]] 121 ; CHECK-NEXT: cmp [[STATUS]], #0 122 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 123 ; CHECK-NOT: dmb 124 ; CHECK-NOT: mcr 125 126 ; CHECK: mov r0, r[[OLD]] 127 ret i8 %old 128 } 129 130 define i16 @test_atomic_load_sub_i16(i16 %offset) nounwind { 131 ; CHECK-LABEL: test_atomic_load_sub_i16: 132 %old = atomicrmw sub i16* @var16, i16 %offset release 133 ; CHECK-NOT: dmb 134 ; CHECK-NOT: mcr 135 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16 136 ; CHECK: movt r[[ADDR]], :upper16:var16 137 138 ; CHECK: .LBB{{[0-9]+}}_1: 139 ; CHECK: ldrexh r[[OLD:[0-9]+]], [r[[ADDR]]] 140 ; r0 below is a reasonable guess but could change: it certainly comes into the 141 ; function there. 142 ; CHECK-NEXT: sub{{s?}} [[NEW:r[0-9]+]], r[[OLD]], r0 143 ; CHECK-NEXT: stlexh [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]] 144 ; CHECK-NEXT: cmp [[STATUS]], #0 145 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 146 ; CHECK-NOT: dmb 147 ; CHECK-NOT: mcr 148 149 ; CHECK: mov r0, r[[OLD]] 150 ret i16 %old 151 } 152 153 define i32 @test_atomic_load_sub_i32(i32 %offset) nounwind { 154 ; CHECK-LABEL: test_atomic_load_sub_i32: 155 %old = atomicrmw sub i32* @var32, i32 %offset acquire 156 ; CHECK-NOT: dmb 157 ; CHECK-NOT: mcr 158 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32 159 ; CHECK: movt r[[ADDR]], :upper16:var32 160 161 ; CHECK: .LBB{{[0-9]+}}_1: 162 ; CHECK: ldaex r[[OLD:[0-9]+]], [r[[ADDR]]] 163 ; r0 below is a reasonable guess but could change: it certainly comes into the 164 ; function there. 165 ; CHECK-NEXT: sub{{s?}} [[NEW:r[0-9]+]], r[[OLD]], r0 166 ; CHECK-NEXT: strex [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]] 167 ; CHECK-NEXT: cmp [[STATUS]], #0 168 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 169 ; CHECK-NOT: dmb 170 ; CHECK-NOT: mcr 171 172 ; CHECK: mov r0, r[[OLD]] 173 ret i32 %old 174 } 175 176 define void @test_atomic_load_sub_i64(i64 %offset) nounwind { 177 ; CHECK-LABEL: test_atomic_load_sub_i64: 178 %old = atomicrmw sub i64* @var64, i64 %offset seq_cst 179 ; CHECK-NOT: dmb 180 ; CHECK-NOT: mcr 181 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64 182 ; CHECK: movt r[[ADDR]], :upper16:var64 183 184 ; CHECK: .LBB{{[0-9]+}}_1: 185 ; CHECK: ldaexd r[[OLD1:[0-9]+]], r[[OLD2:[0-9]+]], [r[[ADDR]]] 186 ; r0, r1 below is a reasonable guess but could change: it certainly comes into the 187 ; function there. 188 ; CHECK-LE-NEXT: subs{{(\.w)?}} [[NEW1:r[0-9]+|lr]], r[[OLD1]], r0 189 ; CHECK-LE-NEXT: sbc{{(\.w)?}} [[NEW2:r[0-9]+]], r[[OLD2]], r1 190 ; CHECK-BE-NEXT: subs{{(\.w)?}} [[NEW2:r[0-9]+|lr]], r[[OLD2]], r1 191 ; CHECK-BE-NEXT: sbc{{(\.w)?}} [[NEW1:r[0-9]+]], r[[OLD1]], r0 192 ; CHECK-NEXT: stlexd [[STATUS:r[0-9]+]], [[NEW1]], [[NEW2]], [r[[ADDR]]] 193 ; CHECK-NEXT: cmp [[STATUS]], #0 194 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 195 ; CHECK-NOT: dmb 196 ; CHECK-NOT: mcr 197 198 ; CHECK: strd r[[OLD1]], r[[OLD2]], [r[[ADDR]]] 199 store i64 %old, i64* @var64 200 ret void 201 } 202 203 define i8 @test_atomic_load_and_i8(i8 %offset) nounwind { 204 ; CHECK-LABEL: test_atomic_load_and_i8: 205 %old = atomicrmw and i8* @var8, i8 %offset release 206 ; CHECK-NOT: dmb 207 ; CHECK-NOT: mcr 208 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8 209 ; CHECK: movt r[[ADDR]], :upper16:var8 210 211 ; CHECK: .LBB{{[0-9]+}}_1: 212 ; CHECK: ldrexb r[[OLD:[0-9]+]], [r[[ADDR]]] 213 ; r0 below is a reasonable guess but could change: it certainly comes into the 214 ; function there. 215 ; CHECK-NEXT: and{{(\.w)?}} [[NEW:r[0-9]+]], r[[OLD]], r0 216 ; CHECK-NEXT: stlexb [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]] 217 ; CHECK-NEXT: cmp [[STATUS]], #0 218 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 219 ; CHECK-NOT: dmb 220 ; CHECK-NOT: mcr 221 222 ; CHECK: mov r0, r[[OLD]] 223 ret i8 %old 224 } 225 226 define i16 @test_atomic_load_and_i16(i16 %offset) nounwind { 227 ; CHECK-LABEL: test_atomic_load_and_i16: 228 %old = atomicrmw and i16* @var16, i16 %offset monotonic 229 ; CHECK-NOT: dmb 230 ; CHECK-NOT: mcr 231 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16 232 ; CHECK: movt r[[ADDR]], :upper16:var16 233 234 ; CHECK: .LBB{{[0-9]+}}_1: 235 ; CHECK: ldrexh r[[OLD:[0-9]+]], [r[[ADDR]]] 236 ; r0 below is a reasonable guess but could change: it certainly comes into the 237 ; function there. 238 ; CHECK-NEXT: and{{(\.w)?}} [[NEW:r[0-9]+]], r[[OLD]], r0 239 ; CHECK-NEXT: strexh [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]] 240 ; CHECK-NEXT: cmp [[STATUS]], #0 241 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 242 ; CHECK-NOT: dmb 243 ; CHECK-NOT: mcr 244 245 ; CHECK: mov r0, r[[OLD]] 246 ret i16 %old 247 } 248 249 define i32 @test_atomic_load_and_i32(i32 %offset) nounwind { 250 ; CHECK-LABEL: test_atomic_load_and_i32: 251 %old = atomicrmw and i32* @var32, i32 %offset seq_cst 252 ; CHECK-NOT: dmb 253 ; CHECK-NOT: mcr 254 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32 255 ; CHECK: movt r[[ADDR]], :upper16:var32 256 257 ; CHECK: .LBB{{[0-9]+}}_1: 258 ; CHECK: ldaex r[[OLD:[0-9]+]], [r[[ADDR]]] 259 ; r0 below is a reasonable guess but could change: it certainly comes into the 260 ; function there. 261 ; CHECK-NEXT: and{{(\.w)?}} [[NEW:r[0-9]+]], r[[OLD]], r0 262 ; CHECK-NEXT: stlex [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]] 263 ; CHECK-NEXT: cmp [[STATUS]], #0 264 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 265 ; CHECK-NOT: dmb 266 ; CHECK-NOT: mcr 267 268 ; CHECK: mov r0, r[[OLD]] 269 ret i32 %old 270 } 271 272 define void @test_atomic_load_and_i64(i64 %offset) nounwind { 273 ; CHECK-LABEL: test_atomic_load_and_i64: 274 %old = atomicrmw and i64* @var64, i64 %offset acquire 275 ; CHECK-NOT: dmb 276 ; CHECK-NOT: mcr 277 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64 278 ; CHECK: movt r[[ADDR]], :upper16:var64 279 280 ; CHECK: .LBB{{[0-9]+}}_1: 281 ; CHECK: ldaexd r[[OLD1:[0-9]+]], r[[OLD2:[0-9]+]], [r[[ADDR]]] 282 ; r0, r1 below is a reasonable guess but could change: it certainly comes into the 283 ; function there. 284 ; CHECK-LE-DAG: and{{(\.w)?}} [[NEW1:r[0-9]+|lr]], r[[OLD1]], r0 285 ; CHECK-LE-DAG: and{{(\.w)?}} [[NEW2:r[0-9]+|lr]], r[[OLD2]], r1 286 ; CHECK-BE-DAG: and{{(\.w)?}} [[NEW2:r[0-9]+|lr]], r[[OLD2]], r1 287 ; CHECK-BE-DAG: and{{(\.w)?}} [[NEW1:r[0-9]+|lr]], r[[OLD1]], r0 288 ; CHECK: strexd [[STATUS:r[0-9]+]], [[NEW1]], [[NEW2]], [r[[ADDR]]] 289 ; CHECK-NEXT: cmp [[STATUS]], #0 290 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 291 ; CHECK-NOT: dmb 292 ; CHECK-NOT: mcr 293 294 ; CHECK: strd r[[OLD1]], r[[OLD2]], [r[[ADDR]]] 295 store i64 %old, i64* @var64 296 ret void 297 } 298 299 define i8 @test_atomic_load_or_i8(i8 %offset) nounwind { 300 ; CHECK-LABEL: test_atomic_load_or_i8: 301 %old = atomicrmw or i8* @var8, i8 %offset seq_cst 302 ; CHECK-NOT: dmb 303 ; CHECK-NOT: mcr 304 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8 305 ; CHECK: movt r[[ADDR]], :upper16:var8 306 307 ; CHECK: .LBB{{[0-9]+}}_1: 308 ; CHECK: ldaexb r[[OLD:[0-9]+]], [r[[ADDR]]] 309 ; r0 below is a reasonable guess but could change: it certainly comes into the 310 ; function there. 311 ; CHECK-NEXT: orr{{(\.w)?}} [[NEW:r[0-9]+]], r[[OLD]], r0 312 ; CHECK-NEXT: stlexb [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]] 313 ; CHECK-NEXT: cmp [[STATUS]], #0 314 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 315 ; CHECK-NOT: dmb 316 ; CHECK-NOT: mcr 317 318 ; CHECK: mov r0, r[[OLD]] 319 ret i8 %old 320 } 321 322 define i16 @test_atomic_load_or_i16(i16 %offset) nounwind { 323 ; CHECK-LABEL: test_atomic_load_or_i16: 324 %old = atomicrmw or i16* @var16, i16 %offset monotonic 325 ; CHECK-NOT: dmb 326 ; CHECK-NOT: mcr 327 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16 328 ; CHECK: movt r[[ADDR]], :upper16:var16 329 330 ; CHECK: .LBB{{[0-9]+}}_1: 331 ; CHECK: ldrexh r[[OLD:[0-9]+]], [r[[ADDR]]] 332 ; r0 below is a reasonable guess but could change: it certainly comes into the 333 ; function there. 334 ; CHECK-NEXT: orr{{(\.w)?}} [[NEW:r[0-9]+]], r[[OLD]], r0 335 ; CHECK-NEXT: strexh [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]] 336 ; CHECK-NEXT: cmp [[STATUS]], #0 337 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 338 ; CHECK-NOT: dmb 339 ; CHECK-NOT: mcr 340 341 ; CHECK: mov r0, r[[OLD]] 342 ret i16 %old 343 } 344 345 define i32 @test_atomic_load_or_i32(i32 %offset) nounwind { 346 ; CHECK-LABEL: test_atomic_load_or_i32: 347 %old = atomicrmw or i32* @var32, i32 %offset acquire 348 ; CHECK-NOT: dmb 349 ; CHECK-NOT: mcr 350 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32 351 ; CHECK: movt r[[ADDR]], :upper16:var32 352 353 ; CHECK: .LBB{{[0-9]+}}_1: 354 ; CHECK: ldaex r[[OLD:[0-9]+]], [r[[ADDR]]] 355 ; r0 below is a reasonable guess but could change: it certainly comes into the 356 ; function there. 357 ; CHECK-NEXT: orr{{(\.w)?}} [[NEW:r[0-9]+]], r[[OLD]], r0 358 ; CHECK-NEXT: strex [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]] 359 ; CHECK-NEXT: cmp [[STATUS]], #0 360 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 361 ; CHECK-NOT: dmb 362 ; CHECK-NOT: mcr 363 364 ; CHECK: mov r0, r[[OLD]] 365 ret i32 %old 366 } 367 368 define void @test_atomic_load_or_i64(i64 %offset) nounwind { 369 ; CHECK-LABEL: test_atomic_load_or_i64: 370 %old = atomicrmw or i64* @var64, i64 %offset release 371 ; CHECK-NOT: dmb 372 ; CHECK-NOT: mcr 373 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64 374 ; CHECK: movt r[[ADDR]], :upper16:var64 375 376 ; CHECK: .LBB{{[0-9]+}}_1: 377 ; CHECK: ldrexd r[[OLD1:[0-9]+]], r[[OLD2:[0-9]+]], [r[[ADDR]]] 378 ; r0, r1 below is a reasonable guess but could change: it certainly comes into the 379 ; function there. 380 ; CHECK-LE-DAG: orr{{(\.w)?}} [[NEW1:r[0-9]+|lr]], r[[OLD1]], r0 381 ; CHECK-LE-DAG: orr{{(\.w)?}} [[NEW2:r[0-9]+|lr]], r[[OLD2]], r1 382 ; CHECK-BE-DAG: orr{{(\.w)?}} [[NEW2:r[0-9]+|lr]], r[[OLD2]], r1 383 ; CHECK-BE-DAG: orr{{(\.w)?}} [[NEW1:r[0-9]+|lr]], r[[OLD1]], r0 384 ; CHECK: stlexd [[STATUS:r[0-9]+]], [[NEW1]], [[NEW2]], [r[[ADDR]]] 385 ; CHECK-NEXT: cmp [[STATUS]], #0 386 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 387 ; CHECK-NOT: dmb 388 ; CHECK-NOT: mcr 389 390 ; CHECK: strd r[[OLD1]], r[[OLD2]], [r[[ADDR]]] 391 store i64 %old, i64* @var64 392 ret void 393 } 394 395 define i8 @test_atomic_load_xor_i8(i8 %offset) nounwind { 396 ; CHECK-LABEL: test_atomic_load_xor_i8: 397 %old = atomicrmw xor i8* @var8, i8 %offset acquire 398 ; CHECK-NOT: dmb 399 ; CHECK-NOT: mcr 400 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8 401 ; CHECK: movt r[[ADDR]], :upper16:var8 402 403 ; CHECK: .LBB{{[0-9]+}}_1: 404 ; CHECK: ldaexb r[[OLD:[0-9]+]], [r[[ADDR]]] 405 ; r0 below is a reasonable guess but could change: it certainly comes into the 406 ; function there. 407 ; CHECK-NEXT: eor{{(\.w)?}} [[NEW:r[0-9]+]], r[[OLD]], r0 408 ; CHECK-NEXT: strexb [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]] 409 ; CHECK-NEXT: cmp [[STATUS]], #0 410 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 411 ; CHECK-NOT: dmb 412 ; CHECK-NOT: mcr 413 414 ; CHECK: mov r0, r[[OLD]] 415 ret i8 %old 416 } 417 418 define i16 @test_atomic_load_xor_i16(i16 %offset) nounwind { 419 ; CHECK-LABEL: test_atomic_load_xor_i16: 420 %old = atomicrmw xor i16* @var16, i16 %offset release 421 ; CHECK-NOT: dmb 422 ; CHECK-NOT: mcr 423 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16 424 ; CHECK: movt r[[ADDR]], :upper16:var16 425 426 ; CHECK: .LBB{{[0-9]+}}_1: 427 ; CHECK: ldrexh r[[OLD:[0-9]+]], [r[[ADDR]]] 428 ; r0 below is a reasonable guess but could change: it certainly comes into the 429 ; function there. 430 ; CHECK-NEXT: eor{{(\.w)?}} [[NEW:r[0-9]+]], r[[OLD]], r0 431 ; CHECK-NEXT: stlexh [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]] 432 ; CHECK-NEXT: cmp [[STATUS]], #0 433 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 434 ; CHECK-NOT: dmb 435 ; CHECK-NOT: mcr 436 437 ; CHECK: mov r0, r[[OLD]] 438 ret i16 %old 439 } 440 441 define i32 @test_atomic_load_xor_i32(i32 %offset) nounwind { 442 ; CHECK-LABEL: test_atomic_load_xor_i32: 443 %old = atomicrmw xor i32* @var32, i32 %offset seq_cst 444 ; CHECK-NOT: dmb 445 ; CHECK-NOT: mcr 446 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32 447 ; CHECK: movt r[[ADDR]], :upper16:var32 448 449 ; CHECK: .LBB{{[0-9]+}}_1: 450 ; CHECK: ldaex r[[OLD:[0-9]+]], [r[[ADDR]]] 451 ; r0 below is a reasonable guess but could change: it certainly comes into the 452 ; function there. 453 ; CHECK-NEXT: eor{{(\.w)?}} [[NEW:r[0-9]+]], r[[OLD]], r0 454 ; CHECK-NEXT: stlex [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]] 455 ; CHECK-NEXT: cmp [[STATUS]], #0 456 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 457 ; CHECK-NOT: dmb 458 ; CHECK-NOT: mcr 459 460 ; CHECK: mov r0, r[[OLD]] 461 ret i32 %old 462 } 463 464 define void @test_atomic_load_xor_i64(i64 %offset) nounwind { 465 ; CHECK-LABEL: test_atomic_load_xor_i64: 466 %old = atomicrmw xor i64* @var64, i64 %offset monotonic 467 ; CHECK-NOT: dmb 468 ; CHECK-NOT: mcr 469 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64 470 ; CHECK: movt r[[ADDR]], :upper16:var64 471 472 ; CHECK: .LBB{{[0-9]+}}_1: 473 ; CHECK: ldrexd r[[OLD1:[0-9]+]], r[[OLD2:[0-9]+]], [r[[ADDR]]] 474 ; r0, r1 below is a reasonable guess but could change: it certainly comes into the 475 ; function there. 476 ; CHECK-LE-DAG: eor{{(\.w)?}} [[NEW1:r[0-9]+|lr]], r[[OLD1]], r0 477 ; CHECK-LE-DAG: eor{{(\.w)?}} [[NEW2:r[0-9]+|lr]], r[[OLD2]], r1 478 ; CHECK-BE-DAG: eor{{(\.w)?}} [[NEW2:r[0-9]+|lr]], r[[OLD2]], r1 479 ; CHECK-BE-DAG: eor{{(\.w)?}} [[NEW1:r[0-9]+|lr]], r[[OLD1]], r0 480 ; CHECK: strexd [[STATUS:r[0-9]+]], [[NEW1]], [[NEW2]], [r[[ADDR]]] 481 ; CHECK-NEXT: cmp [[STATUS]], #0 482 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 483 ; CHECK-NOT: dmb 484 ; CHECK-NOT: mcr 485 486 ; CHECK: strd r[[OLD1]], r[[OLD2]], [r[[ADDR]]] 487 store i64 %old, i64* @var64 488 ret void 489 } 490 491 define i8 @test_atomic_load_xchg_i8(i8 %offset) nounwind { 492 ; CHECK-LABEL: test_atomic_load_xchg_i8: 493 %old = atomicrmw xchg i8* @var8, i8 %offset monotonic 494 ; CHECK-NOT: dmb 495 ; CHECK-NOT: mcr 496 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8 497 ; CHECK: movt r[[ADDR]], :upper16:var8 498 499 ; CHECK: .LBB{{[0-9]+}}_1: 500 ; CHECK: ldrexb r[[OLD:[0-9]+]], [r[[ADDR]]] 501 ; r0 below is a reasonable guess but could change: it certainly comes into the 502 ; function there. 503 ; CHECK-NEXT: strexb [[STATUS:r[0-9]+]], r0, [r[[ADDR]]] 504 ; CHECK-NEXT: cmp [[STATUS]], #0 505 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 506 ; CHECK-NOT: dmb 507 ; CHECK-NOT: mcr 508 509 ; CHECK: mov r0, r[[OLD]] 510 ret i8 %old 511 } 512 513 define i16 @test_atomic_load_xchg_i16(i16 %offset) nounwind { 514 ; CHECK-LABEL: test_atomic_load_xchg_i16: 515 %old = atomicrmw xchg i16* @var16, i16 %offset seq_cst 516 ; CHECK-NOT: dmb 517 ; CHECK-NOT: mcr 518 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16 519 ; CHECK: movt r[[ADDR]], :upper16:var16 520 521 ; CHECK: .LBB{{[0-9]+}}_1: 522 ; CHECK: ldaexh r[[OLD:[0-9]+]], [r[[ADDR]]] 523 ; r0 below is a reasonable guess but could change: it certainly comes into the 524 ; function there. 525 ; CHECK-NEXT: stlexh [[STATUS:r[0-9]+]], r0, [r[[ADDR]]] 526 ; CHECK-NEXT: cmp [[STATUS]], #0 527 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 528 ; CHECK-NOT: dmb 529 ; CHECK-NOT: mcr 530 531 ; CHECK: mov r0, r[[OLD]] 532 ret i16 %old 533 } 534 535 define i32 @test_atomic_load_xchg_i32(i32 %offset) nounwind { 536 ; CHECK-LABEL: test_atomic_load_xchg_i32: 537 %old = atomicrmw xchg i32* @var32, i32 %offset release 538 ; CHECK-NOT: dmb 539 ; CHECK-NOT: mcr 540 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32 541 ; CHECK: movt r[[ADDR]], :upper16:var32 542 543 ; CHECK: .LBB{{[0-9]+}}_1: 544 ; CHECK: ldrex r[[OLD:[0-9]+]], [r[[ADDR]]] 545 ; r0 below is a reasonable guess but could change: it certainly comes into the 546 ; function there. 547 ; CHECK-NEXT: stlex [[STATUS:r[0-9]+]], r0, [r[[ADDR]]] 548 ; CHECK-NEXT: cmp [[STATUS]], #0 549 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 550 ; CHECK-NOT: dmb 551 ; CHECK-NOT: mcr 552 553 ; CHECK: mov r0, r[[OLD]] 554 ret i32 %old 555 } 556 557 define void @test_atomic_load_xchg_i64(i64 %offset) nounwind { 558 ; CHECK-LABEL: test_atomic_load_xchg_i64: 559 %old = atomicrmw xchg i64* @var64, i64 %offset acquire 560 ; CHECK-NOT: dmb 561 ; CHECK-NOT: mcr 562 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64 563 ; CHECK: movt r[[ADDR]], :upper16:var64 564 565 ; CHECK: .LBB{{[0-9]+}}_1: 566 ; CHECK: ldaexd [[OLD1:r[0-9]+]], [[OLD2:r[0-9]+|lr]], [r[[ADDR]]] 567 ; r0, r1 below is a reasonable guess but could change: it certainly comes into the 568 ; function there. 569 ; CHECK-NEXT: strexd [[STATUS:r[0-9]+]], r0, r1, [r[[ADDR]]] 570 ; CHECK-NEXT: cmp [[STATUS]], #0 571 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 572 ; CHECK-NOT: dmb 573 ; CHECK-NOT: mcr 574 575 ; CHECK: strd [[OLD1]], [[OLD2]], [r[[ADDR]]] 576 store i64 %old, i64* @var64 577 ret void 578 } 579 580 define i8 @test_atomic_load_min_i8(i8 signext %offset) nounwind { 581 ; CHECK-LABEL: test_atomic_load_min_i8: 582 %old = atomicrmw min i8* @var8, i8 %offset acquire 583 ; CHECK-NOT: dmb 584 ; CHECK-NOT: mcr 585 ; CHECK-DAG: movw [[ADDR:r[0-9]+|lr]], :lower16:var8 586 ; CHECK-DAG: movt [[ADDR]], :upper16:var8 587 588 ; CHECK: .LBB{{[0-9]+}}_1: 589 ; CHECK: ldaexb r[[OLD:[0-9]+]], {{.*}}[[ADDR]] 590 ; CHECK-NEXT: sxtb r[[OLDX:[0-9]+]], r[[OLD]] 591 ; r0 below is a reasonable guess but could change: it certainly comes into the 592 ; function there. 593 ; CHECK-NEXT: cmp r[[OLDX]], r0 594 ; Thumb mode: it le 595 ; CHECK: movle r[[OLDX]], r[[OLD]] 596 ; CHECK-NEXT: strexb [[STATUS:r[0-9]+]], r[[OLDX]], {{.*}}[[ADDR]]] 597 ; CHECK-NEXT: cmp [[STATUS]], #0 598 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 599 ; CHECK-NOT: dmb 600 ; CHECK-NOT: mcr 601 602 ; CHECK: mov r0, r[[OLD]] 603 ret i8 %old 604 } 605 606 define i16 @test_atomic_load_min_i16(i16 signext %offset) nounwind { 607 ; CHECK-LABEL: test_atomic_load_min_i16: 608 %old = atomicrmw min i16* @var16, i16 %offset release 609 ; CHECK-NOT: dmb 610 ; CHECK-NOT: mcr 611 ; CHECK: movw [[ADDR:r[0-9]+|lr]], :lower16:var16 612 ; CHECK: movt [[ADDR]], :upper16:var16 613 614 ; CHECK: .LBB{{[0-9]+}}_1: 615 ; CHECK: ldrexh r[[OLD:[0-9]+]], {{.*}}[[ADDR]] 616 ; CHECK-NEXT: sxth r[[OLDX:[0-9]+]], r[[OLD]] 617 ; r0 below is a reasonable guess but could change: it certainly comes into the 618 ; function there. 619 ; CHECK-NEXT: cmp r[[OLDX]], r0 620 ; Thumb mode: it le 621 ; CHECK: movle r[[OLDX]], r[[OLD]] 622 ; CHECK-NEXT: stlexh [[STATUS:r[0-9]+]], r[[OLDX]], {{.*}}[[ADDR]] 623 ; CHECK-NEXT: cmp [[STATUS]], #0 624 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 625 ; CHECK-NOT: dmb 626 ; CHECK-NOT: mcr 627 628 ; CHECK: mov r0, r[[OLD]] 629 ret i16 %old 630 } 631 632 define i32 @test_atomic_load_min_i32(i32 %offset) nounwind { 633 ; CHECK-LABEL: test_atomic_load_min_i32: 634 %old = atomicrmw min i32* @var32, i32 %offset monotonic 635 ; CHECK-NOT: dmb 636 ; CHECK-NOT: mcr 637 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32 638 ; CHECK: movt r[[ADDR]], :upper16:var32 639 640 ; CHECK: .LBB{{[0-9]+}}_1: 641 ; CHECK: ldrex r[[OLD:[0-9]+]], [r[[ADDR]]] 642 ; r0 below is a reasonable guess but could change: it certainly comes into the 643 ; function there. 644 ; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0 645 ; CHECK-NEXT: cmp r[[OLD]], r0 646 ; Thumb mode: it le 647 ; CHECK: movle r[[NEW]], r[[OLD]] 648 ; CHECK-NEXT: strex [[STATUS:r[0-9]+]], r[[NEW]], [r[[ADDR]]] 649 ; CHECK-NEXT: cmp [[STATUS]], #0 650 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 651 ; CHECK-NOT: dmb 652 ; CHECK-NOT: mcr 653 654 ; CHECK: mov r0, r[[OLD]] 655 ret i32 %old 656 } 657 658 define void @test_atomic_load_min_i64(i64 %offset) nounwind { 659 ; CHECK-LABEL: test_atomic_load_min_i64: 660 %old = atomicrmw min i64* @var64, i64 %offset seq_cst 661 ; CHECK-NOT: dmb 662 ; CHECK-NOT: mcr 663 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64 664 ; CHECK: movt r[[ADDR]], :upper16:var64 665 666 ; CHECK: .LBB{{[0-9]+}}_1: 667 ; CHECK: ldaexd [[OLD1:r[0-9]+|lr]], [[OLD2:r[0-9]+|lr]], [r[[ADDR]]] 668 ; r0, r1 below is a reasonable guess but could change: it certainly comes into the 669 ; function there. 670 ; CHECK-ARM: mov [[MINHI:r[0-9]+]], r1 671 ; CHECK-ARM-LE: subs {{[^,]+}}, r0, [[OLD1]] 672 ; CHECK-ARM-LE: sbcs {{[^,]+}}, r1, [[OLD2]] 673 ; CHECK-ARM-BE: subs {{[^,]+}}, r1, [[OLD2]] 674 ; CHECK-ARM-BE: sbcs {{[^,]+}}, r0, [[OLD1]] 675 ; CHECK-ARM: mov [[CMP:r[0-9]+|lr]], #0 676 ; CHECK-ARM: movwge [[CMP:r[0-9]+|lr]], #1 677 ; CHECK-ARM: cmp [[CMP:r[0-9]+|lr]], #0 678 ; CHECK-ARM: movne [[MINHI]], [[OLD2]] 679 ; CHECK-ARM: mov [[MINLO:r[0-9]+]], r0 680 ; CHECK-ARM: movne [[MINLO]], [[OLD1]] 681 ; CHECK-ARM: stlexd [[STATUS:r[0-9]+]], [[MINLO]], [[MINHI]], [r[[ADDR]]] 682 ; CHECK-THUMB: stlexd [[STATUS:r[0-9]+]], {{r[0-9]+}}, {{r[0-9]+}}, [r[[ADDR]]] 683 ; CHECK-NEXT: cmp [[STATUS]], #0 684 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 685 ; CHECK-NOT: dmb 686 ; CHECK-NOT: mcr 687 688 ; CHECK-ARM: strd [[OLD1]], [[OLD2]], [r[[ADDR]]] 689 store i64 %old, i64* @var64 690 ret void 691 } 692 693 define i8 @test_atomic_load_max_i8(i8 signext %offset) nounwind { 694 ; CHECK-LABEL: test_atomic_load_max_i8: 695 %old = atomicrmw max i8* @var8, i8 %offset seq_cst 696 ; CHECK-NOT: dmb 697 ; CHECK-NOT: mcr 698 ; CHECK: movw [[ADDR:r[0-9]+|lr]], :lower16:var8 699 ; CHECK: movt [[ADDR]], :upper16:var8 700 701 ; CHECK: .LBB{{[0-9]+}}_1: 702 ; CHECK: ldaexb r[[OLD:[0-9]+]], {{.*}}[[ADDR]] 703 ; CHECK-NEXT: sxtb r[[OLDX:[0-9]+]], r[[OLD]] 704 ; r0 below is a reasonable guess but could change: it certainly comes into the 705 ; function there. 706 ; CHECK-NEXT: cmp r[[OLDX]], r0 707 ; Thumb mode: it gt 708 ; CHECK: movgt r[[OLDX]], r[[OLD]] 709 ; CHECK-NEXT: stlexb [[STATUS:r[0-9]+]], r[[OLDX]], {{.*}}[[ADDR]] 710 ; CHECK-NEXT: cmp [[STATUS]], #0 711 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 712 ; CHECK-NOT: dmb 713 ; CHECK-NOT: mcr 714 715 ; CHECK: mov r0, r[[OLD]] 716 ret i8 %old 717 } 718 719 define i16 @test_atomic_load_max_i16(i16 signext %offset) nounwind { 720 ; CHECK-LABEL: test_atomic_load_max_i16: 721 %old = atomicrmw max i16* @var16, i16 %offset acquire 722 ; CHECK-NOT: dmb 723 ; CHECK-NOT: mcr 724 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16 725 ; CHECK: movt r[[ADDR]], :upper16:var16 726 727 ; CHECK: .LBB{{[0-9]+}}_1: 728 ; CHECK: ldaexh r[[OLD:[0-9]+]], [r[[ADDR]]] 729 ; CHECK-NEXT: sxth r[[OLDX:[0-9]+]], r[[OLD]] 730 ; r0 below is a reasonable guess but could change: it certainly comes into the 731 ; function there. 732 ; CHECK-NEXT: cmp r[[OLDX]], r0 733 ; Thumb mode: it gt 734 ; CHECK: movgt r[[OLDX]], r[[OLD]] 735 ; CHECK-NEXT: strexh [[STATUS:r[0-9]+]], r[[OLDX]], [r[[ADDR]]] 736 ; CHECK-NEXT: cmp [[STATUS]], #0 737 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 738 ; CHECK-NOT: dmb 739 ; CHECK-NOT: mcr 740 741 ; CHECK: mov r0, r[[OLD]] 742 ret i16 %old 743 } 744 745 define i32 @test_atomic_load_max_i32(i32 %offset) nounwind { 746 ; CHECK-LABEL: test_atomic_load_max_i32: 747 %old = atomicrmw max i32* @var32, i32 %offset release 748 ; CHECK-NOT: dmb 749 ; CHECK-NOT: mcr 750 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32 751 ; CHECK: movt r[[ADDR]], :upper16:var32 752 753 ; CHECK: .LBB{{[0-9]+}}_1: 754 ; CHECK: ldrex r[[OLD:[0-9]+]], [r[[ADDR]]] 755 ; r0 below is a reasonable guess but could change: it certainly comes into the 756 ; function there. 757 ; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0 758 ; CHECK-NEXT: cmp r[[OLD]], r0 759 ; Thumb mode: it gt 760 ; CHECK: movgt r[[NEW]], r[[OLD]] 761 ; CHECK-NEXT: stlex [[STATUS:r[0-9]+]], r[[NEW]], [r[[ADDR]]] 762 ; CHECK-NEXT: cmp [[STATUS]], #0 763 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 764 ; CHECK-NOT: dmb 765 ; CHECK-NOT: mcr 766 767 ; CHECK: mov r0, r[[OLD]] 768 ret i32 %old 769 } 770 771 define void @test_atomic_load_max_i64(i64 %offset) nounwind { 772 ; CHECK-LABEL: test_atomic_load_max_i64: 773 %old = atomicrmw max i64* @var64, i64 %offset monotonic 774 ; CHECK-NOT: dmb 775 ; CHECK-NOT: mcr 776 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64 777 ; CHECK: movt r[[ADDR]], :upper16:var64 778 779 ; CHECK: .LBB{{[0-9]+}}_1: 780 ; CHECK: ldrexd [[OLD1:r[0-9]+]], [[OLD2:r[0-9]+|lr]], [r[[ADDR]]] 781 ; r0, r1 below is a reasonable guess but could change: it certainly comes into the 782 ; function there. 783 ; CHECK-ARM: mov [[MINHI:r[0-9]+]], r1 784 ; CHECK-ARM-LE: subs {{[^,]+}}, r0, [[OLD1]] 785 ; CHECK-ARM-LE: sbcs {{[^,]+}}, r1, [[OLD2]] 786 ; CHECK-ARM-BE: subs {{[^,]+}}, r1, [[OLD2]] 787 ; CHECK-ARM-BE: sbcs {{[^,]+}}, r0, [[OLD1]] 788 ; CHECK-ARM: mov [[CMP:r[0-9]+|lr]], #0 789 ; CHECK-ARM: movwlt [[CMP:r[0-9]+|lr]], #1 790 ; CHECK-ARM: cmp [[CMP:r[0-9]+|lr]], #0 791 ; CHECK-ARM: movne [[MINHI]], [[OLD2]] 792 ; CHECK-ARM: mov [[MINLO:r[0-9]+]], r0 793 ; CHECK-ARM: movne [[MINLO]], [[OLD1]] 794 ; CHECK-ARM: strexd [[STATUS:r[0-9]+]], [[MINLO]], [[MINHI]], [r[[ADDR]]] 795 ; CHECK-THUMB: strexd [[STATUS:r[0-9]+]], {{r[0-9]+}}, {{r[0-9]+}}, [r[[ADDR]]] 796 ; CHECK-NEXT: cmp [[STATUS]], #0 797 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 798 ; CHECK-NOT: dmb 799 ; CHECK-NOT: mcr 800 801 ; CHECK-ARM: strd [[OLD1]], [[OLD2]], [r[[ADDR]]] 802 store i64 %old, i64* @var64 803 ret void 804 } 805 806 define i8 @test_atomic_load_umin_i8(i8 zeroext %offset) nounwind { 807 ; CHECK-LABEL: test_atomic_load_umin_i8: 808 %old = atomicrmw umin i8* @var8, i8 %offset monotonic 809 ; CHECK-NOT: dmb 810 ; CHECK-NOT: mcr 811 ; CHECK: movw [[ADDR:r[0-9]+|lr]], :lower16:var8 812 ; CHECK: movt [[ADDR]], :upper16:var8 813 814 ; CHECK: .LBB{{[0-9]+}}_1: 815 ; CHECK: ldrexb r[[OLD:[0-9]+]], {{.*}}[[ADDR]] 816 ; r0 below is a reasonable guess but could change: it certainly comes into the 817 ; function there. 818 ; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0 819 ; CHECK-NEXT: cmp r[[OLD]], r0 820 ; Thumb mode: it ls 821 ; CHECK: movls r[[NEW]], r[[OLD]] 822 ; CHECK-NEXT: strexb [[STATUS:r[0-9]+]], r[[NEW]], {{.*}}[[ADDR]] 823 ; CHECK-NEXT: cmp [[STATUS]], #0 824 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 825 ; CHECK-NOT: dmb 826 ; CHECK-NOT: mcr 827 828 ; CHECK: mov r0, r[[OLD]] 829 ret i8 %old 830 } 831 832 define i16 @test_atomic_load_umin_i16(i16 zeroext %offset) nounwind { 833 ; CHECK-LABEL: test_atomic_load_umin_i16: 834 %old = atomicrmw umin i16* @var16, i16 %offset acquire 835 ; CHECK-NOT: dmb 836 ; CHECK-NOT: mcr 837 ; CHECK: movw [[ADDR:r[0-9]+|lr]], :lower16:var16 838 ; CHECK: movt [[ADDR]], :upper16:var16 839 840 ; CHECK: .LBB{{[0-9]+}}_1: 841 ; CHECK: ldaexh r[[OLD:[0-9]+]], {{.*}}[[ADDR]] 842 ; r0 below is a reasonable guess but could change: it certainly comes into the 843 ; function there. 844 ; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0 845 ; CHECK-NEXT: cmp r[[OLD]], r0 846 ; Thumb mode: it ls 847 ; CHECK: movls r[[NEW]], r[[OLD]] 848 ; CHECK-NEXT: strexh [[STATUS:r[0-9]+]], r[[NEW]], {{.*}}[[ADDR]] 849 ; CHECK-NEXT: cmp [[STATUS]], #0 850 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 851 ; CHECK-NOT: dmb 852 ; CHECK-NOT: mcr 853 854 ; CHECK: mov r0, r[[OLD]] 855 ret i16 %old 856 } 857 858 define i32 @test_atomic_load_umin_i32(i32 %offset) nounwind { 859 ; CHECK-LABEL: test_atomic_load_umin_i32: 860 %old = atomicrmw umin i32* @var32, i32 %offset seq_cst 861 ; CHECK-NOT: dmb 862 ; CHECK-NOT: mcr 863 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32 864 ; CHECK: movt r[[ADDR]], :upper16:var32 865 866 ; CHECK: .LBB{{[0-9]+}}_1: 867 ; CHECK: ldaex r[[OLD:[0-9]+]], [r[[ADDR]]] 868 ; r0 below is a reasonable guess but could change: it certainly comes into the 869 ; function there. 870 ; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0 871 ; CHECK-NEXT: cmp r[[OLD]], r0 872 ; Thumb mode: it ls 873 ; CHECK: movls r[[NEW]], r[[OLD]] 874 ; CHECK-NEXT: stlex [[STATUS:r[0-9]+]], r[[NEW]], [r[[ADDR]]] 875 ; CHECK-NEXT: cmp [[STATUS]], #0 876 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 877 ; CHECK-NOT: dmb 878 ; CHECK-NOT: mcr 879 880 ; CHECK: mov r0, r[[OLD]] 881 ret i32 %old 882 } 883 884 define void @test_atomic_load_umin_i64(i64 %offset) nounwind { 885 ; CHECK-LABEL: test_atomic_load_umin_i64: 886 %old = atomicrmw umin i64* @var64, i64 %offset seq_cst 887 ; CHECK-NOT: dmb 888 ; CHECK-NOT: mcr 889 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64 890 ; CHECK: movt r[[ADDR]], :upper16:var64 891 892 ; CHECK: .LBB{{[0-9]+}}_1: 893 ; CHECK: ldaexd [[OLD1:r[0-9]+|lr]], [[OLD2:r[0-9]+|lr]], [r[[ADDR]]] 894 ; r0, r1 below is a reasonable guess but could change: it certainly comes into the 895 ; function there. 896 ; CHECK-ARM: mov [[MINHI:r[0-9]+]], r1 897 ; CHECK-ARM-LE: subs {{[^,]+}}, r0, [[OLD1]] 898 ; CHECK-ARM-LE: sbcs {{[^,]+}}, r1, [[OLD2]] 899 ; CHECK-ARM-BE: subs {{[^,]+}}, r1, [[OLD2]] 900 ; CHECK-ARM-BE: sbcs {{[^,]+}}, r0, [[OLD1]] 901 ; CHECK-ARM: mov [[CMP:r[0-9]+|lr]], #0 902 ; CHECK-ARM: movwhs [[CMP:r[0-9]+|lr]], #1 903 ; CHECK-ARM: cmp [[CMP:r[0-9]+|lr]], #0 904 ; CHECK-ARM: movne [[MINHI]], [[OLD2]] 905 ; CHECK-ARM: mov [[MINLO:r[0-9]+]], r0 906 ; CHECK-ARM: movne [[MINLO]], [[OLD1]] 907 ; CHECK-ARM: stlexd [[STATUS:r[0-9]+]], [[MINLO]], [[MINHI]], [r[[ADDR]]] 908 ; CHECK-THUMB: stlexd [[STATUS:r[0-9]+]], {{r[0-9]+}}, {{r[0-9]+}}, [r[[ADDR]]] 909 ; CHECK-NEXT: cmp [[STATUS]], #0 910 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 911 ; CHECK-NOT: dmb 912 ; CHECK-NOT: mcr 913 914 ; CHECK-ARM: strd [[OLD1]], [[OLD2]], [r[[ADDR]]] 915 store i64 %old, i64* @var64 916 ret void 917 } 918 919 define i8 @test_atomic_load_umax_i8(i8 zeroext %offset) nounwind { 920 ; CHECK-LABEL: test_atomic_load_umax_i8: 921 %old = atomicrmw umax i8* @var8, i8 %offset acq_rel 922 ; CHECK-NOT: dmb 923 ; CHECK-NOT: mcr 924 ; CHECK: movw [[ADDR:r[0-9]+|lr]], :lower16:var8 925 ; CHECK: movt [[ADDR]], :upper16:var8 926 927 ; CHECK: .LBB{{[0-9]+}}_1: 928 ; CHECK: ldaexb r[[OLD:[0-9]+]], {{.*}}[[ADDR]] 929 ; r0 below is a reasonable guess but could change: it certainly comes into the 930 ; function there. 931 ; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0 932 ; CHECK-NEXT: cmp r[[OLD]], r0 933 ; Thumb mode: it hi 934 ; CHECK: movhi r[[NEW]], r[[OLD]] 935 ; CHECK-NEXT: stlexb [[STATUS:r[0-9]+]], r[[NEW]], {{.*}}[[ADDR]] 936 ; CHECK-NEXT: cmp [[STATUS]], #0 937 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 938 ; CHECK-NOT: dmb 939 ; CHECK-NOT: mcr 940 941 ; CHECK: mov r0, r[[OLD]] 942 ret i8 %old 943 } 944 945 define i16 @test_atomic_load_umax_i16(i16 zeroext %offset) nounwind { 946 ; CHECK-LABEL: test_atomic_load_umax_i16: 947 %old = atomicrmw umax i16* @var16, i16 %offset monotonic 948 ; CHECK-NOT: dmb 949 ; CHECK-NOT: mcr 950 ; CHECK: movw [[ADDR:r[0-9]+|lr]], :lower16:var16 951 ; CHECK: movt [[ADDR]], :upper16:var16 952 953 ; CHECK: .LBB{{[0-9]+}}_1: 954 ; CHECK: ldrexh r[[OLD:[0-9]+]], {{.*}}[[ADDR]] 955 ; r0 below is a reasonable guess but could change: it certainly comes into the 956 ; function there. 957 ; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0 958 ; CHECK-NEXT: cmp r[[OLD]], r0 959 ; Thumb mode: it hi 960 ; CHECK: movhi r[[NEW]], r[[OLD]] 961 ; CHECK-NEXT: strexh [[STATUS:r[0-9]+]], r[[NEW]], {{.*}}[[ADDR]] 962 ; CHECK-NEXT: cmp [[STATUS]], #0 963 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 964 ; CHECK-NOT: dmb 965 ; CHECK-NOT: mcr 966 967 ; CHECK: mov r0, r[[OLD]] 968 ret i16 %old 969 } 970 971 define i32 @test_atomic_load_umax_i32(i32 %offset) nounwind { 972 ; CHECK-LABEL: test_atomic_load_umax_i32: 973 %old = atomicrmw umax i32* @var32, i32 %offset seq_cst 974 ; CHECK-NOT: dmb 975 ; CHECK-NOT: mcr 976 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32 977 ; CHECK: movt r[[ADDR]], :upper16:var32 978 979 ; CHECK: .LBB{{[0-9]+}}_1: 980 ; CHECK: ldaex r[[OLD:[0-9]+]], [r[[ADDR]]] 981 ; r0 below is a reasonable guess but could change: it certainly comes into the 982 ; function there. 983 ; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0 984 ; CHECK-NEXT: cmp r[[OLD]], r0 985 ; Thumb mode: it hi 986 ; CHECK: movhi r[[NEW]], r[[OLD]] 987 ; CHECK-NEXT: stlex [[STATUS:r[0-9]+]], r[[NEW]], [r[[ADDR]]] 988 ; CHECK-NEXT: cmp [[STATUS]], #0 989 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 990 ; CHECK-NOT: dmb 991 ; CHECK-NOT: mcr 992 993 ; CHECK: mov r0, r[[OLD]] 994 ret i32 %old 995 } 996 997 define void @test_atomic_load_umax_i64(i64 %offset) nounwind { 998 ; CHECK-LABEL: test_atomic_load_umax_i64: 999 %old = atomicrmw umax i64* @var64, i64 %offset seq_cst 1000 ; CHECK-NOT: dmb 1001 ; CHECK-NOT: mcr 1002 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64 1003 ; CHECK: movt r[[ADDR]], :upper16:var64 1004 1005 ; CHECK: .LBB{{[0-9]+}}_1: 1006 ; CHECK: ldaexd [[OLD1:r[0-9]+|lr]], [[OLD2:r[0-9]+|lr]], [r[[ADDR]]] 1007 ; r0, r1 below is a reasonable guess but could change: it certainly comes into the 1008 ; function there. 1009 ; CHECK-ARM: mov [[MINHI:r[0-9]+]], r1 1010 ; CHECK-ARM-LE: subs {{[^,]+}}, r0, [[OLD1]] 1011 ; CHECK-ARM-LE: sbcs {{[^,]+}}, r1, [[OLD2]] 1012 ; CHECK-ARM-BE: subs {{[^,]+}}, r1, [[OLD2]] 1013 ; CHECK-ARM-BE: sbcs {{[^,]+}}, r0, [[OLD1]] 1014 ; CHECK-ARM: mov [[CMP:r[0-9]+|lr]], #0 1015 ; CHECK-ARM: movwlo [[CMP:r[0-9]+|lr]], #1 1016 ; CHECK-ARM: cmp [[CMP:r[0-9]+|lr]], #0 1017 ; CHECK-ARM: movne [[MINHI]], [[OLD2]] 1018 ; CHECK-ARM: mov [[MINLO:r[0-9]+]], r0 1019 ; CHECK-ARM: movne [[MINLO]], [[OLD1]] 1020 ; CHECK-ARM: stlexd [[STATUS:r[0-9]+]], [[MINLO]], [[MINHI]], [r[[ADDR]]] 1021 ; CHECK-THUMB: stlexd [[STATUS:r[0-9]+]], {{r[0-9]+}}, {{r[0-9]+}}, [r[[ADDR]]] 1022 ; CHECK-NEXT: cmp [[STATUS]], #0 1023 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 1024 ; CHECK-NOT: dmb 1025 ; CHECK-NOT: mcr 1026 1027 ; CHECK-ARM: strd [[OLD1]], [[OLD2]], [r[[ADDR]]] 1028 store i64 %old, i64* @var64 1029 ret void 1030 } 1031 1032 define i8 @test_atomic_cmpxchg_i8(i8 zeroext %wanted, i8 zeroext %new) nounwind { 1033 ; CHECK-LABEL: test_atomic_cmpxchg_i8: 1034 %pair = cmpxchg i8* @var8, i8 %wanted, i8 %new acquire acquire 1035 %old = extractvalue { i8, i1 } %pair, 0 1036 ; CHECK-NOT: dmb 1037 ; CHECK-NOT: mcr 1038 ; CHECK-DAG: movw r[[ADDR:[0-9]+]], :lower16:var8 1039 ; CHECK-DAG: movt r[[ADDR]], :upper16:var8 1040 ; CHECK-THUMB-DAG: mov r[[WANTED:[0-9]+]], r0 1041 1042 ; CHECK: .LBB{{[0-9]+}}_1: 1043 ; CHECK: ldaexb r[[OLD:[0-9]+]], [r[[ADDR]]] 1044 ; r0 below is a reasonable guess but could change: it certainly comes into the 1045 ; function there. 1046 ; CHECK-ARM-NEXT: cmp r[[OLD]], r0 1047 ; CHECK-THUMB-NEXT: cmp r[[OLD]], r[[WANTED]] 1048 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_3 1049 ; CHECK-NEXT: BB#2: 1050 ; As above, r1 is a reasonable guess. 1051 ; CHECK: strexb [[STATUS:r[0-9]+]], r1, [r[[ADDR]]] 1052 ; CHECK-NEXT: cmp [[STATUS]], #0 1053 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 1054 ; CHECK-NEXT: b .LBB{{[0-9]+}}_4 1055 ; CHECK-NEXT: .LBB{{[0-9]+}}_3: 1056 ; CHECK-NEXT: clrex 1057 ; CHECK-NEXT: .LBB{{[0-9]+}}_4: 1058 ; CHECK-NOT: dmb 1059 ; CHECK-NOT: mcr 1060 1061 ; CHECK-ARM: mov r0, r[[OLD]] 1062 ret i8 %old 1063 } 1064 1065 define i16 @test_atomic_cmpxchg_i16(i16 zeroext %wanted, i16 zeroext %new) nounwind { 1066 ; CHECK-LABEL: test_atomic_cmpxchg_i16: 1067 %pair = cmpxchg i16* @var16, i16 %wanted, i16 %new seq_cst seq_cst 1068 %old = extractvalue { i16, i1 } %pair, 0 1069 ; CHECK-NOT: dmb 1070 ; CHECK-NOT: mcr 1071 ; CHECK-DAG: movw r[[ADDR:[0-9]+]], :lower16:var16 1072 ; CHECK-DAG: movt r[[ADDR]], :upper16:var16 1073 ; CHECK-THUMB-DAG: mov r[[WANTED:[0-9]+]], r0 1074 1075 ; CHECK: .LBB{{[0-9]+}}_1: 1076 ; CHECK: ldaexh r[[OLD:[0-9]+]], [r[[ADDR]]] 1077 ; r0 below is a reasonable guess but could change: it certainly comes into the 1078 ; function there. 1079 ; CHECK-ARM-NEXT: cmp r[[OLD]], r0 1080 ; CHECK-THUMB-NEXT: cmp r[[OLD]], r[[WANTED]] 1081 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_3 1082 ; CHECK-NEXT: BB#2: 1083 ; As above, r1 is a reasonable guess. 1084 ; CHECK: stlexh [[STATUS:r[0-9]+]], r1, [r[[ADDR]]] 1085 ; CHECK-NEXT: cmp [[STATUS]], #0 1086 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 1087 ; CHECK-NEXT: b .LBB{{[0-9]+}}_4 1088 ; CHECK-NEXT: .LBB{{[0-9]+}}_3: 1089 ; CHECK-NEXT: clrex 1090 ; CHECK-NEXT: .LBB{{[0-9]+}}_4: 1091 ; CHECK-NOT: dmb 1092 ; CHECK-NOT: mcr 1093 1094 ; CHECK-ARM: mov r0, r[[OLD]] 1095 ret i16 %old 1096 } 1097 1098 define void @test_atomic_cmpxchg_i32(i32 %wanted, i32 %new) nounwind { 1099 ; CHECK-LABEL: test_atomic_cmpxchg_i32: 1100 %pair = cmpxchg i32* @var32, i32 %wanted, i32 %new release monotonic 1101 %old = extractvalue { i32, i1 } %pair, 0 1102 store i32 %old, i32* @var32 1103 ; CHECK-NOT: dmb 1104 ; CHECK-NOT: mcr 1105 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32 1106 ; CHECK: movt r[[ADDR]], :upper16:var32 1107 1108 ; CHECK: .LBB{{[0-9]+}}_1: 1109 ; CHECK: ldrex r[[OLD:[0-9]+]], [r[[ADDR]]] 1110 ; r0 below is a reasonable guess but could change: it certainly comes into the 1111 ; function there. 1112 ; CHECK-NEXT: cmp r[[OLD]], r0 1113 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_3 1114 ; CHECK-NEXT: BB#2: 1115 ; As above, r1 is a reasonable guess. 1116 ; CHECK: stlex [[STATUS:r[0-9]+]], r1, [r[[ADDR]]] 1117 ; CHECK-NEXT: cmp [[STATUS]], #0 1118 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 1119 ; CHECK-NEXT: b .LBB{{[0-9]+}}_4 1120 ; CHECK-NEXT: .LBB{{[0-9]+}}_3: 1121 ; CHECK-NEXT: clrex 1122 ; CHECK-NEXT: .LBB{{[0-9]+}}_4: 1123 ; CHECK-NOT: dmb 1124 ; CHECK-NOT: mcr 1125 1126 ; CHECK: str{{(.w)?}} r[[OLD]], 1127 ret void 1128 } 1129 1130 define void @test_atomic_cmpxchg_i64(i64 %wanted, i64 %new) nounwind { 1131 ; CHECK-LABEL: test_atomic_cmpxchg_i64: 1132 %pair = cmpxchg i64* @var64, i64 %wanted, i64 %new monotonic monotonic 1133 %old = extractvalue { i64, i1 } %pair, 0 1134 ; CHECK-NOT: dmb 1135 ; CHECK-NOT: mcr 1136 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64 1137 ; CHECK: movt r[[ADDR]], :upper16:var64 1138 1139 ; CHECK: .LBB{{[0-9]+}}_1: 1140 ; CHECK: ldrexd [[OLD1:r[0-9]+|lr]], [[OLD2:r[0-9]+|lr]], [r[[ADDR]]] 1141 ; r0, r1 below is a reasonable guess but could change: it certainly comes into the 1142 ; function there. 1143 ; CHECK-LE-DAG: eor{{(\.w)?}} [[MISMATCH_LO:r[0-9]+|lr]], [[OLD1]], r0 1144 ; CHECK-LE-DAG: eor{{(\.w)?}} [[MISMATCH_HI:r[0-9]+|lr]], [[OLD2]], r1 1145 ; CHECK-ARM-LE: orrs{{(\.w)?}} {{r[0-9]+}}, [[MISMATCH_LO]], [[MISMATCH_HI]] 1146 ; CHECK-THUMB-LE: orrs{{(\.w)?}} {{(r[0-9]+, )?}}[[MISMATCH_HI]], [[MISMATCH_LO]] 1147 ; CHECK-BE-DAG: eor{{(\.w)?}} [[MISMATCH_HI:r[0-9]+|lr]], [[OLD2]], r1 1148 ; CHECK-BE-DAG: eor{{(\.w)?}} [[MISMATCH_LO:r[0-9]+|lr]], [[OLD1]], r0 1149 ; CHECK-ARM-BE: orrs{{(\.w)?}} {{r[0-9]+}}, [[MISMATCH_HI]], [[MISMATCH_LO]] 1150 ; CHECK-THUMB-BE: orrs{{(\.w)?}} {{(r[0-9]+, )?}}[[MISMATCH_LO]], [[MISMATCH_HI]] 1151 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_3 1152 ; CHECK-NEXT: BB#2: 1153 ; As above, r2, r3 is a reasonable guess. 1154 ; CHECK: strexd [[STATUS:r[0-9]+]], r2, r3, [r[[ADDR]]] 1155 ; CHECK-NEXT: cmp [[STATUS]], #0 1156 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 1157 ; CHECK-NEXT: b .LBB{{[0-9]+}}_4 1158 ; CHECK-NEXT: .LBB{{[0-9]+}}_3: 1159 ; CHECK-NEXT: clrex 1160 ; CHECK-NEXT: .LBB{{[0-9]+}}_4: 1161 ; CHECK-NOT: dmb 1162 ; CHECK-NOT: mcr 1163 1164 ; CHECK-ARM: strd [[OLD1]], [[OLD2]], [r[[ADDR]]] 1165 store i64 %old, i64* @var64 1166 ret void 1167 } 1168 1169 define i8 @test_atomic_load_monotonic_i8() nounwind { 1170 ; CHECK-LABEL: test_atomic_load_monotonic_i8: 1171 %val = load atomic i8, i8* @var8 monotonic, align 1 1172 ; CHECK-NOT: dmb 1173 ; CHECK-NOT: mcr 1174 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8 1175 ; CHECK: movt r[[ADDR]], :upper16:var8 1176 ; CHECK: ldrb r0, [r[[ADDR]]] 1177 ; CHECK-NOT: dmb 1178 ; CHECK-NOT: mcr 1179 1180 ret i8 %val 1181 } 1182 1183 define i8 @test_atomic_load_monotonic_regoff_i8(i64 %base, i64 %off) nounwind { 1184 ; CHECK-LABEL: test_atomic_load_monotonic_regoff_i8: 1185 %addr_int = add i64 %base, %off 1186 %addr = inttoptr i64 %addr_int to i8* 1187 1188 %val = load atomic i8, i8* %addr monotonic, align 1 1189 ; CHECK-NOT: dmb 1190 ; CHECK-NOT: mcr 1191 ; CHECK-LE: ldrb r0, [r0, r2] 1192 ; CHECK-BE: ldrb r0, [r1, r3] 1193 ; CHECK-NOT: dmb 1194 ; CHECK-NOT: mcr 1195 1196 ret i8 %val 1197 } 1198 1199 define i8 @test_atomic_load_acquire_i8() nounwind { 1200 ; CHECK-LABEL: test_atomic_load_acquire_i8: 1201 %val = load atomic i8, i8* @var8 acquire, align 1 1202 ; CHECK-NOT: dmb 1203 ; CHECK-NOT: mcr 1204 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8 1205 ; CHECK-NOT: dmb 1206 ; CHECK-NOT: mcr 1207 ; CHECK: movt r[[ADDR]], :upper16:var8 1208 ; CHECK-NOT: dmb 1209 ; CHECK-NOT: mcr 1210 ; CHECK: ldab r0, [r[[ADDR]]] 1211 ; CHECK-NOT: dmb 1212 ; CHECK-NOT: mcr 1213 ret i8 %val 1214 } 1215 1216 define i8 @test_atomic_load_seq_cst_i8() nounwind { 1217 ; CHECK-LABEL: test_atomic_load_seq_cst_i8: 1218 %val = load atomic i8, i8* @var8 seq_cst, align 1 1219 ; CHECK-NOT: dmb 1220 ; CHECK-NOT: mcr 1221 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8 1222 ; CHECK-NOT: dmb 1223 ; CHECK-NOT: mcr 1224 ; CHECK: movt r[[ADDR]], :upper16:var8 1225 ; CHECK-NOT: dmb 1226 ; CHECK-NOT: mcr 1227 ; CHECK: ldab r0, [r[[ADDR]]] 1228 ; CHECK-NOT: dmb 1229 ; CHECK-NOT: mcr 1230 ret i8 %val 1231 } 1232 1233 define i16 @test_atomic_load_monotonic_i16() nounwind { 1234 ; CHECK-LABEL: test_atomic_load_monotonic_i16: 1235 %val = load atomic i16, i16* @var16 monotonic, align 2 1236 ; CHECK-NOT: dmb 1237 ; CHECK-NOT: mcr 1238 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16 1239 ; CHECK-NOT: dmb 1240 ; CHECK-NOT: mcr 1241 ; CHECK: movt r[[ADDR]], :upper16:var16 1242 ; CHECK-NOT: dmb 1243 ; CHECK-NOT: mcr 1244 ; CHECK: ldrh r0, [r[[ADDR]]] 1245 ; CHECK-NOT: dmb 1246 ; CHECK-NOT: mcr 1247 1248 ret i16 %val 1249 } 1250 1251 define i32 @test_atomic_load_monotonic_regoff_i32(i64 %base, i64 %off) nounwind { 1252 ; CHECK-LABEL: test_atomic_load_monotonic_regoff_i32: 1253 %addr_int = add i64 %base, %off 1254 %addr = inttoptr i64 %addr_int to i32* 1255 1256 %val = load atomic i32, i32* %addr monotonic, align 4 1257 ; CHECK-NOT: dmb 1258 ; CHECK-NOT: mcr 1259 ; CHECK-LE: ldr r0, [r0, r2] 1260 ; CHECK-BE: ldr r0, [r1, r3] 1261 ; CHECK-NOT: dmb 1262 ; CHECK-NOT: mcr 1263 1264 ret i32 %val 1265 } 1266 1267 define i64 @test_atomic_load_seq_cst_i64() nounwind { 1268 ; CHECK-LABEL: test_atomic_load_seq_cst_i64: 1269 %val = load atomic i64, i64* @var64 seq_cst, align 8 1270 ; CHECK-NOT: dmb 1271 ; CHECK-NOT: mcr 1272 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64 1273 ; CHECK-NOT: dmb 1274 ; CHECK-NOT: mcr 1275 ; CHECK: movt r[[ADDR]], :upper16:var64 1276 ; CHECK-NOT: dmb 1277 ; CHECK-NOT: mcr 1278 ; CHECK: ldaexd r0, r1, [r[[ADDR]]] 1279 ; CHECK-NOT: dmb 1280 ; CHECK-NOT: mcr 1281 ret i64 %val 1282 } 1283 1284 define void @test_atomic_store_monotonic_i8(i8 %val) nounwind { 1285 ; CHECK-LABEL: test_atomic_store_monotonic_i8: 1286 store atomic i8 %val, i8* @var8 monotonic, align 1 1287 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8 1288 ; CHECK: movt r[[ADDR]], :upper16:var8 1289 ; CHECK: strb r0, [r[[ADDR]]] 1290 1291 ret void 1292 } 1293 1294 define void @test_atomic_store_monotonic_regoff_i8(i64 %base, i64 %off, i8 %val) nounwind { 1295 ; CHECK-LABEL: test_atomic_store_monotonic_regoff_i8: 1296 1297 %addr_int = add i64 %base, %off 1298 %addr = inttoptr i64 %addr_int to i8* 1299 1300 store atomic i8 %val, i8* %addr monotonic, align 1 1301 ; CHECK-LE: ldr{{b?(\.w)?}} [[VAL:r[0-9]+]], [sp] 1302 ; CHECK-LE: strb [[VAL]], [r0, r2] 1303 ; CHECK-BE: ldrb{{(\.w)?}} [[VAL:r[0-9]+]], [sp, #3] 1304 ; CHECK-BE: strb [[VAL]], [r1, r3] 1305 1306 ret void 1307 } 1308 1309 define void @test_atomic_store_release_i8(i8 %val) nounwind { 1310 ; CHECK-LABEL: test_atomic_store_release_i8: 1311 store atomic i8 %val, i8* @var8 release, align 1 1312 ; CHECK-NOT: dmb 1313 ; CHECK-NOT: mcr 1314 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8 1315 ; CHECK-NOT: dmb 1316 ; CHECK-NOT: mcr 1317 ; CHECK: movt r[[ADDR]], :upper16:var8 1318 ; CHECK-NOT: dmb 1319 ; CHECK-NOT: mcr 1320 ; CHECK: stlb r0, [r[[ADDR]]] 1321 ; CHECK-NOT: dmb 1322 ; CHECK-NOT: mcr 1323 ret void 1324 } 1325 1326 define void @test_atomic_store_seq_cst_i8(i8 %val) nounwind { 1327 ; CHECK-LABEL: test_atomic_store_seq_cst_i8: 1328 store atomic i8 %val, i8* @var8 seq_cst, align 1 1329 ; CHECK-NOT: dmb 1330 ; CHECK-NOT: mcr 1331 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8 1332 ; CHECK-NOT: dmb 1333 ; CHECK-NOT: mcr 1334 ; CHECK: movt r[[ADDR]], :upper16:var8 1335 ; CHECK-NOT: dmb 1336 ; CHECK-NOT: mcr 1337 ; CHECK: stlb r0, [r[[ADDR]]] 1338 ; CHECK-NOT: dmb 1339 ; CHECK-NOT: mcr 1340 ret void 1341 } 1342 1343 define void @test_atomic_store_monotonic_i16(i16 %val) nounwind { 1344 ; CHECK-LABEL: test_atomic_store_monotonic_i16: 1345 store atomic i16 %val, i16* @var16 monotonic, align 2 1346 ; CHECK-NOT: dmb 1347 ; CHECK-NOT: mcr 1348 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16 1349 ; CHECK-NOT: dmb 1350 ; CHECK-NOT: mcr 1351 ; CHECK: movt r[[ADDR]], :upper16:var16 1352 ; CHECK-NOT: dmb 1353 ; CHECK-NOT: mcr 1354 ; CHECK: strh r0, [r[[ADDR]]] 1355 ; CHECK-NOT: dmb 1356 ; CHECK-NOT: mcr 1357 ret void 1358 } 1359 1360 define void @test_atomic_store_monotonic_regoff_i32(i64 %base, i64 %off, i32 %val) nounwind { 1361 ; CHECK-LABEL: test_atomic_store_monotonic_regoff_i32: 1362 1363 %addr_int = add i64 %base, %off 1364 %addr = inttoptr i64 %addr_int to i32* 1365 1366 store atomic i32 %val, i32* %addr monotonic, align 4 1367 ; CHECK-NOT: dmb 1368 ; CHECK-NOT: mcr 1369 ; CHECK: ldr [[VAL:r[0-9]+]], [sp] 1370 ; CHECK-NOT: dmb 1371 ; CHECK-NOT: mcr 1372 ; CHECK-LE: str [[VAL]], [r0, r2] 1373 ; CHECK-BE: str [[VAL]], [r1, r3] 1374 ; CHECK-NOT: dmb 1375 ; CHECK-NOT: mcr 1376 1377 ret void 1378 } 1379 1380 define void @test_atomic_store_release_i64(i64 %val) nounwind { 1381 ; CHECK-LABEL: test_atomic_store_release_i64: 1382 store atomic i64 %val, i64* @var64 release, align 8 1383 ; CHECK-NOT: dmb 1384 ; CHECK-NOT: mcr 1385 ; CHECK: movw [[ADDR:r[0-9]+|lr]], :lower16:var64 1386 ; CHECK: movt [[ADDR]], :upper16:var64 1387 1388 ; CHECK: .LBB{{[0-9]+}}_1: 1389 ; r0, r1 below is a reasonable guess but could change: it certainly comes into the 1390 ; function there. 1391 ; CHECK: stlexd [[STATUS:r[0-9]+]], r0, r1, {{.*}}[[ADDR]] 1392 ; CHECK-NEXT: cmp [[STATUS]], #0 1393 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 1394 ; CHECK-NOT: dmb 1395 ; CHECK-NOT: mcr 1396 1397 ret void 1398 } 1399 1400 define i32 @not.barriers(i32* %var, i1 %cond) { 1401 ; CHECK-LABEL: not.barriers: 1402 br i1 %cond, label %atomic_ver, label %simple_ver 1403 simple_ver: 1404 %oldval = load i32, i32* %var 1405 %newval = add nsw i32 %oldval, -1 1406 store i32 %newval, i32* %var 1407 br label %somewhere 1408 atomic_ver: 1409 fence seq_cst 1410 %val = atomicrmw add i32* %var, i32 -1 monotonic 1411 fence seq_cst 1412 br label %somewhere 1413 ; CHECK: dmb 1414 ; CHECK: ldrex 1415 ; CHECK: dmb 1416 ; The key point here is that the second dmb isn't immediately followed by the 1417 ; simple_ver basic block, which LLVM attempted to do when DMB had been marked 1418 ; with isBarrier. For now, look for something that looks like "somewhere". 1419 ; CHECK-NEXT: {{mov|bx}} 1420 somewhere: 1421 %combined = phi i32 [ %val, %atomic_ver ], [ %newval, %simple_ver] 1422 ret i32 %combined 1423 } 1424