* src/vm/jit/mips/emit.c (config.h): Added.
[cacao.git] / src / vm / jit / mips / emit.c
1 /* src/vm/jit/mips/emit.c - MIPS code emitter functions
2
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
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    Contact: cacao@cacaojvm.org
26
27    Authors: Christian Thalinger
28
29    Changes:
30
31    $Id: emitfuncs.c 4398 2006-01-31 23:43:08Z twisti $
32
33 */
34
35
36 #include "config.h"
37
38 #include "vm/types.h"
39
40 #include "md-abi.h"
41
42 #include "vm/jit/mips/codegen.h"
43
44 #if defined(ENABLE_THREADS)
45 # include "threads/native/lock.h"
46 #endif
47
48 #include "vm/exceptions.h"
49 #include "vm/stringlocal.h" /* XXX for gen_resolvebranch */
50 #include "vm/jit/asmpart.h"
51 #include "vm/jit/dseg.h"
52 #include "vm/jit/emit.h"
53 #include "vm/jit/jit.h"
54 #include "vm/jit/replace.h"
55
56
57 /* code generation functions **************************************************/
58
59 /* emit_load_s1 ****************************************************************
60
61    Emits a possible load of the first source operand.
62
63 *******************************************************************************/
64
65 s4 emit_load_s1(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
66 {
67         codegendata  *cd;
68         s4            disp;
69         s4            reg;
70
71         /* get required compiler data */
72
73         cd = jd->cd;
74
75         if (src->flags & INMEMORY) {
76                 COUNT_SPILLS;
77
78                 disp = src->regoff * 8;
79
80                 if (IS_FLT_DBL_TYPE(src->type)) {
81                         if (IS_2_WORD_TYPE(src->type))
82                                 M_DLD(tempreg, REG_SP, disp);
83                         else
84                                 M_FLD(tempreg, REG_SP, disp);
85                 } else
86                         M_LLD(tempreg, REG_SP, disp);
87
88                 reg = tempreg;
89         } else
90                 reg = src->regoff;
91
92         return reg;
93 }
94
95
96 /* emit_load_s2 ****************************************************************
97
98    Emits a possible load of the second source operand.
99
100 *******************************************************************************/
101
102 s4 emit_load_s2(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
103 {
104         codegendata  *cd;
105         s4            disp;
106         s4            reg;
107
108         /* get required compiler data */
109
110         cd = jd->cd;
111
112         if (src->flags & INMEMORY) {
113                 COUNT_SPILLS;
114
115                 disp = src->regoff * 8;
116
117                 if (IS_FLT_DBL_TYPE(src->type)) {
118                         if (IS_2_WORD_TYPE(src->type))
119                                 M_DLD(tempreg, REG_SP, disp);
120                         else
121                                 M_FLD(tempreg, REG_SP, disp);
122                 } else
123                         M_LLD(tempreg, REG_SP, disp);
124
125                 reg = tempreg;
126         } else
127                 reg = src->regoff;
128
129         return reg;
130 }
131
132
133 /* emit_load_s3 ****************************************************************
134
135    Emits a possible load of the third source operand.
136
137 *******************************************************************************/
138
139 s4 emit_load_s3(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
140 {
141         codegendata  *cd;
142         s4            disp;
143         s4            reg;
144
145         /* get required compiler data */
146
147         cd = jd->cd;
148
149         if (src->flags & INMEMORY) {
150                 COUNT_SPILLS;
151
152                 disp = src->regoff * 8;
153
154                 if (IS_FLT_DBL_TYPE(src->type)) {
155                         if (IS_2_WORD_TYPE(src->type))
156                                 M_DLD(tempreg, REG_SP, disp);
157                         else
158                                 M_FLD(tempreg, REG_SP, disp);
159                 } else
160                         M_LLD(tempreg, REG_SP, disp);
161
162                 reg = tempreg;
163         } else
164                 reg = src->regoff;
165
166         return reg;
167 }
168
169
170 /* emit_store ******************************************************************
171
172    XXX
173
174 *******************************************************************************/
175
176 void emit_store(jitdata *jd, instruction *iptr, stackptr dst, s4 d)
177 {
178         codegendata  *cd;
179         s4            disp;
180
181         /* get required compiler data */
182
183         cd = jd->cd;
184
185         if (dst->flags & INMEMORY) {
186                 COUNT_SPILLS;
187
188                 disp = dst->regoff * 8;
189
190                 if (IS_FLT_DBL_TYPE(dst->type)) {
191                         if (IS_2_WORD_TYPE(dst->type))
192                                 M_DST(d, REG_SP, disp);
193                         else
194                                 M_FST(d, REG_SP, disp);
195                 } else
196                         M_LST(d, REG_SP, disp);
197         }
198 }
199
200
201 /* emit_copy *******************************************************************
202
203    XXX
204
205 *******************************************************************************/
206
207 void emit_copy(jitdata *jd, instruction *iptr, stackptr src, stackptr dst)
208 {
209         codegendata  *cd;
210         registerdata *rd;
211         s4            s1, d;
212
213         /* get required compiler data */
214
215         cd = jd->cd;
216         rd = jd->rd;
217
218         if ((src->regoff != dst->regoff) ||
219                 ((src->flags ^ dst->flags) & INMEMORY)) {
220                 d = codegen_reg_of_var(rd, iptr->opc, dst, REG_IFTMP);
221                 s1 = emit_load_s1(jd, iptr, src, d);
222
223                 if (s1 != d) {
224                         if (IS_FLT_DBL_TYPE(src->type)) {
225                                 if (IS_2_WORD_TYPE(src->type))
226                                         M_DMOV(s1, d);
227                                 else
228                                         M_FMOV(s1, d);
229                         } else
230                                 M_MOV(s1, d);
231                 }
232
233                 emit_store(jd, iptr, dst, d);
234         }
235 }
236
237
238 /* emit_iconst *****************************************************************
239
240    XXX
241
242 *******************************************************************************/
243
244 void emit_iconst(codegendata *cd, s4 d, s4 value)
245 {
246         s4 disp;
247
248     if ((value >= -32768) && (value <= 32767))
249         M_IADD_IMM(REG_ZERO, value, d);
250         else if ((value >= 0) && (value <= 0xffff))
251         M_OR_IMM(REG_ZERO, value, d);
252         else {
253         disp = dseg_adds4(cd, value);
254         M_ILD(d, REG_PV, disp);
255     }
256 }
257
258
259 /* emit_lconst *****************************************************************
260
261    XXX
262
263 *******************************************************************************/
264
265 void emit_lconst(codegendata *cd, s4 d, s8 value)
266 {
267         s4 disp;
268
269         if ((value >= -32768) && (value <= 32767))
270                 M_LADD_IMM(REG_ZERO, value, d);
271         else if ((value >= 0) && (value <= 0xffff))
272                 M_OR_IMM(REG_ZERO, value, d);
273         else {
274                 disp = dseg_adds8(cd, value);
275                 M_LLD(d, REG_PV, disp);
276         }
277 }
278
279
280 /* emit_exception_stubs ********************************************************
281
282    Generates the code for the exception stubs.
283
284 *******************************************************************************/
285
286 void emit_exception_stubs(jitdata *jd)
287 {
288         codegendata  *cd;
289         registerdata *rd;
290         exceptionref *eref;
291         s4            targetdisp;
292         s4            disp;
293
294         /* get required compiler data */
295
296         cd = jd->cd;
297         rd = jd->rd;
298
299         /* generate exception stubs */
300
301         targetdisp = 0;
302
303         for (eref = cd->exceptionrefs; eref != NULL; eref = eref->next) {
304                 gen_resolvebranch(cd->mcodebase + eref->branchpos, 
305                                                   eref->branchpos, cd->mcodeptr - cd->mcodebase);
306
307                 MCODECHECK(100);
308
309                 /* Check if the exception is an
310                    ArrayIndexOutOfBoundsException.  If so, move index register
311                    into REG_ITMP1. */
312
313                 if (eref->reg != -1)
314                         M_MOV(eref->reg, REG_ITMP1);
315
316                 /* calcuate exception address */
317
318                 M_LDA(REG_ITMP2_XPC, REG_PV, eref->branchpos - 4);
319
320                 /* move function to call into REG_ITMP3 */
321
322                 disp = dseg_addaddress(cd, eref->function);
323                 M_ALD(REG_ITMP3, REG_PV, disp);
324
325                 if (targetdisp == 0) {
326                         targetdisp = ((u4 *) cd->mcodeptr) - ((u4 *) cd->mcodebase);
327
328                         M_MOV(REG_PV, rd->argintregs[0]);
329                         M_MOV(REG_SP, rd->argintregs[1]);
330
331                         if (jd->isleafmethod)
332                                 M_MOV(REG_RA, rd->argintregs[2]);
333                         else
334                                 M_ALD(rd->argintregs[2],
335                                           REG_SP, cd->stackframesize * 8 - SIZEOF_VOID_P);
336
337                         M_MOV(REG_ITMP2_XPC, rd->argintregs[3]);
338                         M_MOV(REG_ITMP1, rd->argintregs[4]);
339
340                         M_ASUB_IMM(REG_SP, 2 * 8, REG_SP);
341                         M_AST(REG_ITMP2_XPC, REG_SP, 0 * 8);
342
343                         if (jd->isleafmethod)
344                                 M_AST(REG_RA, REG_SP, 1 * 8);
345
346                         M_JSR(REG_RA, REG_ITMP3);
347                         M_NOP;
348                         M_MOV(REG_RESULT, REG_ITMP1_XPTR);
349
350                         if (jd->isleafmethod)
351                                 M_ALD(REG_RA, REG_SP, 1 * 8);
352
353                         M_ALD(REG_ITMP2_XPC, REG_SP, 0 * 8);
354                         M_AADD_IMM(REG_SP, 2 * 8, REG_SP);
355
356                         disp = dseg_addaddress(cd, asm_handle_exception);
357                         M_ALD(REG_ITMP3, REG_PV, disp);
358                         M_JMP(REG_ITMP3);
359                         M_NOP;
360                 }
361                 else {
362                         disp = (((u4 *) cd->mcodebase) + targetdisp) -
363                                 (((u4 *) cd->mcodeptr) + 1);
364                         M_BR(disp);
365                         M_NOP;
366                 }
367         }
368 }
369
370
371 /* emit_patcher_stubs **********************************************************
372
373    Generates the code for the patcher stubs.
374
375 *******************************************************************************/
376
377 void emit_patcher_stubs(jitdata *jd)
378 {
379         codegendata *cd;
380         patchref    *pref;
381         u4           mcode;
382         u1          *savedmcodeptr;
383         u1          *tmpmcodeptr;
384         s4           targetdisp;
385         s4           disp;
386
387         /* get required compiler data */
388
389         cd = jd->cd;
390
391         /* generate code patching stub call code */
392
393         targetdisp = 0;
394
395         for (pref = cd->patchrefs; pref != NULL; pref = pref->next) {
396                 /* check code segment size */
397
398                 MCODECHECK(100);
399
400                 /* Get machine code which is patched back in later. The
401                    call is 2 instruction words long. */
402
403                 tmpmcodeptr = (u1 *) (cd->mcodebase + pref->branchpos);
404
405                 /* We need to split this, because an unaligned 8 byte read
406                    causes a SIGSEGV. */
407
408                 mcode = ((u8) ((u4 *) tmpmcodeptr)[1] << 32) +
409                         ((u4 *) tmpmcodeptr)[0];
410
411                 /* Patch in the call to call the following code (done at
412                    compile time). */
413
414                 savedmcodeptr = cd->mcodeptr;   /* save current mcodeptr          */
415                 cd->mcodeptr  = tmpmcodeptr;    /* set mcodeptr to patch position */
416
417                 disp = ((u4 *) savedmcodeptr) - (((u4 *) tmpmcodeptr) + 1);
418
419                 if ((disp < (s4) 0xffff8000) || (disp > (s4) 0x00007fff)) {
420                         *exceptionptr =
421                                 new_internalerror("Jump offset is out of range: %d > +/-%d",
422                                                                   disp, 0x00007fff);
423                         return;
424                 }
425
426                 M_BR(disp);
427                 M_NOP;
428
429                 cd->mcodeptr = savedmcodeptr;   /* restore the current mcodeptr   */
430
431                 /* create stack frame */
432
433                 M_ASUB_IMM(REG_SP, 6 * 8, REG_SP);
434
435                 /* calculate return address and move it onto the stack */
436
437                 M_LDA(REG_ITMP3, REG_PV, pref->branchpos);
438                 M_AST(REG_ITMP3, REG_SP, 5 * 8);
439
440                 /* move pointer to java_objectheader onto stack */
441
442 #if defined(ENABLE_THREADS)
443                 /* create a virtual java_objectheader */
444
445                 (void) dseg_addaddress(cd, NULL);                          /* flcword */
446                 (void) dseg_addaddress(cd, lock_get_initial_lock_word());
447                 disp = dseg_addaddress(cd, NULL);                          /* vftbl   */
448
449                 M_LDA(REG_ITMP3, REG_PV, disp);
450                 M_AST(REG_ITMP3, REG_SP, 4 * 8);
451 #else
452                 /* do nothing */
453 #endif
454
455                 /* move machine code onto stack */
456
457                 disp = dseg_adds8(cd, mcode);
458                 M_LLD(REG_ITMP3, REG_PV, disp);
459                 M_LST(REG_ITMP3, REG_SP, 3 * 8);
460
461                 /* move class/method/field reference onto stack */
462
463                 disp = dseg_addaddress(cd, pref->ref);
464                 M_ALD(REG_ITMP3, REG_PV, disp);
465                 M_AST(REG_ITMP3, REG_SP, 2 * 8);
466
467                 /* move data segment displacement onto stack */
468
469                 disp = dseg_adds4(cd, pref->disp);
470                 M_ILD(REG_ITMP3, REG_PV, disp);
471                 M_IST(REG_ITMP3, REG_SP, 1 * 8);
472
473                 /* move patcher function pointer onto stack */
474
475                 disp = dseg_addaddress(cd, pref->patcher);
476                 M_ALD(REG_ITMP3, REG_PV, disp);
477                 M_AST(REG_ITMP3, REG_SP, 0 * 8);
478
479                 if (targetdisp == 0) {
480                         targetdisp = ((u4 *) cd->mcodeptr) - ((u4 *) cd->mcodebase);
481
482                         disp = dseg_addaddress(cd, asm_patcher_wrapper);
483                         M_ALD(REG_ITMP3, REG_PV, disp);
484                         M_JMP(REG_ITMP3);
485                         M_NOP;
486                 }
487                 else {
488                         disp = (((u4 *) cd->mcodebase) + targetdisp) -
489                                 (((u4 *) cd->mcodeptr) + 1);
490                         M_BR(disp);
491                         M_NOP;
492                 }
493         }
494 }
495
496
497 /* emit_replacement_stubs ******************************************************
498
499    Generates the code for the replacement stubs.
500
501 *******************************************************************************/
502
503 void emit_replacement_stubs(jitdata *jd)
504 {
505         codegendata *cd;
506         codeinfo    *code;
507         rplpoint    *rplp;
508         u1          *savedmcodeptr;
509         s4           disp;
510         s4           i;
511
512         /* get required compiler data */
513
514         cd   = jd->cd;
515         code = jd->code;
516
517         rplp = code->rplpoints;
518
519         for (i = 0; i < code->rplpointcount; ++i, ++rplp) {
520                 /* check code segment size */
521
522                 MCODECHECK(100);
523
524                 /* note start of stub code */
525
526                 rplp->outcode = (u1 *) (ptrint) (cd->mcodeptr - cd->mcodebase);
527
528                 /* make machine code for patching */
529
530                 savedmcodeptr = cd->mcodeptr;
531                 cd->mcodeptr  = (u1 *) &(rplp->mcode);
532
533                 disp = (ptrint) ((s4 *) rplp->outcode - (s4 *) rplp->pc) - 1;
534
535                 if ((disp < (s4) 0xffff8000) || (disp > (s4) 0x00007fff)) {
536                         *exceptionptr =
537                                 new_internalerror("Jump offset is out of range: %d > +/-%d",
538                                                                   disp, 0x00007fff);
539                         return;
540                 }
541
542                 M_BR(disp);
543                 M_NOP; /* delay slot */
544
545                 cd->mcodeptr = savedmcodeptr;
546
547                 /* create stack frame - 16-byte aligned */
548
549                 M_ASUB_IMM(REG_SP, 2 * 8, REG_SP);
550
551                 /* push address of `rplpoint` struct */
552
553                 disp = dseg_addaddress(cd, rplp);
554                 M_ALD(REG_ITMP3, REG_PV, disp);
555                 M_AST(REG_ITMP3, REG_SP, 0 * 8);
556
557                 /* jump to replacement function */
558
559                 disp = dseg_addaddress(cd, asm_replacement_out);
560                 M_ALD(REG_ITMP3, REG_PV, disp);
561                 M_JMP(REG_ITMP3);
562                 M_NOP; /* delay slot */
563         }
564 }
565
566
567 /*
568  * These are local overrides for various environment variables in Emacs.
569  * Please do not remove this and leave it at the end of the file, where
570  * Emacs will automagically detect them.
571  * ---------------------------------------------------------------------
572  * Local variables:
573  * mode: c
574  * indent-tabs-mode: t
575  * c-basic-offset: 4
576  * tab-width: 4
577  * End:
578  * vim:noexpandtab:sw=4:ts=4:
579  */