8 #include "vm/jit/sparc64/md-abi.h"
10 #include "vm/exceptions.h"
11 #include "vm/stringlocal.h"
12 #include "vm/jit/asmpart.h"
13 #include "vm/jit/stacktrace.h"
15 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
16 #include "vm/options.h" /* XXX debug */
17 #include "vm/jit/disass.h" /* XXX debug */
20 /* shift away 13-bit immediate, mask rd and rs1 */
21 #define SHIFT_AND_MASK(instr) \
22 ((instr >> 13) & 0x60fc1)
24 #define IS_SETHI(instr) \
25 ((instr & 0xc1c00000) == 0x00800000)
27 inline s2 decode_13bit_imm(u4 instr) {
30 /* mask everything else in the instruction */
31 imm = instr & 0x00001fff;
33 /* sign extend 13-bit to 16-bit */
40 /* md_init *********************************************************************
42 Do some machine dependent initialization.
44 *******************************************************************************/
52 /* md_codegen_patch_branch *****************************************************
54 Back-patches a branch instruction.
56 *******************************************************************************/
58 void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc)
62 s4 disp; /* branch displacement */
64 /* calculate the patch position */
66 mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
68 /* get the instruction before the exception point */
72 /* check for BPcc or FBPfcc instruction */
73 if (((mcode >> 16) & 0xc1c0) == 0x0040) {
76 /* Calculate the branch displacement. For branches we need a
77 displacement relative and shifted to the branch PC. */
79 disp = (targetmpc - branchmpc) >> 2;
81 /* check branch displacement (19-bit)*/
83 if ((disp < (s4) 0xfffc0000) || (disp > (s4) 0x003ffff))
84 vm_abort("branch displacement is out of range: %d > +/-%d", disp, 0x003ffff);
86 /* patch the branch instruction before the mcodeptr */
88 mcodeptr[-1] |= (disp & 0x003ffff);
90 /* check for BPr instruction */
91 else if (((mcode >> 16) & 0xd1c0) == 0x00c0) {
93 /* check branch displacement (16-bit)*/
95 disp = (targetmpc - branchmpc) >> 2;
97 if ((disp < (s4) 0xffff8000) || (disp > (s4) 0x0007fff))
98 vm_abort("branch displacement is out of range: %d > +/-%d", disp, 0x0007fff);
100 /* patch the upper 2-bit of the branch displacement */
101 mcodeptr[-1] |= ((disp & 0xc000) << 6);
103 /* patch the lower 14-bit of the branch displacement */
104 mcodeptr[-1] |= (disp & 0x003fff);
112 /* md_stacktrace_get_returnaddress *********************************************
114 Returns the return address of the current stackframe, specified by
115 the passed stack pointer and the stack frame size.
117 *******************************************************************************/
119 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
122 /* flush register windows to the stack */
125 /* the return address resides in register i7, the last register in the
126 * 16-extended-word save area
128 ra = *((u1 **) (sp + 120 + BIAS));
130 /* NOTE: on SPARC ra is the address of the call instruction */
136 /* md_codegen_get_pv_from_pc ***************************************************
138 This reconstructs and returns the PV of a method given a return address
139 pointer. (basically, same was as the generated code following the jump does)
145 277afffe ldah pv,-2(ra)
146 237ba61c lda pv,-23012(pv)
148 *******************************************************************************/
150 u1 *md_codegen_get_pv_from_pc(u1 *ra)
159 /* get the instruction word after jump and nop */
160 mcode = *((u4 *) (ra+8) );
162 /* check if we have 2 instructions (ldah, lda) */
164 mcode_masked = SHIFT_AND_MASK(mcode);
166 if (mcode_masked == 0x40001) {
168 /* get displacement of first instruction (ldah) */
170 offset = (s4) (mcode << 16);
173 /* get displacement of second instruction (lda) */
175 mcode = *((u4 *) (ra + 1 * 4));
177 assert((mcode >> 16) == 0x237b);
179 offset = (s2) (mcode & 0x0000ffff);
183 /* get displacement of first instruction (lda) */
185 assert((mcode >> 16) == 0x237a);
187 /* mask and extend the negative sign for the 13 bit immediate */
188 offset = decode_13bit_imm(mcode);
200 /* md_get_method_patch_address *************************************************
202 Gets the patch address of the currently compiled method. The offset
203 is extracted from the load instruction(s) before the jump and added
204 to the right base address (PV or REG_METHODPTR).
206 INVOKESTATIC/SPECIAL:
208 dfdeffb8 ldx [i5 - 72],o5
215 df3e0000 ld [g2 + 0],o5
222 df39ff90 ld [g2 - 112],g2
223 df3e0018 ld [g2 + 24],o5
227 *******************************************************************************/
229 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
231 u4 mcode, mcode_masked;
235 /* go back to the actual load instruction (1 instruction before jump) */
236 /* ra is the address of the jump instruction on SPARC */
239 /* get first instruction word on current PC */
241 mcode = *((u4 *) ra);
244 /* check if we have 2 instructions (lui) */
246 if (IS_SETHI(mcode)) {
247 /* XXX write a regression for this */
250 /* get displacement of first instruction (lui) */
252 offset = (s4) (mcode << 16);
254 /* get displacement of second instruction (daddiu) */
256 mcode = *((u4 *) (ra + 1 * 4));
258 assert((mcode >> 16) != 0x6739);
260 offset += (s2) (mcode & 0x0000ffff);
264 /* shift and maks rd */
266 mcode_masked = (mcode >> 13) & 0x060fff;
268 /* get the offset from the instruction */
270 offset = decode_13bit_imm(mcode);
272 /* check for call with rs1 == REG_METHODPTR: ldx [g2+x],pv_caller */
274 if (mcode_masked == 0x0602c5) {
275 /* in this case we use the passed method pointer */
277 /* return NULL if no mptr was specified (used for replacement) */
285 /* in the normal case we check for a `ldx [i5+x],pv_caller' instruction */
287 assert(mcode_masked == 0x0602fb);
289 printf("data segment: pv=0x%08x, offset=%d\n", sfi->pv, offset);
291 /* and get the final data segment address */
293 pa = sfi->pv + offset;
301 /* md_cacheflush ***************************************************************
303 Calls the system's function to flush the instruction and data
306 *******************************************************************************/
308 void md_cacheflush(u1 *addr, s4 nbytes)
314 /* md_icacheflush **************************************************************
316 Calls the system's function to flush the instruction cache.
318 *******************************************************************************/
320 void md_icacheflush(u1 *addr, s4 nbytes)
322 /* XXX don't know yet */
325 /* md_dcacheflush **************************************************************
327 Calls the system's function to flush the data cache.
329 *******************************************************************************/
331 void md_dcacheflush(u1 *addr, s4 nbytes)
333 /* XXX don't know yet */
337 /* md_patch_replacement_point **************************************************
339 Patch the given replacement point.
341 *******************************************************************************/
343 void md_patch_replacement_point(codeinfo *code, s4 index, rplpoint *rp, u1 *savedmcode)
349 /* restore the patched-over instruction */
350 *(u4*)(rp->pc) = *(u4*)(savedmcode);
353 /* save the current machine code */
354 *(u4*)(savedmcode) = *(u4*)(rp->pc);
356 /* build the machine code for the patch */
357 disp = ((u4*)code->replacementstubs - (u4*)rp->pc)
358 + index * REPLACEMENT_STUB_SIZE
361 mcode = (((s4)(0x00))<<30) | ((0)<<29) | ((0x8)<<25) | (0x1<<22) | (0<<20)
362 | (1 << 19 ) | ((disp) & 0x007ffff);
364 /* write the new machine code */
365 *(u4*)(rp->pc) = (u4) mcode;
368 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
376 /* flush instruction cache */
377 /* md_icacheflush(rp->pc,4); */
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 * ---------------------------------------------------------------------
387 * indent-tabs-mode: t
391 * vim:noexpandtab:sw=4:ts=4: