1; Test 32-bit compare and swap. 2; 3; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s 4 5; Check the low end of the CS range. 6define i32 @f1(i32 %cmp, i32 %swap, i32 *%src) { 7; CHECK-LABEL: f1: 8; CHECK: cs %r2, %r3, 0(%r4) 9; CHECK: br %r14 10 %pair = cmpxchg i32 *%src, i32 %cmp, i32 %swap seq_cst seq_cst 11 %val = extractvalue { i32, i1 } %pair, 0 12 ret i32 %val 13} 14 15; Check the high end of the aligned CS range. 16define i32 @f2(i32 %cmp, i32 %swap, i32 *%src) { 17; CHECK-LABEL: f2: 18; CHECK: cs %r2, %r3, 4092(%r4) 19; CHECK: br %r14 20 %ptr = getelementptr i32, i32 *%src, i64 1023 21 %pair = cmpxchg i32 *%ptr, i32 %cmp, i32 %swap seq_cst seq_cst 22 %val = extractvalue { i32, i1 } %pair, 0 23 ret i32 %val 24} 25 26; Check the next word up, which should use CSY instead of CS. 27define i32 @f3(i32 %cmp, i32 %swap, i32 *%src) { 28; CHECK-LABEL: f3: 29; CHECK: csy %r2, %r3, 4096(%r4) 30; CHECK: br %r14 31 %ptr = getelementptr i32, i32 *%src, i64 1024 32 %pair = cmpxchg i32 *%ptr, i32 %cmp, i32 %swap seq_cst seq_cst 33 %val = extractvalue { i32, i1 } %pair, 0 34 ret i32 %val 35} 36 37; Check the high end of the aligned CSY range. 38define i32 @f4(i32 %cmp, i32 %swap, i32 *%src) { 39; CHECK-LABEL: f4: 40; CHECK: csy %r2, %r3, 524284(%r4) 41; CHECK: br %r14 42 %ptr = getelementptr i32, i32 *%src, i64 131071 43 %pair = cmpxchg i32 *%ptr, i32 %cmp, i32 %swap seq_cst seq_cst 44 %val = extractvalue { i32, i1 } %pair, 0 45 ret i32 %val 46} 47 48; Check the next word up, which needs separate address logic. 49; Other sequences besides this one would be OK. 50define i32 @f5(i32 %cmp, i32 %swap, i32 *%src) { 51; CHECK-LABEL: f5: 52; CHECK: agfi %r4, 524288 53; CHECK: cs %r2, %r3, 0(%r4) 54; CHECK: br %r14 55 %ptr = getelementptr i32, i32 *%src, i64 131072 56 %pair = cmpxchg i32 *%ptr, i32 %cmp, i32 %swap seq_cst seq_cst 57 %val = extractvalue { i32, i1 } %pair, 0 58 ret i32 %val 59} 60 61; Check the high end of the negative aligned CSY range. 62define i32 @f6(i32 %cmp, i32 %swap, i32 *%src) { 63; CHECK-LABEL: f6: 64; CHECK: csy %r2, %r3, -4(%r4) 65; CHECK: br %r14 66 %ptr = getelementptr i32, i32 *%src, i64 -1 67 %pair = cmpxchg i32 *%ptr, i32 %cmp, i32 %swap seq_cst seq_cst 68 %val = extractvalue { i32, i1 } %pair, 0 69 ret i32 %val 70} 71 72; Check the low end of the CSY range. 73define i32 @f7(i32 %cmp, i32 %swap, i32 *%src) { 74; CHECK-LABEL: f7: 75; CHECK: csy %r2, %r3, -524288(%r4) 76; CHECK: br %r14 77 %ptr = getelementptr i32, i32 *%src, i64 -131072 78 %pair = cmpxchg i32 *%ptr, i32 %cmp, i32 %swap seq_cst seq_cst 79 %val = extractvalue { i32, i1 } %pair, 0 80 ret i32 %val 81} 82 83; Check the next word down, which needs separate address logic. 84; Other sequences besides this one would be OK. 85define i32 @f8(i32 %cmp, i32 %swap, i32 *%src) { 86; CHECK-LABEL: f8: 87; CHECK: agfi %r4, -524292 88; CHECK: cs %r2, %r3, 0(%r4) 89; CHECK: br %r14 90 %ptr = getelementptr i32, i32 *%src, i64 -131073 91 %pair = cmpxchg i32 *%ptr, i32 %cmp, i32 %swap seq_cst seq_cst 92 %val = extractvalue { i32, i1 } %pair, 0 93 ret i32 %val 94} 95 96; Check that CS does not allow an index. 97define i32 @f9(i32 %cmp, i32 %swap, i64 %src, i64 %index) { 98; CHECK-LABEL: f9: 99; CHECK: agr %r4, %r5 100; CHECK: cs %r2, %r3, 0(%r4) 101; CHECK: br %r14 102 %add1 = add i64 %src, %index 103 %ptr = inttoptr i64 %add1 to i32 * 104 %pair = cmpxchg i32 *%ptr, i32 %cmp, i32 %swap seq_cst seq_cst 105 %val = extractvalue { i32, i1 } %pair, 0 106 ret i32 %val 107} 108 109; Check that CSY does not allow an index. 110define i32 @f10(i32 %cmp, i32 %swap, i64 %src, i64 %index) { 111; CHECK-LABEL: f10: 112; CHECK: agr %r4, %r5 113; CHECK: csy %r2, %r3, 4096(%r4) 114; CHECK: br %r14 115 %add1 = add i64 %src, %index 116 %add2 = add i64 %add1, 4096 117 %ptr = inttoptr i64 %add2 to i32 * 118 %pair = cmpxchg i32 *%ptr, i32 %cmp, i32 %swap seq_cst seq_cst 119 %val = extractvalue { i32, i1 } %pair, 0 120 ret i32 %val 121} 122 123; Check that a constant %cmp value is loaded into a register first. 124define i32 @f11(i32 %dummy, i32 %swap, i32 *%ptr) { 125; CHECK-LABEL: f11: 126; CHECK: lhi %r2, 1001 127; CHECK: cs %r2, %r3, 0(%r4) 128; CHECK: br %r14 129 %pair = cmpxchg i32 *%ptr, i32 1001, i32 %swap seq_cst seq_cst 130 %val = extractvalue { i32, i1 } %pair, 0 131 ret i32 %val 132} 133 134; Check that a constant %swap value is loaded into a register first. 135define i32 @f12(i32 %cmp, i32 *%ptr) { 136; CHECK-LABEL: f12: 137; CHECK: lhi [[SWAP:%r[0-9]+]], 1002 138; CHECK: cs %r2, [[SWAP]], 0(%r3) 139; CHECK: br %r14 140 %pair = cmpxchg i32 *%ptr, i32 %cmp, i32 1002 seq_cst seq_cst 141 %val = extractvalue { i32, i1 } %pair, 0 142 ret i32 %val 143} 144 145; Check generating the comparison result. 146; CHECK-LABEL: f13 147; CHECK: cs %r2, %r3, 0(%r4) 148; CHECK-NEXT: ipm %r2 149; CHECK-NEXT: afi %r2, -268435456 150; CHECK-NEXT: srl %r2, 31 151; CHECK: br %r14 152define i32 @f13(i32 %cmp, i32 %swap, i32 *%src) { 153 %pairval = cmpxchg i32 *%src, i32 %cmp, i32 %swap seq_cst seq_cst 154 %val = extractvalue { i32, i1 } %pairval, 1 155 %res = zext i1 %val to i32 156 ret i32 %res 157} 158 159declare void @g() 160 161; Check using the comparison result for a branch. 162; CHECK-LABEL: f14 163; CHECK: cs %r2, %r3, 0(%r4) 164; CHECK-NEXT: jge g 165; CHECK: br %r14 166define void @f14(i32 %cmp, i32 %swap, i32 *%src) { 167 %pairval = cmpxchg i32 *%src, i32 %cmp, i32 %swap seq_cst seq_cst 168 %cond = extractvalue { i32, i1 } %pairval, 1 169 br i1 %cond, label %call, label %exit 170 171call: 172 tail call void @g() 173 br label %exit 174 175exit: 176 ret void 177} 178 179; ... and the same with the inverted direction. 180; CHECK-LABEL: f15 181; CHECK: cs %r2, %r3, 0(%r4) 182; CHECK-NEXT: jgl g 183; CHECK: br %r14 184define void @f15(i32 %cmp, i32 %swap, i32 *%src) { 185 %pairval = cmpxchg i32 *%src, i32 %cmp, i32 %swap seq_cst seq_cst 186 %cond = extractvalue { i32, i1 } %pairval, 1 187 br i1 %cond, label %exit, label %call 188 189call: 190 tail call void @g() 191 br label %exit 192 193exit: 194 ret void 195} 196 197