12cdd796db60b4d312fe42af5437d5130f211cd2
[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, 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: emit.c 4398 2006-01-31 23:43:08Z twisti $
26
27 */
28
29
30 #include "config.h"
31
32 #include <assert.h>
33
34 #include "vm/types.h"
35
36 #include "vm/jit/mips/codegen.h"
37 #include "vm/jit/mips/md-abi.h"
38
39 #include "mm/memory.h"
40
41 #if defined(ENABLE_THREADS)
42 # include "threads/native/lock.h"
43 #endif
44
45 #include "vm/builtin.h"
46 #include "vm/exceptions.h"
47 #include "vm/stringlocal.h" /* XXX for gen_resolvebranch */
48
49 #include "vm/jit/abi-asm.h"
50 #include "vm/jit/asmpart.h"
51 #include "vm/jit/dseg.h"
52 #include "vm/jit/emit-common.h"
53 #include "vm/jit/jit.h"
54 #include "vm/jit/replace.h"
55
56 #include "vmcore/options.h"
57
58
59 /* emit_load *******************************************************************
60
61    Emits a possible load of an operand.
62
63 *******************************************************************************/
64
65 s4 emit_load(jitdata *jd, instruction *iptr, varinfo *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->vv.regoff * 8;
79
80                 switch (src->type) {
81 #if SIZEOF_VOID_P == 8
82                 case TYPE_INT:
83                 case TYPE_LNG:
84                 case TYPE_ADR:
85                         M_LLD(tempreg, REG_SP, disp);
86                         break;
87 #else
88                 case TYPE_INT:
89                 case TYPE_ADR:
90                         M_ILD(tempreg, REG_SP, disp);
91                         break;
92                 case TYPE_LNG:
93                         M_LLD(tempreg, REG_SP, disp);
94                         break;
95 #endif
96                 case TYPE_FLT:
97                         M_FLD(tempreg, REG_SP, disp);
98                         break;
99                 case TYPE_DBL:
100                         M_DLD(tempreg, REG_SP, disp);
101                         break;
102                 default:
103                         vm_abort("emit_load: unknown type %d", src->type);
104                 }
105
106                 reg = tempreg;
107         }
108         else
109                 reg = src->vv.regoff;
110
111         return reg;
112 }
113
114
115 /* emit_load_low ***************************************************************
116
117    Emits a possible load of the low 32-bits of an operand.
118
119 *******************************************************************************/
120
121 #if SIZEOF_VOID_P == 4
122 s4 emit_load_low(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
123 {
124         codegendata  *cd;
125         s4            disp;
126         s4            reg;
127
128         assert(src->type == TYPE_LNG);
129
130         /* get required compiler data */
131
132         cd = jd->cd;
133
134         if (src->flags & INMEMORY) {
135                 COUNT_SPILLS;
136
137                 disp = src->vv.regoff * 8;
138
139 #if WORDS_BIGENDIAN == 1
140                 M_ILD(tempreg, REG_SP, disp + 4);
141 #else
142                 M_ILD(tempreg, REG_SP, disp);
143 #endif
144
145                 reg = tempreg;
146         }
147         else
148                 reg = GET_LOW_REG(src->vv.regoff);
149
150         return reg;
151 }
152 #endif /* SIZEOF_VOID_P == 4 */
153
154
155 /* emit_load_high **************************************************************
156
157    Emits a possible load of the high 32-bits of an operand.
158
159 *******************************************************************************/
160
161 #if SIZEOF_VOID_P == 4
162 s4 emit_load_high(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
163 {
164         codegendata  *cd;
165         s4            disp;
166         s4            reg;
167
168         assert(src->type == TYPE_LNG);
169
170         /* get required compiler data */
171
172         cd = jd->cd;
173
174         if (src->flags & INMEMORY) {
175                 COUNT_SPILLS;
176
177                 disp = src->vv.regoff * 8;
178
179 #if WORDS_BIGENDIAN == 1
180                 M_ILD(tempreg, REG_SP, disp);
181 #else
182                 M_ILD(tempreg, REG_SP, disp + 4);
183 #endif
184
185                 reg = tempreg;
186         }
187         else
188                 reg = GET_HIGH_REG(src->vv.regoff);
189
190         return reg;
191 }
192 #endif /* SIZEOF_VOID_P == 4 */
193
194
195 /* emit_store ******************************************************************
196
197    Emits a possible store to variable.
198
199 *******************************************************************************/
200
201 void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
202 {
203         codegendata  *cd;
204         s4            disp;
205
206         /* get required compiler data */
207
208         cd = jd->cd;
209
210         if (dst->flags & INMEMORY) {
211                 COUNT_SPILLS;
212
213                 disp = dst->vv.regoff * 8;
214
215                 switch (dst->type) {
216 #if SIZEOF_VOID_P == 8
217                 case TYPE_INT:
218                 case TYPE_LNG:
219                 case TYPE_ADR:
220                         M_LST(d, REG_SP, disp);
221                         break;
222 #else
223                 case TYPE_INT:
224                 case TYPE_ADR:
225                         M_IST(d, REG_SP, disp);
226                         break;
227                 case TYPE_LNG:
228                         M_LST(d, REG_SP, disp);
229                         break;
230 #endif
231                 case TYPE_FLT:
232                         M_FST(d, REG_SP, disp);
233                         break;
234                 case TYPE_DBL:
235                         M_DST(d, REG_SP, disp);
236                         break;
237                 default:
238                         vm_abort("emit_store: unknown type %d", dst->type);
239                 }
240         }
241 }
242
243
244 /* emit_copy *******************************************************************
245
246    Generates a register/memory to register/memory copy.
247
248 *******************************************************************************/
249
250 void emit_copy(jitdata *jd, instruction *iptr, varinfo *src, varinfo *dst)
251 {
252         codegendata  *cd;
253         s4            s1, d;
254
255         /* get required compiler data */
256
257         cd = jd->cd;
258
259         if ((src->vv.regoff != dst->vv.regoff) ||
260                 ((src->flags ^ dst->flags) & INMEMORY)) {
261                 /* If one of the variables resides in memory, we can eliminate
262                    the register move from/to the temporary register with the
263                    order of getting the destination register and the load. */
264
265                 if (IS_INMEMORY(src->flags)) {
266 #if SIZEOF_VOID_P == 4
267                         if (IS_2_WORD_TYPE(src->type))
268                                 d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP12_PACKED);
269                         else
270 #endif
271                                 d = codegen_reg_of_var(iptr->opc, dst, REG_IFTMP);
272                         s1 = emit_load(jd, iptr, src, d);
273                 }
274                 else {
275                         s1 = emit_load(jd, iptr, src, REG_IFTMP);
276 #if SIZEOF_VOID_P == 4
277                         if (IS_2_WORD_TYPE(src->type))
278                                 d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP12_PACKED);
279                         else
280 #endif
281                                 d = codegen_reg_of_var(iptr->opc, dst, s1);
282                 }
283
284                 if (s1 != d) {
285                         switch (dst->type) {
286 #if SIZEOF_VOID_P == 8
287                         case TYPE_INT:
288                         case TYPE_LNG:
289                         case TYPE_ADR:
290                                 M_MOV(s1, d);
291                                 break;
292 #else
293                         case TYPE_INT:
294                         case TYPE_ADR:
295                                 M_MOV(s1, d);
296                                 break;
297                         case TYPE_LNG:
298                                 M_LNGMOVE(s1, d);
299                                 break;
300 #endif
301                         case TYPE_FLT:
302                                 M_FMOV(s1, d);
303                                 break;
304                         case TYPE_DBL:
305                                 M_DMOV(s1, d);
306                                 break;
307                         default:
308                                 vm_abort("emit_copy: unknown type %d", dst->type);
309                         }
310                 }
311
312                 emit_store(jd, iptr, dst, d);
313         }
314 }
315
316
317 /* emit_iconst *****************************************************************
318
319    XXX
320
321 *******************************************************************************/
322
323 void emit_iconst(codegendata *cd, s4 d, s4 value)
324 {
325         s4 disp;
326
327     if ((value >= -32768) && (value <= 32767))
328         M_IADD_IMM(REG_ZERO, value, d);
329         else if ((value >= 0) && (value <= 0xffff))
330         M_OR_IMM(REG_ZERO, value, d);
331         else {
332         disp = dseg_add_s4(cd, value);
333         M_ILD(d, REG_PV, disp);
334     }
335 }
336
337
338 /* emit_lconst *****************************************************************
339
340    XXX
341
342 *******************************************************************************/
343
344 void emit_lconst(codegendata *cd, s4 d, s8 value)
345 {
346         s4 disp;
347
348 #if SIZEOF_VOID_P == 8
349         if ((value >= -32768) && (value <= 32767))
350                 M_LADD_IMM(REG_ZERO, value, d);
351         else if ((value >= 0) && (value <= 0xffff))
352                 M_OR_IMM(REG_ZERO, value, d);
353         else {
354                 disp = dseg_add_s8(cd, value);
355                 M_LLD(d, REG_PV, disp);
356         }
357 #else
358         disp = dseg_add_s8(cd, value);
359         M_LLD(d, REG_PV, disp);
360 #endif
361 }
362
363
364 /* emit_branch *****************************************************************
365
366    Emits the code for conditional and unconditional branchs.
367
368    NOTE: The reg argument may contain two packed registers.
369
370 *******************************************************************************/
371
372 void emit_branch(codegendata *cd, s4 disp, s4 condition, s4 reg, u4 opt)
373 {
374         s4 checkdisp;
375         s4 branchdisp;
376
377         /* calculate the different displacements */
378
379         checkdisp  = (disp - 4);
380         branchdisp = (disp - 4) >> 2;
381
382         /* check which branch to generate */
383
384         if (condition == BRANCH_UNCONDITIONAL) {
385                 /* check displacement for overflow */
386
387                 if ((checkdisp < (s4) 0xffff8000) || (checkdisp > (s4) 0x00007fff)) {
388                         /* if the long-branches flag isn't set yet, do it */
389
390                         if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
391                                 cd->flags |= (CODEGENDATA_FLAG_ERROR |
392                                                           CODEGENDATA_FLAG_LONGBRANCHES);
393                         }
394
395                         vm_abort("emit_branch: emit unconditional long-branch code");
396                 }
397                 else {
398                         M_BR(branchdisp);
399                         M_NOP;
400                 }
401         }
402         else {
403                 /* and displacement for overflow */
404
405                 if ((checkdisp < (s4) 0xffff8000) || (checkdisp > (s4) 0x00007fff)) {
406                         /* if the long-branches flag isn't set yet, do it */
407
408                         if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
409                                 cd->flags |= (CODEGENDATA_FLAG_ERROR |
410                                                           CODEGENDATA_FLAG_LONGBRANCHES);
411                         }
412
413                         switch (condition) {
414                         case BRANCH_EQ:
415                                 M_BNE(GET_HIGH_REG(reg), GET_LOW_REG(reg), 5);
416                                 break;
417                         case BRANCH_NE:
418                                 M_BEQ(GET_HIGH_REG(reg), GET_LOW_REG(reg), 5);
419                                 break;
420                         case BRANCH_LT:
421                                 M_BGEZ(reg, 5);
422                                 break;
423                         case BRANCH_GE:
424                                 M_BLTZ(reg, 5);
425                                 break;
426                         case BRANCH_GT:
427                                 M_BLEZ(reg, 5);
428                                 break;
429                         case BRANCH_LE:
430                                 M_BGTZ(reg, 5);
431                                 break;
432                         default:
433                                 vm_abort("emit_branch: unknown condition %d", condition);
434                         }
435
436                         /* The actual branch code which is over-jumped (NOTE: we
437                            don't use a branch delay slot here). */
438
439                         M_LUI(REG_ITMP3, branchdisp >> 16);
440                         M_OR_IMM(REG_ITMP3, branchdisp, REG_ITMP3);
441                         M_AADD(REG_PV, REG_ITMP3, REG_ITMP3);
442                         M_JMP(REG_ITMP3);
443                         M_NOP;
444
445                 }
446                 else {
447                         switch (condition) {
448                         case BRANCH_EQ:
449                                 M_BEQ(GET_HIGH_REG(reg), GET_LOW_REG(reg), branchdisp);
450                                 break;
451                         case BRANCH_NE:
452                                 M_BNE(GET_HIGH_REG(reg), GET_LOW_REG(reg), branchdisp);
453                                 break;
454                         case BRANCH_LT:
455                                 M_BLTZ(reg, branchdisp);
456                                 break;
457                         case BRANCH_GE:
458                                 M_BGEZ(reg, branchdisp);
459                                 break;
460                         case BRANCH_GT:
461                                 M_BGTZ(reg, branchdisp);
462                                 break;
463                         case BRANCH_LE:
464                                 M_BLEZ(reg, branchdisp);
465                                 break;
466                         default:
467                                 vm_abort("emit_branch: unknown condition %d", condition);
468                         }
469
470                         /* branch delay */
471                         M_NOP;
472                 }
473         }
474 }
475
476
477 /* emit_arithmetic_check *******************************************************
478
479    Emit an ArithmeticException check.
480
481 *******************************************************************************/
482
483 void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg)
484 {
485         if (INSTRUCTION_MUST_CHECK(iptr)) {
486                 M_BNEZ(reg, 2);
487                 M_NOP;
488                 M_ALD_INTERN(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_ARITHMETIC);
489         }
490 }
491
492
493 /* emit_arrayindexoutofbounds_check ********************************************
494
495    Emit an ArrayIndexOutOfBoundsException check.
496
497 *******************************************************************************/
498
499 void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
500 {
501         if (INSTRUCTION_MUST_CHECK(iptr)) {
502                 M_ILD_INTERN(REG_ITMP3, s1, OFFSET(java_arrayheader, size));
503                 M_CMPULT(s2, REG_ITMP3, REG_ITMP3);
504                 M_BNEZ(REG_ITMP3, 2);
505                 M_NOP;
506                 M_ALD_INTERN(s2, REG_ZERO, EXCEPTION_HARDWARE_ARRAYINDEXOUTOFBOUNDS);
507         }
508 }
509
510
511 /* emit_classcast_check ********************************************************
512
513    Emit a ClassCastException check.
514
515 *******************************************************************************/
516
517 void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 reg, s4 s1)
518 {
519         if (INSTRUCTION_MUST_CHECK(iptr)) {
520                 switch (condition) {
521                 case ICMD_IFEQ:
522                         M_BNEZ(reg, 2);
523                         break;
524
525                 case ICMD_IFNE:
526                         M_BEQZ(reg, 2);
527                         break;
528
529                 case ICMD_IFLE:
530                         M_BGTZ(reg, 2);
531                         break;
532
533                 default:
534                         vm_abort("emit_classcast_check: unknown condition %d", condition);
535                 }
536
537                 M_NOP;
538                 M_ALD_INTERN(s1, REG_ZERO, EXCEPTION_HARDWARE_CLASSCAST);
539         }
540 }
541
542
543 /* emit_nullpointer_check ******************************************************
544
545    Emit a NullPointerException check.
546
547 *******************************************************************************/
548
549 void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg)
550 {
551         if (INSTRUCTION_MUST_CHECK(iptr)) {
552                 M_BNEZ(reg, 2);
553                 M_NOP;
554                 M_ALD_INTERN(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_NULLPOINTER);
555         }
556 }
557
558
559 /* emit_exception_check ********************************************************
560
561    Emit an Exception check.
562
563 *******************************************************************************/
564
565 void emit_exception_check(codegendata *cd, instruction *iptr)
566 {
567         if (INSTRUCTION_MUST_CHECK(iptr)) {
568                 M_BNEZ(REG_RESULT, 2);
569                 M_NOP;
570                 M_ALD_INTERN(REG_RESULT, REG_ZERO, EXCEPTION_HARDWARE_EXCEPTION);
571         }
572 }
573
574
575 /* emit_patcher_stubs **********************************************************
576
577    Generates the code for the patcher stubs.
578
579 *******************************************************************************/
580
581 void emit_patcher_stubs(jitdata *jd)
582 {
583         codegendata *cd;
584         patchref    *pr;
585         u4           mcode[5];
586         u1          *savedmcodeptr;
587         u1          *tmpmcodeptr;
588         s4           targetdisp;
589         s4           disp;
590
591         /* get required compiler data */
592
593         cd = jd->cd;
594
595         /* generate code patching stub call code */
596
597         targetdisp = 0;
598
599 /*      for (pr = list_first_unsynced(cd->patchrefs); pr != NULL; */
600 /*               pr = list_next_unsynced(cd->patchrefs, pr)) { */
601         for (pr = cd->patchrefs; pr != NULL; pr = pr->next) {
602                 /* check code segment size */
603
604                 MCODECHECK(100);
605
606                 /* Get machine code which is patched back in later. The
607                    call is 2 instruction words long. */
608
609                 tmpmcodeptr = (u1 *) (cd->mcodebase + pr->branchpos);
610
611                 /* We use 2 loads here as an unaligned 8-byte read on 64-bit
612                    MIPS causes a SIGSEGV and using the same code for both
613                    architectures is much better. */
614
615                 mcode[0] = ((u4 *) tmpmcodeptr)[0];
616                 mcode[1] = ((u4 *) tmpmcodeptr)[1];
617
618                 mcode[2] = ((u4 *) tmpmcodeptr)[2];
619                 mcode[3] = ((u4 *) tmpmcodeptr)[3];
620                 mcode[4] = ((u4 *) tmpmcodeptr)[4];
621
622                 /* Patch in the call to call the following code (done at
623                    compile time). */
624
625                 savedmcodeptr = cd->mcodeptr;   /* save current mcodeptr              */
626                 cd->mcodeptr  = tmpmcodeptr;    /* set mcodeptr to patch position     */
627
628                 disp = ((u4 *) savedmcodeptr) - (((u4 *) tmpmcodeptr) + 1);
629
630 /*              if ((disp < (s4) 0xffff8000) || (disp > (s4) 0x00007fff)) { */
631                         /* Recalculate the displacement to be relative to PV. */
632
633                         disp = savedmcodeptr - cd->mcodebase;
634
635                         M_LUI(REG_ITMP3, disp >> 16);
636                         M_OR_IMM(REG_ITMP3, disp, REG_ITMP3);
637                         M_AADD(REG_PV, REG_ITMP3, REG_ITMP3);
638                         M_JMP(REG_ITMP3);
639                         M_NOP;
640 /*              } */
641 /*              else { */
642 /*                      M_BR(disp); */
643 /*                      M_NOP; */
644 /*                      M_NOP; */
645 /*                      M_NOP; */
646 /*                      M_NOP; */
647 /*              } */
648
649                 cd->mcodeptr = savedmcodeptr;   /* restore the current mcodeptr   */
650
651                 /* create stack frame */
652
653                 M_ASUB_IMM(REG_SP, 8 * 8, REG_SP);
654
655                 /* calculate return address and move it onto the stack */
656
657                 M_LDA(REG_ITMP3, REG_PV, pr->branchpos);
658                 M_AST(REG_ITMP3, REG_SP, 7 * 8);
659
660                 /* move pointer to java_objectheader onto stack */
661
662 #if defined(ENABLE_THREADS)
663                 /* create a virtual java_objectheader */
664
665                 (void) dseg_add_unique_address(cd, NULL);                  /* flcword */
666                 (void) dseg_add_unique_address(cd, lock_get_initial_lock_word());
667                 disp = dseg_add_unique_address(cd, NULL);                  /* vftbl   */
668
669                 M_LDA(REG_ITMP3, REG_PV, disp);
670                 M_AST(REG_ITMP3, REG_SP, 6 * 8);
671 #else
672                 /* do nothing */
673 #endif
674
675                 /* move machine code onto stack */
676
677                 disp = dseg_add_s4(cd, mcode[0]);
678                 M_ILD(REG_ITMP3, REG_PV, disp);
679                 M_IST(REG_ITMP3, REG_SP, 3 * 8 + 0);
680
681                 disp = dseg_add_s4(cd, mcode[1]);
682                 M_ILD(REG_ITMP3, REG_PV, disp);
683                 M_IST(REG_ITMP3, REG_SP, 3 * 8 + 4);
684
685                 disp = dseg_add_s4(cd, mcode[2]);
686                 M_ILD(REG_ITMP3, REG_PV, disp);
687                 M_IST(REG_ITMP3, REG_SP, 4 * 8 + 0);
688
689                 disp = dseg_add_s4(cd, mcode[3]);
690                 M_ILD(REG_ITMP3, REG_PV, disp);
691                 M_IST(REG_ITMP3, REG_SP, 4 * 8 + 4);
692
693                 disp = dseg_add_s4(cd, mcode[4]);
694                 M_ILD(REG_ITMP3, REG_PV, disp);
695                 M_IST(REG_ITMP3, REG_SP, 5 * 8 + 0);
696
697                 /* move class/method/field reference onto stack */
698
699                 disp = dseg_add_address(cd, pr->ref);
700                 M_ALD(REG_ITMP3, REG_PV, disp);
701                 M_AST(REG_ITMP3, REG_SP, 2 * 8);
702
703                 /* move data segment displacement onto stack */
704
705                 disp = dseg_add_s4(cd, pr->disp);
706                 M_ILD(REG_ITMP3, REG_PV, disp);
707                 M_IST(REG_ITMP3, REG_SP, 1 * 8);
708
709                 /* move patcher function pointer onto stack */
710
711                 disp = dseg_add_functionptr(cd, pr->patcher);
712                 M_ALD(REG_ITMP3, REG_PV, disp);
713                 M_AST(REG_ITMP3, REG_SP, 0 * 8);
714
715                 if (targetdisp == 0) {
716                         targetdisp = ((u4 *) cd->mcodeptr) - ((u4 *) cd->mcodebase);
717
718                         disp = dseg_add_functionptr(cd, asm_patcher_wrapper);
719                         M_ALD(REG_ITMP3, REG_PV, disp);
720                         M_JMP(REG_ITMP3);
721                         M_NOP;
722                 }
723                 else {
724                         disp = (((u4 *) cd->mcodebase) + targetdisp) -
725                                 (((u4 *) cd->mcodeptr) + 1);
726
727                         M_BR(disp);
728                         M_NOP;
729                 }
730         }
731 }
732
733
734 /* emit_replacement_stubs ******************************************************
735
736    Generates the code for the replacement stubs.
737
738 *******************************************************************************/
739
740 #if defined(ENABLE_REPLACEMENT)
741 void emit_replacement_stubs(jitdata *jd)
742 {
743         codegendata *cd;
744         codeinfo    *code;
745         rplpoint    *rplp;
746         s4           disp;
747         s4           i;
748 #if !defined(NDEBUG)
749         u1          *savedmcodeptr;
750 #endif
751
752         /* get required compiler data */
753
754         cd   = jd->cd;
755         code = jd->code;
756
757         rplp = code->rplpoints;
758
759         /* store beginning of replacement stubs */
760
761         code->replacementstubs = (u1*) (cd->mcodeptr - cd->mcodebase);
762
763         for (i = 0; i < code->rplpointcount; ++i, ++rplp) {
764                 /* do not generate stubs for non-trappable points */
765
766                 if (rplp->flags & RPLPOINT_FLAG_NOTRAP)
767                         continue;
768
769                 /* check code segment size */
770
771                 MCODECHECK(100);
772
773 #if !defined(NDEBUG)
774                 savedmcodeptr = cd->mcodeptr;
775 #endif
776
777                 /* create stack frame - 16-byte aligned */
778
779                 M_ASUB_IMM(REG_SP, 2 * 8, REG_SP);
780
781                 /* push address of `rplpoint` struct */
782
783                 disp = dseg_add_address(cd, rplp);
784                 M_ALD(REG_ITMP3, REG_PV, disp);
785                 M_AST(REG_ITMP3, REG_SP, 0 * 8);
786
787                 /* jump to replacement function */
788
789                 disp = dseg_add_functionptr(cd, asm_replacement_out);
790                 M_ALD(REG_ITMP3, REG_PV, disp);
791                 M_JMP(REG_ITMP3);
792                 M_NOP; /* delay slot */
793
794                 assert((cd->mcodeptr - savedmcodeptr) == 4*REPLACEMENT_STUB_SIZE);
795         }
796 }
797 #endif /* defined(ENABLE_REPLACEMENT) */
798
799
800 /* emit_verbosecall_enter ******************************************************
801
802    Generates the code for the call trace.
803
804 *******************************************************************************/
805
806 #if !defined(NDEBUG)
807 void emit_verbosecall_enter(jitdata *jd)
808 {
809         methodinfo   *m;
810         codegendata  *cd;
811         registerdata *rd;
812         methoddesc   *md;
813         s4            disp;
814         s4            i, j, t;
815
816         /* get required compiler data */
817
818         m  = jd->m;
819         cd = jd->cd;
820         rd = jd->rd;
821
822         md = m->parseddesc;
823
824         /* mark trace code */
825
826         M_NOP;
827
828         M_LDA(REG_SP, REG_SP, -(PA_SIZE + (2 + ARG_CNT + TMP_CNT) * 8));
829         M_AST(REG_RA, REG_SP, PA_SIZE + 1 * 8);
830
831         /* save argument registers (we store the registers as address
832            types, so it's correct for MIPS32 too) */
833
834         for (i = 0; i < INT_ARG_CNT; i++)
835                 M_AST(rd->argintregs[i], REG_SP, PA_SIZE + (2 + i) * 8);
836
837         for (i = 0; i < FLT_ARG_CNT; i++)
838                 M_DST(rd->argfltregs[i], REG_SP, PA_SIZE + (2 + INT_ARG_CNT + i) * 8);
839
840         /* save temporary registers for leaf methods */
841
842         if (jd->isleafmethod) {
843                 for (i = 0; i < INT_TMP_CNT; i++)
844                         M_AST(rd->tmpintregs[i], REG_SP, PA_SIZE + (2 + ARG_CNT + i) * 8);
845
846                 for (i = 0; i < FLT_TMP_CNT; i++)
847                         M_DST(rd->tmpfltregs[i], REG_SP, PA_SIZE + (2 + ARG_CNT + INT_TMP_CNT + i) * 8);
848         }
849
850         /* Load float arguments into integer registers.  MIPS32 has less
851            float argument registers than integer ones, we need to check
852            that. */
853
854         for (i = 0; i < md->paramcount && i < INT_ARG_CNT && i < FLT_ARG_CNT; i++) {
855                 t = md->paramtypes[i].type;
856
857                 if (IS_FLT_DBL_TYPE(t)) {
858                         if (IS_2_WORD_TYPE(t)) {
859                                 M_DST(rd->argfltregs[i], REG_SP, 0 * 8);
860                                 M_LLD(rd->argintregs[i], REG_SP, 0 * 8);
861                         }
862                         else {
863                                 M_FST(rd->argfltregs[i], REG_SP, 0 * 8);
864                                 M_ILD(rd->argintregs[i], REG_SP, 0 * 8);
865                         }
866                 }
867         }
868
869 #if SIZEOF_VOID_P == 4
870                 for (i = 0, j = 0; i < md->paramcount && i < TRACE_ARGS_NUM; i++) {
871                         t = md->paramtypes[i].type;
872
873                         if (IS_INT_LNG_TYPE(t)) {
874                                 if (IS_2_WORD_TYPE(t)) {
875                                         M_ILD(rd->argintregs[j], REG_SP, PA_SIZE + (2 + i) * 8);
876                                         M_ILD(rd->argintregs[j + 1], REG_SP, PA_SIZE + (2 + i) * 8 + 4);
877                                 }
878                                 else {
879 # if WORDS_BIGENDIAN == 1
880                                         M_MOV(REG_ZERO, rd->argintregs[j]);
881                                         M_ILD(rd->argintregs[j + 1], REG_SP, PA_SIZE + (2 + i) * 8);
882 # else
883                                         M_ILD(rd->argintregs[j], REG_SP, PA_SIZE + (2 + i) * 8);
884                                         M_MOV(REG_ZERO, rd->argintregs[j + 1]);
885 # endif
886                                 }
887                                 j += 2;
888                         }
889                 }
890 #endif
891
892         disp = dseg_add_address(cd, m);
893         M_ALD(REG_ITMP1, REG_PV, disp);
894         M_AST(REG_ITMP1, REG_SP, PA_SIZE + 0 * 8);
895         disp = dseg_add_functionptr(cd, builtin_verbosecall_enter);
896         M_ALD(REG_ITMP3, REG_PV, disp);
897         M_JSR(REG_RA, REG_ITMP3);
898         M_NOP;
899
900         /* restore argument registers */
901
902         for (i = 0; i < INT_ARG_CNT; i++)
903                 M_ALD(rd->argintregs[i], REG_SP, PA_SIZE + (2 + i) * 8);
904
905         for (i = 0; i < FLT_ARG_CNT; i++)
906                 M_DLD(rd->argfltregs[i], REG_SP, PA_SIZE + (2 + INT_ARG_CNT + i) * 8);
907
908         /* restore temporary registers for leaf methods */
909
910         if (jd->isleafmethod) {
911                 for (i = 0; i < INT_TMP_CNT; i++)
912                         M_ALD(rd->tmpintregs[i], REG_SP, PA_SIZE + (2 + ARG_CNT + i) * 8);
913
914                 for (i = 0; i < FLT_TMP_CNT; i++)
915                         M_DLD(rd->tmpfltregs[i], REG_SP, PA_SIZE + (2 + ARG_CNT + INT_TMP_CNT + i) * 8);
916         }
917
918         M_ALD(REG_RA, REG_SP, PA_SIZE + 1 * 8);
919         M_LDA(REG_SP, REG_SP, PA_SIZE + (2 + ARG_CNT + TMP_CNT) * 8);
920
921         /* mark trace code */
922
923         M_NOP;
924 }
925 #endif /* !defined(NDEBUG) */
926
927
928 /* emit_verbosecall_exit *******************************************************
929
930    Generates the code for the call trace.
931
932    void builtin_verbosecall_exit(s8 l, double d, float f, methodinfo *m);
933
934 *******************************************************************************/
935
936 #if !defined(NDEBUG)
937 void emit_verbosecall_exit(jitdata *jd)
938 {
939         methodinfo   *m;
940         codegendata  *cd;
941         registerdata *rd;
942         methoddesc   *md;
943         s4            disp;
944
945         /* get required compiler data */
946
947         m  = jd->m;
948         cd = jd->cd;
949         rd = jd->rd;
950
951         md = m->parseddesc;
952
953         /* mark trace code */
954
955         M_NOP;
956
957 #if SIZEOF_VOID_P == 8
958         M_ASUB_IMM(REG_SP, 4 * 8, REG_SP);          /* keep stack 16-byte aligned */
959         M_AST(REG_RA, REG_SP, 0 * 8);
960
961         M_LST(REG_RESULT, REG_SP, 1 * 8);
962         M_DST(REG_FRESULT, REG_SP, 2 * 8);
963
964         M_MOV(REG_RESULT, REG_A0);
965         M_DMOV(REG_FRESULT, REG_FA1);
966         M_FMOV(REG_FRESULT, REG_FA2);
967
968         disp = dseg_add_address(cd, m);
969         M_ALD(REG_A4, REG_PV, disp);
970 #else
971         M_ASUB_IMM(REG_SP, (8*4 + 4 * 8), REG_SP);
972         M_AST(REG_RA, REG_SP, 8*4 + 0 * 8);
973
974         M_LST(REG_RESULT_PACKED, REG_SP, 8*4 + 1 * 8);
975         M_DST(REG_FRESULT, REG_SP, 8*4 + 2 * 8);
976
977         switch (md->returntype.type) {
978         case TYPE_LNG:
979                 M_LNGMOVE(REG_RESULT_PACKED, REG_A0_A1_PACKED);
980                 break;
981
982         default:
983 # if WORDS_BIGENDIAN == 1
984                 M_MOV(REG_ZERO, REG_A0);
985                 M_MOV(REG_RESULT, REG_A1);
986 # else
987                 M_MOV(REG_RESULT, REG_A0);
988                 M_MOV(REG_ZERO, REG_A1);
989 # endif
990         }
991
992         M_LLD(REG_A2_A3_PACKED, REG_SP, 8*4 + 2 * 8);
993         M_FST(REG_FRESULT, REG_SP, 4*4 + 0 * 4);
994
995         disp = dseg_add_address(cd, m);
996         M_ALD(REG_ITMP1, REG_PV, disp);
997         M_AST(REG_ITMP1, REG_SP, 4*4 + 1 * 4);
998 #endif
999
1000         disp = dseg_add_functionptr(cd, builtin_verbosecall_exit);
1001         M_ALD(REG_ITMP3, REG_PV, disp);
1002         M_JSR(REG_RA, REG_ITMP3);
1003         M_NOP;
1004
1005 #if SIZEOF_VOID_P == 8
1006         M_DLD(REG_FRESULT, REG_SP, 2 * 8);
1007         M_LLD(REG_RESULT, REG_SP, 1 * 8);
1008
1009         M_ALD(REG_RA, REG_SP, 0 * 8);
1010         M_AADD_IMM(REG_SP, 4 * 8, REG_SP);
1011 #else
1012         M_DLD(REG_FRESULT, REG_SP, 8*4 + 2 * 8);
1013         M_LLD(REG_RESULT_PACKED, REG_SP, 8*4 + 1 * 8);
1014
1015         M_ALD(REG_RA, REG_SP, 8*4 + 0 * 8);
1016         M_AADD_IMM(REG_SP, 8*4 + 4 * 8, REG_SP);
1017 #endif
1018
1019         /* mark trace code */
1020
1021         M_NOP;
1022 }
1023 #endif /* !defined(NDEBUG) */
1024
1025
1026 /*
1027  * These are local overrides for various environment variables in Emacs.
1028  * Please do not remove this and leave it at the end of the file, where
1029  * Emacs will automagically detect them.
1030  * ---------------------------------------------------------------------
1031  * Local variables:
1032  * mode: c
1033  * indent-tabs-mode: t
1034  * c-basic-offset: 4
1035  * tab-width: 4
1036  * End:
1037  * vim:noexpandtab:sw=4:ts=4:
1038  */