ee1bdfe29ab8164ce5231fec7dba95a423282399
[cacao.git] / src / vm / jit / sparc64 / md.c
1 /* src/vm/jit/alpha/md.c - machine dependent SPARC 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    $Id: md.c 6265 2007-01-02 20:40:57Z edwin $
26
27 */
28
29
30 #include "config.h"
31
32 #include <assert.h>
33
34
35 #include "vm/types.h"
36
37 #include "vm/jit/sparc64/md-abi.h"
38
39 #include "vm/exceptions.h"
40 #include "vm/stringlocal.h"
41 #include "vm/jit/asmpart.h"
42 #include "vm/jit/stacktrace.h"
43
44
45 /* shift away 13-bit immediate,  mask rd and rs1    */
46 #define SHIFT_AND_MASK(instr) \
47         ((instr >> 13) & 0x60fc1)
48
49 #define IS_SETHI(instr) \
50         ((instr & 0xc1c00000)  == 0x00800000)
51
52 inline s2 decode_13bit_imm(u4 instr) {
53         s2 imm;
54
55         /* mask everything else in the instruction */
56         imm = instr & 0x00001fff;
57
58         /* sign extend 13-bit to 16-bit */
59         imm <<= 3;
60         imm >>= 3;
61
62         return imm;
63 }
64
65 /* md_init *********************************************************************
66
67    Do some machine dependent initialization.
68
69 *******************************************************************************/
70
71 void md_init(void)
72 {
73         /* do nothing */
74 }
75
76
77 /* md_codegen_patch_branch *****************************************************
78
79    Back-patches a branch instruction.
80
81 *******************************************************************************/
82
83 void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc)
84 {
85         s4 *mcodeptr;
86         s4  mcode;
87         s4  disp;                           /* branch displacement                */
88
89         /* calculate the patch position */
90
91         mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
92
93         /* get the instruction before the exception point */
94
95         mcode = mcodeptr[-1];
96         
97         /* Calculate the branch displacement.  SPARC displacements regard current
98            PC as base => (branchmpc - 4 */
99         
100         disp = (targetmpc - (branchmpc - 4)) >> 2;
101         
102
103         /* check for BPcc or FBPfcc instruction */
104         if (((mcode >> 16) & 0xc1c0) == 0x0040) {
105         
106                 /* check branch displacement (19-bit)*/
107         
108                 if ((disp < (s4) 0xfffc0000) || (disp > (s4) 0x003ffff))
109                         vm_abort("branch displacement is out of range: %d > +/-%d", disp, 0x003ffff);
110         
111                 /* patch the branch instruction before the mcodeptr */
112         
113                 mcodeptr[-1] |= (disp & 0x007ffff);
114         }
115         /* check for BPr instruction */
116         else if (((mcode >> 16) & 0xd1c0) == 0x00c0) {
117
118                 /* check branch displacement (16-bit)*/
119         
120                 if ((disp < (s4) 0xffff8000) || (disp > (s4) 0x0007fff))
121                         vm_abort("branch displacement is out of range: %d > +/-%d", disp, 0x0007fff);
122                         
123                 /* patch the upper 2-bit of the branch displacement */
124                 mcodeptr[-1] |= ((disp & 0xc000) << 6);
125                         
126                 /* patch the lower 14-bit of the branch displacement */
127                 mcodeptr[-1] |= (disp & 0x003fff);
128                 
129         }
130         else
131                 assert(0);
132 }
133
134
135 /* md_stacktrace_get_returnaddress *********************************************
136
137    Returns the return address of the current stackframe, specified by
138    the passed stack pointer and the stack frame size.
139
140 *******************************************************************************/
141
142 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
143 {
144         u1 *ra;
145         /* flush register windows to the stack */
146         __asm__ ("flushw");
147
148         /* the return address resides in register i7, the last register in the
149          * 16-extended-word save area
150          */
151         ra = *((u1 **) (sp + 120 + BIAS));
152         
153         /* NOTE: on SPARC ra is the address of the call instruction */
154
155         return ra;
156 }
157
158 u1 *md_get_framepointer(u1 *sp)
159 {
160         u1 *fp;
161         /* flush register windows to the stack */
162         __asm__ ("flushw");
163
164         fp = *((u1 **) (sp + 112 + BIAS));
165
166         return fp;
167 }
168
169 u1 *md_get_pv_from_stackframe(u1 *sp)
170 {
171         u1 *pv;
172         /* flush register windows to the stack */
173         __asm__ ("flushw");
174
175         pv = *((u1 **) (sp + 104 + BIAS));
176
177         return pv;
178 }
179
180 /* md_codegen_get_pv_from_pc ***************************************************
181
182    This reconstructs and returns the PV of a method given a return address
183    pointer. (basically, same was as the generated code following the jump does)
184    
185    Machine code:
186
187    6b5b4000    jmpl    (pv)
188    10000000    nop
189    277afffe    ldah    pv,-2(ra)
190    237ba61c    lda     pv,-23012(pv)
191
192 *******************************************************************************/
193
194 u1 *md_codegen_get_pv_from_pc(u1 *ra)
195 {
196         u1 *pv;
197         u8  mcode;
198         u4  mcode_masked;
199         s2  offset;
200
201         pv = ra;
202
203         /* get the instruction word after jump and nop */
204         mcode = *((u4 *) (ra+8) );
205
206         /* check if we have 2 instructions (ldah, lda) */
207
208         mcode_masked = SHIFT_AND_MASK(mcode);
209
210         if (mcode_masked == 0x40001) {
211 #if 0
212                 /* get displacement of first instruction (ldah) */
213
214                 offset = (s4) (mcode << 16);
215                 pv += offset;
216
217                 /* get displacement of second instruction (lda) */
218
219                 mcode = *((u4 *) (ra + 1 * 4));
220
221                 assert((mcode >> 16) == 0x237b);
222
223                 offset = (s2) (mcode & 0x0000ffff);
224                 pv += offset;
225
226         } else {
227                 /* get displacement of first instruction (lda) */
228
229                 assert((mcode >> 16) == 0x237a);
230 #endif
231                 /* mask and extend the negative sign for the 13 bit immediate */
232                 offset = decode_13bit_imm(mcode);
233
234                 pv += offset;
235         }
236         else
237         {
238                 assert(0);
239         }
240
241         return pv;
242 }
243
244 /* md_get_method_patch_address *************************************************
245
246    Gets the patch address of the currently compiled method. The offset
247    is extracted from the load instruction(s) before the jump and added
248    to the right base address (PV or REG_METHODPTR).
249
250    INVOKESTATIC/SPECIAL:
251
252    dfdeffb8    ldx      [i5 - 72],o5
253    03c0f809    jmp      o5
254    00000000    nop
255
256    INVOKEVIRTUAL:
257
258    dc990000    ld       t9,0(a0)
259    df3e0000    ld       [g2 + 0],o5
260    03c0f809    jmp      o5
261    00000000    nop
262
263    INVOKEINTERFACE:
264
265    dc990000    ld       t9,0(a0)
266    df39ff90    ld       [g2 - 112],g2
267    df3e0018    ld       [g2 + 24],o5
268    03c0f809    jmp      o5
269    00000000    nop
270
271 *******************************************************************************/
272
273 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
274 {
275         u4  mcode, mcode_masked;
276         s4  offset;
277         u1 *pa;
278
279         /* go back to the actual load instruction (1 instruction before jump) */
280         /* ra is the address of the jump instruction on SPARC                 */
281         ra -= 1 * 4;
282
283         /* get first instruction word on current PC */
284
285         mcode = *((u4 *) ra);
286
287
288         /* check if we have 2 instructions (lui) */
289
290         if (IS_SETHI(mcode)) {
291                 /* XXX write a regression for this */
292                 assert(0);
293
294                 /* get displacement of first instruction (lui) */
295
296                 offset = (s4) (mcode << 16);
297
298                 /* get displacement of second instruction (daddiu) */
299
300                 mcode = *((u4 *) (ra + 1 * 4));
301
302                 assert((mcode >> 16) != 0x6739);
303
304                 offset += (s2) (mcode & 0x0000ffff);
305
306         } else {
307
308                 /* shift and maks rd */
309
310                 mcode_masked = (mcode >> 13) & 0x060fff;
311                 
312                 /* get the offset from the instruction */
313
314                 offset = decode_13bit_imm(mcode);
315
316                 /* check for call with rs1 == REG_METHODPTR: ldx [g2+x],pv_caller */
317
318                 if (mcode_masked == 0x0602c5) {
319                         /* in this case we use the passed method pointer */
320
321                         /* return NULL if no mptr was specified (used for replacement) */
322
323                         if (mptr == NULL)
324                                 return NULL;
325
326                         pa = mptr + offset;
327
328                 } else {
329                         /* in the normal case we check for a `ldx [i5+x],pv_caller' instruction */
330
331                         assert(mcode_masked  == 0x0602fb);
332
333                         /* and get the final data segment address */
334
335                         pa = sfi->pv + offset;
336                 }
337         }
338
339         return pa;
340 }
341
342
343 /* md_cacheflush ***************************************************************
344
345    Calls the system's function to flush the instruction and data
346    cache.
347
348 *******************************************************************************/
349
350 void md_cacheflush(u1 *addr, s4 nbytes)
351 {
352         /* don't know yet */    
353 }
354
355
356 /* md_dcacheflush **************************************************************
357
358    Calls the system's function to flush the data cache.
359
360 *******************************************************************************/
361
362 void md_dcacheflush(u1 *addr, s4 nbytes)
363 {
364         /* XXX don't know yet */        
365 }
366
367
368 /* md_patch_replacement_point **************************************************
369
370    Patch the given replacement point.
371
372 *******************************************************************************/
373
374 #if defined(ENABLE_REPLACEMENT)
375 void md_patch_replacement_point(codeinfo *code, s4 index, rplpoint *rp, u1 *savedmcode)
376 {
377         s4 disp;
378         u4 mcode;
379         
380         assert(0);
381
382         if (index < 0) {
383                 /* restore the patched-over instruction */
384                 *(u4*)(rp->pc) = *(u4*)(savedmcode);
385         }
386         else {
387                 /* save the current machine code */
388                 *(u4*)(savedmcode) = *(u4*)(rp->pc);
389
390                 /* build the machine code for the patch */
391                 disp = ((u4*)code->replacementstubs - (u4*)rp->pc)
392                            + index * REPLACEMENT_STUB_SIZE
393                            - 1;
394
395                 mcode = (((s4)(0x00))<<30) | ((0)<<29) | ((0x8)<<25) | (0x1<<22) | (0<<20)
396                           | (1 << 19 ) | ((disp) & 0x007ffff);
397
398                 /* write the new machine code */
399                 *(u4*)(rp->pc) = (u4) mcode;
400         }
401         
402 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
403         {
404                 u1* u1ptr = rp->pc;
405                 DISASSINSTR(u1ptr);
406                 fflush(stdout);
407         }
408 #endif
409                         
410         /* flush instruction cache */
411     /* md_icacheflush(rp->pc,4); */
412 }
413 #endif /* defined(ENABLE_REPLACEMENT) */
414
415 /*
416  * These are local overrides for various environment variables in Emacs.
417  * Please do not remove this and leave it at the end of the file, where
418  * Emacs will automagically detect them.
419  * ---------------------------------------------------------------------
420  * Local variables:
421  * mode: c
422  * indent-tabs-mode: t
423  * c-basic-offset: 4
424  * tab-width: 4
425  * End:
426  * vim:noexpandtab:sw=4:ts=4:
427  */