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