Home | History | Annotate | Download | only in ARM
      1 ; RUN: opt -S -o - -mtriple=armv7-apple-ios7.0 -atomic-expand -codegen-opt-level=1 %s | FileCheck %s
      2 
      3 define i8 @test_atomic_xchg_i8(i8* %ptr, i8 %xchgend) {
      4 ; CHECK-LABEL: @test_atomic_xchg_i8
      5 ; CHECK-NOT: dmb
      6 ; CHECK: br label %[[LOOP:.*]]
      7 ; CHECK: [[LOOP]]:
      8 ; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0i8(i8* %ptr)
      9 ; CHECK: [[OLDVAL:%.*]] = trunc i32 [[OLDVAL32]] to i8
     10 ; CHECK: [[NEWVAL32:%.*]] = zext i8 %xchgend to i32
     11 ; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strex.p0i8(i32 [[NEWVAL32]], i8* %ptr)
     12 ; CHECK: [[TST:%.*]] = icmp ne i32 [[TRYAGAIN]], 0
     13 ; CHECK: br i1 [[TST]], label %[[LOOP]], label %[[END:.*]]
     14 ; CHECK: [[END]]:
     15 ; CHECK-NOT: dmb
     16 ; CHECK: ret i8 [[OLDVAL]]
     17   %res = atomicrmw xchg i8* %ptr, i8 %xchgend monotonic
     18   ret i8 %res
     19 }
     20 
     21 define i16 @test_atomic_add_i16(i16* %ptr, i16 %addend) {
     22 ; CHECK-LABEL: @test_atomic_add_i16
     23 ; CHECK: call void @llvm.arm.dmb(i32 11)
     24 ; CHECK: br label %[[LOOP:.*]]
     25 ; CHECK: [[LOOP]]:
     26 ; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0i16(i16* %ptr)
     27 ; CHECK: [[OLDVAL:%.*]] = trunc i32 [[OLDVAL32]] to i16
     28 ; CHECK: [[NEWVAL:%.*]] = add i16 [[OLDVAL]], %addend
     29 ; CHECK: [[NEWVAL32:%.*]] = zext i16 [[NEWVAL]] to i32
     30 ; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strex.p0i16(i32 [[NEWVAL32]], i16* %ptr)
     31 ; CHECK: [[TST:%.*]] = icmp ne i32 [[TRYAGAIN]], 0
     32 ; CHECK: br i1 [[TST]], label %[[LOOP]], label %[[END:.*]]
     33 ; CHECK: [[END]]:
     34 ; CHECK: call void @llvm.arm.dmb(i32 11)
     35 ; CHECK: ret i16 [[OLDVAL]]
     36   %res = atomicrmw add i16* %ptr, i16 %addend seq_cst
     37   ret i16 %res
     38 }
     39 
     40 define i32 @test_atomic_sub_i32(i32* %ptr, i32 %subend) {
     41 ; CHECK-LABEL: @test_atomic_sub_i32
     42 ; CHECK-NOT: dmb
     43 ; CHECK: br label %[[LOOP:.*]]
     44 ; CHECK: [[LOOP]]:
     45 ; CHECK: [[OLDVAL:%.*]] = call i32 @llvm.arm.ldrex.p0i32(i32* %ptr)
     46 ; CHECK: [[NEWVAL:%.*]] = sub i32 [[OLDVAL]], %subend
     47 ; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strex.p0i32(i32 [[NEWVAL]], i32* %ptr)
     48 ; CHECK: [[TST:%.*]] = icmp ne i32 [[TRYAGAIN]], 0
     49 ; CHECK: br i1 [[TST]], label %[[LOOP]], label %[[END:.*]]
     50 ; CHECK: [[END]]:
     51 ; CHECK: call void @llvm.arm.dmb(i32 11)
     52 ; CHECK: ret i32 [[OLDVAL]]
     53   %res = atomicrmw sub i32* %ptr, i32 %subend acquire
     54   ret i32 %res
     55 }
     56 
     57 define i8 @test_atomic_and_i8(i8* %ptr, i8 %andend) {
     58 ; CHECK-LABEL: @test_atomic_and_i8
     59 ; CHECK: call void @llvm.arm.dmb(i32 11)
     60 ; CHECK: br label %[[LOOP:.*]]
     61 ; CHECK: [[LOOP]]:
     62 ; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0i8(i8* %ptr)
     63 ; CHECK: [[OLDVAL:%.*]] = trunc i32 [[OLDVAL32]] to i8
     64 ; CHECK: [[NEWVAL:%.*]] = and i8 [[OLDVAL]], %andend
     65 ; CHECK: [[NEWVAL32:%.*]] = zext i8 [[NEWVAL]] to i32
     66 ; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strex.p0i8(i32 [[NEWVAL32]], i8* %ptr)
     67 ; CHECK: [[TST:%.*]] = icmp ne i32 [[TRYAGAIN]], 0
     68 ; CHECK: br i1 [[TST]], label %[[LOOP]], label %[[END:.*]]
     69 ; CHECK: [[END]]:
     70 ; CHECK-NOT: dmb
     71 ; CHECK: ret i8 [[OLDVAL]]
     72   %res = atomicrmw and i8* %ptr, i8 %andend release
     73   ret i8 %res
     74 }
     75 
     76 define i16 @test_atomic_nand_i16(i16* %ptr, i16 %nandend) {
     77 ; CHECK-LABEL: @test_atomic_nand_i16
     78 ; CHECK: call void @llvm.arm.dmb(i32 11)
     79 ; CHECK: br label %[[LOOP:.*]]
     80 ; CHECK: [[LOOP]]:
     81 ; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0i16(i16* %ptr)
     82 ; CHECK: [[OLDVAL:%.*]] = trunc i32 [[OLDVAL32]] to i16
     83 ; CHECK: [[NEWVAL_TMP:%.*]] = and i16 [[OLDVAL]], %nandend
     84 ; CHECK: [[NEWVAL:%.*]] = xor i16 [[NEWVAL_TMP]], -1
     85 ; CHECK: [[NEWVAL32:%.*]] = zext i16 [[NEWVAL]] to i32
     86 ; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strex.p0i16(i32 [[NEWVAL32]], i16* %ptr)
     87 ; CHECK: [[TST:%.*]] = icmp ne i32 [[TRYAGAIN]], 0
     88 ; CHECK: br i1 [[TST]], label %[[LOOP]], label %[[END:.*]]
     89 ; CHECK: [[END]]:
     90 ; CHECK: call void @llvm.arm.dmb(i32 11)
     91 ; CHECK: ret i16 [[OLDVAL]]
     92   %res = atomicrmw nand i16* %ptr, i16 %nandend seq_cst
     93   ret i16 %res
     94 }
     95 
     96 define i64 @test_atomic_or_i64(i64* %ptr, i64 %orend) {
     97 ; CHECK-LABEL: @test_atomic_or_i64
     98 ; CHECK: call void @llvm.arm.dmb(i32 11)
     99 ; CHECK: br label %[[LOOP:.*]]
    100 ; CHECK: [[LOOP]]:
    101 ; CHECK: [[PTR8:%.*]] = bitcast i64* %ptr to i8*
    102 ; CHECK: [[LOHI:%.*]] = call { i32, i32 } @llvm.arm.ldrexd(i8* [[PTR8]])
    103 ; CHECK: [[LO:%.*]] = extractvalue { i32, i32 } [[LOHI]], 0
    104 ; CHECK: [[HI:%.*]] = extractvalue { i32, i32 } [[LOHI]], 1
    105 ; CHECK: [[LO64:%.*]] = zext i32 [[LO]] to i64
    106 ; CHECK: [[HI64_TMP:%.*]] = zext i32 [[HI]] to i64
    107 ; CHECK: [[HI64:%.*]] = shl i64 [[HI64_TMP]], 32
    108 ; CHECK: [[OLDVAL:%.*]] = or i64 [[LO64]], [[HI64]]
    109 ; CHECK: [[NEWVAL:%.*]] = or i64 [[OLDVAL]], %orend
    110 ; CHECK: [[NEWLO:%.*]] = trunc i64 [[NEWVAL]] to i32
    111 ; CHECK: [[NEWHI_TMP:%.*]] = lshr i64 [[NEWVAL]], 32
    112 ; CHECK: [[NEWHI:%.*]] = trunc i64 [[NEWHI_TMP]] to i32
    113 ; CHECK: [[PTR8:%.*]] = bitcast i64* %ptr to i8*
    114 ; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strexd(i32 [[NEWLO]], i32 [[NEWHI]], i8* [[PTR8]])
    115 ; CHECK: [[TST:%.*]] = icmp ne i32 [[TRYAGAIN]], 0
    116 ; CHECK: br i1 [[TST]], label %[[LOOP]], label %[[END:.*]]
    117 ; CHECK: [[END]]:
    118 ; CHECK: call void @llvm.arm.dmb(i32 11)
    119 ; CHECK: ret i64 [[OLDVAL]]
    120   %res = atomicrmw or i64* %ptr, i64 %orend seq_cst
    121   ret i64 %res
    122 }
    123 
    124 define i8 @test_atomic_xor_i8(i8* %ptr, i8 %xorend) {
    125 ; CHECK-LABEL: @test_atomic_xor_i8
    126 ; CHECK: call void @llvm.arm.dmb(i32 11)
    127 ; CHECK: br label %[[LOOP:.*]]
    128 ; CHECK: [[LOOP]]:
    129 ; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0i8(i8* %ptr)
    130 ; CHECK: [[OLDVAL:%.*]] = trunc i32 [[OLDVAL32]] to i8
    131 ; CHECK: [[NEWVAL:%.*]] = xor i8 [[OLDVAL]], %xorend
    132 ; CHECK: [[NEWVAL32:%.*]] = zext i8 [[NEWVAL]] to i32
    133 ; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strex.p0i8(i32 [[NEWVAL32]], i8* %ptr)
    134 ; CHECK: [[TST:%.*]] = icmp ne i32 [[TRYAGAIN]], 0
    135 ; CHECK: br i1 [[TST]], label %[[LOOP]], label %[[END:.*]]
    136 ; CHECK: [[END]]:
    137 ; CHECK: call void @llvm.arm.dmb(i32 11)
    138 ; CHECK: ret i8 [[OLDVAL]]
    139   %res = atomicrmw xor i8* %ptr, i8 %xorend seq_cst
    140   ret i8 %res
    141 }
    142 
    143 define i8 @test_atomic_max_i8(i8* %ptr, i8 %maxend) {
    144 ; CHECK-LABEL: @test_atomic_max_i8
    145 ; CHECK: call void @llvm.arm.dmb(i32 11)
    146 ; CHECK: br label %[[LOOP:.*]]
    147 ; CHECK: [[LOOP]]:
    148 ; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0i8(i8* %ptr)
    149 ; CHECK: [[OLDVAL:%.*]] = trunc i32 [[OLDVAL32]] to i8
    150 ; CHECK: [[WANT_OLD:%.*]] = icmp sgt i8 [[OLDVAL]], %maxend
    151 ; CHECK: [[NEWVAL:%.*]] = select i1 [[WANT_OLD]], i8 [[OLDVAL]], i8 %maxend
    152 ; CHECK: [[NEWVAL32:%.*]] = zext i8 [[NEWVAL]] to i32
    153 ; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strex.p0i8(i32 [[NEWVAL32]], i8* %ptr)
    154 ; CHECK: [[TST:%.*]] = icmp ne i32 [[TRYAGAIN]], 0
    155 ; CHECK: br i1 [[TST]], label %[[LOOP]], label %[[END:.*]]
    156 ; CHECK: [[END]]:
    157 ; CHECK: call void @llvm.arm.dmb(i32 11)
    158 ; CHECK: ret i8 [[OLDVAL]]
    159   %res = atomicrmw max i8* %ptr, i8 %maxend seq_cst
    160   ret i8 %res
    161 }
    162 
    163 define i8 @test_atomic_min_i8(i8* %ptr, i8 %minend) {
    164 ; CHECK-LABEL: @test_atomic_min_i8
    165 ; CHECK: call void @llvm.arm.dmb(i32 11)
    166 ; CHECK: br label %[[LOOP:.*]]
    167 ; CHECK: [[LOOP]]:
    168 ; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0i8(i8* %ptr)
    169 ; CHECK: [[OLDVAL:%.*]] = trunc i32 [[OLDVAL32]] to i8
    170 ; CHECK: [[WANT_OLD:%.*]] = icmp sle i8 [[OLDVAL]], %minend
    171 ; CHECK: [[NEWVAL:%.*]] = select i1 [[WANT_OLD]], i8 [[OLDVAL]], i8 %minend
    172 ; CHECK: [[NEWVAL32:%.*]] = zext i8 [[NEWVAL]] to i32
    173 ; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strex.p0i8(i32 [[NEWVAL32]], i8* %ptr)
    174 ; CHECK: [[TST:%.*]] = icmp ne i32 [[TRYAGAIN]], 0
    175 ; CHECK: br i1 [[TST]], label %[[LOOP]], label %[[END:.*]]
    176 ; CHECK: [[END]]:
    177 ; CHECK: call void @llvm.arm.dmb(i32 11)
    178 ; CHECK: ret i8 [[OLDVAL]]
    179   %res = atomicrmw min i8* %ptr, i8 %minend seq_cst
    180   ret i8 %res
    181 }
    182 
    183 define i8 @test_atomic_umax_i8(i8* %ptr, i8 %umaxend) {
    184 ; CHECK-LABEL: @test_atomic_umax_i8
    185 ; CHECK: call void @llvm.arm.dmb(i32 11)
    186 ; CHECK: br label %[[LOOP:.*]]
    187 ; CHECK: [[LOOP]]:
    188 ; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0i8(i8* %ptr)
    189 ; CHECK: [[OLDVAL:%.*]] = trunc i32 [[OLDVAL32]] to i8
    190 ; CHECK: [[WANT_OLD:%.*]] = icmp ugt i8 [[OLDVAL]], %umaxend
    191 ; CHECK: [[NEWVAL:%.*]] = select i1 [[WANT_OLD]], i8 [[OLDVAL]], i8 %umaxend
    192 ; CHECK: [[NEWVAL32:%.*]] = zext i8 [[NEWVAL]] to i32
    193 ; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strex.p0i8(i32 [[NEWVAL32]], i8* %ptr)
    194 ; CHECK: [[TST:%.*]] = icmp ne i32 [[TRYAGAIN]], 0
    195 ; CHECK: br i1 [[TST]], label %[[LOOP]], label %[[END:.*]]
    196 ; CHECK: [[END]]:
    197 ; CHECK: call void @llvm.arm.dmb(i32 11)
    198 ; CHECK: ret i8 [[OLDVAL]]
    199   %res = atomicrmw umax i8* %ptr, i8 %umaxend seq_cst
    200   ret i8 %res
    201 }
    202 
    203 define i8 @test_atomic_umin_i8(i8* %ptr, i8 %uminend) {
    204 ; CHECK-LABEL: @test_atomic_umin_i8
    205 ; CHECK: call void @llvm.arm.dmb(i32 11)
    206 ; CHECK: br label %[[LOOP:.*]]
    207 ; CHECK: [[LOOP]]:
    208 ; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0i8(i8* %ptr)
    209 ; CHECK: [[OLDVAL:%.*]] = trunc i32 [[OLDVAL32]] to i8
    210 ; CHECK: [[WANT_OLD:%.*]] = icmp ule i8 [[OLDVAL]], %uminend
    211 ; CHECK: [[NEWVAL:%.*]] = select i1 [[WANT_OLD]], i8 [[OLDVAL]], i8 %uminend
    212 ; CHECK: [[NEWVAL32:%.*]] = zext i8 [[NEWVAL]] to i32
    213 ; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strex.p0i8(i32 [[NEWVAL32]], i8* %ptr)
    214 ; CHECK: [[TST:%.*]] = icmp ne i32 [[TRYAGAIN]], 0
    215 ; CHECK: br i1 [[TST]], label %[[LOOP]], label %[[END:.*]]
    216 ; CHECK: [[END]]:
    217 ; CHECK: call void @llvm.arm.dmb(i32 11)
    218 ; CHECK: ret i8 [[OLDVAL]]
    219   %res = atomicrmw umin i8* %ptr, i8 %uminend seq_cst
    220   ret i8 %res
    221 }
    222 
    223 define i8 @test_cmpxchg_i8_seqcst_seqcst(i8* %ptr, i8 %desired, i8 %newval) {
    224 ; CHECK-LABEL: @test_cmpxchg_i8_seqcst_seqcst
    225 ; CHECK: br label %[[START:.*]]
    226 
    227 ; CHECK: [[START]]:
    228 ; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0i8(i8* %ptr)
    229 ; CHECK: [[OLDVAL:%.*]] = trunc i32 [[OLDVAL32]] to i8
    230 ; CHECK: [[SHOULD_STORE:%.*]] = icmp eq i8 [[OLDVAL]], %desired
    231 ; CHECK: br i1 [[SHOULD_STORE]], label %[[FENCED_STORE:.*]], label %[[NO_STORE_BB:.*]]
    232 
    233 ; CHECK: [[FENCED_STORE]]:
    234 ; CHECK: call void @llvm.arm.dmb(i32 11)
    235 ; CHECK: br label %[[LOOP:.*]]
    236 
    237 ; CHECK: [[LOOP]]:
    238 ; CHECK: [[LOADED_LOOP:%.*]] = phi i8 [ [[OLDVAL]], %[[FENCED_STORE]] ], [ [[OLDVAL_LOOP:%.*]], %[[RELEASED_LOAD:.*]] ]
    239 ; CHECK: [[NEWVAL32:%.*]] = zext i8 %newval to i32
    240 ; CHECK: [[TRYAGAIN:%.*]] =  call i32 @llvm.arm.strex.p0i8(i32 [[NEWVAL32]], i8* %ptr)
    241 ; CHECK: [[TST:%.*]] = icmp eq i32 [[TRYAGAIN]], 0
    242 ; CHECK: br i1 [[TST]], label %[[SUCCESS_BB:.*]], label %[[RELEASED_LOAD]]
    243 
    244 ; CHECK: [[RELEASED_LOAD]]:
    245 ; CHECK: [[OLDVAL32_LOOP:%.*]] = call i32 @llvm.arm.ldrex.p0i8(i8* %ptr)
    246 ; CHECK: [[OLDVAL_LOOP]] = trunc i32 [[OLDVAL32_LOOP]] to i8
    247 ; CHECK: [[SHOULD_STORE_LOOP:%.*]] = icmp eq i8 [[OLDVAL_LOOP]], %desired
    248 ; CHECK: br i1 [[SHOULD_STORE_LOOP]], label %[[LOOP]], label %[[NO_STORE_BB]]
    249 
    250 ; CHECK: [[SUCCESS_BB]]:
    251 ; CHECK: call void @llvm.arm.dmb(i32 11)
    252 ; CHECK: br label %[[DONE:.*]]
    253 
    254 ; CHECK: [[NO_STORE_BB]]:
    255 ; CHECK-NEXT: [[LOADED_NO_STORE:%.*]] = phi i8 [ [[OLDVAL]], %[[START]] ], [ [[OLDVAL_LOOP]], %[[RELEASED_LOAD]] ]
    256 ; CHECK-NEXT: call void @llvm.arm.clrex()
    257 ; CHECK-NEXT: br label %[[FAILURE_BB:.*]]
    258 
    259 ; CHECK: [[FAILURE_BB]]:
    260 ; CHECK: call void @llvm.arm.dmb(i32 11)
    261 ; CHECK: br label %[[DONE]]
    262 
    263 ; CHECK: [[DONE]]:
    264 ; CHECK: [[SUCCESS:%.*]] = phi i1 [ true, %[[SUCCESS_BB]] ], [ false, %[[FAILURE_BB]] ]
    265 ; CHECK: [[LOADED:%.*]] = phi i8 [ [[LOADED_LOOP]], %[[SUCCESS_BB]] ], [ [[LOADED_NO_STORE]], %[[FAILURE_BB]] ]
    266 ; CHECK: ret i8 [[LOADED]]
    267 
    268   %pairold = cmpxchg i8* %ptr, i8 %desired, i8 %newval seq_cst seq_cst
    269   %old = extractvalue { i8, i1 } %pairold, 0
    270   ret i8 %old
    271 }
    272 
    273 define i16 @test_cmpxchg_i16_seqcst_monotonic(i16* %ptr, i16 %desired, i16 %newval) {
    274 ; CHECK-LABEL: @test_cmpxchg_i16_seqcst_monotonic
    275 ; CHECK: br label %[[LOOP:.*]]
    276 
    277 ; CHECK: [[LOOP]]:
    278 ; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0i16(i16* %ptr)
    279 ; CHECK: [[OLDVAL:%.*]] = trunc i32 %1 to i16
    280 ; CHECK: [[SHOULD_STORE:%.*]] = icmp eq i16 [[OLDVAL]], %desired
    281 ; CHECK: br i1 [[SHOULD_STORE]], label %[[FENCED_STORE:.*]], label %[[NO_STORE_BB:.*]]
    282 
    283 ; CHECK: [[FENCED_STORE]]:
    284 ; CHECK: call void @llvm.arm.dmb(i32 11)
    285 ; CHECK: br label %[[LOOP:.*]]
    286 
    287 ; CHECK: [[LOOP]]:
    288 ; CHECK: [[LOADED_LOOP:%.*]] = phi i16 [ [[OLDVAL]], %[[FENCED_STORE]] ], [ [[OLDVAL_LOOP:%.*]], %[[RELEASED_LOAD:.*]] ]
    289 ; CHECK: [[NEWVAL32:%.*]] = zext i16 %newval to i32
    290 ; CHECK: [[TRYAGAIN:%.*]] =  call i32 @llvm.arm.strex.p0i16(i32 [[NEWVAL32]], i16* %ptr)
    291 ; CHECK: [[TST:%.*]] = icmp eq i32 [[TRYAGAIN]], 0
    292 ; CHECK: br i1 [[TST]], label %[[SUCCESS_BB:.*]], label %[[RELEASED_LOAD:.*]]
    293 
    294 ; CHECK: [[RELEASED_LOAD]]:
    295 ; CHECK: [[OLDVAL32_LOOP:%.*]] = call i32 @llvm.arm.ldrex.p0i16(i16* %ptr)
    296 ; CHECK: [[OLDVAL_LOOP]] = trunc i32 [[OLDVAL32_LOOP]] to i16
    297 ; CHECK: [[SHOULD_STORE_LOOP:%.*]] = icmp eq i16 [[OLDVAL_LOOP]], %desired
    298 ; CHECK: br i1 [[SHOULD_STORE_LOOP]], label %[[LOOP]], label %[[NO_STORE_BB]]
    299 
    300 ; CHECK: [[SUCCESS_BB]]:
    301 ; CHECK: call void @llvm.arm.dmb(i32 11)
    302 ; CHECK: br label %[[DONE:.*]]
    303 
    304 ; CHECK: [[NO_STORE_BB]]:
    305 ; CHECK-NEXT: [[LOADED_NO_STORE:%.*]] = phi i16 [ [[OLDVAL]], %[[START]] ], [ [[OLDVAL_LOOP]], %[[RELEASED_LOAD]] ]
    306 ; CHECK-NEXT: call void @llvm.arm.clrex()
    307 ; CHECK-NEXT: br label %[[FAILURE_BB:.*]]
    308 
    309 ; CHECK: [[FAILURE_BB]]:
    310 ; CHECK-NOT: dmb
    311 ; CHECK: br label %[[DONE]]
    312 
    313 ; CHECK: [[DONE]]:
    314 ; CHECK: [[SUCCESS:%.*]] = phi i1 [ true, %[[SUCCESS_BB]] ], [ false, %[[FAILURE_BB]] ]
    315 ; CHECK: [[LOADED:%.*]] = phi i16 [ [[LOADED_LOOP]], %[[SUCCESS_BB]] ], [ [[LOADED_NO_STORE]], %[[FAILURE_BB]] ]
    316 ; CHECK: ret i16 [[LOADED]]
    317 
    318   %pairold = cmpxchg i16* %ptr, i16 %desired, i16 %newval seq_cst monotonic
    319   %old = extractvalue { i16, i1 } %pairold, 0
    320   ret i16 %old
    321 }
    322 
    323 define i32 @test_cmpxchg_i32_acquire_acquire(i32* %ptr, i32 %desired, i32 %newval) {
    324 ; CHECK-LABEL: @test_cmpxchg_i32_acquire_acquire
    325 ; CHECK-NOT: dmb
    326 ; CHECK: br label %[[LOOP:.*]]
    327 
    328 ; CHECK: [[LOOP]]:
    329 ; CHECK: [[OLDVAL:%.*]] = call i32 @llvm.arm.ldrex.p0i32(i32* %ptr)
    330 ; CHECK: [[SHOULD_STORE:%.*]] = icmp eq i32 [[OLDVAL]], %desired
    331 ; CHECK: br i1 [[SHOULD_STORE]], label %[[TRY_STORE:.*]], label %[[NO_STORE_BB:.*]]
    332 
    333 ; CHECK: [[TRY_STORE]]:
    334 ; CHECK: [[TRYAGAIN:%.*]] =  call i32 @llvm.arm.strex.p0i32(i32 %newval, i32* %ptr)
    335 ; CHECK: [[TST:%.*]] = icmp eq i32 [[TRYAGAIN]], 0
    336 ; CHECK: br i1 [[TST]], label %[[SUCCESS_BB:.*]], label %[[LOOP]]
    337 
    338 ; CHECK: [[SUCCESS_BB]]:
    339 ; CHECK: call void @llvm.arm.dmb(i32 11)
    340 ; CHECK: br label %[[DONE:.*]]
    341 
    342 ; CHECK: [[NO_STORE_BB]]:
    343 ; CHECK-NEXT: call void @llvm.arm.clrex()
    344 ; CHECK-NEXT: br label %[[FAILURE_BB:.*]]
    345 
    346 ; CHECK: [[FAILURE_BB]]:
    347 ; CHECK: call void @llvm.arm.dmb(i32 11)
    348 ; CHECK: br label %[[DONE]]
    349 
    350 ; CHECK: [[DONE]]:
    351 ; CHECK: [[SUCCESS:%.*]] = phi i1 [ true, %[[SUCCESS_BB]] ], [ false, %[[FAILURE_BB]] ]
    352 ; CHECK: ret i32 [[OLDVAL]]
    353 
    354   %pairold = cmpxchg i32* %ptr, i32 %desired, i32 %newval acquire acquire
    355   %old = extractvalue { i32, i1 } %pairold, 0
    356   ret i32 %old
    357 }
    358 
    359 define i64 @test_cmpxchg_i64_monotonic_monotonic(i64* %ptr, i64 %desired, i64 %newval) {
    360 ; CHECK-LABEL: @test_cmpxchg_i64_monotonic_monotonic
    361 ; CHECK-NOT: dmb
    362 ; CHECK: br label %[[LOOP:.*]]
    363 
    364 ; CHECK: [[LOOP]]:
    365 ; CHECK: [[PTR8:%.*]] = bitcast i64* %ptr to i8*
    366 ; CHECK: [[LOHI:%.*]] = call { i32, i32 } @llvm.arm.ldrexd(i8* [[PTR8]])
    367 ; CHECK: [[LO:%.*]] = extractvalue { i32, i32 } [[LOHI]], 0
    368 ; CHECK: [[HI:%.*]] = extractvalue { i32, i32 } [[LOHI]], 1
    369 ; CHECK: [[LO64:%.*]] = zext i32 [[LO]] to i64
    370 ; CHECK: [[HI64_TMP:%.*]] = zext i32 [[HI]] to i64
    371 ; CHECK: [[HI64:%.*]] = shl i64 [[HI64_TMP]], 32
    372 ; CHECK: [[OLDVAL:%.*]] = or i64 [[LO64]], [[HI64]]
    373 ; CHECK: [[SHOULD_STORE:%.*]] = icmp eq i64 [[OLDVAL]], %desired
    374 ; CHECK: br i1 [[SHOULD_STORE]], label %[[TRY_STORE:.*]], label %[[NO_STORE_BB:.*]]
    375 
    376 ; CHECK: [[TRY_STORE]]:
    377 ; CHECK: [[NEWLO:%.*]] = trunc i64 %newval to i32
    378 ; CHECK: [[NEWHI_TMP:%.*]] = lshr i64 %newval, 32
    379 ; CHECK: [[NEWHI:%.*]] = trunc i64 [[NEWHI_TMP]] to i32
    380 ; CHECK: [[PTR8:%.*]] = bitcast i64* %ptr to i8*
    381 ; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strexd(i32 [[NEWLO]], i32 [[NEWHI]], i8* [[PTR8]])
    382 ; CHECK: [[TST:%.*]] = icmp eq i32 [[TRYAGAIN]], 0
    383 ; CHECK: br i1 [[TST]], label %[[SUCCESS_BB:.*]], label %[[LOOP]]
    384 
    385 ; CHECK: [[SUCCESS_BB]]:
    386 ; CHECK-NOT: dmb
    387 ; CHECK: br label %[[DONE:.*]]
    388 
    389 ; CHECK: [[NO_STORE_BB]]:
    390 ; CHECK-NEXT: call void @llvm.arm.clrex()
    391 ; CHECK-NEXT: br label %[[FAILURE_BB:.*]]
    392 
    393 ; CHECK: [[FAILURE_BB]]:
    394 ; CHECK-NOT: dmb
    395 ; CHECK: br label %[[DONE]]
    396 
    397 ; CHECK: [[DONE]]:
    398 ; CHECK: [[SUCCESS:%.*]] = phi i1 [ true, %[[SUCCESS_BB]] ], [ false, %[[FAILURE_BB]] ]
    399 ; CHECK: ret i64 [[OLDVAL]]
    400 
    401   %pairold = cmpxchg i64* %ptr, i64 %desired, i64 %newval monotonic monotonic
    402   %old = extractvalue { i64, i1 } %pairold, 0
    403   ret i64 %old
    404 }
    405 
    406 define i32 @test_cmpxchg_minsize(i32* %addr, i32 %desired, i32 %new) minsize {
    407 ; CHECK-LABEL: @test_cmpxchg_minsize
    408 ; CHECK:     call void @llvm.arm.dmb(i32 11)
    409 ; CHECK:     br label %[[START:.*]]
    410 
    411 ; CHECK: [[START]]:
    412 ; CHECK:     [[LOADED:%.*]] = call i32 @llvm.arm.ldrex.p0i32(i32* %addr)
    413 ; CHECK:     [[SHOULD_STORE:%.*]] = icmp eq i32 [[LOADED]], %desired
    414 ; CHECK:     br i1 [[SHOULD_STORE]], label %[[TRY_STORE:.*]], label %[[NO_STORE_BB:.*]]
    415 
    416 ; CHECK: [[TRY_STORE]]:
    417 ; CHECK:     [[STREX:%.*]] = call i32 @llvm.arm.strex.p0i32(i32 %new, i32* %addr)
    418 ; CHECK:     [[SUCCESS:%.*]] = icmp eq i32 [[STREX]], 0
    419 ; CHECK:     br i1 [[SUCCESS]], label %[[SUCCESS_BB:.*]], label %[[START]]
    420 
    421 ; CHECK: [[SUCCESS_BB]]:
    422 ; CHECK:     call void @llvm.arm.dmb(i32 11)
    423 ; CHECK:     br label %[[END:.*]]
    424 
    425 ; CHECK: [[NO_STORE_BB]]:
    426 ; CHECK:     call void @llvm.arm.clrex()
    427 ; CHECK:     br label %[[FAILURE_BB]]
    428 
    429 ; CHECK: [[FAILURE_BB]]:
    430 ; CHECK:     call void @llvm.arm.dmb(i32 11)
    431 ; CHECK:     br label %[[END]]
    432 
    433 ; CHECK: [[END]]:
    434 ; CHECK:     [[SUCCESS:%.*]] = phi i1 [ true, %[[SUCCESS_BB]] ], [ false, %[[FAILURE_BB]] ]
    435 ; CHECK:     ret i32 [[LOADED]]
    436 
    437   %pair = cmpxchg i32* %addr, i32 %desired, i32 %new seq_cst seq_cst
    438   %oldval = extractvalue { i32, i1 } %pair, 0
    439   ret i32 %oldval
    440 }
    441