54207d22ec0ca45b68c3f9163ca4aa04655da7fe
[cacao.git] / src / vm / jit / powerpc64 / md.c
1 /* src/vm/jit/powerpc64/md.c - machine dependent PowerPC functions
2
3    Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
4    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6    J. Wenninger, Institut f. Computersprachen - TU Wien
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301, USA.
24
25    Contact: cacao@cacaojvm.org
26
27    Authors: Christian Thalinger
28
29    Changes: Edwin Steiner
30
31    $Id: md.c 5940 2006-11-09 09:59:28Z tbfg $
32
33 */
34
35 #include "config.h"
36
37 #include <assert.h>
38
39 #include "vm/types.h"
40
41 #include "md-abi.h"
42
43 #include "vm/global.h"
44 #include "vm/jit/asmpart.h"
45 #include "codegen.h"
46
47 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
48 #include "vm/options.h" /* XXX debug */
49 #include "vm/jit/disass.h" /* XXX debug */
50 #endif
51
52
53 /* md_init *********************************************************************
54
55    Do some machine dependent initialization.
56
57 *******************************************************************************/
58
59 void md_init(void)
60 {
61         /* nothing to do */
62 }
63
64
65 /* md_stacktrace_get_returnaddress *********************************************
66
67    Returns the return address of the current stackframe, specified by
68    the passed stack pointer and the stack frame size.
69
70 *******************************************************************************/
71
72 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
73 {
74         u1 *ra;
75
76         /* on PowerPC the return address is located in the linkage area */
77
78         ra = *((u1 **) (sp + framesize + LA_LR_OFFSET));
79
80         return ra;
81 }
82
83 /* md_codegen_patch_branch *****************************************************
84
85    Back-patches a branch instruction.
86    Changes the dispacment of the jump instruction.
87
88 *******************************************************************************/
89
90 void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc)
91 {
92         s4 *mcodeptr;
93         s4  disp;                           /* branch displacement                */
94         s4  mcode;              
95
96         /* calculate the patch position */
97         mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
98
99         /* Calculate the branch displacement. */
100         disp = targetmpc - branchmpc + 4;
101         mcode = mcodeptr[-1];
102
103         if ((mcode & 0xfc000000) == 0x40000000) {
104                 /* conditional jump bcx */
105                 if ((disp < (s4) 0xffff8000) || (disp > (s4) 0x00007fff))
106                         vm_abort("jump displacement is out of range: %d > +/-%d", disp, 0x00007fff);
107
108                 mcode &= 0xffff0000;
109                 mcode |= (((disp)& M_BCMASK));
110         } else if ((mcode & 0xfc000000) == 0x48000000) {
111                 /* unconditional jump bx */
112                 if ((disp < (s4) 0xfc000000) || (disp > (s4) 0x03ffffff))
113                         vm_abort("jump displacement is out of range: %d > +/-%d", disp, 0x0cffffff);
114                 mcode &= 0xfc000000;
115                 mcode |= (((disp)& M_BMASK));
116         } else {
117                 vm_abort("md_codegen_patch_branch, patching unsupported branch: %xd", mcode);
118         }
119
120         mcodeptr[-1] = mcode;
121 }
122
123
124
125 /* md_get_method_patch_address *************************************************
126
127    Gets the patch address of the currently compiled method. The offset
128    is extracted from the load instruction(s) before the jump and added
129    to the right base address (PV or REG_METHODPTR).
130
131    INVOKESTATIC/SPECIAL:
132
133    e9ceffb8    ld      r14,-72(r14)     
134    7dc903a6    mtctr   r14              
135    4e800421    bctrl
136
137    INVOKEVIRTUAL:
138
139 FIXME   81830000    lwz     r12,0(r3)
140    e9cc0000     ld      r14,0(r12)
141    7dc903a6     mtctr   r14
142    4e800421     bctrl
143
144
145    INVOKEINTERFACE:
146
147 FIXME   81830000    lwz     r12,0(r3)
148 FIXME   818c0000    lwz     r12,0(r12)
149 FIXME   81ac0000    lwz     r13,0(r12)
150   7dc903a6    mtctr   r14
151   4e800421    bctrl
152
153 *******************************************************************************/
154
155 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
156 {
157         u4  mcode;
158         s4  offset;
159         u1 *pa;
160
161         /* go back to the actual load instruction (3 instructions) */
162
163         ra = ra - 3 * 4;
164
165         /* get first instruction word (lwz) */
166
167         mcode = *((u4 *) ra);
168
169         /* check if we have 2 instructions (addis, addi) */
170
171         if ((mcode >> 16) == 0x3c19) {
172                 /* XXX write a regression for this */
173                 assert(0);
174
175                 /* get displacement of first instruction (addis) */
176
177                 offset = (s4) (mcode << 16);
178
179                 /* get displacement of second instruction (addi) */
180
181                 mcode = *((u4 *) (ra + 1 * 4));
182
183                 assert((mcode >> 16) != 0x6739);
184
185                 offset += (s2) (mcode & 0x0000ffff);
186
187         } else {
188                 /* get the offset from the instruction */
189
190                 offset = (s2) (mcode & 0x0000ffff);
191
192                 /* check for load from PV */
193
194                 if ((mcode >> 16) == 0xe9ce) {  
195                         /* get the final data segment address */
196
197                         pa = sfi->pv + offset;
198
199                 } else if ((mcode >> 16) == 0xe9cc) { 
200                         /* in this case we use the passed method pointer */
201
202                         pa = mptr + offset;
203
204                 } else {
205                         /* catch any problems */
206
207                         assert(0);
208                 }
209         }
210
211         return pa;
212 }
213
214
215 /* md_codegen_get_pv_from_pc ***************************************************
216
217    Machine code:
218
219    7d6802a6    mflr    r11
220    39cbffe0    addi    r14,r11,-32
221
222    or
223
224    7d6802a6    mflr    r11
225    3dcbffff    addis   r14,r11,-1
226    39ce68b0    addi    r14,r13,26800
227
228 *******************************************************************************/
229
230 u1 *md_codegen_get_pv_from_pc(u1 *ra)
231 {
232         u1 *pv;
233         u4  mcode;
234         s4  offset;
235
236         /* get first instruction word after jump */
237
238         mcode = *((u4 *) (ra + 1 * 4));
239
240         /* check if we have 2 instructions (addis, addi) */
241
242         if ((mcode >> 16) == 0x3dcb) {
243                 /* get displacement of first instruction (addis) */
244
245                 offset = (s4) (mcode << 16);
246
247                 /* get displacement of second instruction (addi) */
248
249                 mcode = *((u4 *) (ra + 2 * 4));
250
251                 /* check for addi instruction */
252
253                 assert((mcode >> 16) == 0x39ce);
254
255                 offset += (s2) (mcode & 0x0000ffff);
256
257         } else {
258                 /* check for addi instruction */
259
260                 assert((mcode >> 16) == 0x39cb);
261
262                 /* get offset of first instruction (addi) */
263
264                 offset = (s2) (mcode & 0x0000ffff);
265         }
266
267         /* calculate PV via RA + offset */
268
269         pv = ra + offset;
270
271         return pv;
272 }
273
274
275 /* md_cacheflush ***************************************************************
276
277    Calls the system's function to flush the instruction and data
278    cache.
279
280 *******************************************************************************/
281
282 void md_cacheflush(u1 *addr, s4 nbytes)
283 {
284         asm_cacheflush(addr, nbytes);
285 }
286
287
288 /* md_icacheflush **************************************************************
289
290    Calls the system's function to flush the instruction cache.
291
292 *******************************************************************************/
293
294 void md_icacheflush(u1 *addr, s4 nbytes)
295 {
296         asm_cacheflush(addr, nbytes);
297 }
298
299
300 /* md_dcacheflush **************************************************************
301
302    Calls the system's function to flush the data cache.
303
304 *******************************************************************************/
305
306 void md_dcacheflush(u1 *addr, s4 nbytes)
307 {
308         asm_cacheflush(addr, nbytes);
309 }
310
311
312 /* md_patch_replacement_point **************************************************
313
314    Patch the given replacement point.
315
316 *******************************************************************************/
317
318 void md_patch_replacement_point(rplpoint *rp)
319 {
320     u8 mcode;
321
322         /* save the current machine code */
323         mcode = *(u4*)rp->pc;
324
325         /* write the new machine code */
326     *(u4*)(rp->pc) = (u4) rp->mcode;
327
328         /* store saved mcode */
329         rp->mcode = mcode;
330         
331 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
332         {
333                 u1* u1ptr = rp->pc;
334                 DISASSINSTR(u1ptr);
335                 fflush(stdout);
336         }
337 #endif
338                         
339         /* flush instruction cache */
340     md_icacheflush(rp->pc,4);
341 }
342
343 /*
344  * These are local overrides for various environment variables in Emacs.
345  * Please do not remove this and leave it at the end of the file, where
346  * Emacs will automagically detect them.
347  * ---------------------------------------------------------------------
348  * Local variables:
349  * mode: c
350  * indent-tabs-mode: t
351  * c-basic-offset: 4
352  * tab-width: 4
353  * End:
354  * vim:noexpandtab:sw=4:ts=4:
355  */