1/*  This file contains the exception-handling save_world and
2 *  restore_world routines, which need to do a run-time check to see if
3 *  they should save and restore the vector registers.
4 *
5 *   Copyright (C) 2004-2020 Free Software Foundation, Inc.
6 *
7 * This file is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 3, or (at your option) any
10 * later version.
11 *
12 * This file is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * General Public License for more details.
16 *
17 * Under Section 7 of GPL version 3, you are granted additional
18 * permissions described in the GCC Runtime Library Exception, version
19 * 3.1, as published by the Free Software Foundation.
20 *
21 * You should have received a copy of the GNU General Public License and
22 * a copy of the GCC Runtime Library Exception along with this program;
23 * see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24 * <http://www.gnu.org/licenses/>.
25 */
26
27#ifndef __ppc64__
28
29	.machine ppc7400
30.data
31	.align 2
32
33#ifdef __DYNAMIC__
34
35.non_lazy_symbol_pointer
36L_has_vec$non_lazy_ptr:
37	.indirect_symbol __cpu_has_altivec
38	.long	0
39#else
40
41/* For static, "pretend" we have a non-lazy-pointer.  */
42
43L_has_vec$non_lazy_ptr:
44	.long __cpu_has_altivec
45
46#endif
47
48
49.text
50	.align 2
51
52/* save_world and rest_world save/restore F14-F31 and possibly V20-V31
53   (assuming you have a CPU with vector registers; we use a global var
54   provided by the System Framework to determine this.)
55
56   SAVE_WORLD takes R0 (the caller`s caller`s return address) and R11
57   (the stack frame size) as parameters.  It returns the updated VRsave
58   in R0 if we`re on a CPU with vector regs.
59
60   For gcc3 onward, we need to save and restore CR as well, since scheduled
61   prologs can cause comparisons to be moved before calls to save_world.
62
63   USES: R0 R11 R12  */
64
65.private_extern save_world
66save_world:
67	stw r0,8(r1)
68	mflr r0
69	bcl 20,31,Ls$pb
70Ls$pb:	mflr r12
71	addis r12,r12,ha16(L_has_vec$non_lazy_ptr-Ls$pb)
72	lwz r12,lo16(L_has_vec$non_lazy_ptr-Ls$pb)(r12)
73	mtlr r0
74	lwz r12,0(r12)
75				/* grab CR  */
76	mfcr r0
77				/* test HAS_VEC  */
78	cmpwi r12,0
79	stfd f14,-144(r1)
80	stfd f15,-136(r1)
81	stfd f16,-128(r1)
82	stfd f17,-120(r1)
83	stfd f18,-112(r1)
84	stfd f19,-104(r1)
85	stfd f20,-96(r1)
86	stfd f21,-88(r1)
87	stfd f22,-80(r1)
88	stfd f23,-72(r1)
89	stfd f24,-64(r1)
90	stfd f25,-56(r1)
91	stfd f26,-48(r1)
92	stfd f27,-40(r1)
93	stfd f28,-32(r1)
94	stfd f29,-24(r1)
95	stfd f30,-16(r1)
96	stfd f31,-8(r1)
97	stmw r13,-220(r1)
98				/* stash CR  */
99	stw r0,4(r1)
100				/* set R12 pointing at Vector Reg save area  */
101	addi r12,r1,-224
102				/* allocate stack frame  */
103	stwux r1,r1,r11
104				/* ...but return if HAS_VEC is zero   */
105	bne+ L$saveVMX
106				/* Not forgetting to restore CR.  */
107	mtcr r0
108	blr
109
110L$saveVMX:
111				/* We're saving Vector regs too.  */
112				/* Restore CR from R0.  No More Branches!  */
113	mtcr r0
114
115	/* We should really use VRSAVE to figure out which vector regs
116	   we actually need to save and restore.  Some other time :-/  */
117
118	li r11,-192
119	stvx v20,r11,r12
120	li r11,-176
121	stvx v21,r11,r12
122	li r11,-160
123	stvx v22,r11,r12
124	li r11,-144
125	stvx v23,r11,r12
126	li r11,-128
127	stvx v24,r11,r12
128	li r11,-112
129	stvx v25,r11,r12
130	li r11,-96
131	stvx v26,r11,r12
132	li r11,-80
133	stvx v27,r11,r12
134	li r11,-64
135	stvx v28,r11,r12
136	li r11,-48
137	stvx v29,r11,r12
138	li r11,-32
139	stvx v30,r11,r12
140	mfspr r0,VRsave
141	li r11,-16
142	stvx v31,r11,r12
143	stw r0,0(r12)		/* VRsave lives at -224(R1).  */
144	ori r0,r0,0xfff		/* We just saved these.  */
145	mtspr VRsave,r0
146	blr
147
148/* rest_world  is jumped to, not called, so no need to worry about LR.
149   clobbers R0, R7, R11 and R12.  This just undoes the work done above.  */
150
151	.private_extern rest_world
152rest_world:
153
154	lwz r11, 0(r1)		/* Pickup previous SP  */
155	li r7, 0		/* Stack offset is zero, r10 is ignored.  */
156	b Lrest_world_eh_r7
157
158/* eh_rest_world_r10 is jumped to, not called, so no need to worry about LR.
159   R10 is the C++ EH stack adjust parameter, we return to the caller`s caller.
160
161   clobbers: R0, R7, R11 and R12
162   uses    : R10
163   RETURNS : C++ EH Data registers (R3 - R6).  */
164
165	.private_extern eh_rest_world_r10
166eh_rest_world_r10:
167
168	lwz r11, 0(r1)		/* Pickup previous SP  */
169	mr  r7,r10		/* Stack offset.  */
170
171	/* pickup the C++ EH data regs (R3 - R6.)  */
172	lwz r6,-420(r11)
173	lwz r5,-424(r11)
174	lwz r4,-428(r11)
175	lwz r3,-432(r11)
176
177	/* Fall through to Lrest_world_eh_r7.  */
178
179/* When we are doing the exception-handling epilog, R7 contains the offset to
180   add to the SP.
181
182   clobbers: R0, R11 and R12
183   uses    : R7.  */
184
185Lrest_world_eh_r7:
186	/* See if we have Altivec.  */
187	bcl 20,31,Lr7$pb
188Lr7$pb: mflr r12
189
190	addis r12,r12,ha16(L_has_vec$non_lazy_ptr-Lr7$pb)
191	lwz r12,lo16(L_has_vec$non_lazy_ptr-Lr7$pb)(r12)
192	lwz r12,0(r12)		/* R12 := HAS_VEC  */
193	cmpwi r12,0
194	lmw r13,-220(r11)
195	beq L.rest_world_fp_eh
196
197	/* We have Altivec, restore VRsave and V20..V31  */
198	lwz r0,-224(r11)
199	li r12,-416
200	mtspr VRsave,r0
201	lvx v20,r11,r12
202	li r12,-400
203	lvx v21,r11,r12
204	li r12,-384
205	lvx v22,r11,r12
206	li r12,-368
207	lvx v23,r11,r12
208	li r12,-352
209	lvx v24,r11,r12
210	li r12,-336
211	lvx v25,r11,r12
212	li r12,-320
213	lvx v26,r11,r12
214	li r12,-304
215	lvx v27,r11,r12
216	li r12,-288
217	lvx v28,r11,r12
218	li r12,-272
219	lvx v29,r11,r12
220	li r12,-256
221	lvx v30,r11,r12
222	li r12,-240
223	lvx v31,r11,r12
224
225L.rest_world_fp_eh:
226	lwz r0,4(r11)		/* recover saved CR  */
227	lfd f14,-144(r11)
228	lfd f15,-136(r11)
229	lfd f16,-128(r11)
230	lfd f17,-120(r11)
231	lfd f18,-112(r11)
232	lfd f19,-104(r11)
233	lfd f20,-96(r11)
234	lfd f21,-88(r11)
235	lfd f22,-80(r11)
236	lfd f23,-72(r11)
237	lfd f24,-64(r11)
238	lfd f25,-56(r11)
239	lfd f26,-48(r11)
240	lfd f27,-40(r11)
241	lfd f28,-32(r11)
242	lfd f29,-24(r11)
243	lfd f30,-16(r11)
244	mtcr r0			/* restore the saved cr.  */
245	lwz r0, 8(r11)		/* Pick up the 'real' return address.  */
246	lfd f31,-8(r11)
247	mtctr r0		/* exception-handler ret. address  */
248	add r1,r11,r7		/* set SP to original value + R7 offset  */
249	bctr
250#endif
251/* we should never be called on ppc64 for this ... */
252/* Done.  */
253