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