* src/vm/jit/intrp/peephole.c: Updated to current codebase.
[cacao.git] / src / vm / jit / alpha / md.c
1 /* src/vm/jit/alpha/md.c - machine dependent Alpha functions
2
3    Copyright (C) 1996-2005, 2006, 2007 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
7
8    This file is part of CACAO.
9
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.
14
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.
19
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
23    02110-1301, USA.
24
25    $Id: md.c 7355 2007-02-14 10:57:32Z twisti $
26
27 */
28
29
30 #include "config.h"
31
32 #include <assert.h>
33 #include <ucontext.h>
34
35 #if defined(__LINUX__)
36 # include <asm/fpu.h>
37
38 extern unsigned long ieee_get_fp_control();
39 extern void ieee_set_fp_control(unsigned long fp_control);
40 #endif
41
42 #include "vm/types.h"
43
44 #include "vm/jit/alpha/md-abi.h"
45
46 #include "vm/exceptions.h"
47 #include "vm/stringlocal.h"
48
49 #include "vm/jit/asmpart.h"
50 #include "vm/jit/stacktrace.h"
51
52 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
53 #include "vmcore/options.h" /* XXX debug */
54 #include "vm/jit/disass.h" /* XXX debug */
55 #endif
56
57
58 /* global variables ***********************************************************/
59
60 bool has_ext_instr_set = false;             /* has instruction set extensions */
61
62
63 /* md_init *********************************************************************
64
65    Do some machine dependent initialization.
66
67 *******************************************************************************/
68
69 void md_init(void)
70 {
71         /* check for extended instruction set */
72
73         has_ext_instr_set = !asm_md_init();
74
75 #if defined(__LINUX__)
76         /* Linux on Digital Alpha needs an initialisation of the ieee
77            floating point control for IEEE compliant arithmetic (option
78            -mieee of GCC). Under Digital Unix this is done
79            automatically. */
80
81         /* initialize floating point control */
82
83         ieee_set_fp_control(ieee_get_fp_control()
84                                                 & ~IEEE_TRAP_ENABLE_INV
85                                                 & ~IEEE_TRAP_ENABLE_DZE
86 /*                                              & ~IEEE_TRAP_ENABLE_UNF   we dont want underflow */
87                                                 & ~IEEE_TRAP_ENABLE_OVF);
88 #endif
89 }
90
91
92 /* md_codegen_patch_branch *****************************************************
93
94    Back-patches a branch instruction.
95
96 *******************************************************************************/
97
98 void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc)
99 {
100         s4 *mcodeptr;
101         s4  mcode;
102         s4  disp;                           /* branch displacement                */
103
104         /* calculate the patch position */
105
106         mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
107
108         /* get the instruction before the exception point */
109
110         mcode = mcodeptr[-1];
111
112         /* Calculate the branch displacement.  For branches we need a
113            displacement relative and shifted to the branch PC. */
114
115         disp = (targetmpc - branchmpc) >> 2;
116
117         /* check branch displacement */
118
119         if ((disp < (s4) 0xffe00000) || (disp > (s4) 0x001fffff))
120                 vm_abort("branch displacement is out of range: %d > +/-%d", disp, 0x001fffff);
121
122         /* patch the branch instruction before the mcodeptr */
123
124         mcodeptr[-1] |= (disp & 0x001fffff);
125 }
126
127
128 /* md_stacktrace_get_returnaddress *********************************************
129
130    Returns the return address of the current stackframe, specified by
131    the passed stack pointer and the stack frame size.
132
133 *******************************************************************************/
134
135 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
136 {
137         u1 *ra;
138
139         /* on Alpha the return address is located on the top of the stackframe */
140
141         ra = *((u1 **) (sp + framesize - SIZEOF_VOID_P));
142
143         return ra;
144 }
145
146
147 /* md_get_method_patch_address *************************************************
148
149    Gets the patch address of the currently compiled method. The offset
150    is extracted from the load instruction(s) before the jump and added
151    to the right base address (PV or REG_METHODPTR).
152
153    INVOKESTATIC/SPECIAL:
154
155    a77bffb8    ldq     pv,-72(pv)
156    6b5b4000    jsr     (pv)
157
158    INVOKEVIRTUAL:
159
160    a7900000    ldq     at,0(a0)
161    a77c0000    ldq     pv,0(at)
162    6b5b4000    jsr     (pv)
163
164    INVOKEINTERFACE:
165
166    a7900000    ldq     at,0(a0)
167    a79cff98    ldq     at,-104(at)
168    a77c0018    ldq     pv,24(at)
169    6b5b4000    jsr     (pv)
170
171 *******************************************************************************/
172
173 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
174 {
175         u4  mcode;
176         s4  offset;
177         u1 *pa;                             /* patch address                      */
178
179         /* go back to the actual load instruction (2 instructions on Alpha) */
180
181         ra = ra - 2 * 4;
182
183         /* get first instruction word on current PC */
184
185         mcode = *((u4 *) ra);
186
187         /* check if we have 2 instructions (lui) */
188
189         if ((mcode >> 16) == 0x3c19) {
190                 /* XXX write a regression for this */
191                 assert(0);
192
193                 /* get displacement of first instruction (lui) */
194
195                 offset = (s4) (mcode << 16);
196
197                 /* get displacement of second instruction (daddiu) */
198
199                 mcode = *((u4 *) (ra + 1 * 4));
200
201                 assert((mcode >> 16) == 0x6739);
202
203                 offset += (s2) (mcode & 0x0000ffff);
204
205         } else {
206                 /* get first instruction (ldq) */
207
208                 mcode = *((u4 *) ra);
209
210                 /* get the offset from the instruction */
211
212                 offset = (s2) (mcode & 0x0000ffff);
213
214                 /* check for call with REG_METHODPTR: ldq pv,0(at) */
215
216                 if ((mcode >> 16) == 0xa77c) {
217                         /* in this case we use the passed method pointer */
218
219                         /* return NULL if no mptr was specified (used for replacement) */
220
221                         if (mptr == NULL)
222                                 return NULL;
223
224                         pa = mptr + offset;
225
226                 } else {
227                         /* in the normal case we check for a `ldq pv,-72(pv)' instruction */
228
229                         assert((mcode >> 16) == 0xa77b);
230
231                         /* and get the final data segment address */
232
233                         pa = sfi->pv + offset;
234                 }
235         }
236
237         return pa;
238 }
239
240
241 /* md_codegen_get_pv_from_pc ***************************************************
242
243    Machine code:
244
245    6b5b4000    jsr     (pv)
246    277afffe    ldah    pv,-2(ra)
247    237ba61c    lda     pv,-23012(pv)
248
249 *******************************************************************************/
250
251 u1 *md_codegen_get_pv_from_pc(u1 *ra)
252 {
253         u1 *pv;
254         u4  mcode;
255         s4  offset;
256
257         pv = ra;
258
259         /* get first instruction word after jump */
260
261         mcode = *((u4 *) ra);
262
263         /* check if we have 2 instructions (ldah, lda) */
264
265         if ((mcode >> 16) == 0x277a) {
266                 /* get displacement of first instruction (ldah) */
267
268                 offset = (s4) (mcode << 16);
269                 pv += offset;
270
271                 /* get displacement of second instruction (lda) */
272
273                 mcode = *((u4 *) (ra + 1 * 4));
274
275                 assert((mcode >> 16) == 0x237b);
276
277                 offset = (s2) (mcode & 0x0000ffff);
278                 pv += offset;
279         }
280         else {
281                 /* get displacement of first instruction (lda) */
282
283                 assert((mcode >> 16) == 0x237a);
284
285                 offset = (s2) (mcode & 0x0000ffff);
286                 pv += offset;
287         }
288
289         return pv;
290 }
291
292
293 /* md_cacheflush ***************************************************************
294
295    Calls the system's function to flush the instruction and data
296    cache.
297
298 *******************************************************************************/
299
300 void md_cacheflush(u1 *addr, s4 nbytes)
301 {
302         asm_cacheflush(addr, nbytes);
303 }
304
305
306 /* md_icacheflush **************************************************************
307
308    Calls the system's function to flush the instruction cache.
309
310 *******************************************************************************/
311
312 void md_icacheflush(u1 *addr, s4 nbytes)
313 {
314         asm_cacheflush(addr, nbytes);
315 }
316
317
318 /* md_patch_replacement_point **************************************************
319
320    Patch the given replacement point.
321
322 *******************************************************************************/
323
324 #if defined(ENABLE_REPLACEMENT)
325 void md_patch_replacement_point(codeinfo *code, s4 index, rplpoint *rp, u1 *savedmcode)
326 {
327         s4 disp;
328         u4 mcode;
329
330         if (index < 0) {
331                 /* restore the patched-over instruction */
332                 *(u4*)(rp->pc) = *(u4*)(savedmcode);
333         }
334         else {
335                 /* save the current machine code */
336                 *(u4*)(savedmcode) = *(u4*)(rp->pc);
337
338                 /* build the machine code for the patch */
339                 disp = ((u4*)code->replacementstubs - (u4*)rp->pc)
340                            + index * REPLACEMENT_STUB_SIZE
341                            - 1;
342
343                 /* BR */
344         mcode = (((s4) (0x30)) << 26) | ((REG_ZERO) << 21) | ((disp) & 0x1fffff);
345
346                 /* write the new machine code */
347                 *(u4*)(rp->pc) = mcode;
348         }
349         
350 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER) && 0
351         {
352                 u1* u1ptr = rp->pc;
353                 DISASSINSTR(u1ptr);
354                 fflush(stdout);
355         }
356 #endif
357                         
358         /* flush instruction cache */
359     md_icacheflush(rp->pc,4);
360 }
361 #endif /* defined(ENABLE_REPLACEMENT) */
362
363 /*
364  * These are local overrides for various environment variables in Emacs.
365  * Please do not remove this and leave it at the end of the file, where
366  * Emacs will automagically detect them.
367  * ---------------------------------------------------------------------
368  * Local variables:
369  * mode: c
370  * indent-tabs-mode: t
371  * c-basic-offset: 4
372  * tab-width: 4
373  * End:
374  * vim:noexpandtab:sw=4:ts=4:
375  */