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