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 /* Calculate the branch displacement. SPARC displacements regard current
73 PC as base => (branchmpc - 4 */
75 disp = (targetmpc - (branchmpc - 4)) >> 2;
78 /* check for BPcc or FBPfcc instruction */
79 if (((mcode >> 16) & 0xc1c0) == 0x0040) {
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 & 0x007ffff);
90 /* check for BPr instruction */
91 else if (((mcode >> 16) & 0xd1c0) == 0x00c0) {
93 /* check branch displacement (16-bit)*/
95 if ((disp < (s4) 0xffff8000) || (disp > (s4) 0x0007fff))
96 vm_abort("branch displacement is out of range: %d > +/-%d", disp, 0x0007fff);
98 /* patch the upper 2-bit of the branch displacement */
99 mcodeptr[-1] |= ((disp & 0xc000) << 6);
101 /* patch the lower 14-bit of the branch displacement */
102 mcodeptr[-1] |= (disp & 0x003fff);
110 /* md_stacktrace_get_returnaddress *********************************************
112 Returns the return address of the current stackframe, specified by
113 the passed stack pointer and the stack frame size.
115 *******************************************************************************/
117 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
120 /* flush register windows to the stack */
123 /* the return address resides in register i7, the last register in the
124 * 16-extended-word save area
126 ra = *((u1 **) (sp + 120 + BIAS));
128 /* NOTE: on SPARC ra is the address of the call instruction */
134 /* md_codegen_get_pv_from_pc ***************************************************
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)
143 277afffe ldah pv,-2(ra)
144 237ba61c lda pv,-23012(pv)
146 *******************************************************************************/
148 u1 *md_codegen_get_pv_from_pc(u1 *ra)
157 /* get the instruction word after jump and nop */
158 mcode = *((u4 *) (ra+8) );
160 /* check if we have 2 instructions (ldah, lda) */
162 mcode_masked = SHIFT_AND_MASK(mcode);
164 if (mcode_masked == 0x40001) {
166 /* get displacement of first instruction (ldah) */
168 offset = (s4) (mcode << 16);
171 /* get displacement of second instruction (lda) */
173 mcode = *((u4 *) (ra + 1 * 4));
175 assert((mcode >> 16) == 0x237b);
177 offset = (s2) (mcode & 0x0000ffff);
181 /* get displacement of first instruction (lda) */
183 assert((mcode >> 16) == 0x237a);
185 /* mask and extend the negative sign for the 13 bit immediate */
186 offset = decode_13bit_imm(mcode);
198 /* md_get_method_patch_address *************************************************
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).
204 INVOKESTATIC/SPECIAL:
206 dfdeffb8 ldx [i5 - 72],o5
213 df3e0000 ld [g2 + 0],o5
220 df39ff90 ld [g2 - 112],g2
221 df3e0018 ld [g2 + 24],o5
225 *******************************************************************************/
227 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
229 u4 mcode, mcode_masked;
233 /* go back to the actual load instruction (1 instruction before jump) */
234 /* ra is the address of the jump instruction on SPARC */
237 /* get first instruction word on current PC */
239 mcode = *((u4 *) ra);
242 /* check if we have 2 instructions (lui) */
244 if (IS_SETHI(mcode)) {
245 /* XXX write a regression for this */
248 /* get displacement of first instruction (lui) */
250 offset = (s4) (mcode << 16);
252 /* get displacement of second instruction (daddiu) */
254 mcode = *((u4 *) (ra + 1 * 4));
256 assert((mcode >> 16) != 0x6739);
258 offset += (s2) (mcode & 0x0000ffff);
262 /* shift and maks rd */
264 mcode_masked = (mcode >> 13) & 0x060fff;
266 /* get the offset from the instruction */
268 offset = decode_13bit_imm(mcode);
270 /* check for call with rs1 == REG_METHODPTR: ldx [g2+x],pv_caller */
272 if (mcode_masked == 0x0602c5) {
273 /* in this case we use the passed method pointer */
275 /* return NULL if no mptr was specified (used for replacement) */
283 /* in the normal case we check for a `ldx [i5+x],pv_caller' instruction */
285 assert(mcode_masked == 0x0602fb);
287 printf("data segment: pv=0x%08x, offset=%d\n", sfi->pv, offset);
289 /* and get the final data segment address */
291 pa = sfi->pv + offset;
299 /* md_cacheflush ***************************************************************
301 Calls the system's function to flush the instruction and data
304 *******************************************************************************/
306 void md_cacheflush(u1 *addr, s4 nbytes)
312 /* md_dcacheflush **************************************************************
314 Calls the system's function to flush the data cache.
316 *******************************************************************************/
318 void md_dcacheflush(u1 *addr, s4 nbytes)
320 /* XXX don't know yet */
324 /* md_patch_replacement_point **************************************************
326 Patch the given replacement point.
328 *******************************************************************************/
330 #if defined(ENABLE_REPLACEMENT)
331 void md_patch_replacement_point(codeinfo *code, s4 index, rplpoint *rp, u1 *savedmcode)
339 /* restore the patched-over instruction */
340 *(u4*)(rp->pc) = *(u4*)(savedmcode);
343 /* save the current machine code */
344 *(u4*)(savedmcode) = *(u4*)(rp->pc);
346 /* build the machine code for the patch */
347 disp = ((u4*)code->replacementstubs - (u4*)rp->pc)
348 + index * REPLACEMENT_STUB_SIZE
351 mcode = (((s4)(0x00))<<30) | ((0)<<29) | ((0x8)<<25) | (0x1<<22) | (0<<20)
352 | (1 << 19 ) | ((disp) & 0x007ffff);
354 /* write the new machine code */
355 *(u4*)(rp->pc) = (u4) mcode;
358 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
366 /* flush instruction cache */
367 /* md_icacheflush(rp->pc,4); */
369 #endif /* defined(ENABLE_REPLACEMENT) */
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 * ---------------------------------------------------------------------
378 * indent-tabs-mode: t
382 * vim:noexpandtab:sw=4:ts=4: