Home | History | Annotate | Download | only in ARM
      1 ; RUN: opt -S -o - -mtriple=armv7-apple-ios7.0 -atomic-ll-sc %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: fence
      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: fence
     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: fence release
     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: fence seq_cst
     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: fence
     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: fence acquire
     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: fence release
     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: fence
     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: fence release
     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: fence seq_cst
     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: fence release
     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: fence seq_cst
    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: fence release
    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: fence seq_cst
    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: fence release
    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: fence seq_cst
    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: fence release
    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: fence seq_cst
    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: fence release
    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: fence seq_cst
    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: fence release
    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: fence seq_cst
    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: fence release
    226 ; CHECK: br label %[[LOOP:.*]]
    227 
    228 ; CHECK: [[LOOP]]:
    229 ; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0i8(i8* %ptr)
    230 ; CHECK: [[OLDVAL:%.*]] = trunc i32 %1 to i8
    231 ; CHECK: [[SHOULD_STORE:%.*]] = icmp eq i8 [[OLDVAL]], %desired
    232 ; CHECK: br i1 [[SHOULD_STORE]], label %[[TRY_STORE:.*]], label %[[FAILURE_BB:.*]]
    233 
    234 ; CHECK: [[TRY_STORE]]:
    235 ; CHECK: [[NEWVAL32:%.*]] = zext i8 %newval to i32
    236 ; CHECK: [[TRYAGAIN:%.*]] =  call i32 @llvm.arm.strex.p0i8(i32 [[NEWVAL32]], i8* %ptr)
    237 ; CHECK: [[TST:%.*]] = icmp eq i32 [[TRYAGAIN]], 0
    238 ; CHECK: br i1 [[TST]], label %[[SUCCESS_BB:.*]], label %[[LOOP]]
    239 
    240 ; CHECK: [[SUCCESS_BB]]:
    241 ; CHECK: fence seq_cst
    242 ; CHECK: br label %[[DONE:.*]]
    243 
    244 ; CHECK: [[FAILURE_BB]]:
    245 ; CHECK: fence seq_cst
    246 ; CHECK: br label %[[DONE]]
    247 
    248 ; CHECK: [[DONE]]:
    249 ; CHECK: [[SUCCESS:%.*]] = phi i1 [ true, %[[SUCCESS_BB]] ], [ false, %[[FAILURE_BB]] ]
    250 ; CHECK: ret i8 [[OLDVAL]]
    251 
    252   %pairold = cmpxchg i8* %ptr, i8 %desired, i8 %newval seq_cst seq_cst
    253   %old = extractvalue { i8, i1 } %pairold, 0
    254   ret i8 %old
    255 }
    256 
    257 define i16 @test_cmpxchg_i16_seqcst_monotonic(i16* %ptr, i16 %desired, i16 %newval) {
    258 ; CHECK-LABEL: @test_cmpxchg_i16_seqcst_monotonic
    259 ; CHECK: fence release
    260 ; CHECK: br label %[[LOOP:.*]]
    261 
    262 ; CHECK: [[LOOP]]:
    263 ; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0i16(i16* %ptr)
    264 ; CHECK: [[OLDVAL:%.*]] = trunc i32 %1 to i16
    265 ; CHECK: [[SHOULD_STORE:%.*]] = icmp eq i16 [[OLDVAL]], %desired
    266 ; CHECK: br i1 [[SHOULD_STORE]], label %[[TRY_STORE:.*]], label %[[FAILURE_BB:.*]]
    267 
    268 ; CHECK: [[TRY_STORE]]:
    269 ; CHECK: [[NEWVAL32:%.*]] = zext i16 %newval to i32
    270 ; CHECK: [[TRYAGAIN:%.*]] =  call i32 @llvm.arm.strex.p0i16(i32 [[NEWVAL32]], i16* %ptr)
    271 ; CHECK: [[TST:%.*]] = icmp eq i32 [[TRYAGAIN]], 0
    272 ; CHECK: br i1 [[TST]], label %[[SUCCESS_BB:.*]], label %[[LOOP]]
    273 
    274 ; CHECK: [[SUCCESS_BB]]:
    275 ; CHECK: fence seq_cst
    276 ; CHECK: br label %[[DONE:.*]]
    277 
    278 ; CHECK: [[FAILURE_BB]]:
    279 ; CHECK-NOT: fence
    280 ; CHECK: br label %[[DONE]]
    281 
    282 ; CHECK: [[DONE]]:
    283 ; CHECK: [[SUCCESS:%.*]] = phi i1 [ true, %[[SUCCESS_BB]] ], [ false, %[[FAILURE_BB]] ]
    284 ; CHECK: ret i16 [[OLDVAL]]
    285 
    286   %pairold = cmpxchg i16* %ptr, i16 %desired, i16 %newval seq_cst monotonic
    287   %old = extractvalue { i16, i1 } %pairold, 0
    288   ret i16 %old
    289 }
    290 
    291 define i32 @test_cmpxchg_i32_acquire_acquire(i32* %ptr, i32 %desired, i32 %newval) {
    292 ; CHECK-LABEL: @test_cmpxchg_i32_acquire_acquire
    293 ; CHECK-NOT: fence
    294 ; CHECK: br label %[[LOOP:.*]]
    295 
    296 ; CHECK: [[LOOP]]:
    297 ; CHECK: [[OLDVAL:%.*]] = call i32 @llvm.arm.ldrex.p0i32(i32* %ptr)
    298 ; CHECK: [[SHOULD_STORE:%.*]] = icmp eq i32 [[OLDVAL]], %desired
    299 ; CHECK: br i1 [[SHOULD_STORE]], label %[[TRY_STORE:.*]], label %[[FAILURE_BB:.*]]
    300 
    301 ; CHECK: [[TRY_STORE]]:
    302 ; CHECK: [[TRYAGAIN:%.*]] =  call i32 @llvm.arm.strex.p0i32(i32 %newval, i32* %ptr)
    303 ; CHECK: [[TST:%.*]] = icmp eq i32 [[TRYAGAIN]], 0
    304 ; CHECK: br i1 [[TST]], label %[[SUCCESS_BB:.*]], label %[[LOOP]]
    305 
    306 ; CHECK: [[SUCCESS_BB]]:
    307 ; CHECK: fence acquire
    308 ; CHECK: br label %[[DONE:.*]]
    309 
    310 ; CHECK: [[FAILURE_BB]]:
    311 ; CHECK: fence acquire
    312 ; CHECK: br label %[[DONE]]
    313 
    314 ; CHECK: [[DONE]]:
    315 ; CHECK: [[SUCCESS:%.*]] = phi i1 [ true, %[[SUCCESS_BB]] ], [ false, %[[FAILURE_BB]] ]
    316 ; CHECK: ret i32 [[OLDVAL]]
    317 
    318   %pairold = cmpxchg i32* %ptr, i32 %desired, i32 %newval acquire acquire
    319   %old = extractvalue { i32, i1 } %pairold, 0
    320   ret i32 %old
    321 }
    322 
    323 define i64 @test_cmpxchg_i64_monotonic_monotonic(i64* %ptr, i64 %desired, i64 %newval) {
    324 ; CHECK-LABEL: @test_cmpxchg_i64_monotonic_monotonic
    325 ; CHECK-NOT: fence
    326 ; CHECK: br label %[[LOOP:.*]]
    327 
    328 ; CHECK: [[LOOP]]:
    329 ; CHECK: [[PTR8:%.*]] = bitcast i64* %ptr to i8*
    330 ; CHECK: [[LOHI:%.*]] = call { i32, i32 } @llvm.arm.ldrexd(i8* [[PTR8]])
    331 ; CHECK: [[LO:%.*]] = extractvalue { i32, i32 } [[LOHI]], 0
    332 ; CHECK: [[HI:%.*]] = extractvalue { i32, i32 } [[LOHI]], 1
    333 ; CHECK: [[LO64:%.*]] = zext i32 [[LO]] to i64
    334 ; CHECK: [[HI64_TMP:%.*]] = zext i32 [[HI]] to i64
    335 ; CHECK: [[HI64:%.*]] = shl i64 [[HI64_TMP]], 32
    336 ; CHECK: [[OLDVAL:%.*]] = or i64 [[LO64]], [[HI64]]
    337 ; CHECK: [[SHOULD_STORE:%.*]] = icmp eq i64 [[OLDVAL]], %desired
    338 ; CHECK: br i1 [[SHOULD_STORE]], label %[[TRY_STORE:.*]], label %[[FAILURE_BB:.*]]
    339 
    340 ; CHECK: [[TRY_STORE]]:
    341 ; CHECK: [[NEWLO:%.*]] = trunc i64 %newval to i32
    342 ; CHECK: [[NEWHI_TMP:%.*]] = lshr i64 %newval, 32
    343 ; CHECK: [[NEWHI:%.*]] = trunc i64 [[NEWHI_TMP]] to i32
    344 ; CHECK: [[PTR8:%.*]] = bitcast i64* %ptr to i8*
    345 ; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strexd(i32 [[NEWLO]], i32 [[NEWHI]], i8* [[PTR8]])
    346 ; CHECK: [[TST:%.*]] = icmp eq i32 [[TRYAGAIN]], 0
    347 ; CHECK: br i1 [[TST]], label %[[SUCCESS_BB:.*]], label %[[LOOP]]
    348 
    349 ; CHECK: [[SUCCESS_BB]]:
    350 ; CHECK-NOT: fence
    351 ; CHECK: br label %[[DONE:.*]]
    352 
    353 ; CHECK: [[FAILURE_BB]]:
    354 ; CHECK-NOT: fence
    355 ; CHECK: br label %[[DONE]]
    356 
    357 ; CHECK: [[DONE]]:
    358 ; CHECK: [[SUCCESS:%.*]] = phi i1 [ true, %[[SUCCESS_BB]] ], [ false, %[[FAILURE_BB]] ]
    359 ; CHECK: ret i64 [[OLDVAL]]
    360 
    361   %pairold = cmpxchg i64* %ptr, i64 %desired, i64 %newval monotonic monotonic
    362   %old = extractvalue { i64, i1 } %pairold, 0
    363   ret i64 %old
    364 }