1169689Skan/*  This file contains the exception-handling save_world and
2169689Skan *  restore_world routines, which need to do a run-time check to see if
3169689Skan *  they should save and restore the vector registers.
4169689Skan *
5169689Skan *   Copyright (C) 2004 Free Software Foundation, Inc.
6169689Skan * 
7169689Skan * This file is free software; you can redistribute it and/or modify it
8169689Skan * under the terms of the GNU General Public License as published by the
9169689Skan * Free Software Foundation; either version 2, or (at your option) any
10169689Skan * later version.
11169689Skan * 
12169689Skan * In addition to the permissions in the GNU General Public License, the
13169689Skan * Free Software Foundation gives you unlimited permission to link the
14169689Skan * compiled version of this file with other programs, and to distribute
15169689Skan * those programs without any restriction coming from the use of this
16169689Skan * file.  (The General Public License restrictions do apply in other
17169689Skan * respects; for example, they cover modification of the file, and
18169689Skan * distribution when not linked into another program.)
19169689Skan * 
20169689Skan * This file is distributed in the hope that it will be useful, but
21169689Skan * WITHOUT ANY WARRANTY; without even the implied warranty of
22169689Skan * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23169689Skan * General Public License for more details.
24169689Skan * 
25169689Skan * You should have received a copy of the GNU General Public License
26169689Skan * along with this program; see the file COPYING.  If not, write to
27169689Skan * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
28169689Skan * Boston, MA 02110-1301, USA.
29169689Skan * 
30169689Skan *  As a special exception, if you link this library with files
31169689Skan *  compiled with GCC to produce an executable, this does not cause the
32169689Skan *  resulting executable to be covered by the GNU General Public License.
33169689Skan *  This exception does not however invalidate any other reasons why the
34169689Skan *  executable file might be covered by the GNU General Public License.
35169689Skan */ 
36169689Skan
37169689Skan	.machine ppc7400
38169689Skan.data
39169689Skan	.align 2
40169689Skan
41169689Skan#ifdef __DYNAMIC__
42169689Skan
43169689Skan.non_lazy_symbol_pointer
44169689SkanL_has_vec$non_lazy_ptr:
45169689Skan	.indirect_symbol __cpu_has_altivec
46169689Skan#ifdef __ppc64__
47169689Skan	.quad	0
48169689Skan#else
49169689Skan	.long	0
50169689Skan#endif
51169689Skan
52169689Skan#else
53169689Skan
54169689Skan/* For static, "pretend" we have a non-lazy-pointer.  */
55169689Skan
56169689SkanL_has_vec$non_lazy_ptr:
57169689Skan	.long __cpu_has_altivec
58169689Skan
59169689Skan#endif
60169689Skan
61169689Skan
62169689Skan.text
63169689Skan	.align 2
64169689Skan
65169689Skan/* save_world and rest_world save/restore F14-F31 and possibly V20-V31
66169689Skan   (assuming you have a CPU with vector registers; we use a global var
67169689Skan   provided by the System Framework to determine this.)
68169689Skan
69169689Skan   SAVE_WORLD takes R0 (the caller`s caller`s return address) and R11
70169689Skan   (the stack frame size) as parameters.  It returns VRsave in R0 if
71169689Skan   we`re on a CPU with vector regs.
72169689Skan
73169689Skan   With gcc3, we now need to save and restore CR as well, since gcc3's
74169689Skan   scheduled prologs can cause comparisons to be moved before calls to
75169689Skan   save_world!
76169689Skan
77169689Skan   USES: R0 R11 R12  */
78169689Skan
79169689Skan.private_extern save_world
80169689Skansave_world:
81169689Skan	stw r0,8(r1)
82169689Skan	mflr r0
83169689Skan	bcl 20,31,Ls$pb
84169689SkanLs$pb:	mflr r12
85169689Skan	addis r12,r12,ha16(L_has_vec$non_lazy_ptr-Ls$pb)
86169689Skan	lwz r12,lo16(L_has_vec$non_lazy_ptr-Ls$pb)(r12)
87169689Skan	mtlr r0
88169689Skan	lwz r12,0(r12)
89169689Skan				/* grab CR  */
90169689Skan	mfcr r0	
91169689Skan				/* test HAS_VEC  */
92169689Skan	cmpwi r12,0
93169689Skan	stfd f14,-144(r1)
94169689Skan	stfd f15,-136(r1)
95169689Skan	stfd f16,-128(r1)
96169689Skan	stfd f17,-120(r1)
97169689Skan	stfd f18,-112(r1)
98169689Skan	stfd f19,-104(r1)
99169689Skan	stfd f20,-96(r1)
100169689Skan	stfd f21,-88(r1)
101169689Skan	stfd f22,-80(r1)
102169689Skan	stfd f23,-72(r1)
103169689Skan	stfd f24,-64(r1)
104169689Skan	stfd f25,-56(r1)
105169689Skan	stfd f26,-48(r1)
106169689Skan	stfd f27,-40(r1)
107169689Skan	stfd f28,-32(r1)
108169689Skan	stfd f29,-24(r1)
109169689Skan	stfd f30,-16(r1)
110169689Skan	stfd f31,-8(r1)
111169689Skan	stmw r13,-220(r1)
112169689Skan				/* stash CR  */
113169689Skan	stw r0,4(r1)
114169689Skan				/* set R12 pointing at Vector Reg save area  */
115169689Skan	addi r12,r1,-224
116169689Skan				/* allocate stack frame  */
117169689Skan	stwux r1,r1,r11
118169689Skan				/* ...but return if HAS_VEC is zero   */
119169689Skan	bne+ L$saveVMX
120169689Skan				/* Not forgetting to restore CR.  */
121169689Skan	mtcr r0
122169689Skan	blr
123169689Skan
124169689SkanL$saveVMX:
125169689Skan				/* We're saving Vector regs too.  */
126169689Skan				/* Restore CR from R0.  No More Branches!  */
127169689Skan	mtcr r0
128169689Skan
129169689Skan	/* We should really use VRSAVE to figure out which vector regs
130169689Skan	   we actually need to save and restore.  Some other time :-/  */
131169689Skan
132169689Skan	li r11,-192
133169689Skan	stvx v20,r11,r12
134169689Skan	li r11,-176
135169689Skan	stvx v21,r11,r12
136169689Skan	li r11,-160
137169689Skan	stvx v22,r11,r12
138169689Skan	li r11,-144
139169689Skan	stvx v23,r11,r12
140169689Skan	li r11,-128
141169689Skan	stvx v24,r11,r12
142169689Skan	li r11,-112
143169689Skan	stvx v25,r11,r12
144169689Skan	li r11,-96
145169689Skan	stvx v26,r11,r12
146169689Skan	li r11,-80
147169689Skan	stvx v27,r11,r12
148169689Skan	li r11,-64
149169689Skan	stvx v28,r11,r12
150169689Skan	li r11,-48
151169689Skan	stvx v29,r11,r12
152169689Skan	li r11,-32
153169689Skan	stvx v30,r11,r12
154169689Skan	mfspr r0,VRsave
155169689Skan	li r11,-16
156169689Skan	stvx v31,r11,r12
157169689Skan				/* VRsave lives at -224(R1)  */
158169689Skan	stw r0,0(r12)
159169689Skan	blr
160169689Skan
161169689Skan
162169689Skan/* eh_rest_world_r10 is jumped to, not called, so no need to worry about LR.
163169689Skan   R10 is the C++ EH stack adjust parameter, we return to the caller`s caller.
164169689Skan
165169689Skan   USES: R0 R10 R11 R12   and R7 R8
166169689Skan   RETURNS: C++ EH Data registers (R3 - R6.)
167169689Skan
168169689Skan   We now set up R7/R8 and jump to rest_world_eh_r7r8.
169169689Skan
170169689Skan   rest_world doesn't use the R10 stack adjust parameter, nor does it
171169689Skan   pick up the R3-R6 exception handling stuff.  */
172169689Skan
173169689Skan.private_extern rest_world
174169689Skanrest_world:
175169689Skan				/* Pickup previous SP  */
176169689Skan	lwz r11, 0(r1)
177169689Skan	li r7, 0
178169689Skan	lwz r8, 8(r11)
179169689Skan	li r10, 0
180169689Skan	b rest_world_eh_r7r8
181169689Skan
182169689Skan.private_extern eh_rest_world_r10
183169689Skaneh_rest_world_r10:
184169689Skan				/* Pickup previous SP  */
185169689Skan	lwz r11, 0(r1)
186169689Skan	mr  r7,r10
187169689Skan	lwz r8, 8(r11)
188169689Skan			/* pickup the C++ EH data regs (R3 - R6.)  */
189169689Skan	lwz r6,-420(r11)
190169689Skan	lwz r5,-424(r11)
191169689Skan	lwz r4,-428(r11)
192169689Skan	lwz r3,-432(r11)
193169689Skan
194169689Skan	b rest_world_eh_r7r8
195169689Skan
196169689Skan/* rest_world_eh_r7r8 is jumped to -- not called! -- when we're doing
197169689Skan   the exception-handling epilog.  R7 contains the offset to add to
198169689Skan   the SP, and R8 contains the 'real' return address.
199169689Skan
200169689Skan   USES: R0 R11 R12  [R7/R8]
201169689Skan   RETURNS: C++ EH Data registers (R3 - R6.)  */
202169689Skan
203169689Skanrest_world_eh_r7r8:
204169689Skan	bcl 20,31,Lr7r8$pb
205169689SkanLr7r8$pb: mflr r12
206169689Skan	lwz r11,0(r1)
207169689Skan				/* R11 := previous SP  */
208169689Skan	addis r12,r12,ha16(L_has_vec$non_lazy_ptr-Lr7r8$pb)
209169689Skan	lwz r12,lo16(L_has_vec$non_lazy_ptr-Lr7r8$pb)(r12)
210169689Skan	lwz r0,4(r11)
211169689Skan				/* R0 := old CR  */
212169689Skan	lwz r12,0(r12)
213169689Skan				/* R12 := HAS_VEC  */
214169689Skan	mtcr r0	
215169689Skan	cmpwi r12,0
216169689Skan	lmw r13,-220(r11)
217169689Skan	beq L.rest_world_fp_eh
218169689Skan				/* restore VRsave and V20..V31  */
219169689Skan	lwz r0,-224(r11)
220169689Skan	li r12,-416
221169689Skan	mtspr VRsave,r0
222169689Skan	lvx v20,r11,r12
223169689Skan	li r12,-400
224169689Skan	lvx v21,r11,r12
225169689Skan	li r12,-384
226169689Skan	lvx v22,r11,r12
227169689Skan	li r12,-368
228169689Skan	lvx v23,r11,r12
229169689Skan	li r12,-352
230169689Skan	lvx v24,r11,r12
231169689Skan	li r12,-336
232169689Skan	lvx v25,r11,r12
233169689Skan	li r12,-320
234169689Skan	lvx v26,r11,r12
235169689Skan	li r12,-304
236169689Skan	lvx v27,r11,r12
237169689Skan	li r12,-288
238169689Skan	lvx v28,r11,r12
239169689Skan	li r12,-272
240169689Skan	lvx v29,r11,r12
241169689Skan	li r12,-256
242169689Skan	lvx v30,r11,r12
243169689Skan	li r12,-240
244169689Skan	lvx v31,r11,r12
245169689Skan
246169689SkanL.rest_world_fp_eh:
247169689Skan	lfd f14,-144(r11)
248169689Skan	lfd f15,-136(r11)
249169689Skan	lfd f16,-128(r11)
250169689Skan	lfd f17,-120(r11)
251169689Skan	lfd f18,-112(r11)
252169689Skan	lfd f19,-104(r11)
253169689Skan	lfd f20,-96(r11)
254169689Skan	lfd f21,-88(r11)
255169689Skan	lfd f22,-80(r11)
256169689Skan	lfd f23,-72(r11)
257169689Skan	lfd f24,-64(r11)
258169689Skan	lfd f25,-56(r11)
259169689Skan	lfd f26,-48(r11)
260169689Skan	lfd f27,-40(r11)
261169689Skan	lfd f28,-32(r11)
262169689Skan	lfd f29,-24(r11)
263169689Skan	lfd f30,-16(r11)
264169689Skan			/* R8 is the exception-handler's address  */
265169689Skan	mtctr r8
266169689Skan	lfd f31,-8(r11)
267169689Skan			/* set SP to original value + R7 offset  */
268169689Skan	add r1,r11,r7
269169689Skan	bctr
270