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 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 2, or (at your option) any
10 * later version.
11 * 
12 * In addition to the permissions in the GNU General Public License, the
13 * Free Software Foundation gives you unlimited permission to link the
14 * compiled version of this file with other programs, and to distribute
15 * those programs without any restriction coming from the use of this
16 * file.  (The General Public License restrictions do apply in other
17 * respects; for example, they cover modification of the file, and
18 * distribution when not linked into another program.)
19 * 
20 * This file is distributed in the hope that it will be useful, but
21 * WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23 * General Public License for more details.
24 * 
25 * You should have received a copy of the GNU General Public License
26 * along with this program; see the file COPYING.  If not, write to
27 * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
28 * Boston, MA 02110-1301, USA.
29 * 
30 *  As a special exception, if you link this library with files
31 *  compiled with GCC to produce an executable, this does not cause the
32 *  resulting executable to be covered by the GNU General Public License.
33 *  This exception does not however invalidate any other reasons why the
34 *  executable file might be covered by the GNU General Public License.
35 */ 
36
37	.machine ppc7400
38.data
39	.align 2
40
41#ifdef __DYNAMIC__
42
43.non_lazy_symbol_pointer
44L_has_vec$non_lazy_ptr:
45	.indirect_symbol __cpu_has_altivec
46#ifdef __ppc64__
47	.quad	0
48#else
49	.long	0
50#endif
51
52#else
53
54/* For static, "pretend" we have a non-lazy-pointer.  */
55
56L_has_vec$non_lazy_ptr:
57	.long __cpu_has_altivec
58
59#endif
60
61
62.text
63	.align 2
64
65/* save_world and rest_world save/restore F14-F31 and possibly V20-V31
66   (assuming you have a CPU with vector registers; we use a global var
67   provided by the System Framework to determine this.)
68
69   SAVE_WORLD takes R0 (the caller`s caller`s return address) and R11
70   (the stack frame size) as parameters.  It returns VRsave in R0 if
71   we`re on a CPU with vector regs.
72
73   With gcc3, we now need to save and restore CR as well, since gcc3's
74   scheduled prologs can cause comparisons to be moved before calls to
75   save_world!
76
77   USES: R0 R11 R12  */
78
79.private_extern save_world
80save_world:
81	stw r0,8(r1)
82	mflr r0
83	bcl 20,31,Ls$pb
84Ls$pb:	mflr r12
85	addis r12,r12,ha16(L_has_vec$non_lazy_ptr-Ls$pb)
86	lwz r12,lo16(L_has_vec$non_lazy_ptr-Ls$pb)(r12)
87	mtlr r0
88	lwz r12,0(r12)
89				/* grab CR  */
90	mfcr r0	
91				/* test HAS_VEC  */
92	cmpwi r12,0
93	stfd f14,-144(r1)
94	stfd f15,-136(r1)
95	stfd f16,-128(r1)
96	stfd f17,-120(r1)
97	stfd f18,-112(r1)
98	stfd f19,-104(r1)
99	stfd f20,-96(r1)
100	stfd f21,-88(r1)
101	stfd f22,-80(r1)
102	stfd f23,-72(r1)
103	stfd f24,-64(r1)
104	stfd f25,-56(r1)
105	stfd f26,-48(r1)
106	stfd f27,-40(r1)
107	stfd f28,-32(r1)
108	stfd f29,-24(r1)
109	stfd f30,-16(r1)
110	stfd f31,-8(r1)
111	stmw r13,-220(r1)
112				/* stash CR  */
113	stw r0,4(r1)
114				/* set R12 pointing at Vector Reg save area  */
115	addi r12,r1,-224
116				/* allocate stack frame  */
117	stwux r1,r1,r11
118				/* ...but return if HAS_VEC is zero   */
119	bne+ L$saveVMX
120				/* Not forgetting to restore CR.  */
121	mtcr r0
122	blr
123
124L$saveVMX:
125				/* We're saving Vector regs too.  */
126				/* Restore CR from R0.  No More Branches!  */
127	mtcr r0
128
129	/* We should really use VRSAVE to figure out which vector regs
130	   we actually need to save and restore.  Some other time :-/  */
131
132	li r11,-192
133	stvx v20,r11,r12
134	li r11,-176
135	stvx v21,r11,r12
136	li r11,-160
137	stvx v22,r11,r12
138	li r11,-144
139	stvx v23,r11,r12
140	li r11,-128
141	stvx v24,r11,r12
142	li r11,-112
143	stvx v25,r11,r12
144	li r11,-96
145	stvx v26,r11,r12
146	li r11,-80
147	stvx v27,r11,r12
148	li r11,-64
149	stvx v28,r11,r12
150	li r11,-48
151	stvx v29,r11,r12
152	li r11,-32
153	stvx v30,r11,r12
154	mfspr r0,VRsave
155	li r11,-16
156	stvx v31,r11,r12
157				/* VRsave lives at -224(R1)  */
158	stw r0,0(r12)
159	blr
160
161
162/* eh_rest_world_r10 is jumped to, not called, so no need to worry about LR.
163   R10 is the C++ EH stack adjust parameter, we return to the caller`s caller.
164
165   USES: R0 R10 R11 R12   and R7 R8
166   RETURNS: C++ EH Data registers (R3 - R6.)
167
168   We now set up R7/R8 and jump to rest_world_eh_r7r8.
169
170   rest_world doesn't use the R10 stack adjust parameter, nor does it
171   pick up the R3-R6 exception handling stuff.  */
172
173.private_extern rest_world
174rest_world:
175				/* Pickup previous SP  */
176	lwz r11, 0(r1)
177	li r7, 0
178	lwz r8, 8(r11)
179	li r10, 0
180	b rest_world_eh_r7r8
181
182.private_extern eh_rest_world_r10
183eh_rest_world_r10:
184				/* Pickup previous SP  */
185	lwz r11, 0(r1)
186	mr  r7,r10
187	lwz r8, 8(r11)
188			/* pickup the C++ EH data regs (R3 - R6.)  */
189	lwz r6,-420(r11)
190	lwz r5,-424(r11)
191	lwz r4,-428(r11)
192	lwz r3,-432(r11)
193
194	b rest_world_eh_r7r8
195
196/* rest_world_eh_r7r8 is jumped to -- not called! -- when we're doing
197   the exception-handling epilog.  R7 contains the offset to add to
198   the SP, and R8 contains the 'real' return address.
199
200   USES: R0 R11 R12  [R7/R8]
201   RETURNS: C++ EH Data registers (R3 - R6.)  */
202
203rest_world_eh_r7r8:
204	bcl 20,31,Lr7r8$pb
205Lr7r8$pb: mflr r12
206	lwz r11,0(r1)
207				/* R11 := previous SP  */
208	addis r12,r12,ha16(L_has_vec$non_lazy_ptr-Lr7r8$pb)
209	lwz r12,lo16(L_has_vec$non_lazy_ptr-Lr7r8$pb)(r12)
210	lwz r0,4(r11)
211				/* R0 := old CR  */
212	lwz r12,0(r12)
213				/* R12 := HAS_VEC  */
214	mtcr r0	
215	cmpwi r12,0
216	lmw r13,-220(r11)
217	beq L.rest_world_fp_eh
218				/* restore VRsave and V20..V31  */
219	lwz r0,-224(r11)
220	li r12,-416
221	mtspr VRsave,r0
222	lvx v20,r11,r12
223	li r12,-400
224	lvx v21,r11,r12
225	li r12,-384
226	lvx v22,r11,r12
227	li r12,-368
228	lvx v23,r11,r12
229	li r12,-352
230	lvx v24,r11,r12
231	li r12,-336
232	lvx v25,r11,r12
233	li r12,-320
234	lvx v26,r11,r12
235	li r12,-304
236	lvx v27,r11,r12
237	li r12,-288
238	lvx v28,r11,r12
239	li r12,-272
240	lvx v29,r11,r12
241	li r12,-256
242	lvx v30,r11,r12
243	li r12,-240
244	lvx v31,r11,r12
245
246L.rest_world_fp_eh:
247	lfd f14,-144(r11)
248	lfd f15,-136(r11)
249	lfd f16,-128(r11)
250	lfd f17,-120(r11)
251	lfd f18,-112(r11)
252	lfd f19,-104(r11)
253	lfd f20,-96(r11)
254	lfd f21,-88(r11)
255	lfd f22,-80(r11)
256	lfd f23,-72(r11)
257	lfd f24,-64(r11)
258	lfd f25,-56(r11)
259	lfd f26,-48(r11)
260	lfd f27,-40(r11)
261	lfd f28,-32(r11)
262	lfd f29,-24(r11)
263	lfd f30,-16(r11)
264			/* R8 is the exception-handler's address  */
265	mtctr r8
266	lfd f31,-8(r11)
267			/* set SP to original value + R7 offset  */
268	add r1,r11,r7
269	bctr
270