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