1; Test subtractions between an i64 and a sign-extended i16 on z14. 2; 3; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z14 | FileCheck %s 4 5declare i64 @foo() 6 7; Check SGH with no displacement. 8define zeroext i1 @f1(i64 %dummy, i64 %a, i16 *%src, i64 *%res) { 9; CHECK-LABEL: f1: 10; CHECK: sgh %r3, 0(%r4) 11; CHECK-DAG: stg %r3, 0(%r5) 12; CHECK-DAG: lghi %r2, 0 13; CHECK-DAG: locghio %r2, 1 14; CHECK: br %r14 15 %half = load i16, i16 *%src 16 %b = sext i16 %half to i64 17 %t = call {i64, i1} @llvm.ssub.with.overflow.i64(i64 %a, i64 %b) 18 %val = extractvalue {i64, i1} %t, 0 19 %obit = extractvalue {i64, i1} %t, 1 20 store i64 %val, i64 *%res 21 ret i1 %obit 22} 23 24; Check the high end of the aligned SGH range. 25define zeroext i1 @f4(i64 %dummy, i64 %a, i16 *%src, i64 *%res) { 26; CHECK-LABEL: f4: 27; CHECK: sgh %r3, 524286(%r4) 28; CHECK-DAG: stg %r3, 0(%r5) 29; CHECK-DAG: lghi %r2, 0 30; CHECK-DAG: locghio %r2, 1 31; CHECK: br %r14 32 %ptr = getelementptr i16, i16 *%src, i64 262143 33 %half = load i16, i16 *%ptr 34 %b = sext i16 %half to i64 35 %t = call {i64, i1} @llvm.ssub.with.overflow.i64(i64 %a, i64 %b) 36 %val = extractvalue {i64, i1} %t, 0 37 %obit = extractvalue {i64, i1} %t, 1 38 store i64 %val, i64 *%res 39 ret i1 %obit 40} 41 42; Check the next halfword up, which needs separate address logic. 43; Other sequences besides this one would be OK. 44define zeroext i1 @f5(i64 %dummy, i64 %a, i16 *%src, i64 *%res) { 45; CHECK-LABEL: f5: 46; CHECK: agfi %r4, 524288 47; CHECK: sgh %r3, 0(%r4) 48; CHECK-DAG: stg %r3, 0(%r5) 49; CHECK-DAG: lghi %r2, 0 50; CHECK-DAG: locghio %r2, 1 51; CHECK: br %r14 52 %ptr = getelementptr i16, i16 *%src, i64 262144 53 %half = load i16, i16 *%ptr 54 %b = sext i16 %half to i64 55 %t = call {i64, i1} @llvm.ssub.with.overflow.i64(i64 %a, i64 %b) 56 %val = extractvalue {i64, i1} %t, 0 57 %obit = extractvalue {i64, i1} %t, 1 58 store i64 %val, i64 *%res 59 ret i1 %obit 60} 61 62; Check the high end of the negative aligned SGH range. 63define zeroext i1 @f6(i64 %dummy, i64 %a, i16 *%src, i64 *%res) { 64; CHECK-LABEL: f6: 65; CHECK: sgh %r3, -2(%r4) 66; CHECK-DAG: stg %r3, 0(%r5) 67; CHECK-DAG: lghi %r2, 0 68; CHECK-DAG: locghio %r2, 1 69; CHECK: br %r14 70 %ptr = getelementptr i16, i16 *%src, i64 -1 71 %half = load i16, i16 *%ptr 72 %b = sext i16 %half to i64 73 %t = call {i64, i1} @llvm.ssub.with.overflow.i64(i64 %a, i64 %b) 74 %val = extractvalue {i64, i1} %t, 0 75 %obit = extractvalue {i64, i1} %t, 1 76 store i64 %val, i64 *%res 77 ret i1 %obit 78} 79 80; Check the low end of the SGH range. 81define zeroext i1 @f7(i64 %dummy, i64 %a, i16 *%src, i64 *%res) { 82; CHECK-LABEL: f7: 83; CHECK: sgh %r3, -524288(%r4) 84; CHECK-DAG: stg %r3, 0(%r5) 85; CHECK-DAG: lghi %r2, 0 86; CHECK-DAG: locghio %r2, 1 87; CHECK: br %r14 88 %ptr = getelementptr i16, i16 *%src, i64 -262144 89 %half = load i16, i16 *%ptr 90 %b = sext i16 %half to i64 91 %t = call {i64, i1} @llvm.ssub.with.overflow.i64(i64 %a, i64 %b) 92 %val = extractvalue {i64, i1} %t, 0 93 %obit = extractvalue {i64, i1} %t, 1 94 store i64 %val, i64 *%res 95 ret i1 %obit 96} 97 98; Check the next halfword down, which needs separate address logic. 99; Other sequences besides this one would be OK. 100define zeroext i1 @f8(i64 %dummy, i64 %a, i16 *%src, i64 *%res) { 101; CHECK-LABEL: f8: 102; CHECK: agfi %r4, -524290 103; CHECK: sgh %r3, 0(%r4) 104; CHECK-DAG: stg %r3, 0(%r5) 105; CHECK-DAG: lghi %r2, 0 106; CHECK-DAG: locghio %r2, 1 107; CHECK: br %r14 108 %ptr = getelementptr i16, i16 *%src, i64 -262145 109 %half = load i16, i16 *%ptr 110 %b = sext i16 %half to i64 111 %t = call {i64, i1} @llvm.ssub.with.overflow.i64(i64 %a, i64 %b) 112 %val = extractvalue {i64, i1} %t, 0 113 %obit = extractvalue {i64, i1} %t, 1 114 store i64 %val, i64 *%res 115 ret i1 %obit 116} 117 118; Check that SGH allows an index. 119define zeroext i1 @f9(i64 %src, i64 %index, i64 %a, i64 *%res) { 120; CHECK-LABEL: f9: 121; CHECK: sgh %r4, 524284({{%r3,%r2|%r2,%r3}}) 122; CHECK-DAG: stg %r4, 0(%r5) 123; CHECK-DAG: lghi %r2, 0 124; CHECK-DAG: locghio %r2, 1 125; CHECK: br %r14 126 %add1 = add i64 %src, %index 127 %add2 = add i64 %add1, 524284 128 %ptr = inttoptr i64 %add2 to i16 * 129 %half = load i16, i16 *%ptr 130 %b = sext i16 %half to i64 131 %t = call {i64, i1} @llvm.ssub.with.overflow.i64(i64 %a, i64 %b) 132 %val = extractvalue {i64, i1} %t, 0 133 %obit = extractvalue {i64, i1} %t, 1 134 store i64 %val, i64 *%res 135 ret i1 %obit 136} 137 138; Check using the overflow result for a branch. 139define void @f11(i64 %dummy, i64 %a, i16 *%src, i64 *%res) { 140; CHECK-LABEL: f11: 141; CHECK: sgh %r3, 0(%r4) 142; CHECK: stg %r3, 0(%r5) 143; CHECK: jgo foo@PLT 144; CHECK: br %r14 145 %half = load i16, i16 *%src 146 %b = sext i16 %half to i64 147 %t = call {i64, i1} @llvm.ssub.with.overflow.i64(i64 %a, i64 %b) 148 %val = extractvalue {i64, i1} %t, 0 149 %obit = extractvalue {i64, i1} %t, 1 150 store i64 %val, i64 *%res 151 br i1 %obit, label %call, label %exit 152 153call: 154 tail call i64 @foo() 155 br label %exit 156 157exit: 158 ret void 159} 160 161; ... and the same with the inverted direction. 162define void @f12(i64 %dummy, i64 %a, i16 *%src, i64 *%res) { 163; CHECK-LABEL: f12: 164; CHECK: sgh %r3, 0(%r4) 165; CHECK: stg %r3, 0(%r5) 166; CHECK: jgno foo@PLT 167; CHECK: br %r14 168 %half = load i16, i16 *%src 169 %b = sext i16 %half to i64 170 %t = call {i64, i1} @llvm.ssub.with.overflow.i64(i64 %a, i64 %b) 171 %val = extractvalue {i64, i1} %t, 0 172 %obit = extractvalue {i64, i1} %t, 1 173 store i64 %val, i64 *%res 174 br i1 %obit, label %exit, label %call 175 176call: 177 tail call i64 @foo() 178 br label %exit 179 180exit: 181 ret void 182} 183 184 185declare {i64, i1} @llvm.ssub.with.overflow.i64(i64, i64) nounwind readnone 186 187