1 /* src/vm/jit/alpha/md.c - machine dependent Alpha functions
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
8 This file is part of CACAO.
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.
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.
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
25 Contact: cacao@cacaojvm.org
27 Authors: Andreas Krall
33 $Id: md.c 6265 2007-01-02 20:40:57Z edwin $
43 #if defined(__LINUX__)
46 extern unsigned long ieee_get_fp_control();
47 extern void ieee_set_fp_control(unsigned long fp_control);
52 #include "vm/jit/alpha/md-abi.h"
54 #include "vm/exceptions.h"
55 #include "vm/stringlocal.h"
56 #include "vm/jit/asmpart.h"
57 #include "vm/jit/stacktrace.h"
59 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
60 #include "vm/options.h" /* XXX debug */
61 #include "vm/jit/disass.h" /* XXX debug */
65 /* global variables ***********************************************************/
67 bool has_ext_instr_set = false; /* has instruction set extensions */
70 /* md_init *********************************************************************
72 Do some machine dependent initialization.
74 *******************************************************************************/
78 /* check for extended instruction set */
80 has_ext_instr_set = !asm_md_init();
82 #if defined(__LINUX__)
83 /* Linux on Digital Alpha needs an initialisation of the ieee
84 floating point control for IEEE compliant arithmetic (option
85 -mieee of GCC). Under Digital Unix this is done
88 /* initialize floating point control */
90 ieee_set_fp_control(ieee_get_fp_control()
91 & ~IEEE_TRAP_ENABLE_INV
92 & ~IEEE_TRAP_ENABLE_DZE
93 /* & ~IEEE_TRAP_ENABLE_UNF we dont want underflow */
94 & ~IEEE_TRAP_ENABLE_OVF);
99 /* md_codegen_patch_branch *****************************************************
101 Back-patches a branch instruction.
103 *******************************************************************************/
105 void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc)
109 s4 disp; /* branch displacement */
111 /* calculate the patch position */
113 mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
115 /* get the instruction before the exception point */
117 mcode = mcodeptr[-1];
119 /* Calculate the branch displacement. For branches we need a
120 displacement relative and shifted to the branch PC. */
122 disp = (targetmpc - branchmpc) >> 2;
124 /* check branch displacement */
126 if ((disp < (s4) 0xffe00000) || (disp > (s4) 0x001fffff))
127 vm_abort("branch displacement is out of range: %d > +/-%d", disp, 0x001fffff);
129 /* patch the branch instruction before the mcodeptr */
131 mcodeptr[-1] |= (disp & 0x001fffff);
135 /* md_stacktrace_get_returnaddress *********************************************
137 Returns the return address of the current stackframe, specified by
138 the passed stack pointer and the stack frame size.
140 *******************************************************************************/
142 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
146 /* on Alpha the return address is located on the top of the stackframe */
148 ra = *((u1 **) (sp + framesize - SIZEOF_VOID_P));
154 /* md_get_method_patch_address *************************************************
156 Gets the patch address of the currently compiled method. The offset
157 is extracted from the load instruction(s) before the jump and added
158 to the right base address (PV or REG_METHODPTR).
160 INVOKESTATIC/SPECIAL:
162 a77bffb8 ldq pv,-72(pv)
167 a7900000 ldq at,0(a0)
168 a77c0000 ldq pv,0(at)
173 a7900000 ldq at,0(a0)
174 a79cff98 ldq at,-104(at)
175 a77c0018 ldq pv,24(at)
178 *******************************************************************************/
180 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
184 u1 *pa; /* patch address */
186 /* go back to the actual load instruction (2 instructions on Alpha) */
190 /* get first instruction word on current PC */
192 mcode = *((u4 *) ra);
194 /* check if we have 2 instructions (lui) */
196 if ((mcode >> 16) == 0x3c19) {
197 /* XXX write a regression for this */
200 /* get displacement of first instruction (lui) */
202 offset = (s4) (mcode << 16);
204 /* get displacement of second instruction (daddiu) */
206 mcode = *((u4 *) (ra + 1 * 4));
208 assert((mcode >> 16) == 0x6739);
210 offset += (s2) (mcode & 0x0000ffff);
213 /* get first instruction (ldq) */
215 mcode = *((u4 *) ra);
217 /* get the offset from the instruction */
219 offset = (s2) (mcode & 0x0000ffff);
221 /* check for call with REG_METHODPTR: ldq pv,0(at) */
223 if ((mcode >> 16) == 0xa77c) {
224 /* in this case we use the passed method pointer */
226 /* return NULL if no mptr was specified (used for replacement) */
234 /* in the normal case we check for a `ldq pv,-72(pv)' instruction */
236 assert((mcode >> 16) == 0xa77b);
238 /* and get the final data segment address */
240 pa = sfi->pv + offset;
248 /* md_codegen_get_pv_from_pc ***************************************************
253 277afffe ldah pv,-2(ra)
254 237ba61c lda pv,-23012(pv)
256 *******************************************************************************/
258 u1 *md_codegen_get_pv_from_pc(u1 *ra)
266 /* get first instruction word after jump */
268 mcode = *((u4 *) ra);
270 /* check if we have 2 instructions (ldah, lda) */
272 if ((mcode >> 16) == 0x277a) {
273 /* get displacement of first instruction (ldah) */
275 offset = (s4) (mcode << 16);
278 /* get displacement of second instruction (lda) */
280 mcode = *((u4 *) (ra + 1 * 4));
282 assert((mcode >> 16) == 0x237b);
284 offset = (s2) (mcode & 0x0000ffff);
288 /* get displacement of first instruction (lda) */
290 assert((mcode >> 16) == 0x237a);
292 offset = (s2) (mcode & 0x0000ffff);
300 /* md_cacheflush ***************************************************************
302 Calls the system's function to flush the instruction and data
305 *******************************************************************************/
307 void md_cacheflush(u1 *addr, s4 nbytes)
309 asm_cacheflush(addr, nbytes);
313 /* md_icacheflush **************************************************************
315 Calls the system's function to flush the instruction cache.
317 *******************************************************************************/
319 void md_icacheflush(u1 *addr, s4 nbytes)
321 asm_cacheflush(addr, nbytes);
325 /* md_patch_replacement_point **************************************************
327 Patch the given replacement point.
329 *******************************************************************************/
331 #if defined(ENABLE_REPLACEMENT)
332 void md_patch_replacement_point(codeinfo *code, s4 index, rplpoint *rp, u1 *savedmcode)
338 /* restore the patched-over instruction */
339 *(u4*)(rp->pc) = *(u4*)(savedmcode);
342 /* save the current machine code */
343 *(u4*)(savedmcode) = *(u4*)(rp->pc);
345 /* build the machine code for the patch */
346 disp = ((u4*)code->replacementstubs - (u4*)rp->pc)
347 + index * REPLACEMENT_STUB_SIZE
351 mcode = (((s4) (0x30)) << 26) | ((REG_ZERO) << 21) | ((disp) & 0x1fffff);
353 /* write the new machine code */
354 *(u4*)(rp->pc) = mcode;
357 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER) && 0
365 /* flush instruction cache */
366 md_icacheflush(rp->pc,4);
368 #endif /* defined(ENABLE_REPLACEMENT) */
371 * These are local overrides for various environment variables in Emacs.
372 * Please do not remove this and leave it at the end of the file, where
373 * Emacs will automagically detect them.
374 * ---------------------------------------------------------------------
377 * indent-tabs-mode: t
381 * vim:noexpandtab:sw=4:ts=4: