fcd62cead4902d82c27a3e0097efe1cd5ab2227b
[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/abi-asm.h"
51 #include "vm/jit/asmpart.h"
52 #include "vm/jit/dseg.h"
53 #include "vm/jit/emit.h"
54 #include "vm/jit/jit.h"
55 #include "vm/jit/replace.h"
56
57
58 /* code generation functions **************************************************/
59
60 /* emit_load *******************************************************************
61
62    Emits a possible load of an operand.
63
64 *******************************************************************************/
65
66 s4 emit_load(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
67 {
68         codegendata  *cd;
69         s4            disp;
70         s4            reg;
71
72         /* get required compiler data */
73
74         cd = jd->cd;
75
76         if (src->flags & INMEMORY) {
77                 COUNT_SPILLS;
78
79                 disp = src->regoff * 8;
80
81                 if (IS_FLT_DBL_TYPE(src->type)) {
82                         if (IS_2_WORD_TYPE(src->type))
83                                 M_DLD(tempreg, REG_SP, disp);
84                         else
85                                 M_FLD(tempreg, REG_SP, disp);
86                 } else
87                         M_LLD(tempreg, REG_SP, disp);
88
89                 reg = tempreg;
90         } else
91                 reg = src->regoff;
92
93         return reg;
94 }
95
96 /* emit_load_s1 ****************************************************************
97
98    Emits a possible load of the first source operand.
99
100 *******************************************************************************/
101
102 s4 emit_load_s1(jitdata *jd, instruction *iptr, s4 tempreg)
103 {
104         stackptr src;
105         s4       reg;
106
107         src = iptr->s1.var;
108
109         reg = emit_load(jd, iptr, src, tempreg);
110
111         return reg;
112 }
113
114
115 /* emit_load_s2 ****************************************************************
116
117    Emits a possible load of the second source operand.
118
119 *******************************************************************************/
120
121 s4 emit_load_s2(jitdata *jd, instruction *iptr, s4 tempreg)
122 {
123         stackptr src;
124         s4       reg;
125
126         src = iptr->sx.s23.s2.var;
127
128         reg = emit_load(jd, iptr, src, tempreg);
129
130         return reg;
131 }
132
133
134 /* emit_load_s3 ****************************************************************
135
136    Emits a possible load of the third source operand.
137
138 *******************************************************************************/
139
140 s4 emit_load_s3(jitdata *jd, instruction *iptr, s4 tempreg)
141 {
142         stackptr src;
143         s4       reg;
144
145         src = iptr->sx.s23.s3.var;
146
147         reg = emit_load(jd, iptr, src, tempreg);
148
149         return reg;
150 }
151
152
153 /* emit_store ******************************************************************
154
155    Emits a possible store to variable.
156
157 *******************************************************************************/
158
159 void emit_store(jitdata *jd, instruction *iptr, stackptr dst, s4 d)
160 {
161         codegendata  *cd;
162         s4            disp;
163
164         /* get required compiler data */
165
166         cd = jd->cd;
167
168         if (dst->flags & INMEMORY) {
169                 COUNT_SPILLS;
170
171                 disp = dst->regoff * 8;
172
173                 if (IS_FLT_DBL_TYPE(dst->type)) {
174                         if (IS_2_WORD_TYPE(dst->type))
175                                 M_DST(d, REG_SP, disp);
176                         else
177                                 M_FST(d, REG_SP, disp);
178                 } else
179                         M_LST(d, REG_SP, disp);
180         }
181 }
182
183 /* emit_store_dst **************************************************************
184
185    Emits a possible store to the destination operand of an instruction.
186
187 *******************************************************************************/
188
189 void emit_store_dst(jitdata *jd, instruction *iptr, s4 d)
190 {
191         emit_store(jd, iptr, iptr->dst.var, d);
192 }
193
194
195 /* emit_copy *******************************************************************
196
197    XXX
198
199 *******************************************************************************/
200
201 void emit_copy(jitdata *jd, instruction *iptr, stackptr src, stackptr dst)
202 {
203         codegendata  *cd;
204         registerdata *rd;
205         s4            s1, d;
206
207         /* get required compiler data */
208
209         cd = jd->cd;
210         rd = jd->rd;
211
212         stackptr src;
213         s4       reg;
214
215         src = iptr->sx.s23.s3.var;
216
217         reg = emit_load(jd, iptr, src, tempreg);
218
219         return reg;
220         if ((src->regoff != dst->regoff) ||
221                 ((src->flags ^ dst->flags) & INMEMORY)) {
222                 d = codegen_reg_of_var(rd, iptr->opc, dst, REG_IFTMP);
223                 s1 = emit_load_s1(jd, iptr, src, d);
224
225                 if (s1 != d) {
226                         if (IS_FLT_DBL_TYPE(src->type)) {
227                                 if (IS_2_WORD_TYPE(src->type))
228                                         M_DMOV(s1, d);
229                                 else
230                                         M_FMOV(s1, d);
231                         } else
232                                 M_MOV(s1, d);
233                 }
234
235                 emit_store(jd, iptr, dst, d);
236         }
237 }
238
239
240 /* emit_iconst *****************************************************************
241
242    XXX
243
244 *******************************************************************************/
245
246 void emit_iconst(codegendata *cd, s4 d, s4 value)
247 {
248         s4 disp;
249
250     if ((value >= -32768) && (value <= 32767))
251         M_IADD_IMM(REG_ZERO, value, d);
252         else if ((value >= 0) && (value <= 0xffff))
253         M_OR_IMM(REG_ZERO, value, d);
254         else {
255         disp = dseg_adds4(cd, value);
256         M_ILD(d, REG_PV, disp);
257     }
258 }
259
260
261 /* emit_lconst *****************************************************************
262
263    XXX
264
265 *******************************************************************************/
266
267 void emit_lconst(codegendata *cd, s4 d, s8 value)
268 {
269         s4 disp;
270
271         if ((value >= -32768) && (value <= 32767))
272                 M_LADD_IMM(REG_ZERO, value, d);
273         else if ((value >= 0) && (value <= 0xffff))
274                 M_OR_IMM(REG_ZERO, value, d);
275         else {
276                 disp = dseg_adds8(cd, value);
277                 M_LLD(d, REG_PV, disp);
278         }
279 }
280
281
282 /* emit_exception_stubs ********************************************************
283
284    Generates the code for the exception stubs.
285
286 *******************************************************************************/
287
288 void emit_exception_stubs(jitdata *jd)
289 {
290         codegendata  *cd;
291         registerdata *rd;
292         exceptionref *eref;
293         s4            targetdisp;
294         s4            disp;
295
296         /* get required compiler data */
297
298         cd = jd->cd;
299         rd = jd->rd;
300
301         /* generate exception stubs */
302
303         targetdisp = 0;
304
305         for (eref = cd->exceptionrefs; eref != NULL; eref = eref->next) {
306                 gen_resolvebranch(cd->mcodebase + eref->branchpos, 
307                                                   eref->branchpos, cd->mcodeptr - cd->mcodebase);
308
309                 MCODECHECK(100);
310
311                 /* Check if the exception is an
312                    ArrayIndexOutOfBoundsException.  If so, move index register
313                    into REG_ITMP1. */
314
315                 if (eref->reg != -1)
316                         M_MOV(eref->reg, REG_ITMP1);
317
318                 /* calcuate exception address */
319
320                 M_LDA(REG_ITMP2_XPC, REG_PV, eref->branchpos - 4);
321
322                 /* move function to call into REG_ITMP3 */
323
324                 disp = dseg_addaddress(cd, eref->function);
325                 M_ALD(REG_ITMP3, REG_PV, disp);
326
327                 if (targetdisp == 0) {
328                         targetdisp = ((u4 *) cd->mcodeptr) - ((u4 *) cd->mcodebase);
329
330                         M_MOV(REG_PV, rd->argintregs[0]);
331                         M_MOV(REG_SP, rd->argintregs[1]);
332
333                         if (jd->isleafmethod)
334                                 M_MOV(REG_RA, rd->argintregs[2]);
335                         else
336                                 M_ALD(rd->argintregs[2],
337                                           REG_SP, cd->stackframesize * 8 - SIZEOF_VOID_P);
338
339                         M_MOV(REG_ITMP2_XPC, rd->argintregs[3]);
340                         M_MOV(REG_ITMP1, rd->argintregs[4]);
341
342                         M_ASUB_IMM(REG_SP, 2 * 8, REG_SP);
343                         M_AST(REG_ITMP2_XPC, REG_SP, 0 * 8);
344
345                         if (jd->isleafmethod)
346                                 M_AST(REG_RA, REG_SP, 1 * 8);
347
348                         M_JSR(REG_RA, REG_ITMP3);
349                         M_NOP;
350                         M_MOV(REG_RESULT, REG_ITMP1_XPTR);
351
352                         if (jd->isleafmethod)
353                                 M_ALD(REG_RA, REG_SP, 1 * 8);
354
355                         M_ALD(REG_ITMP2_XPC, REG_SP, 0 * 8);
356                         M_AADD_IMM(REG_SP, 2 * 8, REG_SP);
357
358                         disp = dseg_addaddress(cd, asm_handle_exception);
359                         M_ALD(REG_ITMP3, REG_PV, disp);
360                         M_JMP(REG_ITMP3);
361                         M_NOP;
362                 }
363                 else {
364                         disp = (((u4 *) cd->mcodebase) + targetdisp) -
365                                 (((u4 *) cd->mcodeptr) + 1);
366
367                         M_BR(disp);
368                         M_NOP;
369                 }
370         }
371 }
372
373
374 /* emit_patcher_stubs **********************************************************
375
376    Generates the code for the patcher stubs.
377
378 *******************************************************************************/
379
380 void emit_patcher_stubs(jitdata *jd)
381 {
382         codegendata *cd;
383         patchref    *pref;
384         u4           mcode[2];
385         u1          *savedmcodeptr;
386         u1          *tmpmcodeptr;
387         s4           targetdisp;
388         s4           disp;
389
390         /* get required compiler data */
391
392         cd = jd->cd;
393
394         /* generate code patching stub call code */
395
396         targetdisp = 0;
397
398         for (pref = cd->patchrefs; pref != NULL; pref = pref->next) {
399                 /* check code segment size */
400
401                 MCODECHECK(100);
402
403                 /* Get machine code which is patched back in later. The
404                    call is 2 instruction words long. */
405
406                 tmpmcodeptr = (u1 *) (cd->mcodebase + pref->branchpos);
407
408                 /* We use 2 loads here as an unaligned 8-byte read on 64-bit
409                    MIPS causes a SIGSEGV and using the same code for both
410                    architectures is much better. */
411
412                 mcode[0] = ((u4 *) tmpmcodeptr)[0];
413                 mcode[1] = ((u4 *) tmpmcodeptr)[1];
414
415                 /* Patch in the call to call the following code (done at
416                    compile time). */
417
418                 savedmcodeptr = cd->mcodeptr;   /* save current mcodeptr          */
419                 cd->mcodeptr  = tmpmcodeptr;    /* set mcodeptr to patch position */
420
421                 disp = ((u4 *) savedmcodeptr) - (((u4 *) tmpmcodeptr) + 1);
422
423                 if ((disp < (s4) 0xffff8000) || (disp > (s4) 0x00007fff)) {
424                         *exceptionptr =
425                                 new_internalerror("Jump offset is out of range: %d > +/-%d",
426                                                                   disp, 0x00007fff);
427                         return;
428                 }
429
430                 M_BR(disp);
431                 M_NOP;
432
433                 cd->mcodeptr = savedmcodeptr;   /* restore the current mcodeptr   */
434
435                 /* create stack frame */
436
437                 M_ASUB_IMM(REG_SP, 6 * 8, REG_SP);
438
439                 /* calculate return address and move it onto the stack */
440
441                 M_LDA(REG_ITMP3, REG_PV, pref->branchpos);
442                 M_AST(REG_ITMP3, REG_SP, 5 * 8);
443
444                 /* move pointer to java_objectheader onto stack */
445
446 #if defined(ENABLE_THREADS)
447                 /* create a virtual java_objectheader */
448
449                 (void) dseg_addaddress(cd, NULL);                          /* flcword */
450                 (void) dseg_addaddress(cd, lock_get_initial_lock_word());
451                 disp = dseg_addaddress(cd, NULL);                          /* vftbl   */
452
453                 M_LDA(REG_ITMP3, REG_PV, disp);
454                 M_AST(REG_ITMP3, REG_SP, 4 * 8);
455 #else
456                 /* do nothing */
457 #endif
458
459                 /* move machine code onto stack */
460
461                 disp = dseg_adds4(cd, mcode[0]);
462                 M_ILD(REG_ITMP3, REG_PV, disp);
463                 M_IST(REG_ITMP3, REG_SP, 3 * 8);
464
465                 disp = dseg_adds4(cd, mcode[1]);
466                 M_ILD(REG_ITMP3, REG_PV, disp);
467                 M_IST(REG_ITMP3, REG_SP, 3 * 8 + 4);
468
469                 /* move class/method/field reference onto stack */
470
471                 disp = dseg_addaddress(cd, pref->ref);
472                 M_ALD(REG_ITMP3, REG_PV, disp);
473                 M_AST(REG_ITMP3, REG_SP, 2 * 8);
474
475                 /* move data segment displacement onto stack */
476
477                 disp = dseg_adds4(cd, pref->disp);
478                 M_ILD(REG_ITMP3, REG_PV, disp);
479                 M_IST(REG_ITMP3, REG_SP, 1 * 8);
480
481                 /* move patcher function pointer onto stack */
482
483                 disp = dseg_addaddress(cd, pref->patcher);
484                 M_ALD(REG_ITMP3, REG_PV, disp);
485                 M_AST(REG_ITMP3, REG_SP, 0 * 8);
486
487                 if (targetdisp == 0) {
488                         targetdisp = ((u4 *) cd->mcodeptr) - ((u4 *) cd->mcodebase);
489
490                         disp = dseg_addaddress(cd, asm_patcher_wrapper);
491                         M_ALD(REG_ITMP3, REG_PV, disp);
492                         M_JMP(REG_ITMP3);
493                         M_NOP;
494                 }
495                 else {
496                         disp = (((u4 *) cd->mcodebase) + targetdisp) -
497                                 (((u4 *) cd->mcodeptr) + 1);
498
499                         M_BR(disp);
500                         M_NOP;
501                 }
502         }
503 }
504
505
506 /* emit_replacement_stubs ******************************************************
507
508    Generates the code for the replacement stubs.
509
510 *******************************************************************************/
511
512 void emit_replacement_stubs(jitdata *jd)
513 {
514         codegendata *cd;
515         codeinfo    *code;
516         rplpoint    *rplp;
517         u1          *savedmcodeptr;
518         s4           disp;
519         s4           i;
520
521         /* get required compiler data */
522
523         cd   = jd->cd;
524         code = jd->code;
525
526         rplp = code->rplpoints;
527
528         for (i = 0; i < code->rplpointcount; ++i, ++rplp) {
529                 /* check code segment size */
530
531                 MCODECHECK(100);
532
533                 /* note start of stub code */
534
535                 rplp->outcode = (u1 *) (ptrint) (cd->mcodeptr - cd->mcodebase);
536
537                 /* make machine code for patching */
538
539                 savedmcodeptr = cd->mcodeptr;
540                 cd->mcodeptr  = (u1 *) &(rplp->mcode);
541
542                 disp = (ptrint) ((s4 *) rplp->outcode - (s4 *) rplp->pc) - 1;
543
544                 if ((disp < (s4) 0xffff8000) || (disp > (s4) 0x00007fff)) {
545                         *exceptionptr =
546                                 new_internalerror("Jump offset is out of range: %d > +/-%d",
547                                                                   disp, 0x00007fff);
548                         return;
549                 }
550
551                 M_BR(disp);
552                 M_NOP; /* delay slot */
553
554                 cd->mcodeptr = savedmcodeptr;
555
556                 /* create stack frame - 16-byte aligned */
557
558                 M_ASUB_IMM(REG_SP, 2 * 8, REG_SP);
559
560                 /* push address of `rplpoint` struct */
561
562                 disp = dseg_addaddress(cd, rplp);
563                 M_ALD(REG_ITMP3, REG_PV, disp);
564                 M_AST(REG_ITMP3, REG_SP, 0 * 8);
565
566                 /* jump to replacement function */
567
568                 disp = dseg_addaddress(cd, asm_replacement_out);
569                 M_ALD(REG_ITMP3, REG_PV, disp);
570                 M_JMP(REG_ITMP3);
571                 M_NOP; /* delay slot */
572         }
573 }
574
575
576 /* emit_verbosecall_enter ******************************************************
577
578    Generates the code for the call trace.
579
580 *******************************************************************************/
581
582 #if !defined(NDEBUG)
583 void emit_verbosecall_enter(jitdata *jd)
584 {
585         methodinfo   *m;
586         codegendata  *cd;
587         registerdata *rd;
588         methoddesc   *md;
589         s4            disp;
590         s4            i, t;
591
592         /* get required compiler data */
593
594         m  = jd->m;
595         cd = jd->cd;
596         rd = jd->rd;
597
598         md = m->parseddesc;
599
600         /* mark trace code */
601
602         M_NOP;
603
604         M_LDA(REG_SP, REG_SP, -(2 + ARG_CNT + TMP_CNT) * 8);
605         M_AST(REG_RA, REG_SP, 1 * 8);
606
607         /* save argument registers */
608
609         for (i = 0; i < INT_ARG_CNT; i++)
610                 M_LST(rd->argintregs[i], REG_SP, (2 + i) * 8);
611
612         for (i = 0; i < FLT_ARG_CNT; i++)
613                 M_DST(rd->argfltregs[i], REG_SP, (2 + INT_ARG_CNT + i) * 8);
614
615         /* save temporary registers for leaf methods */
616
617         if (jd->isleafmethod) {
618                 for (i = 0; i < INT_TMP_CNT; i++)
619                         M_LST(rd->tmpintregs[i], REG_SP, (2 + ARG_CNT + i) * 8);
620
621                 for (i = 0; i < FLT_TMP_CNT; i++)
622                         M_DST(rd->tmpfltregs[i], REG_SP, (2 + ARG_CNT + INT_TMP_CNT + i) * 8);
623         }
624
625         /* load float arguments into integer registers */
626
627         for (i = 0; i < md->paramcount && i < INT_ARG_CNT; i++) {
628                 t = md->paramtypes[i].type;
629
630                 if (IS_FLT_DBL_TYPE(t)) {
631                         if (IS_2_WORD_TYPE(t)) {
632                                 M_DST(rd->argfltregs[i], REG_SP, 0 * 8);
633                                 M_LLD(rd->argintregs[i], REG_SP, 0 * 8);
634                         }
635                         else {
636                                 M_FST(rd->argfltregs[i], REG_SP, 0 * 8);
637                                 M_ILD(rd->argintregs[i], REG_SP, 0 * 8);
638                         }
639                 }
640         }
641
642         disp = dseg_addaddress(cd, m);
643         M_ALD(REG_ITMP1, REG_PV, disp);
644         M_AST(REG_ITMP1, REG_SP, 0 * 8);
645         disp = dseg_addaddress(cd, builtin_trace_args);
646         M_ALD(REG_ITMP3, REG_PV, disp);
647         M_JSR(REG_RA, REG_ITMP3);
648         M_NOP;
649
650         /* restore argument registers */
651
652         for (i = 0; i < INT_ARG_CNT; i++)
653                 M_LLD(rd->argintregs[i], REG_SP, (2 + i) * 8);
654
655         for (i = 0; i < FLT_ARG_CNT; i++)
656                 M_DLD(rd->argfltregs[i], REG_SP, (2 + INT_ARG_CNT + i) * 8);
657
658         /* restore temporary registers for leaf methods */
659
660         if (jd->isleafmethod) {
661                 for (i = 0; i < INT_TMP_CNT; i++)
662                         M_LLD(rd->tmpintregs[i], REG_SP, (2 + ARG_CNT + i) * 8);
663
664                 for (i = 0; i < FLT_TMP_CNT; i++)
665                         M_DLD(rd->tmpfltregs[i], REG_SP, (2 + ARG_CNT + INT_TMP_CNT + i) * 8);
666         }
667
668         M_ALD(REG_RA, REG_SP, 1 * 8);
669         M_LDA(REG_SP, REG_SP, (2 + ARG_CNT + TMP_CNT) * 8);
670
671         /* mark trace code */
672
673         M_NOP;
674 }
675 #endif /* !defined(NDEBUG) */
676
677
678 /* emit_verbosecall_exit *******************************************************
679
680    Generates the code for the call trace.
681
682 *******************************************************************************/
683
684 #if !defined(NDEBUG)
685 void emit_verbosecall_exit(jitdata *jd)
686 {
687         methodinfo   *m;
688         codegendata  *cd;
689         registerdata *rd;
690         s4            disp;
691
692         /* get required compiler data */
693
694         m  = jd->m;
695         cd = jd->cd;
696         rd = jd->rd;
697
698         /* mark trace code */
699
700         M_NOP;
701
702         M_LDA(REG_SP, REG_SP, -4 * 8);              /* keep stack 16-byte aligned */
703         M_LST(REG_RA, REG_SP, 0 * 8);
704
705         M_LST(REG_RESULT, REG_SP, 1 * 8);
706         M_DST(REG_FRESULT, REG_SP, 2 * 8);
707
708         disp = dseg_addaddress(cd, m);
709         M_ALD(rd->argintregs[0], REG_PV, disp);
710
711         M_MOV(REG_RESULT, rd->argintregs[1]);
712         M_DMOV(REG_FRESULT, rd->argfltregs[2]);
713         M_FMOV(REG_FRESULT, rd->argfltregs[3]);
714
715         disp = dseg_addaddress(cd, builtin_displaymethodstop);
716         M_ALD(REG_ITMP3, REG_PV, disp);
717         M_JSR(REG_RA, REG_ITMP3);
718         M_NOP;
719
720         M_DLD(REG_FRESULT, REG_SP, 2 * 8);
721         M_LLD(REG_RESULT, REG_SP, 1 * 8);
722
723         M_LLD(REG_RA, REG_SP, 0 * 8);
724         M_LDA(REG_SP, REG_SP, 4 * 8);
725
726         /* mark trace code */
727
728         M_NOP;
729 }
730 #endif /* !defined(NDEBUG) */
731
732
733 /*
734  * These are local overrides for various environment variables in Emacs.
735  * Please do not remove this and leave it at the end of the file, where
736  * Emacs will automagically detect them.
737  * ---------------------------------------------------------------------
738  * Local variables:
739  * mode: c
740  * indent-tabs-mode: t
741  * c-basic-offset: 4
742  * tab-width: 4
743  * End:
744  * vim:noexpandtab:sw=4:ts=4:
745  */