* src/vm/jit/arm/emit.c (emit_exception_stubs): Removed.
[cacao.git] / src / vm / jit / arm / emit.c
1 /* src/vm/jit/arm/emit.c - Arm 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 "md-abi.h"
37
38 #include "vm/jit/arm/codegen.h"
39
40 #include "mm/memory.h"
41
42 #if defined(ENABLE_THREADS)
43 # include "threads/native/lock.h"
44 #endif
45
46 #include "vm/builtin.h"
47 #include "vm/exceptions.h"
48 #include "vm/global.h"
49
50 #include "vm/jit/asmpart.h"
51 #include "vm/jit/emit-common.h"
52 #include "vm/jit/jit.h"
53 #include "vm/jit/replace.h"
54
55 #include "toolbox/logging.h" /* XXX for debugging only */
56
57
58 /* emit_load *******************************************************************
59
60    Emits a possible load of an operand.
61
62 *******************************************************************************/
63
64 s4 emit_load(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
65 {
66         codegendata  *cd;
67         s4            disp;
68         s4            reg;
69
70         /* get required compiler data */
71
72         cd = jd->cd;
73
74         if (src->flags & INMEMORY) {
75                 COUNT_SPILLS;
76
77                 disp = src->vv.regoff * 4;
78
79                 if (IS_FLT_DBL_TYPE(src->type)) {
80 #if defined(ENABLE_SOFTFLOAT)
81                         if (IS_2_WORD_TYPE(src->type))
82                                 M_LLD(tempreg, REG_SP, disp);
83                         else
84                                 M_ILD(tempreg, REG_SP, disp);
85 #else
86                         if (IS_2_WORD_TYPE(src->type))
87                                 M_DLD(tempreg, REG_SP, disp);
88                         else
89                                 M_FLD(tempreg, REG_SP, disp);
90 #endif
91                 }
92                 else {
93                         if (IS_2_WORD_TYPE(src->type))
94                                 M_LLD(tempreg, REG_SP, disp);
95                         else
96                                 M_ILD(tempreg, REG_SP, disp);
97                 }
98
99                 reg = tempreg;
100         }
101         else
102                 reg = src->vv.regoff;
103
104         return reg;
105 }
106
107
108 /* emit_load_low ***************************************************************
109
110    Emits a possible load of the low 32-bits of a long source operand.
111
112 *******************************************************************************/
113
114 s4 emit_load_low(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
115 {
116         codegendata  *cd;
117         s4            disp;
118         s4            reg;
119
120         assert(src->type == TYPE_LNG);
121
122         /* get required compiler data */
123
124         cd = jd->cd;
125
126         if (src->flags & INMEMORY) {
127                 COUNT_SPILLS;
128
129                 disp = src->vv.regoff * 4;
130
131 #if defined(__ARMEL__)
132                 M_ILD(tempreg, REG_SP, disp);
133 #else
134                 M_ILD(tempreg, REG_SP, disp + 4);
135 #endif
136
137                 reg = tempreg;
138         }
139         else
140                 reg = GET_LOW_REG(src->vv.regoff);
141
142         return reg;
143 }
144
145
146 /* emit_load_high **************************************************************
147
148    Emits a possible load of the high 32-bits of a long source operand.
149
150 *******************************************************************************/
151
152 s4 emit_load_high(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
153 {
154         codegendata  *cd;
155         s4            disp;
156         s4            reg;
157
158         assert(src->type == TYPE_LNG);
159
160         /* get required compiler data */
161
162         cd = jd->cd;
163
164         if (src->flags & INMEMORY) {
165                 COUNT_SPILLS;
166
167                 disp = src->vv.regoff * 4;
168
169 #if defined(__ARMEL__)
170                 M_ILD(tempreg, REG_SP, disp + 4);
171 #else
172                 M_ILD(tempreg, REG_SP, disp);
173 #endif
174
175                 reg = tempreg;
176         }
177         else
178                 reg = GET_HIGH_REG(src->vv.regoff);
179
180         return reg;
181 }
182
183
184 /* emit_store ******************************************************************
185
186    Emits a possible store to a variable.
187
188 *******************************************************************************/
189
190 void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
191 {
192         codegendata  *cd;
193         s4            disp;
194
195         /* get required compiler data */
196
197         cd = jd->cd;
198
199         if (dst->flags & INMEMORY) {
200                 COUNT_SPILLS;
201
202                 disp = dst->vv.regoff * 4;
203
204                 if (IS_FLT_DBL_TYPE(dst->type)) {
205 #if defined(ENABLE_SOFTFLOAT)
206                         if (IS_2_WORD_TYPE(dst->type))
207                                 M_LST(d, REG_SP, disp);
208                         else
209                                 M_IST(d, REG_SP, disp);
210 #else
211                         if (IS_2_WORD_TYPE(dst->type))
212                                 M_DST(d, REG_SP, disp);
213                         else
214                                 M_FST(d, REG_SP, disp);
215 #endif
216                 }
217                 else {
218                         if (IS_2_WORD_TYPE(dst->type))
219                                 M_LST(d, REG_SP, disp);
220                         else
221                                 M_IST(d, REG_SP, disp);
222                 }
223         }
224         else if (IS_LNG_TYPE(dst->type)) {
225 #if defined(__ARMEL__)
226                 if (GET_HIGH_REG(dst->vv.regoff) == REG_SPLIT)
227                         M_IST_INTERN(GET_HIGH_REG(d), REG_SP, 0 * 4);
228 #else
229                 if (GET_LOW_REG(dst->vv.regoff) == REG_SPLIT)
230                         M_IST_INTERN(GET_LOW_REG(d), REG_SP, 0 * 4);
231 #endif
232         }
233 }
234
235
236 /* emit_copy *******************************************************************
237
238    XXX
239
240 *******************************************************************************/
241
242 void emit_copy(jitdata *jd, instruction *iptr, varinfo *src, varinfo *dst)
243 {
244         codegendata  *cd;
245         registerdata *rd;
246         s4            s1, d;
247
248         /* get required compiler data */
249
250         cd = jd->cd;
251         rd = jd->rd;
252
253         /* XXX dummy call, removed me!!! */
254         d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP1);
255
256         if ((src->vv.regoff != dst->vv.regoff) ||
257                 ((src->flags ^ dst->flags) & INMEMORY)) {
258
259                 /* If one of the variables resides in memory, we can eliminate
260                    the register move from/to the temporary register with the
261                    order of getting the destination register and the load. */
262
263                 if (IS_INMEMORY(src->flags)) {
264 #if !defined(ENABLE_SOFTFLOAT)
265                         if (IS_FLT_DBL_TYPE(src->type))
266                                 d = codegen_reg_of_var(iptr->opc, dst, REG_FTMP1);
267                         else
268 #endif
269                         {
270                                 if (IS_2_WORD_TYPE(src->type))
271                                         d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP12_PACKED);
272                                 else
273                                         d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP1);
274                         }
275
276                         s1 = emit_load(jd, iptr, src, d);
277                 }
278                 else {
279 #if !defined(ENABLE_SOFTFLOAT)
280                         if (IS_FLT_DBL_TYPE(src->type))
281                                 s1 = emit_load(jd, iptr, src, REG_FTMP1);
282                         else
283 #endif
284                         {
285                                 if (IS_2_WORD_TYPE(src->type))
286                                         s1 = emit_load(jd, iptr, src, REG_ITMP12_PACKED);
287                                 else
288                                         s1 = emit_load(jd, iptr, src, REG_ITMP1);
289                         }
290
291                         d = codegen_reg_of_var(iptr->opc, dst, s1);
292                 }
293
294                 if (s1 != d) {
295                         if (IS_FLT_DBL_TYPE(src->type)) {
296 #if defined(ENABLE_SOFTFLOAT)
297                                 if (IS_2_WORD_TYPE(src->type))
298                                         M_LNGMOVE(s1, d);
299                                 else
300                                         /* XXX grrrr, wrong direction! */
301                                         M_MOV(d, s1);
302 #else
303                                 if (IS_2_WORD_TYPE(src->type))
304                                         M_DMOV(s1, d);
305                                 else
306                                         M_FMOV(s1, d);
307 #endif
308                         }
309                         else {
310                                 if (IS_2_WORD_TYPE(src->type))
311                                         M_LNGMOVE(s1, d);
312                                 else
313                                         /* XXX grrrr, wrong direction! */
314                                         M_MOV(d, s1);
315                         }
316                 }
317
318                 emit_store(jd, iptr, dst, d);
319         }
320 }
321
322
323 /* emit_iconst *****************************************************************
324
325    XXX
326
327 *******************************************************************************/
328
329 void emit_iconst(codegendata *cd, s4 d, s4 value)
330 {
331         s4 disp;
332
333         if (IS_IMM(value))
334                 M_MOV_IMM(d, value);
335         else {
336                 disp = dseg_add_s4(cd, value);
337                 M_DSEG_LOAD(d, disp);
338         }
339 }
340
341
342 /* emit_branch *****************************************************************
343
344    Emits the code for conditional and unconditional branchs.
345
346 *******************************************************************************/
347
348 void emit_branch(codegendata *cd, s4 disp, s4 condition, s4 reg, u4 opt)
349 {
350         s4 checkdisp;
351         s4 branchdisp;
352
353         /* calculate the different displacements */
354
355         checkdisp  = (disp - 8);
356         branchdisp = (disp - 8) >> 2;
357
358         /* check which branch to generate */
359
360         if (condition == BRANCH_UNCONDITIONAL) {
361                 /* check displacement for overflow */
362
363                 if ((checkdisp < (s4) 0xff000000) || (checkdisp > (s4) 0x00ffffff)) {
364                         /* if the long-branches flag isn't set yet, do it */
365
366                         if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
367                                 cd->flags |= (CODEGENDATA_FLAG_ERROR |
368                                                           CODEGENDATA_FLAG_LONGBRANCHES);
369                         }
370
371                         vm_abort("emit_branch: emit unconditional long-branch code");
372                 }
373                 else {
374                         M_B(branchdisp);
375                 }
376         }
377         else {
378                 /* and displacement for overflow */
379
380                 if ((checkdisp < (s4) 0xff000000) || (checkdisp > (s4) 0x00ffffff)) {
381                         /* if the long-branches flag isn't set yet, do it */
382
383                         if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
384                                 cd->flags |= (CODEGENDATA_FLAG_ERROR |
385                                                           CODEGENDATA_FLAG_LONGBRANCHES);
386                         }
387
388                         vm_abort("emit_branch: emit conditional long-branch code");
389                 }
390                 else {
391                         switch (condition) {
392                         case BRANCH_EQ:
393                                 M_BEQ(branchdisp);
394                                 break;
395                         case BRANCH_NE:
396                                 M_BNE(branchdisp);
397                                 break;
398                         case BRANCH_LT:
399                                 M_BLT(branchdisp);
400                                 break;
401                         case BRANCH_GE:
402                                 M_BGE(branchdisp);
403                                 break;
404                         case BRANCH_GT:
405                                 M_BGT(branchdisp);
406                                 break;
407                         case BRANCH_LE:
408                                 M_BLE(branchdisp);
409                                 break;
410                         case BRANCH_UGT:
411                                 M_BHI(branchdisp);
412                                 break;
413                         default:
414                                 vm_abort("emit_branch: unknown condition %d", condition);
415                         }
416                 }
417         }
418 }
419
420
421 /* emit_arithmetic_check *******************************************************
422
423    Emit an ArithmeticException check.
424
425 *******************************************************************************/
426
427 void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg)
428 {
429         if (INSTRUCTION_MUST_CHECK(iptr)) {
430                 CHECK_INT_REG(reg);
431                 M_TEQ_IMM(reg, 0);
432                 M_TRAPEQ(0, EXCEPTION_HARDWARE_ARITHMETIC);
433         }
434 }
435
436
437 /* emit_nullpointer_check ******************************************************
438
439    Emit a NullPointerException check.
440
441 *******************************************************************************/
442
443 void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg)
444 {
445         if (INSTRUCTION_MUST_CHECK(iptr)) {
446                 M_TST(reg, reg);
447                 M_TRAPEQ(0, EXCEPTION_HARDWARE_NULLPOINTER);
448         }
449 }
450
451 void emit_nullpointer_check_force(codegendata *cd, instruction *iptr, s4 reg)
452 {
453         M_TST(reg, reg);
454         M_TRAPEQ(0, EXCEPTION_HARDWARE_NULLPOINTER);
455 }
456
457
458 /* emit_arrayindexoutofbounds_check ********************************************
459
460    Emit a ArrayIndexOutOfBoundsException check.
461
462 *******************************************************************************/
463
464 void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
465 {
466         if (INSTRUCTION_MUST_CHECK(iptr)) {
467                 M_ILD_INTERN(REG_ITMP3, s1, OFFSET(java_arrayheader, size));
468                 M_CMP(s2, REG_ITMP3);
469                 M_TRAPHS(s2, EXCEPTION_HARDWARE_ARRAYINDEXOUTOFBOUNDS);
470         }
471 }
472
473
474 /* emit_classcast_check ********************************************************
475
476    Emit a ClassCastException check.
477
478 *******************************************************************************/
479
480 void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 reg, s4 s1)
481 {
482         if (INSTRUCTION_MUST_CHECK(iptr)) {
483                 switch (condition) {
484                 case BRANCH_EQ:
485                         M_TRAPEQ(s1, EXCEPTION_HARDWARE_CLASSCAST);
486                         break;
487
488                 case BRANCH_LE:
489                         M_TRAPLE(s1, EXCEPTION_HARDWARE_CLASSCAST);
490                         break;
491
492                 case BRANCH_UGT:
493                         M_TRAPHI(s1, EXCEPTION_HARDWARE_CLASSCAST);
494                         break;
495
496                 default:
497                         vm_abort("emit_classcast_check: unknown condition %d", condition);
498                 }
499         }
500 }
501
502 /* emit_exception_check ********************************************************
503
504    Emit an Exception check.
505
506 *******************************************************************************/
507
508 void emit_exception_check(codegendata *cd, instruction *iptr)
509 {
510         if (INSTRUCTION_MUST_CHECK(iptr)) {
511                 M_TST(REG_RESULT, REG_RESULT);
512                 M_TRAPEQ(0, 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    *pref;
527         u4           mcode;
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 patcher stub call code */
538
539         targetdisp = 0;
540
541         for (pref = cd->patchrefs; pref != NULL; pref = pref->next) {
542                 /* check code segment size */
543
544                 MCODECHECK(100);
545
546                 /* Get machine code which is patched back in later. The
547                    call is 1 instruction word long. */
548
549                 tmpmcodeptr = (u1 *) (cd->mcodebase + pref->branchpos);
550
551                 mcode = *((u4 *) tmpmcodeptr);
552
553                 /* Patch in the call to call the following code (done at
554                    compile time). */
555
556                 savedmcodeptr = cd->mcodeptr;   /* save current mcodeptr              */
557                 cd->mcodeptr  = tmpmcodeptr;    /* set mcodeptr to patch position     */
558
559                 disp = ((u4 *) savedmcodeptr) - (((u4 *) tmpmcodeptr) + 2);
560                 M_B(disp);
561
562                 cd->mcodeptr = savedmcodeptr;   /* restore the current mcodeptr       */
563
564                 /* create stack frame (align stack to 8-byte) */
565
566                 M_SUB_IMM(REG_SP, REG_SP, 8 * 4);
567
568                 /* save itmp3 onto stack */
569
570                 M_STR_INTERN(REG_ITMP3, REG_SP, 6 * 4);
571
572                 /* calculate return address and move it onto stack */
573                 /* ATTENTION: we can not use BL to branch to patcher stub,        */
574                 /* ATTENTION: because we need to preserve LR for leaf methods     */
575
576                 disp = (s4) (((u4 *) cd->mcodeptr) - (((u4 *) tmpmcodeptr) + 1) + 2);
577
578                 M_SUB_IMM_EXT_MUL4(REG_ITMP3, REG_PC, disp);
579                 M_STR_INTERN(REG_ITMP3, REG_SP, 4 * 4);
580
581                 /* move pointer to java_objectheader onto stack */
582
583 #if defined(ENABLE_THREADS)
584                 /* order reversed because of data segment layout */
585
586                 (void) dseg_add_unique_address(cd, NULL);           /* flcword    */
587                 (void) dseg_add_unique_address(cd, lock_get_initial_lock_word());
588                 disp = dseg_add_unique_address(cd, NULL);           /* vftbl      */
589
590                 M_SUB_IMM_EXT_MUL4(REG_ITMP3, REG_PV, -disp / 4);
591                 M_STR_INTERN(REG_ITMP3, REG_SP, 3 * 4);
592 #else
593                 M_EOR(REG_ITMP3, REG_ITMP3, REG_ITMP3);
594                 M_STR_INTERN(REG_ITMP3, REG_SP, 3 * 4);
595 #endif
596
597                 /* move machine code onto stack */
598
599                 disp = dseg_add_unique_s4(cd, mcode);
600                 M_DSEG_LOAD(REG_ITMP3, disp);
601                 M_STR_INTERN(REG_ITMP3, REG_SP, 2 * 4);
602
603                 /* move class/method/field reference onto stack */
604
605                 disp = dseg_add_unique_address(cd, pref->ref);
606                 M_DSEG_LOAD(REG_ITMP3, disp);
607                 M_STR_INTERN(REG_ITMP3, REG_SP, 1 * 4);
608
609                 /* move data segment displacement onto stack */
610
611                 disp = dseg_add_unique_s4(cd, pref->disp);
612                 M_DSEG_LOAD(REG_ITMP3, disp);
613                 M_STR_INTERN(REG_ITMP3, REG_SP, 5 * 4);
614
615                 /* move patcher function pointer onto stack */
616
617                 disp = dseg_add_functionptr(cd, pref->patcher);
618                 M_DSEG_LOAD(REG_ITMP3, disp);
619                 M_STR_INTERN(REG_ITMP3, REG_SP, 0 * 4);
620
621                 /* finally call the patcher via asm_patcher_wrapper */
622                 /* ATTENTION: don't use REG_PV here, because some patchers need it */
623
624                 if (targetdisp == 0) {
625                         targetdisp = ((u4 *) cd->mcodeptr) - ((u4 *) cd->mcodebase);
626
627                         disp = dseg_add_functionptr(cd, asm_patcher_wrapper);
628                         /*M_DSEG_BRANCH_NOLINK(REG_PC, REG_PV, a);*/
629                         /* TODO: this is only a hack */
630                         M_DSEG_LOAD(REG_ITMP3, disp);
631                         M_MOV(REG_PC, REG_ITMP3);
632                 }
633                 else {
634                         disp = (((u4 *) cd->mcodebase) + targetdisp) -
635                                 (((u4 *) cd->mcodeptr) + 2);
636
637                         M_B(disp);
638                 }
639         }
640 }
641
642
643 /* emit_replacement_stubs ******************************************************
644
645    Generates the code for the replacement stubs.
646
647 *******************************************************************************/
648
649 #if defined(ENABLE_REPLACEMENT)
650 void emit_replacement_stubs(jitdata *jd)
651 {
652         codegendata *cd;
653         codeinfo    *code;
654         rplpoint    *rplp;
655         u1          *savedmcodeptr;
656         s4           disp;
657         s4           i;
658
659         /* get required compiler data */
660
661         cd   = jd->cd;
662         code = jd->code;
663 }
664 #endif /* defined(ENABLE_REPLACEMENT) */
665
666
667 /* emit_verbosecall_enter ******************************************************
668
669    Generates the code for the call trace.
670
671 *******************************************************************************/
672
673 #if !defined(NDEBUG)
674 void emit_verbosecall_enter(jitdata *jd)
675 {
676         methodinfo   *m;
677         codegendata  *cd;
678         registerdata *rd;
679         methoddesc   *md;
680         s4            stackframesize;
681         s4            disp;
682         s4            i, t, s1, s2;
683
684         /* get required compiler data */
685
686         m  = jd->m;
687         cd = jd->cd;
688         rd = jd->rd;
689
690         md = m->parseddesc;
691
692         /* stackframesize is changed below */
693
694         stackframesize = cd->stackframesize;
695
696         /* mark trace code */
697
698         M_NOP;
699
700         /* Save argument registers to stack (including LR and PV).  Keep
701            stack 8-byte aligned. */
702
703         M_STMFD(BITMASK_ARGS | (1<<REG_LR) | (1<<REG_PV), REG_SP);
704         M_SUB_IMM(REG_SP, REG_SP, (2 + 2 + 1 + 1) * 4); /* space for a3, a4 and m */
705
706         stackframesize += 6 + 2 + 2 + 1 + 1;
707
708         /* prepare args for tracer */
709
710         i = md->paramcount - 1;
711
712         if (i > 3)
713                 i = 3;
714
715         for (; i >= 0; i--) {
716                 t = md->paramtypes[i].type;
717
718                 /* load argument into register (s1) and make it of TYPE_LNG */
719
720                 if (!md->params[i].inmemory) {
721                         s1 = md->params[i].regoff;
722
723                         if (!IS_2_WORD_TYPE(t)) {
724                                 M_MOV_IMM(REG_ITMP1, 0);
725                                 s1 = PACK_REGS(s1, REG_ITMP1);
726                         }
727                         else {
728                                 SPLIT_OPEN(t, s1, REG_ITMP1);
729                                 SPLIT_LOAD(t, s1, stackframesize);
730                         }
731                 }
732                 else {
733                         s1 = REG_ITMP12_PACKED;
734                         s2 = md->params[i].regoff + stackframesize;
735
736                         if (IS_2_WORD_TYPE(t))
737                                 M_LLD(s1, REG_SP, s2 * 4);
738                         else {
739                                 M_ILD(GET_LOW_REG(s1), REG_SP, s2 * 4);
740                                 M_MOV_IMM(GET_HIGH_REG(s1), 0);
741                         }
742                 }
743
744                 /* place argument for tracer */
745
746                 if (i < 2) {
747 #if defined(__ARMEL__)
748                         s2 = PACK_REGS(rd->argintregs[i * 2], rd->argintregs[i * 2 + 1]);
749 #else /* defined(__ARMEB__) */
750                         s2 = PACK_REGS(rd->argintregs[i * 2 + 1], rd->argintregs[i * 2]);
751 #endif          
752                         M_LNGMOVE(s1, s2);
753                 }
754                 else {
755                         s2 = (i - 2) * 2;
756                         M_LST(s1, REG_SP, s2 * 4);
757                 }
758         }
759
760         /* prepare methodinfo pointer for tracer */
761
762         disp = dseg_add_address(cd, m);
763         M_DSEG_LOAD(REG_ITMP1, disp);
764         M_STR_INTERN(REG_ITMP1, REG_SP, 16);
765
766         /* call tracer here (we use a long branch) */
767
768         M_LONGBRANCH(builtin_verbosecall_enter);
769
770         /* Restore argument registers from stack.  Keep stack 8-byte
771            aligned. */
772
773         M_ADD_IMM(REG_SP, REG_SP, (2 + 2 + 1 + 1) * 4);    /* free argument stack */
774         M_LDMFD(BITMASK_ARGS | (1<<REG_LR) | (1<<REG_PV), REG_SP);
775
776         /* mark trace code */
777
778         M_NOP;
779 }
780 #endif /* !defined(NDEBUG) */
781
782
783 /* emit_verbosecall_exit *******************************************************
784
785    Generates the code for the call trace.
786
787    void builtin_verbosecall_exit(s8 l, double d, float f, methodinfo *m);
788
789 *******************************************************************************/
790
791 #if !defined(NDEBUG)
792 void emit_verbosecall_exit(jitdata *jd)
793 {
794         methodinfo   *m;
795         codegendata  *cd;
796         registerdata *rd;
797         methoddesc   *md;
798         s4            disp;
799
800         /* get required compiler data */
801
802         m  = jd->m;
803         cd = jd->cd;
804         rd = jd->rd;
805
806         md = m->parseddesc;
807
808         /* mark trace code */
809
810         M_NOP;
811
812         /* Keep stack 8-byte aligned. */
813
814         M_STMFD(BITMASK_RESULT | (1<<REG_LR) | (1<<REG_PV), REG_SP);
815         M_SUB_IMM(REG_SP, REG_SP, (1 + 1) * 4);              /* space for f and m */
816
817         switch (md->returntype.type) {
818         case TYPE_ADR:
819         case TYPE_INT:
820                 M_INTMOVE(REG_RESULT, GET_LOW_REG(REG_A0_A1_PACKED));
821                 M_MOV_IMM(GET_HIGH_REG(REG_A0_A1_PACKED), 0);
822                 break;
823
824         case TYPE_LNG:
825                 M_LNGMOVE(REG_RESULT_PACKED, REG_A0_A1_PACKED);
826                 break;
827
828         case TYPE_FLT:
829                 M_IST(REG_RESULT, REG_SP, 0 * 4);
830                 break;
831
832         case TYPE_DBL:
833                 M_LNGMOVE(REG_RESULT_PACKED, REG_A2_A3_PACKED);
834                 break;
835         }
836
837         disp = dseg_add_address(cd, m);
838         M_DSEG_LOAD(REG_ITMP1, disp);
839         M_AST(REG_ITMP1, REG_SP, 1 * 4);
840         M_LONGBRANCH(builtin_verbosecall_exit);
841
842         /* Keep stack 8-byte aligned. */
843
844         M_ADD_IMM(REG_SP, REG_SP, (1 + 1) * 4);            /* free argument stack */
845         M_LDMFD(BITMASK_RESULT | (1<<REG_LR) | (1<<REG_PV), REG_SP);
846
847         /* mark trace code */
848
849         M_NOP;
850 }
851 #endif /* !defined(NDEBUG) */
852
853
854 /*
855  * These are local overrides for various environment variables in Emacs.
856  * Please do not remove this and leave it at the end of the file, where
857  * Emacs will automagically detect them.
858  * ---------------------------------------------------------------------
859  * Local variables:
860  * mode: c
861  * indent-tabs-mode: t
862  * c-basic-offset: 4
863  * tab-width: 4
864  * End:
865  * vim:noexpandtab:sw=4:ts=4:
866  */