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 /* ra is the address of the call instr, advance to the real return address */
137 /* md_codegen_get_pv_from_pc ***************************************************
139 This reconstructs and returns the PV of a method given a return address
140 pointer. (basically, same was as the generated code following the jump does)
146 277afffe ldah pv,-2(ra)
147 237ba61c lda pv,-23012(pv)
149 *******************************************************************************/
151 u1 *md_codegen_get_pv_from_pc(u1 *ra)
160 /* get the instruction word after jump and nop */
161 mcode = *((u4 *) (ra+8) );
163 /* check if we have 2 instructions (ldah, lda) */
165 mcode_masked = SHIFT_AND_MASK(mcode);
167 if (mcode_masked == 0x40001) {
169 /* get displacement of first instruction (ldah) */
171 offset = (s4) (mcode << 16);
174 /* get displacement of second instruction (lda) */
176 mcode = *((u4 *) (ra + 1 * 4));
178 assert((mcode >> 16) == 0x237b);
180 offset = (s2) (mcode & 0x0000ffff);
184 /* get displacement of first instruction (lda) */
186 assert((mcode >> 16) == 0x237a);
188 /* mask and extend the negative sign for the 13 bit immediate */
189 offset = decode_13bit_imm(mcode);
201 /* md_get_method_patch_address *************************************************
203 Gets the patch address of the currently compiled method. The offset
204 is extracted from the load instruction(s) before the jump and added
205 to the right base address (PV or REG_METHODPTR).
207 INVOKESTATIC/SPECIAL:
209 dfdeffb8 ldx [i5 - 72],o5
216 df3e0000 ld [g2 + 0],o5
223 df39ff90 ld [g2 - 112],g2
224 df3e0018 ld [g2 + 24],o5
228 *******************************************************************************/
230 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
232 u4 mcode, mcode_masked;
236 /* go back to the actual load instruction (1 instruction before jump) */
237 /* ra is the address of the jump instruction on SPARC */
240 /* get first instruction word on current PC */
242 mcode = *((u4 *) ra);
245 /* check if we have 2 instructions (lui) */
247 if (IS_SETHI(mcode)) {
248 /* XXX write a regression for this */
251 /* get displacement of first instruction (lui) */
253 offset = (s4) (mcode << 16);
255 /* get displacement of second instruction (daddiu) */
257 mcode = *((u4 *) (ra + 1 * 4));
259 assert((mcode >> 16) != 0x6739);
261 offset += (s2) (mcode & 0x0000ffff);
265 /* shift and maks rd */
267 mcode_masked = (mcode >> 13) & 0x060fff;
269 /* get the offset from the instruction */
271 offset = decode_13bit_imm(mcode);
273 /* check for call with rs1 == REG_METHODPTR: ldx [g2+x],pv_caller */
275 if (mcode_masked == 0x0602c5) {
276 /* in this case we use the passed method pointer */
281 /* in the normal case we check for a `ldx [i5+x],pv_caller' instruction */
283 assert(mcode_masked == 0x0602fb);
285 printf("data segment: pv=0x%08x, offset=%d\n", sfi->pv, offset);
287 /* and get the final data segment address */
289 pa = sfi->pv + offset;
297 /* md_cacheflush ***************************************************************
299 Calls the system's function to flush the instruction and data
302 *******************************************************************************/
304 void md_cacheflush(u1 *addr, s4 nbytes)
310 /* md_icacheflush **************************************************************
312 Calls the system's function to flush the instruction cache.
314 *******************************************************************************/
316 void md_icacheflush(u1 *addr, s4 nbytes)
318 /* XXX don't know yet */
321 /* md_dcacheflush **************************************************************
323 Calls the system's function to flush the data cache.
325 *******************************************************************************/
327 void md_dcacheflush(u1 *addr, s4 nbytes)
329 /* XXX don't know yet */
333 /* md_patch_replacement_point **************************************************
335 Patch the given replacement point.
337 *******************************************************************************/
339 void md_patch_replacement_point(rplpoint *rp)
343 /* save the current machine code */
344 mcode = *(u4*)rp->pc;
346 /* write the new machine code */
347 *(u4*)(rp->pc) = (u4) rp->mcode;
349 /* store saved mcode */
352 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
360 /* flush instruction cache */
361 /* md_icacheflush(rp->pc,4); */
365 * These are local overrides for various environment variables in Emacs.
366 * Please do not remove this and leave it at the end of the file, where
367 * Emacs will automagically detect them.
368 * ---------------------------------------------------------------------
371 * indent-tabs-mode: t
375 * vim:noexpandtab:sw=4:ts=4: