1; RUN: llc < %s -mtriple=armv7-apple-ios -verify-machineinstrs | FileCheck %s --check-prefix=CHECK --check-prefix CHECK-ARMV7 2; RUN: llc < %s -mtriple=thumbv7-apple-ios -verify-machineinstrs | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-T2 3; RUN: llc < %s -mtriple=thumbv6-apple-ios -verify-machineinstrs | FileCheck %s --check-prefix=CHECK-T1 4; RUN: llc < %s -mtriple=thumbv6-apple-ios -verify-machineinstrs -mcpu=cortex-m0 | FileCheck %s --check-prefix=CHECK-T1-M0 5; RUN: llc < %s -mtriple=thumbv7--none-eabi -thread-model single -verify-machineinstrs | FileCheck %s --check-prefix=CHECK-BAREMETAL 6 7target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" 8 9; CHECK-LABEL: _func: 10define void @func(i32 %argc, ptr %argv) nounwind { 11entry: 12 %argc.addr = alloca i32 ; <ptr> [#uses=1] 13 %argv.addr = alloca ptr ; <ptr> [#uses=1] 14 %val1 = alloca i32 ; <ptr> [#uses=2] 15 %val2 = alloca i32 ; <ptr> [#uses=15] 16 %andt = alloca i32 ; <ptr> [#uses=2] 17 %ort = alloca i32 ; <ptr> [#uses=2] 18 %xort = alloca i32 ; <ptr> [#uses=2] 19 %old = alloca i32 ; <ptr> [#uses=18] 20 %temp = alloca i32 ; <ptr> [#uses=2] 21 store i32 %argc, ptr %argc.addr 22 store ptr %argv, ptr %argv.addr 23 store i32 0, ptr %val1 24 store i32 31, ptr %val2 25 store i32 3855, ptr %andt 26 store i32 3855, ptr %ort 27 store i32 3855, ptr %xort 28 store i32 4, ptr %temp 29 %tmp = load i32, ptr %temp 30 call void asm sideeffect "", "~{memory},~{dirflag},~{fpsr},~{flags}"() 31 ; CHECK: ldrex 32 ; CHECK: add 33 ; CHECK: strex 34 ; CHECK-T1: bl ___sync_fetch_and_add_4 35 ; CHECK-T1-M0: bl ___atomic_fetch_add_4 36 ; CHECK-BAREMETAL: add 37 ; CHECK-BAREMETAL-NOT: __sync 38 %0 = atomicrmw add ptr %val1, i32 %tmp monotonic 39 store i32 %0, ptr %old 40 call void asm sideeffect "", "~{memory},~{dirflag},~{fpsr},~{flags}"() 41 ; CHECK: ldrex 42 ; CHECK: sub 43 ; CHECK: strex 44 ; CHECK-T1: bl ___sync_fetch_and_sub_4 45 ; CHECK-T1-M0: bl ___atomic_fetch_sub_4 46 ; CHECK-BAREMETAL: sub 47 ; CHECK-BAREMETAL-NOT: __sync 48 %1 = atomicrmw sub ptr %val2, i32 30 monotonic 49 store i32 %1, ptr %old 50 call void asm sideeffect "", "~{memory},~{dirflag},~{fpsr},~{flags}"() 51 ; CHECK: ldrex 52 ; CHECK: add 53 ; CHECK: strex 54 ; CHECK-T1: bl ___sync_fetch_and_add_4 55 ; CHECK-T1-M0: bl ___atomic_fetch_add_4 56 ; CHECK-BAREMETAL: add 57 ; CHECK-BAREMETAL-NOT: __sync 58 %2 = atomicrmw add ptr %val2, i32 1 monotonic 59 store i32 %2, ptr %old 60 call void asm sideeffect "", "~{memory},~{dirflag},~{fpsr},~{flags}"() 61 ; CHECK: ldrex 62 ; CHECK: sub 63 ; CHECK: strex 64 ; CHECK-T1: bl ___sync_fetch_and_sub_4 65 ; CHECK-T1-M0: bl ___atomic_fetch_sub_4 66 ; CHECK-BAREMETAL: sub 67 ; CHECK-BAREMETAL-NOT: __sync 68 %3 = atomicrmw sub ptr %val2, i32 1 monotonic 69 store i32 %3, ptr %old 70 call void asm sideeffect "", "~{memory},~{dirflag},~{fpsr},~{flags}"() 71 ; CHECK: ldrex 72 ; CHECK: and 73 ; CHECK: strex 74 ; CHECK-T1: bl ___sync_fetch_and_and_4 75 ; CHECK-T1-M0: bl ___atomic_fetch_and_4 76 ; CHECK-BAREMETAL: and 77 ; CHECK-BAREMETAL-NOT: __sync 78 %4 = atomicrmw and ptr %andt, i32 4080 monotonic 79 store i32 %4, ptr %old 80 call void asm sideeffect "", "~{memory},~{dirflag},~{fpsr},~{flags}"() 81 ; CHECK: ldrex 82 ; CHECK: or 83 ; CHECK: strex 84 ; CHECK-T1: bl ___sync_fetch_and_or_4 85 ; CHECK-T1-M0: bl ___atomic_fetch_or_4 86 ; CHECK-BAREMETAL: or 87 ; CHECK-BAREMETAL-NOT: __sync 88 %5 = atomicrmw or ptr %ort, i32 4080 monotonic 89 store i32 %5, ptr %old 90 call void asm sideeffect "", "~{memory},~{dirflag},~{fpsr},~{flags}"() 91 ; CHECK: ldrex 92 ; CHECK: eor 93 ; CHECK: strex 94 ; CHECK-T1: bl ___sync_fetch_and_xor_4 95 ; CHECK-T1-M0: bl ___atomic_fetch_xor_4 96 ; CHECK-BAREMETAL: eor 97 ; CHECK-BAREMETAL-NOT: __sync 98 %6 = atomicrmw xor ptr %xort, i32 4080 monotonic 99 store i32 %6, ptr %old 100 call void asm sideeffect "", "~{memory},~{dirflag},~{fpsr},~{flags}"() 101 ; CHECK: ldrex 102 ; CHECK: cmp 103 ; CHECK: strex 104 ; CHECK-T1: bl ___sync_fetch_and_min_4 105 ; CHECK-T1-M0: bl ___atomic_compare_exchange_4 106 ; CHECK-BAREMETAL: cmp 107 ; CHECK-BAREMETAL-NOT: __sync 108 %7 = atomicrmw min ptr %val2, i32 16 monotonic 109 store i32 %7, ptr %old 110 call void asm sideeffect "", "~{memory},~{dirflag},~{fpsr},~{flags}"() 111 %neg = sub i32 0, 1 112 ; CHECK: ldrex 113 ; CHECK: cmp 114 ; CHECK: strex 115 ; CHECK-T1: bl ___sync_fetch_and_min_4 116 ; CHECK-T1-M0: bl ___atomic_compare_exchange_4 117 ; CHECK-BAREMETAL: cmp 118 ; CHECK-BAREMETAL-NOT: __sync 119 %8 = atomicrmw min ptr %val2, i32 %neg monotonic 120 store i32 %8, ptr %old 121 call void asm sideeffect "", "~{memory},~{dirflag},~{fpsr},~{flags}"() 122 ; CHECK: ldrex 123 ; CHECK: cmp 124 ; CHECK: strex 125 ; CHECK-T1: bl ___sync_fetch_and_max_4 126 ; CHECK-T1-M0: bl ___atomic_compare_exchange_4 127 ; CHECK-BAREMETAL: cmp 128 ; CHECK-BAREMETAL-NOT: __sync 129 %9 = atomicrmw max ptr %val2, i32 1 monotonic 130 store i32 %9, ptr %old 131 call void asm sideeffect "", "~{memory},~{dirflag},~{fpsr},~{flags}"() 132 ; CHECK: ldrex 133 ; CHECK: bic 134 ; CHECK-NOT: cmp 135 ; CHECK: strex 136 ; CHECK-T1: bl ___sync_fetch_and_max_4 137 ; CHECK-T1-M0: bl ___atomic_compare_exchange_4 138 ; CHECK-BAREMETAL: bic 139 ; CHECK-BAREMETAL-NOT: __sync 140 %10 = atomicrmw max ptr %val2, i32 0 monotonic 141 store i32 %10, ptr %old 142 call void asm sideeffect "", "~{memory},~{dirflag},~{fpsr},~{flags}"() 143 ; CHECK: ldrex 144 ; CHECK: cmp 145 ; CHECK: strex 146 ; CHECK-T1: bl ___sync_fetch_and_umin_4 147 ; CHECK-T1-M0: bl ___atomic_compare_exchange_4 148 ; CHECK-BAREMETAL: cmp 149 ; CHECK-BAREMETAL-NOT: __sync 150 %11 = atomicrmw umin ptr %val2, i32 16 monotonic 151 store i32 %11, ptr %old 152 call void asm sideeffect "", "~{memory},~{dirflag},~{fpsr},~{flags}"() 153 %uneg = sub i32 0, 1 154 ; CHECK: ldrex 155 ; CHECK: cmp 156 ; CHECK: strex 157 ; CHECK-T1: bl ___sync_fetch_and_umin_4 158 ; CHECK-T1-M0: bl ___atomic_compare_exchange_4 159 ; CHECK-BAREMETAL: cmp 160 ; CHECK-BAREMETAL-NOT: __sync 161 %12 = atomicrmw umin ptr %val2, i32 %uneg monotonic 162 store i32 %12, ptr %old 163 call void asm sideeffect "", "~{memory},~{dirflag},~{fpsr},~{flags}"() 164 ; CHECK: ldrex 165 ; CHECK: strex 166 ; CHECK: cmp 167 ; CHECK-T1: bl ___sync_fetch_and_umax_4 168 ; CHECK-T1-M0: bl ___atomic_compare_exchange_4 169 ; CHECK-BAREMETAL: cmp 170 ; CHECK-BAREMETAL-NOT: __sync 171 %13 = atomicrmw umax ptr %val2, i32 1 monotonic 172 store i32 %13, ptr %old 173 call void asm sideeffect "", "~{memory},~{dirflag},~{fpsr},~{flags}"() 174 ; CHECK: ldrex 175 ; CHECK: strex 176 ; CHECK: cmp 177 ; CHECK-T1: bl ___sync_fetch_and_umax_4 178 ; CHECK-T1-M0: bl ___atomic_compare_exchange_4 179 ; CHECK-BAREMETAL: cmp 180 ; CHECK-BAREMETAL-NOT: __sync 181 %14 = atomicrmw umax ptr %val2, i32 0 monotonic 182 store i32 %14, ptr %old 183 184 ret void 185} 186 187; CHECK-LABEL: _func2: 188define void @func2() nounwind { 189entry: 190 %val = alloca i16 191 %old = alloca i16 192 store i16 31, ptr %val 193 ; CHECK: ldrex 194 ; CHECK: strex 195 ; CHECK: cmp 196 ; CHECK-T1: bl ___sync_fetch_and_umin_2 197 ; CHECK-T1-M0: bl ___atomic_compare_exchange_2 198 ; CHECK-BAREMETAL: cmp 199 ; CHECK-BAREMETAL-NOT: __sync 200 %0 = atomicrmw umin ptr %val, i16 16 monotonic 201 store i16 %0, ptr %old 202 %uneg = sub i16 0, 1 203 ; CHECK: ldrex 204 ; CHECK: strex 205 ; CHECK: cmp 206 ; CHECK-T1: bl ___sync_fetch_and_umin_2 207 ; CHECK-T1-M0: bl ___atomic_compare_exchange_2 208 ; CHECK-BAREMETAL: cmp 209 ; CHECK-BAREMETAL-NOT: __sync 210 %1 = atomicrmw umin ptr %val, i16 %uneg monotonic 211 store i16 %1, ptr %old 212 ; CHECK: ldrex 213 ; CHECK: cmp 214 ; CHECK: strex 215 ; CHECK-T1: bl ___sync_fetch_and_umax_2 216 ; CHECK-T1-M0: bl ___atomic_compare_exchange_2 217 ; CHECK-BAREMETAL: cmp 218 ; CHECK-BAREMETAL-NOT: __sync 219 %2 = atomicrmw umax ptr %val, i16 1 monotonic 220 store i16 %2, ptr %old 221 ; CHECK: ldrex 222 ; CHECK: strex 223 ; CHECK: cmp 224 ; CHECK-T1: bl ___sync_fetch_and_umax_2 225 ; CHECK-T1-M0: bl ___atomic_compare_exchange_2 226 ; CHECK-BAREMETAL: cmp 227 ; CHECK-BAREMETAL-NOT: __sync 228 %3 = atomicrmw umax ptr %val, i16 0 monotonic 229 store i16 %3, ptr %old 230 ret void 231} 232 233; CHECK-LABEL: _func3: 234define void @func3() nounwind { 235entry: 236 %val = alloca i8 237 %old = alloca i8 238 store i8 31, ptr %val 239 ; CHECK: ldrex 240 ; CHECK: strex 241 ; CHECK: cmp 242 ; CHECK-T1: bl ___sync_fetch_and_umin_1 243 ; CHECK-T1-M0: bl ___atomic_compare_exchange_1 244 ; CHECK-BAREMETAL: cmp 245 ; CHECK-BAREMETAL-NOT: __sync 246 %0 = atomicrmw umin ptr %val, i8 16 monotonic 247 store i8 %0, ptr %old 248 ; CHECK: ldrex 249 ; CHECK: strex 250 ; CHECK: cmp 251 ; CHECK-T1: bl ___sync_fetch_and_umin_1 252 ; CHECK-T1-M0: bl ___atomic_compare_exchange_1 253 ; CHECK-BAREMETAL: cmp 254 ; CHECK-BAREMETAL-NOT: __sync 255 %uneg = sub i8 0, 1 256 %1 = atomicrmw umin ptr %val, i8 %uneg monotonic 257 store i8 %1, ptr %old 258 ; CHECK: ldrex 259 ; CHECK: strex 260 ; CHECK: cmp 261 ; CHECK-T1: bl ___sync_fetch_and_umax_1 262 ; CHECK-T1-M0: bl ___atomic_compare_exchange_1 263 ; CHECK-BAREMETAL: cmp 264 ; CHECK-BAREMETAL-NOT: __sync 265 %2 = atomicrmw umax ptr %val, i8 1 monotonic 266 store i8 %2, ptr %old 267 ; CHECK: ldrex 268 ; CHECK: strex 269 ; CHECK: cmp 270 ; CHECK-T1: bl ___sync_fetch_and_umax_1 271 ; CHECK-T1-M0: bl ___atomic_compare_exchange_1 272 ; CHECK-BAREMETAL: cmp 273 ; CHECK-BAREMETAL-NOT: __sync 274 %3 = atomicrmw umax ptr %val, i8 0 monotonic 275 store i8 %3, ptr %old 276 ret void 277} 278 279; CHECK-LABEL: _func4: 280; This function should not need to use callee-saved registers. 281; rdar://problem/12203728 282; CHECK-NOT: r4 283define i32 @func4(ptr %p) nounwind optsize ssp { 284entry: 285 %0 = atomicrmw add ptr %p, i32 1 monotonic 286 ret i32 %0 287} 288 289define i32 @test_cmpxchg_fail_order(ptr %addr, i32 %desired, i32 %new) { 290; CHECK-LABEL: test_cmpxchg_fail_order: 291 292 %pair = cmpxchg ptr %addr, i32 %desired, i32 %new seq_cst monotonic 293 %oldval = extractvalue { i32, i1 } %pair, 0 294; CHECK-ARMV7: mov r[[ADDR:[0-9]+]], r0 295; CHECK-ARMV7: ldrex [[OLDVAL:r[0-9]+]], [r0] 296; CHECK-ARMV7: cmp [[OLDVAL]], r1 297; CHECK-ARMV7: bne [[FAIL_BB:\.?LBB[0-9]+_[0-9]+]] 298; CHECK-ARMV7: dmb ish 299; CHECK-ARMV7: [[LOOP_BB:\.?LBB.*]]: 300; CHECK-ARMV7: strex [[SUCCESS:r[0-9]+]], r2, [r[[ADDR]]] 301; CHECK-ARMV7: cmp [[SUCCESS]], #0 302; CHECK-ARMV7: beq [[SUCCESS_BB:\.?LBB.*]] 303; CHECK-ARMV7: ldrex [[OLDVAL]], [r[[ADDR]]] 304; CHECK-ARMV7: cmp [[OLDVAL]], r1 305; CHECK-ARMV7: beq [[LOOP_BB]] 306; CHECK-ARMV7: [[FAIL_BB]]: 307; CHECK-ARMV7: clrex 308; CHECK-ARMV7: bx lr 309; CHECK-ARMV7: [[SUCCESS_BB]]: 310; CHECK-ARMV7: dmb ish 311; CHECK-ARMV7: bx lr 312 313; CHECK-T2: mov r[[ADDR:[0-9]+]], r0 314; CHECK-T2: ldrex [[OLDVAL:r[0-9]+]], [r0] 315; CHECK-T2: cmp [[OLDVAL]], r1 316; CHECK-T2: bne [[FAIL_BB:\.?LBB.*]] 317; CHECK-T2: dmb ish 318; CHECK-T2: [[LOOP_BB:\.?LBB.*]]: 319; CHECK-T2: strex [[SUCCESS:r[0-9]+]], r2, [r[[ADDR]]] 320; CHECK-T2: cmp [[SUCCESS]], #0 321; CHECK-T2: dmbeq ish 322; CHECK-T2: bxeq lr 323; CHECK-T2: ldrex [[OLDVAL]], [r[[ADDR]]] 324; CHECK-T2: cmp [[OLDVAL]], r1 325; CHECK-T2: beq [[LOOP_BB]] 326; CHECK-T2: clrex 327 328 ret i32 %oldval 329} 330 331define i32 @test_cmpxchg_fail_order1(ptr %addr, i32 %desired, i32 %new) { 332; CHECK-LABEL: test_cmpxchg_fail_order1: 333 334 %pair = cmpxchg ptr %addr, i32 %desired, i32 %new acquire acquire 335 %oldval = extractvalue { i32, i1 } %pair, 0 336; CHECK-NOT: dmb ish 337; CHECK: [[LOOP_BB:\.?LBB[0-9]+_1]]: 338; CHECK: ldrex [[OLDVAL:r[0-9]+]], [r[[ADDR:[0-9]+]]] 339; CHECK: cmp [[OLDVAL]], r1 340; CHECK: bne [[FAIL_BB:\.?LBB[0-9]+_[0-9]+]] 341; CHECK: strex [[SUCCESS:r[0-9]+]], r2, [r[[ADDR]]] 342; CHECK: cmp [[SUCCESS]], #0 343; CHECK: bne [[LOOP_BB]] 344; CHECK: dmb ish 345; CHECK: bx lr 346; CHECK: [[FAIL_BB]]: 347; CHECK-NEXT: clrex 348; CHECK: dmb ish 349; CHECK: bx lr 350 351 ret i32 %oldval 352} 353 354define i32 @load_load_add_acquire(ptr %mem1, ptr %mem2) nounwind { 355; CHECK-LABEL: load_load_add_acquire 356 %val1 = load atomic i32, ptr %mem1 acquire, align 4 357 %val2 = load atomic i32, ptr %mem2 acquire, align 4 358 %tmp = add i32 %val1, %val2 359 360; CHECK: ldr {{r[0-9]}}, [r0] 361; CHECK: dmb 362; CHECK: ldr {{r[0-9]}}, [r1] 363; CHECK: dmb 364; CHECK: add r0, 365 366; CHECK-T1-M0: __atomic_load_4 367; CHECK-T1-M0: __atomic_load_4 368 369; CHECK-T1: ___sync_val_compare_and_swap_4 370; CHECK-T1: ___sync_val_compare_and_swap_4 371 372; CHECK-BAREMETAL: ldr {{r[0-9]}}, [r0] 373; CHECK-BAREMETAL-NOT: dmb 374; CHECK-BAREMETAL: ldr {{r[0-9]}}, [r1] 375; CHECK-BAREMETAL-NOT: dmb 376; CHECK-BAREMETAL: add r0, 377 378 ret i32 %tmp 379} 380 381define void @store_store_release(ptr %mem1, i32 %val1, ptr %mem2, i32 %val2) { 382; CHECK-LABEL: store_store_release 383 store atomic i32 %val1, ptr %mem1 release, align 4 384 store atomic i32 %val2, ptr %mem2 release, align 4 385 386; CHECK: dmb 387; CHECK: str r1, [r0] 388; CHECK: dmb 389; CHECK: str r3, [r2] 390 391; CHECK-T1: ___sync_lock_test_and_set 392; CHECK-T1: ___sync_lock_test_and_set 393 394; CHECK-T1-M0: __atomic_store_4 395; CHECK-T1-M0: __atomic_store_4 396 397; CHECK-BAREMETAL-NOT: dmb 398; CHECK-BAREMETAL: str r1, [r0] 399; CHECK-BAREMETAL-NOT: dmb 400; CHECK-BAREMETAL: str r3, [r2] 401 402 ret void 403} 404 405define void @load_fence_store_monotonic(ptr %mem1, ptr %mem2) { 406; CHECK-LABEL: load_fence_store_monotonic 407 %val = load atomic i32, ptr %mem1 monotonic, align 4 408 fence seq_cst 409 store atomic i32 %val, ptr %mem2 monotonic, align 4 410 411; CHECK: ldr [[R0:r[0-9]]], [r0] 412; CHECK: dmb 413; CHECK: str [[R0]], [r1] 414 415; CHECK-T1-M0: __atomic_load_4 416; CHECK-T1-M0: dmb 417; CHECK-T1-M0: __atomic_store_4 418 419; CHECK-T1: ldr [[R0:r[0-9]]], [{{r[0-9]+}}] 420; CHECK-T1: {{dmb|bl ___sync_synchronize}} 421; CHECK-T1: str [[R0]], [{{r[0-9]+}}] 422 423; CHECK-BAREMETAL: ldr [[R0:r[0-9]]], [r0] 424; CHECK-BAREMETAL-NOT: dmb 425; CHECK-BAREMETAL: str [[R0]], [r1] 426 427 ret void 428} 429