1 ; Test subtractions between an i64 and a sign-extended i16 on z14.
3 ; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z14 | FileCheck %s
7 ; Check SGH with no displacement.
8 define zeroext i1 @f1(i64 %dummy, i64 %a, ptr %src, ptr %res) {
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
15 %half = load i16, ptr %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, ptr %res
24 ; Check the high end of the aligned SGH range.
25 define zeroext i1 @f4(i64 %dummy, i64 %a, ptr %src, ptr %res) {
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
32 %ptr = getelementptr i16, ptr %src, i64 262143
33 %half = load i16, ptr %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, ptr %res
42 ; Check the next halfword up, which needs separate address logic.
43 ; Other sequences besides this one would be OK.
44 define zeroext i1 @f5(i64 %dummy, i64 %a, ptr %src, ptr %res) {
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
52 %ptr = getelementptr i16, ptr %src, i64 262144
53 %half = load i16, ptr %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, ptr %res
62 ; Check the high end of the negative aligned SGH range.
63 define zeroext i1 @f6(i64 %dummy, i64 %a, ptr %src, ptr %res) {
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
70 %ptr = getelementptr i16, ptr %src, i64 -1
71 %half = load i16, ptr %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, ptr %res
80 ; Check the low end of the SGH range.
81 define zeroext i1 @f7(i64 %dummy, i64 %a, ptr %src, ptr %res) {
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
88 %ptr = getelementptr i16, ptr %src, i64 -262144
89 %half = load i16, ptr %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, ptr %res
98 ; Check the next halfword down, which needs separate address logic.
99 ; Other sequences besides this one would be OK.
100 define zeroext i1 @f8(i64 %dummy, i64 %a, ptr %src, ptr %res) {
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
108 %ptr = getelementptr i16, ptr %src, i64 -262145
109 %half = load i16, ptr %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, ptr %res
118 ; Check that SGH allows an index.
119 define zeroext i1 @f9(i64 %src, i64 %index, i64 %a, ptr %res) {
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
126 %add1 = add i64 %src, %index
127 %add2 = add i64 %add1, 524284
128 %ptr = inttoptr i64 %add2 to ptr
129 %half = load i16, ptr %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, ptr %res
138 ; Check using the overflow result for a branch.
139 define void @f11(i64 %dummy, i64 %a, ptr %src, ptr %res) {
141 ; CHECK: sgh %r3, 0(%r4)
142 ; CHECK: stg %r3, 0(%r5)
145 %half = load i16, ptr %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, ptr %res
151 br i1 %obit, label %call, label %exit
161 ; ... and the same with the inverted direction.
162 define void @f12(i64 %dummy, i64 %a, ptr %src, ptr %res) {
164 ; CHECK: sgh %r3, 0(%r4)
165 ; CHECK: stg %r3, 0(%r5)
166 ; CHECK: jgno foo@PLT
168 %half = load i16, ptr %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, ptr %res
174 br i1 %obit, label %exit, label %call
185 declare {i64, i1} @llvm.ssub.with.overflow.i64(i64, i64) nounwind readnone