* Removed all Id tags.
[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 */
26
27
28 #include "config.h"
29
30 #include <assert.h>
31
32 #include "vm/types.h"
33
34 #include "vm/jit/mips/codegen.h"
35 #include "vm/jit/mips/md-abi.h"
36
37 #include "mm/memory.h"
38
39 #include "threads/lock-common.h"
40
41 #include "vm/builtin.h"
42 #include "vm/exceptions.h"
43 #include "vm/stringlocal.h" /* XXX for gen_resolvebranch */
44
45 #include "vm/jit/abi.h"
46 #include "vm/jit/abi-asm.h"
47 #include "vm/jit/asmpart.h"
48 #include "vm/jit/dseg.h"
49 #include "vm/jit/emit-common.h"
50 #include "vm/jit/jit.h"
51 #include "vm/jit/patcher-common.h"
52 #include "vm/jit/replace.h"
53
54 #include "vmcore/options.h"
55
56
57 /* emit_load *******************************************************************
58
59    Emits a possible load of an operand.
60
61 *******************************************************************************/
62
63 s4 emit_load(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
64 {
65         codegendata  *cd;
66         s4            disp;
67         s4            reg;
68
69         /* get required compiler data */
70
71         cd = jd->cd;
72
73         if (src->flags & INMEMORY) {
74                 COUNT_SPILLS;
75
76                 disp = src->vv.regoff;
77
78                 switch (src->type) {
79 #if SIZEOF_VOID_P == 8
80                 case TYPE_INT:
81                 case TYPE_LNG:
82                 case TYPE_ADR:
83                         M_LLD(tempreg, REG_SP, disp);
84                         break;
85 #else
86                 case TYPE_INT:
87                 case TYPE_ADR:
88                         M_ILD(tempreg, REG_SP, disp);
89                         break;
90                 case TYPE_LNG:
91                         M_LLD(tempreg, REG_SP, disp);
92                         break;
93 #endif
94                 case TYPE_FLT:
95                         M_FLD(tempreg, REG_SP, disp);
96                         break;
97                 case TYPE_DBL:
98                         M_DLD(tempreg, REG_SP, disp);
99                         break;
100                 default:
101                         vm_abort("emit_load: unknown type %d", src->type);
102                 }
103
104                 reg = tempreg;
105         }
106         else
107                 reg = src->vv.regoff;
108
109         return reg;
110 }
111
112
113 /* emit_load_low ***************************************************************
114
115    Emits a possible load of the low 32-bits of an operand.
116
117 *******************************************************************************/
118
119 #if SIZEOF_VOID_P == 4
120 s4 emit_load_low(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
121 {
122         codegendata  *cd;
123         s4            disp;
124         s4            reg;
125
126         assert(src->type == TYPE_LNG);
127
128         /* get required compiler data */
129
130         cd = jd->cd;
131
132         if (src->flags & INMEMORY) {
133                 COUNT_SPILLS;
134
135                 disp = src->vv.regoff;
136
137 #if WORDS_BIGENDIAN == 1
138                 M_ILD(tempreg, REG_SP, disp + 4);
139 #else
140                 M_ILD(tempreg, REG_SP, disp);
141 #endif
142
143                 reg = tempreg;
144         }
145         else
146                 reg = GET_LOW_REG(src->vv.regoff);
147
148         return reg;
149 }
150 #endif /* SIZEOF_VOID_P == 4 */
151
152
153 /* emit_load_high **************************************************************
154
155    Emits a possible load of the high 32-bits of an operand.
156
157 *******************************************************************************/
158
159 #if SIZEOF_VOID_P == 4
160 s4 emit_load_high(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
161 {
162         codegendata  *cd;
163         s4            disp;
164         s4            reg;
165
166         assert(src->type == TYPE_LNG);
167
168         /* get required compiler data */
169
170         cd = jd->cd;
171
172         if (src->flags & INMEMORY) {
173                 COUNT_SPILLS;
174
175                 disp = src->vv.regoff;
176
177 #if WORDS_BIGENDIAN == 1
178                 M_ILD(tempreg, REG_SP, disp);
179 #else
180                 M_ILD(tempreg, REG_SP, disp + 4);
181 #endif
182
183                 reg = tempreg;
184         }
185         else
186                 reg = GET_HIGH_REG(src->vv.regoff);
187
188         return reg;
189 }
190 #endif /* SIZEOF_VOID_P == 4 */
191
192
193 /* emit_store ******************************************************************
194
195    Emits a possible store to variable.
196
197 *******************************************************************************/
198
199 void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
200 {
201         codegendata  *cd;
202         s4            disp;
203
204         /* get required compiler data */
205
206         cd = jd->cd;
207
208         if (dst->flags & INMEMORY) {
209                 COUNT_SPILLS;
210
211                 disp = dst->vv.regoff;
212
213                 switch (dst->type) {
214 #if SIZEOF_VOID_P == 8
215                 case TYPE_INT:
216                 case TYPE_LNG:
217                 case TYPE_ADR:
218                         M_LST(d, REG_SP, disp);
219                         break;
220 #else
221                 case TYPE_INT:
222                 case TYPE_ADR:
223                         M_IST(d, REG_SP, disp);
224                         break;
225                 case TYPE_LNG:
226                         M_LST(d, REG_SP, disp);
227                         break;
228 #endif
229                 case TYPE_FLT:
230                         M_FST(d, REG_SP, disp);
231                         break;
232                 case TYPE_DBL:
233                         M_DST(d, REG_SP, disp);
234                         break;
235                 default:
236                         vm_abort("emit_store: unknown type %d", dst->type);
237                 }
238         }
239 }
240
241
242 /* emit_copy *******************************************************************
243
244    Generates a register/memory to register/memory copy.
245
246 *******************************************************************************/
247
248 void emit_copy(jitdata *jd, instruction *iptr)
249 {
250         codegendata *cd;
251         varinfo     *src;
252         varinfo     *dst;
253         s4           s1, d;
254
255         /* get required compiler data */
256
257         cd = jd->cd;
258
259         /* get source and destination variables */
260
261         src = VAROP(iptr->s1);
262         dst = VAROP(iptr->dst);
263
264         if ((src->vv.regoff != dst->vv.regoff) ||
265                 ((src->flags ^ dst->flags) & INMEMORY)) {
266
267                 if ((src->type == TYPE_RET) || (dst->type == TYPE_RET)) {
268                         /* emit nothing, as the value won't be used anyway */
269                         return;
270                 }
271
272                 /* If one of the variables resides in memory, we can eliminate
273                    the register move from/to the temporary register with the
274                    order of getting the destination register and the load. */
275
276                 if (IS_INMEMORY(src->flags)) {
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, REG_IFTMP);
283                         s1 = emit_load(jd, iptr, src, d);
284                 }
285                 else {
286                         s1 = emit_load(jd, iptr, src, REG_IFTMP);
287 #if SIZEOF_VOID_P == 4
288                         if (IS_2_WORD_TYPE(src->type))
289                                 d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP12_PACKED);
290                         else
291 #endif
292                                 d = codegen_reg_of_var(iptr->opc, dst, s1);
293                 }
294
295                 if (s1 != d) {
296                         switch (dst->type) {
297 #if SIZEOF_VOID_P == 8
298                         case TYPE_INT:
299                         case TYPE_LNG:
300                         case TYPE_ADR:
301                                 M_MOV(s1, d);
302                                 break;
303 #else
304                         case TYPE_INT:
305                         case TYPE_ADR:
306                                 M_MOV(s1, d);
307                                 break;
308                         case TYPE_LNG:
309                                 M_LNGMOVE(s1, d);
310                                 break;
311 #endif
312                         case TYPE_FLT:
313                                 M_FMOV(s1, d);
314                                 break;
315                         case TYPE_DBL:
316                                 M_DMOV(s1, d);
317                                 break;
318                         default:
319                                 vm_abort("emit_copy: unknown type %d", dst->type);
320                         }
321                 }
322
323                 emit_store(jd, iptr, dst, d);
324         }
325 }
326
327
328 /* emit_iconst *****************************************************************
329
330    XXX
331
332 *******************************************************************************/
333
334 void emit_iconst(codegendata *cd, s4 d, s4 value)
335 {
336         s4 disp;
337
338     if ((value >= -32768) && (value <= 32767))
339         M_IADD_IMM(REG_ZERO, value, d);
340         else if ((value >= 0) && (value <= 0xffff))
341         M_OR_IMM(REG_ZERO, value, d);
342         else {
343         disp = dseg_add_s4(cd, value);
344         M_ILD(d, REG_PV, disp);
345     }
346 }
347
348
349 /* emit_lconst *****************************************************************
350
351    XXX
352
353 *******************************************************************************/
354
355 void emit_lconst(codegendata *cd, s4 d, s8 value)
356 {
357         s4 disp;
358
359 #if SIZEOF_VOID_P == 8
360         if ((value >= -32768) && (value <= 32767))
361                 M_LADD_IMM(REG_ZERO, value, d);
362         else if ((value >= 0) && (value <= 0xffff))
363                 M_OR_IMM(REG_ZERO, value, d);
364         else {
365                 disp = dseg_add_s8(cd, value);
366                 M_LLD(d, REG_PV, disp);
367         }
368 #else
369         disp = dseg_add_s8(cd, value);
370         M_LLD(d, REG_PV, disp);
371 #endif
372 }
373
374
375 /* emit_branch *****************************************************************
376
377    Emits the code for conditional and unconditional branchs.
378
379    NOTE: The reg argument may contain two packed registers.
380
381 *******************************************************************************/
382
383 void emit_branch(codegendata *cd, s4 disp, s4 condition, s4 reg, u4 opt)
384 {
385         s4 checkdisp;
386         s4 branchdisp;
387
388         /* calculate the different displacements */
389
390         checkdisp  = (disp - 4);
391         branchdisp = (disp - 4) >> 2;
392
393         /* check which branch to generate */
394
395         if (condition == BRANCH_UNCONDITIONAL) {
396                 /* check displacement for overflow */
397
398                 if ((checkdisp < (s4) 0xffff8000) || (checkdisp > (s4) 0x00007fff)) {
399                         /* if the long-branches flag isn't set yet, do it */
400
401                         if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
402                                 cd->flags |= (CODEGENDATA_FLAG_ERROR |
403                                                           CODEGENDATA_FLAG_LONGBRANCHES);
404                         }
405
406                         vm_abort("emit_branch: emit unconditional long-branch code");
407                 }
408                 else {
409                         M_BR(branchdisp);
410                         M_NOP;
411                 }
412         }
413         else {
414                 /* and displacement for overflow */
415
416                 if ((checkdisp < (s4) 0xffff8000) || (checkdisp > (s4) 0x00007fff)) {
417                         /* if the long-branches flag isn't set yet, do it */
418
419                         if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
420                                 cd->flags |= (CODEGENDATA_FLAG_ERROR |
421                                                           CODEGENDATA_FLAG_LONGBRANCHES);
422                         }
423
424                         switch (condition) {
425                         case BRANCH_EQ:
426                                 M_BNE(GET_HIGH_REG(reg), GET_LOW_REG(reg), 5);
427                                 break;
428                         case BRANCH_NE:
429                                 M_BEQ(GET_HIGH_REG(reg), GET_LOW_REG(reg), 5);
430                                 break;
431                         case BRANCH_LT:
432                                 M_BGEZ(reg, 5);
433                                 break;
434                         case BRANCH_GE:
435                                 M_BLTZ(reg, 5);
436                                 break;
437                         case BRANCH_GT:
438                                 M_BLEZ(reg, 5);
439                                 break;
440                         case BRANCH_LE:
441                                 M_BGTZ(reg, 5);
442                                 break;
443                         default:
444                                 vm_abort("emit_branch: unknown condition %d", condition);
445                         }
446
447                         /* The actual branch code which is over-jumped (NOTE: we
448                            don't use a branch delay slot here). */
449
450                         M_LUI(REG_ITMP3, branchdisp >> 16);
451                         M_OR_IMM(REG_ITMP3, branchdisp, REG_ITMP3);
452                         M_AADD(REG_PV, REG_ITMP3, REG_ITMP3);
453                         M_JMP(REG_ITMP3);
454                         M_NOP;
455
456                 }
457                 else {
458                         switch (condition) {
459                         case BRANCH_EQ:
460                                 M_BEQ(GET_HIGH_REG(reg), GET_LOW_REG(reg), branchdisp);
461                                 break;
462                         case BRANCH_NE:
463                                 M_BNE(GET_HIGH_REG(reg), GET_LOW_REG(reg), branchdisp);
464                                 break;
465                         case BRANCH_LT:
466                                 M_BLTZ(reg, branchdisp);
467                                 break;
468                         case BRANCH_GE:
469                                 M_BGEZ(reg, branchdisp);
470                                 break;
471                         case BRANCH_GT:
472                                 M_BGTZ(reg, branchdisp);
473                                 break;
474                         case BRANCH_LE:
475                                 M_BLEZ(reg, branchdisp);
476                                 break;
477                         default:
478                                 vm_abort("emit_branch: unknown condition %d", condition);
479                         }
480
481                         /* branch delay */
482                         M_NOP;
483                 }
484         }
485 }
486
487
488 /* emit_arithmetic_check *******************************************************
489
490    Emit an ArithmeticException check.
491
492 *******************************************************************************/
493
494 void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg)
495 {
496         if (INSTRUCTION_MUST_CHECK(iptr)) {
497                 M_BNEZ(reg, 2);
498                 M_NOP;
499                 M_ALD_INTERN(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_ARITHMETIC);
500         }
501 }
502
503
504 /* emit_arrayindexoutofbounds_check ********************************************
505
506    Emit an ArrayIndexOutOfBoundsException check.
507
508 *******************************************************************************/
509
510 void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
511 {
512         if (INSTRUCTION_MUST_CHECK(iptr)) {
513                 M_ILD_INTERN(REG_ITMP3, s1, OFFSET(java_array_t, size));
514                 M_CMPULT(s2, REG_ITMP3, REG_ITMP3);
515                 M_BNEZ(REG_ITMP3, 2);
516                 M_NOP;
517                 M_ALD_INTERN(s2, REG_ZERO, EXCEPTION_HARDWARE_ARRAYINDEXOUTOFBOUNDS);
518         }
519 }
520
521
522 /* emit_classcast_check ********************************************************
523
524    Emit a ClassCastException check.
525
526 *******************************************************************************/
527
528 void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 reg, s4 s1)
529 {
530         if (INSTRUCTION_MUST_CHECK(iptr)) {
531                 switch (condition) {
532                 case ICMD_IFEQ:
533                         M_BNEZ(reg, 2);
534                         break;
535
536                 case ICMD_IFNE:
537                         M_BEQZ(reg, 2);
538                         break;
539
540                 case ICMD_IFLE:
541                         M_BGTZ(reg, 2);
542                         break;
543
544                 default:
545                         vm_abort("emit_classcast_check: unknown condition %d", condition);
546                 }
547
548                 M_NOP;
549                 M_ALD_INTERN(s1, REG_ZERO, EXCEPTION_HARDWARE_CLASSCAST);
550         }
551 }
552
553
554 /* emit_nullpointer_check ******************************************************
555
556    Emit a NullPointerException check.
557
558 *******************************************************************************/
559
560 void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg)
561 {
562         if (INSTRUCTION_MUST_CHECK(iptr)) {
563                 M_BNEZ(reg, 2);
564                 M_NOP;
565                 M_ALD_INTERN(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_NULLPOINTER);
566         }
567 }
568
569
570 /* emit_exception_check ********************************************************
571
572    Emit an Exception check.
573
574 *******************************************************************************/
575
576 void emit_exception_check(codegendata *cd, instruction *iptr)
577 {
578         if (INSTRUCTION_MUST_CHECK(iptr)) {
579                 M_BNEZ(REG_RESULT, 2);
580                 M_NOP;
581                 M_ALD_INTERN(REG_RESULT, REG_ZERO, EXCEPTION_HARDWARE_EXCEPTION);
582         }
583 }
584
585
586 /* emit_trap *******************************************************************
587
588    Emit a trap instruction and return the original machine code.
589
590 *******************************************************************************/
591
592 uint32_t emit_trap(codegendata *cd)
593 {
594         uint32_t mcode;
595
596         /* Get machine code which is patched back in later. The
597            trap is 1 instruction word long. */
598
599         mcode = *((u4 *) cd->mcodeptr);
600
601         M_ALD_INTERN(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_PATCHER);
602
603         return mcode;
604 }
605
606
607 /* emit_verbosecall_enter ******************************************************
608
609    Generates the code for the call trace.
610
611 *******************************************************************************/
612
613 #if !defined(NDEBUG)
614 void emit_verbosecall_enter(jitdata *jd)
615 {
616         methodinfo   *m;
617         codegendata  *cd;
618         registerdata *rd;
619         methoddesc   *md;
620         s4            disp;
621         s4            i, j, t;
622
623         /* get required compiler data */
624
625         m  = jd->m;
626         cd = jd->cd;
627         rd = jd->rd;
628
629         md = m->parseddesc;
630
631         /* mark trace code */
632
633         M_NOP;
634
635         M_LDA(REG_SP, REG_SP, -(PA_SIZE + (2 + ARG_CNT + TMP_CNT) * 8));
636         M_AST(REG_RA, REG_SP, PA_SIZE + 1 * 8);
637
638         /* save argument registers (we store the registers as address
639            types, so it's correct for MIPS32 too) */
640
641         for (i = 0; i < INT_ARG_CNT; i++)
642                 M_AST(abi_registers_integer_argument[i], REG_SP, PA_SIZE + (2 + i) * 8);
643
644         for (i = 0; i < FLT_ARG_CNT; i++)
645                 M_DST(abi_registers_float_argument[i], REG_SP, PA_SIZE + (2 + INT_ARG_CNT + i) * 8);
646
647         /* save temporary registers for leaf methods */
648
649         if (jd->isleafmethod) {
650                 for (i = 0; i < INT_TMP_CNT; i++)
651                         M_AST(rd->tmpintregs[i], REG_SP, PA_SIZE + (2 + ARG_CNT + i) * 8);
652
653                 for (i = 0; i < FLT_TMP_CNT; i++)
654                         M_DST(rd->tmpfltregs[i], REG_SP, PA_SIZE + (2 + ARG_CNT + INT_TMP_CNT + i) * 8);
655         }
656
657         /* Load float arguments into integer registers.  MIPS32 has less
658            float argument registers than integer ones, we need to check
659            that. */
660
661         for (i = 0; i < md->paramcount && i < INT_ARG_CNT && i < FLT_ARG_CNT; i++) {
662                 t = md->paramtypes[i].type;
663
664                 if (IS_FLT_DBL_TYPE(t)) {
665                         if (IS_2_WORD_TYPE(t)) {
666                                 M_DST(abi_registers_float_argument[i], REG_SP, 0 * 8);
667                                 M_LLD(abi_registers_integer_argument[i], REG_SP, 0 * 8);
668                         }
669                         else {
670                                 M_FST(abi_registers_float_argument[i], REG_SP, 0 * 8);
671                                 M_ILD(abi_registers_integer_argument[i], REG_SP, 0 * 8);
672                         }
673                 }
674         }
675
676 #if SIZEOF_VOID_P == 4
677                 for (i = 0, j = 0; i < md->paramcount && i < TRACE_ARGS_NUM; i++) {
678                         t = md->paramtypes[i].type;
679
680                         if (IS_INT_LNG_TYPE(t)) {
681                                 if (IS_2_WORD_TYPE(t)) {
682                                         M_ILD(abi_registers_integer_argument[j], REG_SP, PA_SIZE + (2 + i) * 8);
683                                         M_ILD(abi_registers_integer_argument[j + 1], REG_SP, PA_SIZE + (2 + i) * 8 + 4);
684                                 }
685                                 else {
686 # if WORDS_BIGENDIAN == 1
687                                         M_MOV(REG_ZERO, abi_registers_integer_argument[j]);
688                                         M_ILD(abi_registers_integer_argument[j + 1], REG_SP, PA_SIZE + (2 + i) * 8);
689 # else
690                                         M_ILD(abi_registers_integer_argument[j], REG_SP, PA_SIZE + (2 + i) * 8);
691                                         M_MOV(REG_ZERO, abi_registers_integer_argument[j + 1]);
692 # endif
693                                 }
694                                 j += 2;
695                         }
696                 }
697 #endif
698
699         disp = dseg_add_address(cd, m);
700         M_ALD(REG_ITMP1, REG_PV, disp);
701         M_AST(REG_ITMP1, REG_SP, PA_SIZE + 0 * 8);
702         disp = dseg_add_functionptr(cd, builtin_verbosecall_enter);
703         M_ALD(REG_ITMP3, REG_PV, disp);
704         M_JSR(REG_RA, REG_ITMP3);
705         M_NOP;
706
707         /* restore argument registers */
708
709         for (i = 0; i < INT_ARG_CNT; i++)
710                 M_ALD(abi_registers_integer_argument[i], REG_SP, PA_SIZE + (2 + i) * 8);
711
712         for (i = 0; i < FLT_ARG_CNT; i++)
713                 M_DLD(abi_registers_float_argument[i], REG_SP, PA_SIZE + (2 + INT_ARG_CNT + i) * 8);
714
715         /* restore temporary registers for leaf methods */
716
717         if (jd->isleafmethod) {
718                 for (i = 0; i < INT_TMP_CNT; i++)
719                         M_ALD(rd->tmpintregs[i], REG_SP, PA_SIZE + (2 + ARG_CNT + i) * 8);
720
721                 for (i = 0; i < FLT_TMP_CNT; i++)
722                         M_DLD(rd->tmpfltregs[i], REG_SP, PA_SIZE + (2 + ARG_CNT + INT_TMP_CNT + i) * 8);
723         }
724
725         M_ALD(REG_RA, REG_SP, PA_SIZE + 1 * 8);
726         M_LDA(REG_SP, REG_SP, PA_SIZE + (2 + ARG_CNT + TMP_CNT) * 8);
727
728         /* mark trace code */
729
730         M_NOP;
731 }
732 #endif /* !defined(NDEBUG) */
733
734
735 /* emit_verbosecall_exit *******************************************************
736
737    Generates the code for the call trace.
738
739    void builtin_verbosecall_exit(s8 l, double d, float f, methodinfo *m);
740
741 *******************************************************************************/
742
743 #if !defined(NDEBUG)
744 void emit_verbosecall_exit(jitdata *jd)
745 {
746         methodinfo   *m;
747         codegendata  *cd;
748         registerdata *rd;
749         methoddesc   *md;
750         s4            disp;
751
752         /* get required compiler data */
753
754         m  = jd->m;
755         cd = jd->cd;
756         rd = jd->rd;
757
758         md = m->parseddesc;
759
760         /* mark trace code */
761
762         M_NOP;
763
764 #if SIZEOF_VOID_P == 8
765         M_ASUB_IMM(REG_SP, 4 * 8, REG_SP);          /* keep stack 16-byte aligned */
766         M_AST(REG_RA, REG_SP, 0 * 8);
767
768         M_LST(REG_RESULT, REG_SP, 1 * 8);
769         M_DST(REG_FRESULT, REG_SP, 2 * 8);
770
771         M_MOV(REG_RESULT, REG_A0);
772         M_DMOV(REG_FRESULT, REG_FA1);
773         M_FMOV(REG_FRESULT, REG_FA2);
774
775         disp = dseg_add_address(cd, m);
776         M_ALD(REG_A4, REG_PV, disp);
777 #else
778         M_ASUB_IMM(REG_SP, (8*4 + 4 * 8), REG_SP);
779         M_AST(REG_RA, REG_SP, 8*4 + 0 * 8);
780
781         M_LST(REG_RESULT_PACKED, REG_SP, 8*4 + 1 * 8);
782         M_DST(REG_FRESULT, REG_SP, 8*4 + 2 * 8);
783
784         switch (md->returntype.type) {
785         case TYPE_LNG:
786                 M_LNGMOVE(REG_RESULT_PACKED, REG_A0_A1_PACKED);
787                 break;
788
789         default:
790 # if WORDS_BIGENDIAN == 1
791                 M_MOV(REG_ZERO, REG_A0);
792                 M_MOV(REG_RESULT, REG_A1);
793 # else
794                 M_MOV(REG_RESULT, REG_A0);
795                 M_MOV(REG_ZERO, REG_A1);
796 # endif
797         }
798
799         M_LLD(REG_A2_A3_PACKED, REG_SP, 8*4 + 2 * 8);
800         M_FST(REG_FRESULT, REG_SP, 4*4 + 0 * 4);
801
802         disp = dseg_add_address(cd, m);
803         M_ALD(REG_ITMP1, REG_PV, disp);
804         M_AST(REG_ITMP1, REG_SP, 4*4 + 1 * 4);
805 #endif
806
807         disp = dseg_add_functionptr(cd, builtin_verbosecall_exit);
808         M_ALD(REG_ITMP3, REG_PV, disp);
809         M_JSR(REG_RA, REG_ITMP3);
810         M_NOP;
811
812 #if SIZEOF_VOID_P == 8
813         M_DLD(REG_FRESULT, REG_SP, 2 * 8);
814         M_LLD(REG_RESULT, REG_SP, 1 * 8);
815
816         M_ALD(REG_RA, REG_SP, 0 * 8);
817         M_AADD_IMM(REG_SP, 4 * 8, REG_SP);
818 #else
819         M_DLD(REG_FRESULT, REG_SP, 8*4 + 2 * 8);
820         M_LLD(REG_RESULT_PACKED, REG_SP, 8*4 + 1 * 8);
821
822         M_ALD(REG_RA, REG_SP, 8*4 + 0 * 8);
823         M_AADD_IMM(REG_SP, 8*4 + 4 * 8, REG_SP);
824 #endif
825
826         /* mark trace code */
827
828         M_NOP;
829 }
830 #endif /* !defined(NDEBUG) */
831
832
833 /*
834  * These are local overrides for various environment variables in Emacs.
835  * Please do not remove this and leave it at the end of the file, where
836  * Emacs will automagically detect them.
837  * ---------------------------------------------------------------------
838  * Local variables:
839  * mode: c
840  * indent-tabs-mode: t
841  * c-basic-offset: 4
842  * tab-width: 4
843  * End:
844  * vim:noexpandtab:sw=4:ts=4:
845  */