1; RUN: llc -verify-machineinstrs -mtriple=armv7-linux-gnu -O0 %s -o - | FileCheck %s 2; RUN: llc -verify-machineinstrs -mtriple=thumbv8-linux-gnu -O0 %s -o - | FileCheck %s 3; RUN: llc -verify-machineinstrs -mtriple=thumbv6m-none-eabi -O0 %s -o - | FileCheck %s --check-prefix=CHECK-T1 4 5; CHECK-T1-NOT: ldrex 6; CHECK-T1-NOT: strex 7 8define { i8, i1 } @test_cmpxchg_8(i8* %addr, i8 %desired, i8 %new) nounwind { 9; CHECK-LABEL: test_cmpxchg_8: 10; CHECK: dmb ish 11; CHECK: uxtb [[DESIRED:r[0-9]+]], [[DESIRED]] 12; CHECK: [[RETRY:.LBB[0-9]+_[0-9]+]]: 13; CHECK: ldrexb [[OLD:r[0-9]+]], [r0] 14; CHECK: cmp [[OLD]], [[DESIRED]] 15; CHECK: bne [[DONE:.LBB[0-9]+_[0-9]+]] 16; CHECK: strexb [[STATUS:r[0-9]+]], r2, [r0] 17; CHECK: cmp{{(\.w)?}} [[STATUS]], #0 18; CHECK: bne [[RETRY]] 19; CHECK: [[DONE]]: 20; CHECK: cmp{{(\.w)?}} [[OLD]], [[DESIRED]] 21; CHECK: {{moveq|movweq}} {{r[0-9]+}}, #1 22; CHECK: dmb ish 23 %res = cmpxchg i8* %addr, i8 %desired, i8 %new seq_cst monotonic 24 ret { i8, i1 } %res 25} 26 27define { i16, i1 } @test_cmpxchg_16(i16* %addr, i16 %desired, i16 %new) nounwind { 28; CHECK-LABEL: test_cmpxchg_16: 29; CHECK: dmb ish 30; CHECK: uxth [[DESIRED:r[0-9]+]], [[DESIRED]] 31; CHECK: [[RETRY:.LBB[0-9]+_[0-9]+]]: 32; CHECK: ldrexh [[OLD:r[0-9]+]], [r0] 33; CHECK: cmp [[OLD]], [[DESIRED]] 34; CHECK: bne [[DONE:.LBB[0-9]+_[0-9]+]] 35; CHECK: strexh [[STATUS:r[0-9]+]], r2, [r0] 36; CHECK: cmp{{(\.w)?}} [[STATUS]], #0 37; CHECK: bne [[RETRY]] 38; CHECK: [[DONE]]: 39; CHECK: cmp{{(\.w)?}} [[OLD]], [[DESIRED]] 40; CHECK: {{moveq|movweq}} {{r[0-9]+}}, #1 41; CHECK: dmb ish 42 %res = cmpxchg i16* %addr, i16 %desired, i16 %new seq_cst monotonic 43 ret { i16, i1 } %res 44} 45 46define { i32, i1 } @test_cmpxchg_32(i32* %addr, i32 %desired, i32 %new) nounwind { 47; CHECK-LABEL: test_cmpxchg_32: 48; CHECK: dmb ish 49; CHECK-NOT: uxt 50; CHECK: [[RETRY:.LBB[0-9]+_[0-9]+]]: 51; CHECK: ldrex [[OLD:r[0-9]+]], [r0] 52; CHECK: cmp [[OLD]], [[DESIRED]] 53; CHECK: bne [[DONE:.LBB[0-9]+_[0-9]+]] 54; CHECK: strex [[STATUS:r[0-9]+]], r2, [r0] 55; CHECK: cmp{{(\.w)?}} [[STATUS]], #0 56; CHECK: bne [[RETRY]] 57; CHECK: [[DONE]]: 58; CHECK: cmp{{(\.w)?}} [[OLD]], [[DESIRED]] 59; CHECK: {{moveq|movweq}} {{r[0-9]+}}, #1 60; CHECK: dmb ish 61 %res = cmpxchg i32* %addr, i32 %desired, i32 %new seq_cst monotonic 62 ret { i32, i1 } %res 63} 64 65define { i64, i1 } @test_cmpxchg_64(i64* %addr, i64 %desired, i64 %new) nounwind { 66; CHECK-LABEL: test_cmpxchg_64: 67; CHECK: dmb ish 68; CHECK-NOT: uxt 69; CHECK: [[RETRY:.LBB[0-9]+_[0-9]+]]: 70; CHECK: ldrexd [[OLDLO:r[0-9]+]], [[OLDHI:r[0-9]+]], [r0] 71; CHECK: cmp [[OLDLO]], r6 72; CHECK: sbcs{{(\.w)?}} [[STATUS:r[0-9]+]], [[OLDHI]], r7 73; CHECK: bne [[DONE:.LBB[0-9]+_[0-9]+]] 74; CHECK: strexd [[STATUS]], r4, r5, [r0] 75; CHECK: cmp{{(\.w)?}} [[STATUS]], #0 76; CHECK: bne [[RETRY]] 77; CHECK: [[DONE]]: 78; CHECK: dmb ish 79 %res = cmpxchg i64* %addr, i64 %desired, i64 %new seq_cst monotonic 80 ret { i64, i1 } %res 81} 82 83define { i64, i1 } @test_nontrivial_args(i64* %addr, i64 %desired, i64 %new) { 84; CHECK-LABEL: test_nontrivial_args: 85; CHECK: dmb ish 86; CHECK-NOT: uxt 87; CHECK: [[RETRY:.LBB[0-9]+_[0-9]+]]: 88; CHECK: ldrexd [[OLDLO:r[0-9]+]], [[OLDHI:r[0-9]+]], [r0] 89; CHECK: cmp [[OLDLO]], {{r[0-9]+}} 90; CHECK: sbcs{{(\.w)?}} [[STATUS:r[0-9]+]], [[OLDHI]], {{r[0-9]+}} 91; CHECK: bne [[DONE:.LBB[0-9]+_[0-9]+]] 92; CHECK: strexd [[STATUS]], {{r[0-9]+}}, {{r[0-9]+}}, [r0] 93; CHECK: cmp{{(\.w)?}} [[STATUS]], #0 94; CHECK: bne [[RETRY]] 95; CHECK: [[DONE]]: 96; CHECK: dmb ish 97 98 %desired1 = add i64 %desired, 1 99 %new1 = add i64 %new, 1 100 %res = cmpxchg i64* %addr, i64 %desired1, i64 %new1 seq_cst seq_cst 101 ret { i64, i1 } %res 102} 103 104; The following used to trigger an assertion when creating a spill on thumb2 105; for a physreg with RC==GPRPairRegClass. 106; CHECK-LABEL: test_cmpxchg_spillbug: 107; CHECK: ldrexd 108; CHECK: strexd 109; CHECK: bne 110define void @test_cmpxchg_spillbug() { 111 %v = cmpxchg i64* undef, i64 undef, i64 undef seq_cst seq_cst 112 ret void 113} 114