1; Test saving and restoring of call-saved GPRs.
2;
3; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
4
5; This function should require all GPRs, but no other spill slots.  The caller
6; allocates room for the GPR save slots, so we shouldn't need to allocate any
7; extra space.
8;
9; The function only modifies the low 32 bits of each register, which in
10; itself would allow STM and LM to be used instead of STMG and LMG.
11; However, the ABI defines the offset of each register, so we always
12; use the 64-bit form.
13;
14; Use a different address for the final store, so that we can check that
15; %r15 isn't referenced again until after that.
16define void @f1(i32 *%ptr) {
17; CHECK-LABEL: f1:
18; CHECK: stmg %r6, %r15, 48(%r15)
19; CHECK-NOT: %r15
20; CHECK: .cfi_offset %r6, -112
21; CHECK: .cfi_offset %r7, -104
22; CHECK: .cfi_offset %r8, -96
23; CHECK: .cfi_offset %r9, -88
24; CHECK: .cfi_offset %r10, -80
25; CHECK: .cfi_offset %r11, -72
26; CHECK: .cfi_offset %r12, -64
27; CHECK: .cfi_offset %r13, -56
28; CHECK: .cfi_offset %r14, -48
29; CHECK: .cfi_offset %r15, -40
30; ...main function body...
31; CHECK-NOT: %r15
32; CHECK: st {{.*}}, 4(%r2)
33; CHECK: lmg %r6, %r15, 48(%r15)
34; CHECK: br %r14
35  %l0 = load volatile i32 *%ptr
36  %l1 = load volatile i32 *%ptr
37  %l3 = load volatile i32 *%ptr
38  %l4 = load volatile i32 *%ptr
39  %l5 = load volatile i32 *%ptr
40  %l6 = load volatile i32 *%ptr
41  %l7 = load volatile i32 *%ptr
42  %l8 = load volatile i32 *%ptr
43  %l9 = load volatile i32 *%ptr
44  %l10 = load volatile i32 *%ptr
45  %l11 = load volatile i32 *%ptr
46  %l12 = load volatile i32 *%ptr
47  %l13 = load volatile i32 *%ptr
48  %l14 = load volatile i32 *%ptr
49  %add0 = add i32 %l0, %l0
50  %add1 = add i32 %l1, %add0
51  %add3 = add i32 %l3, %add1
52  %add4 = add i32 %l4, %add3
53  %add5 = add i32 %l5, %add4
54  %add6 = add i32 %l6, %add5
55  %add7 = add i32 %l7, %add6
56  %add8 = add i32 %l8, %add7
57  %add9 = add i32 %l9, %add8
58  %add10 = add i32 %l10, %add9
59  %add11 = add i32 %l11, %add10
60  %add12 = add i32 %l12, %add11
61  %add13 = add i32 %l13, %add12
62  %add14 = add i32 %l14, %add13
63  store volatile i32 %add0, i32 *%ptr
64  store volatile i32 %add1, i32 *%ptr
65  store volatile i32 %add3, i32 *%ptr
66  store volatile i32 %add4, i32 *%ptr
67  store volatile i32 %add5, i32 *%ptr
68  store volatile i32 %add6, i32 *%ptr
69  store volatile i32 %add7, i32 *%ptr
70  store volatile i32 %add8, i32 *%ptr
71  store volatile i32 %add9, i32 *%ptr
72  store volatile i32 %add10, i32 *%ptr
73  store volatile i32 %add11, i32 *%ptr
74  store volatile i32 %add12, i32 *%ptr
75  store volatile i32 %add13, i32 *%ptr
76  %final = getelementptr i32 *%ptr, i32 1
77  store volatile i32 %add14, i32 *%final
78  ret void
79}
80
81; Like f1, but requires one fewer GPR.  We allocate the call-saved GPRs
82; from %r14 down, so that the STMG/LMG sequences aren't any longer than
83; they need to be.
84define void @f2(i32 *%ptr) {
85; CHECK-LABEL: f2:
86; CHECK: stmg %r7, %r15, 56(%r15)
87; CHECK-NOT: %r15
88; CHECK: .cfi_offset %r7, -104
89; CHECK: .cfi_offset %r8, -96
90; CHECK: .cfi_offset %r9, -88
91; CHECK: .cfi_offset %r10, -80
92; CHECK: .cfi_offset %r11, -72
93; CHECK: .cfi_offset %r12, -64
94; CHECK: .cfi_offset %r13, -56
95; CHECK: .cfi_offset %r14, -48
96; CHECK: .cfi_offset %r15, -40
97; ...main function body...
98; CHECK-NOT: %r15
99; CHECK-NOT: %r6
100; CHECK: st {{.*}}, 4(%r2)
101; CHECK: lmg %r7, %r15, 56(%r15)
102; CHECK: br %r14
103  %l0 = load volatile i32 *%ptr
104  %l1 = load volatile i32 *%ptr
105  %l3 = load volatile i32 *%ptr
106  %l4 = load volatile i32 *%ptr
107  %l5 = load volatile i32 *%ptr
108  %l7 = load volatile i32 *%ptr
109  %l8 = load volatile i32 *%ptr
110  %l9 = load volatile i32 *%ptr
111  %l10 = load volatile i32 *%ptr
112  %l11 = load volatile i32 *%ptr
113  %l12 = load volatile i32 *%ptr
114  %l13 = load volatile i32 *%ptr
115  %l14 = load volatile i32 *%ptr
116  %add0 = add i32 %l0, %l0
117  %add1 = add i32 %l1, %add0
118  %add3 = add i32 %l3, %add1
119  %add4 = add i32 %l4, %add3
120  %add5 = add i32 %l5, %add4
121  %add7 = add i32 %l7, %add5
122  %add8 = add i32 %l8, %add7
123  %add9 = add i32 %l9, %add8
124  %add10 = add i32 %l10, %add9
125  %add11 = add i32 %l11, %add10
126  %add12 = add i32 %l12, %add11
127  %add13 = add i32 %l13, %add12
128  %add14 = add i32 %l14, %add13
129  store volatile i32 %add0, i32 *%ptr
130  store volatile i32 %add1, i32 *%ptr
131  store volatile i32 %add3, i32 *%ptr
132  store volatile i32 %add4, i32 *%ptr
133  store volatile i32 %add5, i32 *%ptr
134  store volatile i32 %add7, i32 *%ptr
135  store volatile i32 %add8, i32 *%ptr
136  store volatile i32 %add9, i32 *%ptr
137  store volatile i32 %add10, i32 *%ptr
138  store volatile i32 %add11, i32 *%ptr
139  store volatile i32 %add12, i32 *%ptr
140  store volatile i32 %add13, i32 *%ptr
141  %final = getelementptr i32 *%ptr, i32 1
142  store volatile i32 %add14, i32 *%final
143  ret void
144}
145
146; Like f1, but only needs one call-saved GPR, which ought to be %r14.
147define void @f3(i32 *%ptr) {
148; CHECK-LABEL: f3:
149; CHECK: stmg %r14, %r15, 112(%r15)
150; CHECK-NOT: %r15
151; CHECK: .cfi_offset %r14, -48
152; CHECK: .cfi_offset %r15, -40
153; ...main function body...
154; CHECK-NOT: %r15
155; CHECK-NOT: %r6
156; CHECK-NOT: %r7
157; CHECK-NOT: %r8
158; CHECK-NOT: %r9
159; CHECK-NOT: %r10
160; CHECK-NOT: %r11
161; CHECK-NOT: %r12
162; CHECK-NOT: %r13
163; CHECK: st {{.*}}, 4(%r2)
164; CHECK: lmg %r14, %r15, 112(%r15)
165; CHECK: br %r14
166  %l0 = load volatile i32 *%ptr
167  %l1 = load volatile i32 *%ptr
168  %l3 = load volatile i32 *%ptr
169  %l4 = load volatile i32 *%ptr
170  %l5 = load volatile i32 *%ptr
171  %l14 = load volatile i32 *%ptr
172  %add0 = add i32 %l0, %l0
173  %add1 = add i32 %l1, %add0
174  %add3 = add i32 %l3, %add1
175  %add4 = add i32 %l4, %add3
176  %add5 = add i32 %l5, %add4
177  %add14 = add i32 %l14, %add5
178  store volatile i32 %add0, i32 *%ptr
179  store volatile i32 %add1, i32 *%ptr
180  store volatile i32 %add3, i32 *%ptr
181  store volatile i32 %add4, i32 *%ptr
182  store volatile i32 %add5, i32 *%ptr
183  %final = getelementptr i32 *%ptr, i32 1
184  store volatile i32 %add14, i32 *%final
185  ret void
186}
187
188; This function should use all call-clobbered GPRs but no call-saved ones.
189; It shouldn't need to touch the stack at all.
190define void @f4(i32 *%ptr) {
191; CHECK-LABEL: f4:
192; CHECK-NOT: %r15
193; CHECK-NOT: %r6
194; CHECK-NOT: %r7
195; CHECK-NOT: %r8
196; CHECK-NOT: %r9
197; CHECK-NOT: %r10
198; CHECK-NOT: %r11
199; CHECK-NOT: %r12
200; CHECK-NOT: %r13
201; CHECK: br %r14
202  %l0 = load volatile i32 *%ptr
203  %l1 = load volatile i32 *%ptr
204  %l3 = load volatile i32 *%ptr
205  %l4 = load volatile i32 *%ptr
206  %l5 = load volatile i32 *%ptr
207  %add0 = add i32 %l0, %l0
208  %add1 = add i32 %l1, %add0
209  %add3 = add i32 %l3, %add1
210  %add4 = add i32 %l4, %add3
211  %add5 = add i32 %l5, %add4
212  store volatile i32 %add0, i32 *%ptr
213  store volatile i32 %add1, i32 *%ptr
214  store volatile i32 %add3, i32 *%ptr
215  store volatile i32 %add4, i32 *%ptr
216  %final = getelementptr i32 *%ptr, i32 1
217  store volatile i32 %add5, i32 *%final
218  ret void
219}
220