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