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