* Removed all Id tags.
[cacao.git] / src / vm / jit / sparc64 / md.c
1 /* src/vm/jit/sparc64/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 */
26
27
28 #include "config.h"
29
30 #include <assert.h>
31
32
33 #include "vm/types.h"
34
35 #include "vm/jit/sparc64/md-abi.h"
36
37 #include "vm/exceptions.h"
38 #include "vm/stringlocal.h"
39 #include "vm/jit/asmpart.h"
40 #include "vm/jit/stacktrace.h"
41
42 /* assembler function prototypes **********************************************/
43 void asm_store_fp_state_reg(u8 *mem);
44 void asm_load_fp_state_reg(u8 *mem);
45
46
47
48 /* shift away 13-bit immediate,  mask rd and rs1    */
49 #define SHIFT_AND_MASK(instr) \
50         ((instr >> 13) & 0x60fc1)
51
52 /* NOP is defined as a SETHI instruction with rd and imm. set to zero */
53 /* therefore we check if the 22-bit immediate is zero */
54 #define IS_SETHI(instr) \
55         (((instr & 0xc1c00000)  == 0x01000000) \
56         && ((instr & 0x3fffff) != 0x0))
57         
58 #define IS_LDX_IMM(instr) \
59         (((instr >> 13) & 0x60fc1) == 0x602c1)
60         
61 #define IS_SUB(instr) \
62         (((instr >> 13) & 0x60fc0) == 0x40100)
63
64 inline s2 decode_13bit_imm(u4 instr) {
65         s2 imm;
66
67         /* mask everything else in the instruction */
68         imm = instr & 0x00001fff;
69
70         /* sign extend 13-bit to 16-bit */
71         imm <<= 3;
72         imm >>= 3;
73
74         return imm;
75 }
76
77 /* md_init *********************************************************************
78
79    Do some machine dependent initialization.
80
81 *******************************************************************************/
82
83 void md_init(void)
84 {
85         /* do nothing */
86 }
87
88
89 /* md_stacktrace_get_returnaddress *********************************************
90
91    Returns the return address of the current stackframe, specified by
92    the passed stack pointer and the stack frame size.
93
94 *******************************************************************************/
95
96 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
97 {
98         u1 *ra;
99         /* flush register windows to the stack */
100         __asm__ ("flushw");
101
102         /* the return address resides in register i7, the last register in the
103          * 16-extended-word save area
104          */
105         ra = *((u1 **) (sp + 120 + BIAS));
106         
107         /* NOTE: on SPARC ra is the address of the call instruction */
108
109         return ra;
110 }
111
112 u1 *md_get_framepointer(u1 *sp)
113 {
114         u1 *fp;
115         /* flush register windows to the stack */
116         __asm__ ("flushw");
117
118         fp = *((u1 **) (sp + 112 + BIAS));
119
120         return fp;
121 }
122
123 u1 *md_get_pv_from_stackframe(u1 *sp)
124 {
125         u1 *pv;
126         /* flush register windows to the stack */
127         __asm__ ("flushw");
128
129         pv = *((u1 **) (sp + 104 + BIAS));
130
131         return pv;
132 }
133
134 /* md_codegen_get_pv_from_pc ***************************************************
135
136    This reconstructs and returns the PV of a method given a return address
137    pointer. (basically, same was as the generated code following the jump does)
138    
139    Machine code:
140
141    6b5b4000    jmpl    (pv)
142    10000000    nop
143    277afffe    ldah    pv,-2(ra)
144    237ba61c    lda     pv,-23012(pv)
145
146 *******************************************************************************/
147
148 u1 *md_codegen_get_pv_from_pc(u1 *ra)
149 {
150         u1 *pv;
151         u8  mcode;
152         s4  offset;
153
154         pv = ra;
155
156         /* get the instruction word after jump and nop */
157         mcode = *((u4 *) (ra+8) );
158
159         /* check if we have a sethi insruction */
160         if (IS_SETHI(mcode)) {
161                 s4 xor_imm;
162                                 
163                 /* get 22-bit immediate of sethi instruction */
164                 offset = (s4) (mcode & 0x3fffff);
165                 offset = offset << 10;
166                 
167                 /* now the xor */
168                 mcode = *((u4 *) (ra+12) );
169                 xor_imm = decode_13bit_imm(mcode);
170                 
171                 offset ^= xor_imm;       
172         }
173         else {
174                 u4 mcode_masked;
175                 
176                 mcode_masked = SHIFT_AND_MASK(mcode);
177
178                 assert(mcode_masked == 0x40001);
179
180                 /* mask and extend the negative sign for the 13 bit immediate */
181                 offset = decode_13bit_imm(mcode);
182         }
183         
184         pv += offset;
185
186         return pv;
187 }
188
189 /* md_get_method_patch_address *************************************************
190
191    Gets the patch address of the currently compiled method. The offset
192    is extracted from the load instruction(s) before the jump and added
193    to the right base address (PV or REG_METHODPTR).
194
195    INVOKESTATIC/SPECIAL:
196
197    ????????    ldx      [i5 - 72],o5
198    ????????    jmp      o5             <-- ra
199    ????????    nop
200
201    w/ sethi (mptr in dseg out of 13-bit simm range)
202
203    ????????    sethi    hi(0x2000),o5
204    ????????    sub      i5,o5,o5
205    ????????    ldx      [o5 - 72],o5
206    ????????    jmp      o5             <-- ra
207    ????????    nop
208
209    INVOKEVIRTUAL:
210
211    ????????    ldx      [o0 + 0},g2
212    ????????    ldx      [g2 + 0],o5
213    ????????    jmp      o5             <-- ra
214    ????????    nop
215
216    INVOKEINTERFACE:
217
218    ????????    ldx      [o0 + 0},g2
219    ????????    ldx      [g2 - 112],g2
220    ????????    ldx      [g2 + 24],o5
221    ????????    jmp      o5             <-- ra
222    ????????    nop
223
224 *******************************************************************************/
225
226 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
227 {
228         u4  mcode, mcode_sethi, mcode_masked;
229         s4  offset;
230         u1 *pa, *iptr;
231
232         /* go back to the location of a possible sethi (3 instruction before jump) */
233         /* note: ra is the address of the jump instruction on SPARC                */
234
235         mcode_sethi = *((u4 *) (ra - 3 * 4));
236
237         /* check for sethi instruction */
238
239         if (IS_SETHI(mcode_sethi)) {
240                 u4 mcode_sub, mcode_ldx;
241
242                 mcode_sub = *((u4 *) (ra - 2 * 4));
243                 mcode_ldx = *((u4 *) (ra - 1 * 4));
244
245                 /* make sure the sequence of instructions is a loadhi */
246                 if ((IS_SUB(mcode_sub)) && (IS_LDX_IMM(mcode_ldx)))
247                 {
248
249
250                 /* get 22-bit immediate of sethi instruction */
251
252                 offset = (s4) (mcode_sethi & 0x3fffff);
253                 offset = offset << 10;
254                 
255                 /* goto next instruction */
256                 
257                 /* make sure it's a sub instruction (pv - big_disp) */
258                 assert(IS_SUB(mcode_sub));
259                 offset = -offset;
260
261                 /* get displacement of load instruction */
262
263                 assert(IS_LDX_IMM(mcode_ldx));
264
265                 offset += decode_13bit_imm(mcode_ldx);
266                 
267                 pa = sfi->pv + offset;
268
269                 return pa;
270                 }
271         }
272
273         /* we didn't find a sethi, or it didn't belong to a loadhi */
274         /* check for simple (one-instruction) load */
275         iptr = ra - 1 * 4;
276         mcode = *((u4 *) iptr);
277
278         /* shift and mask rd */
279
280         mcode_masked = (mcode >> 13) & 0x060fff;
281         
282         /* get the offset from the instruction */
283
284         offset = decode_13bit_imm(mcode);
285
286         /* check for call with rs1 == REG_METHODPTR: ldx [g2+x],pv_caller */
287
288         if (mcode_masked == 0x0602c5) {
289                 /* in this case we use the passed method pointer */
290
291                 /* return NULL if no mptr was specified (used for replacement) */
292
293                 if (mptr == NULL)
294                         return NULL;
295
296                 pa = mptr + offset;
297
298         } else {
299                 /* in the normal case we check for a `ldx [i5+x],pv_caller' instruction */
300
301                 assert(mcode_masked  == 0x0602fb);
302
303                 /* and get the final data segment address */
304
305                 pa = sfi->pv + offset;
306         }
307         
308
309         return pa;
310 }
311
312
313 /* md_cacheflush ***************************************************************
314
315    Calls the system's function to flush the instruction and data
316    cache.
317
318 *******************************************************************************/
319
320 void md_cacheflush(u1 *addr, s4 nbytes)
321 {
322         /* don't know yet */    
323 }
324
325
326 /* md_dcacheflush **************************************************************
327
328    Calls the system's function to flush the data cache.
329
330 *******************************************************************************/
331
332 void md_dcacheflush(u1 *addr, s4 nbytes)
333 {
334         /* XXX don't know yet */        
335         /* printf("md_dcacheflush\n"); */
336         __asm__ __volatile__ ( "membar 0x7F" : : : "memory" );
337 }
338
339
340 /* md_patch_replacement_point **************************************************
341
342    Patch the given replacement point.
343
344 *******************************************************************************/
345
346 #if defined(ENABLE_REPLACEMENT)
347 void md_patch_replacement_point(codeinfo *code, s4 index, rplpoint *rp, u1 *savedmcode)
348 {
349         u4 mcode;
350
351         if (index < 0) {
352                 /* restore the patched-over instruction */
353                 *(u4*)(rp->pc) = *(u4*)(savedmcode);
354         }
355         else {
356                 /* save the current machine code */
357                 *(u4*)(savedmcode) = *(u4*)(rp->pc);
358
359                 /* build the machine code for the patch */
360                 assert(0); /* XXX build trap instruction below */
361                 mcode = 0;
362
363                 /* write the new machine code */
364                 *(u4*)(rp->pc) = (u4) mcode;
365         }
366         
367 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
368         {
369                 u1* u1ptr = rp->pc;
370                 DISASSINSTR(u1ptr);
371                 fflush(stdout);
372         }
373 #endif
374                         
375         /* flush instruction cache */
376     /* md_icacheflush(rp->pc,4); */
377 }
378 #endif /* defined(ENABLE_REPLACEMENT) */
379
380 /*
381  * These are local overrides for various environment variables in Emacs.
382  * Please do not remove this and leave it at the end of the file, where
383  * Emacs will automagically detect them.
384  * ---------------------------------------------------------------------
385  * Local variables:
386  * mode: c
387  * indent-tabs-mode: t
388  * c-basic-offset: 4
389  * tab-width: 4
390  * End:
391  * vim:noexpandtab:sw=4:ts=4:
392  */