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