Home | History | Annotate | Download | only in ARM
      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