6c149ff173de2fb2214b5b5c6e792c7707b109b3
[cacao.git] / src / vm / jit / powerpc / emit.c
1 /* src/vm/jit/powerpc/emit.c - PowerPC 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/powerpc/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
49 #include "vm/jit/asmpart.h"
50 #include "vm/jit/dseg.h"
51 #include "vm/jit/emit-common.h"
52 #include "vm/jit/jit.h"
53 #include "vm/jit/replace.h"
54
55 #include "vmcore/options.h"
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 (IS_INMEMORY(src->flags)) {
75                 COUNT_SPILLS;
76
77                 disp = src->vv.regoff * 4;
78
79                 switch (src->type) {
80                 case TYPE_INT:
81                 case TYPE_ADR:
82                         M_ILD(tempreg, REG_SP, disp);
83                         break;
84                 case TYPE_LNG:
85                         M_LLD(tempreg, REG_SP, disp);
86                         break;
87                 case TYPE_FLT:
88                         M_FLD(tempreg, REG_SP, disp);
89                         break;
90                 case TYPE_DBL:
91                         M_DLD(tempreg, REG_SP, disp);
92                         break;
93                 default:
94                         vm_abort("emit_load: unknown type %d", src->type);
95                 }
96
97                 reg = tempreg;
98         }
99         else
100                 reg = src->vv.regoff;
101
102         return reg;
103 }
104
105
106 /* emit_load_low ***************************************************************
107
108    Emits a possible load of the low 32-bits of an operand.
109
110 *******************************************************************************/
111
112 s4 emit_load_low(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
113 {
114         codegendata  *cd;
115         s4            disp;
116         s4            reg;
117
118         assert(src->type == TYPE_LNG);
119
120         /* get required compiler data */
121
122         cd = jd->cd;
123
124         if (IS_INMEMORY(src->flags)) {
125                 COUNT_SPILLS;
126
127                 disp = src->vv.regoff * 4;
128
129                 M_ILD(tempreg, REG_SP, disp + 4);
130
131                 reg = tempreg;
132         }
133         else
134                 reg = GET_LOW_REG(src->vv.regoff);
135
136         return reg;
137 }
138
139
140 /* emit_load_high **************************************************************
141
142    Emits a possible load of the high 32-bits of an operand.
143
144 *******************************************************************************/
145
146 s4 emit_load_high(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
147 {
148         codegendata  *cd;
149         s4            disp;
150         s4            reg;
151
152         assert(src->type == TYPE_LNG);
153
154         /* get required compiler data */
155
156         cd = jd->cd;
157
158         if (IS_INMEMORY(src->flags)) {
159                 COUNT_SPILLS;
160
161                 disp = src->vv.regoff * 4;
162
163                 M_ILD(tempreg, REG_SP, disp);
164
165                 reg = tempreg;
166         }
167         else
168                 reg = GET_HIGH_REG(src->vv.regoff);
169
170         return reg;
171 }
172
173
174 /* emit_store ******************************************************************
175
176    Emit a possible store for the given variable.
177
178 *******************************************************************************/
179
180 void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
181 {
182         codegendata *cd;
183         s4           disp;
184
185         /* get required compiler data */
186
187         cd = jd->cd;
188
189         if (IS_INMEMORY(dst->flags)) {
190                 COUNT_SPILLS;
191
192                 disp = dst->vv.regoff * 4;
193
194                 switch (dst->type) {
195                 case TYPE_INT:
196                 case TYPE_ADR:
197                         M_IST(d, REG_SP, disp);
198                         break;
199                 case TYPE_LNG:
200                         M_LST(d, REG_SP, disp);
201                         break;
202                 case TYPE_FLT:
203                         M_FST(d, REG_SP, disp);
204                         break;
205                 case TYPE_DBL:
206                         M_DST(d, REG_SP, disp);
207                         break;
208                 default:
209                         vm_abort("emit_store: unknown type %d", dst->type);
210                 }
211         }
212 }
213
214
215 /* emit_copy *******************************************************************
216
217    Generates a register/memory to register/memory copy.
218
219 *******************************************************************************/
220
221 void emit_copy(jitdata *jd, instruction *iptr, varinfo *src, varinfo *dst)
222 {
223         codegendata  *cd;
224         s4            s1, d;
225
226         /* get required compiler data */
227
228         cd = jd->cd;
229
230         if ((src->vv.regoff != dst->vv.regoff) ||
231                 (IS_INMEMORY(src->flags ^ dst->flags))) {
232
233                 /* If one of the variables resides in memory, we can eliminate
234                    the register move from/to the temporary register with the
235                    order of getting the destination register and the load. */
236
237                 if (IS_INMEMORY(src->flags)) {
238                         if (IS_LNG_TYPE(src->type))
239                                 d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP12_PACKED);
240                         else
241                                 d = codegen_reg_of_var(iptr->opc, dst, REG_IFTMP);
242
243                         s1 = emit_load(jd, iptr, src, d);
244                 }
245                 else {
246                         if (IS_LNG_TYPE(src->type))
247                                 s1 = emit_load(jd, iptr, src, REG_ITMP12_PACKED);
248                         else
249                                 s1 = emit_load(jd, iptr, src, REG_IFTMP);
250
251                         d = codegen_reg_of_var(iptr->opc, dst, s1);
252                 }
253
254                 if (s1 != d) {
255                         switch (src->type) {
256                         case TYPE_INT:
257                         case TYPE_ADR:
258                                 M_MOV(s1, d);
259                                 break;
260                         case TYPE_LNG:
261                                 M_MOV(GET_LOW_REG(s1), GET_LOW_REG(d));
262                                 M_MOV(GET_HIGH_REG(s1), GET_HIGH_REG(d));
263                                 break;
264                         case TYPE_FLT:
265                         case TYPE_DBL:
266                                 M_FMOV(s1, d);
267                                 break;
268                         default:
269                                 vm_abort("emit_copy: unknown type %d", dst->type);
270                         }
271                 }
272
273                 emit_store(jd, iptr, dst, d);
274         }
275 }
276
277
278 /* emit_iconst *****************************************************************
279
280    XXX
281
282 *******************************************************************************/
283
284 void emit_iconst(codegendata *cd, s4 d, s4 value)
285 {
286         s4 disp;
287
288         if ((value >= -32768) && (value <= 32767))
289                 M_LDA_INTERN(d, REG_ZERO, value);
290         else {
291                 disp = dseg_add_s4(cd, value);
292                 M_ILD(d, REG_PV, disp);
293         }
294 }
295
296
297 /* emit_nullpointer_check ******************************************************
298
299    Emit a NullPointerException check.
300
301 *******************************************************************************/
302
303 void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg)
304 {
305         if (INSTRUCTION_MUST_CHECK(iptr)) {
306                 M_TST(reg);
307                 M_BEQ(0);
308                 codegen_add_nullpointerexception_ref(cd);
309         }
310 }
311
312
313 /* emit_arrayindexoutofbounds_check ********************************************
314
315    Emit a ArrayIndexOutOfBoundsException check.
316
317 *******************************************************************************/
318
319 void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
320 {
321         if (INSTRUCTION_MUST_CHECK(iptr)) {
322                 M_ILD(REG_ITMP3, s1, OFFSET(java_arrayheader, size));
323                 M_CMPU(s2, REG_ITMP3);
324                 M_BGE(0);
325                 codegen_add_arrayindexoutofboundsexception_ref(cd, s2);
326         }
327 }
328
329
330 /* emit_exception_stubs ********************************************************
331
332    Generates the code for the exception stubs.
333
334 *******************************************************************************/
335
336 void emit_exception_stubs(jitdata *jd)
337 {
338         codegendata  *cd;
339         registerdata *rd;
340         exceptionref *er;
341         s4            branchmpc;
342         s4            targetmpc;
343         s4            targetdisp;
344         s4            disp;
345
346         /* get required compiler data */
347
348         cd = jd->cd;
349         rd = jd->rd;
350
351         /* generate exception stubs */
352
353         targetdisp = 0;
354
355         for (er = cd->exceptionrefs; er != NULL; er = er->next) {
356                 /* back-patch the branch to this exception code */
357
358                 branchmpc = er->branchpos;
359                 targetmpc = cd->mcodeptr - cd->mcodebase;
360
361                 md_codegen_patch_branch(cd, branchmpc, targetmpc);
362
363                 MCODECHECK(100);
364
365                 /* Move the value register to a temporary register, if
366                    there is the need for it. */
367
368                 if (er->reg != -1)
369                         M_MOV(er->reg, REG_ITMP1);
370
371                 /* calcuate exception address */
372
373                 M_LDA(REG_ITMP2_XPC, REG_PV, er->branchpos - 4);
374
375                 /* move function to call into REG_ITMP3 */
376
377                 disp = dseg_add_functionptr(cd, er->function);
378                 M_ALD(REG_ITMP3, REG_PV, disp);
379
380                 if (targetdisp == 0) {
381                     targetdisp = ((u4 *) cd->mcodeptr) - ((u4 *) cd->mcodebase);
382
383                         if (jd->isleafmethod) {
384                                 M_MFLR(REG_ZERO);
385                                 M_AST(REG_ZERO, REG_SP, cd->stackframesize * 4 + LA_LR_OFFSET);
386                         }
387
388                         M_MOV(REG_PV, rd->argintregs[0]);
389                         M_MOV(REG_SP, rd->argintregs[1]);
390
391                         if (jd->isleafmethod)
392                                 M_MOV(REG_ZERO, rd->argintregs[2]);
393                         else
394                                 M_ALD(rd->argintregs[2],
395                                           REG_SP, cd->stackframesize * 4 + LA_LR_OFFSET);
396
397                         M_MOV(REG_ITMP2_XPC, rd->argintregs[3]);
398                         M_MOV(REG_ITMP1, rd->argintregs[4]);
399
400                         M_STWU(REG_SP, REG_SP, -(LA_SIZE + 6 * 4));
401                         M_AST(REG_ITMP2_XPC, REG_SP, LA_SIZE + 5 * 4);
402
403                         M_MTCTR(REG_ITMP3);
404                         M_JSR;
405                         M_MOV(REG_RESULT, REG_ITMP1_XPTR);
406
407                         M_ALD(REG_ITMP2_XPC, REG_SP, LA_SIZE + 5 * 4);
408                         M_IADD_IMM(REG_SP, LA_SIZE + 6 * 4, REG_SP);
409
410                         if (jd->isleafmethod) {
411                                 /* XXX FIXME: REG_ZERO can cause problems here! */
412                                 assert(cd->stackframesize * 4 <= 32767);
413
414                                 M_ALD(REG_ZERO, REG_SP, cd->stackframesize * 4 + LA_LR_OFFSET);
415                                 M_MTLR(REG_ZERO);
416                         }
417
418                         disp = dseg_add_functionptr(cd, asm_handle_exception);
419                         M_ALD(REG_ITMP3, REG_PV, disp);
420                         M_MTCTR(REG_ITMP3);
421                         M_RTS;
422                 }
423                 else {
424                         disp = (((u4 *) cd->mcodebase) + targetdisp) -
425                                 (((u4 *) cd->mcodeptr) + 1);
426                         M_BR(disp);
427                 }
428         }
429 }
430
431
432 /* emit_patcher_stubs **********************************************************
433
434    Generates the code for the patcher stubs.
435
436 *******************************************************************************/
437
438 void emit_patcher_stubs(jitdata *jd)
439 {
440         codegendata *cd;
441         patchref    *pref;
442         u4           mcode;
443         u1          *savedmcodeptr;
444         u1          *tmpmcodeptr;
445         s4           targetdisp;
446         s4           disp;
447
448         /* get required compiler data */
449
450         cd = jd->cd;
451
452         /* generate code patching stub call code */
453
454         targetdisp = 0;
455
456         for (pref = cd->patchrefs; pref != NULL; pref = pref->next) {
457                 /* check code segment size */
458
459                 MCODECHECK(100);
460
461                 /* Get machine code which is patched back in later. The
462                    call is 1 instruction word long. */
463
464                 tmpmcodeptr = (u1 *) (cd->mcodebase + pref->branchpos);
465
466                 mcode = *((u4 *) tmpmcodeptr);
467
468                 /* Patch in the call to call the following code (done at
469                    compile time). */
470
471                 savedmcodeptr = cd->mcodeptr;   /* save current mcodeptr          */
472                 cd->mcodeptr  = tmpmcodeptr;    /* set mcodeptr to patch position */
473
474                 disp = ((u4 *) savedmcodeptr) - (((u4 *) tmpmcodeptr) + 1);
475                 M_BR(disp);
476
477                 cd->mcodeptr = savedmcodeptr;   /* restore the current mcodeptr   */
478
479                 /* create stack frame - keep stack 16-byte aligned */
480
481                 M_AADD_IMM(REG_SP, -8 * 4, REG_SP);
482
483                 /* calculate return address and move it onto the stack */
484
485                 M_LDA(REG_ITMP3, REG_PV, pref->branchpos);
486                 M_AST_INTERN(REG_ITMP3, REG_SP, 5 * 4);
487
488                 /* move pointer to java_objectheader onto stack */
489
490 #if defined(ENABLE_THREADS)
491                 /* order reversed because of data segment layout */
492
493                 (void) dseg_add_unique_address(cd, NULL);                  /* flcword */
494                 (void) dseg_add_unique_address(cd, lock_get_initial_lock_word());
495                 disp = dseg_add_unique_address(cd, NULL);                  /* vftbl   */
496
497                 M_LDA(REG_ITMP3, REG_PV, disp);
498                 M_AST_INTERN(REG_ITMP3, REG_SP, 4 * 4);
499 #else
500                 /* do nothing */
501 #endif
502
503                 /* move machine code onto stack */
504
505                 disp = dseg_add_s4(cd, mcode);
506                 M_ILD(REG_ITMP3, REG_PV, disp);
507                 M_IST_INTERN(REG_ITMP3, REG_SP, 3 * 4);
508
509                 /* move class/method/field reference onto stack */
510
511                 disp = dseg_add_address(cd, pref->ref);
512                 M_ALD(REG_ITMP3, REG_PV, disp);
513                 M_AST_INTERN(REG_ITMP3, REG_SP, 2 * 4);
514
515                 /* move data segment displacement onto stack */
516
517                 disp = dseg_add_s4(cd, pref->disp);
518                 M_ILD(REG_ITMP3, REG_PV, disp);
519                 M_IST_INTERN(REG_ITMP3, REG_SP, 1 * 4);
520
521                 /* move patcher function pointer onto stack */
522
523                 disp = dseg_add_functionptr(cd, pref->patcher);
524                 M_ALD(REG_ITMP3, REG_PV, disp);
525                 M_AST_INTERN(REG_ITMP3, REG_SP, 0 * 4);
526
527                 if (targetdisp == 0) {
528                         targetdisp = ((u4 *) cd->mcodeptr) - ((u4 *) cd->mcodebase);
529
530                         disp = dseg_add_functionptr(cd, asm_patcher_wrapper);
531                         M_ALD(REG_ITMP3, REG_PV, disp);
532                         M_MTCTR(REG_ITMP3);
533                         M_RTS;
534                 }
535                 else {
536                         disp = (((u4 *) cd->mcodebase) + targetdisp) -
537                                 (((u4 *) cd->mcodeptr) + 1);
538                         M_BR(disp);
539                 }
540         }
541 }
542
543
544 /* emit_replacement_stubs ******************************************************
545
546    Generates the code for the replacement stubs.
547
548 *******************************************************************************/
549
550 #if defined(ENABLE_REPLACEMENT)
551 void emit_replacement_stubs(jitdata *jd)
552 {
553         codegendata *cd;
554         codeinfo    *code;
555         rplpoint    *rplp;
556         s4           disp;
557         s4           i;
558 #if !defined(NDEBUG)
559         u1          *savedmcodeptr;
560 #endif
561
562         /* get required compiler data */
563
564         cd   = jd->cd;
565         code = jd->code;
566
567         rplp = code->rplpoints;
568
569         /* store beginning of replacement stubs */
570
571         code->replacementstubs = (u1*) (cd->mcodeptr - cd->mcodebase);
572
573         for (i = 0; i < code->rplpointcount; ++i, ++rplp) {
574                 /* do not generate stubs for non-trappable points */
575
576                 if (rplp->flags & RPLPOINT_FLAG_NOTRAP)
577                         continue;
578
579                 /* check code segment size */
580
581                 MCODECHECK(100);
582
583 #if !defined(NDEBUG)
584                 savedmcodeptr = cd->mcodeptr;
585 #endif
586
587                 /* create stack frame - keep 16-byte aligned */
588
589                 M_AADD_IMM(REG_SP, -4 * 4, REG_SP);
590
591                 /* push address of `rplpoint` struct */
592
593                 disp = dseg_add_address(cd, rplp);
594                 M_ALD(REG_ITMP3, REG_PV, disp);
595                 M_AST_INTERN(REG_ITMP3, REG_SP, 0 * 4);
596
597                 /* jump to replacement function */
598
599                 disp = dseg_add_functionptr(cd, asm_replacement_out);
600                 M_ALD(REG_ITMP3, REG_PV, disp);
601                 M_MTCTR(REG_ITMP3);
602                 M_RTS;
603
604                 assert((cd->mcodeptr - savedmcodeptr) == 4*REPLACEMENT_STUB_SIZE);
605         }
606 }
607 #endif /* defined(ENABLE_REPLACEMENT) */
608
609
610 /* emit_verbosecall_enter ******************************************************
611
612    Generates the code for the call trace.
613
614 *******************************************************************************/
615
616 void emit_verbosecall_enter(jitdata *jd)
617 {
618 #if !defined(NDEBUG)
619         methodinfo   *m;
620         codegendata  *cd;
621         registerdata *rd;
622         s4 s1, p, t, d;
623         int stack_off;
624         int stack_size;
625         methoddesc *md;
626
627         if (!JITDATA_HAS_FLAG_VERBOSECALL(jd))
628                 return;
629
630         /* get required compiler data */
631
632         m  = jd->m;
633         cd = jd->cd;
634         rd = jd->rd;
635
636         md = m->parseddesc;
637         
638         /* Build up Stackframe for builtin_trace_args call (a multiple of 16) */
639         /* For Darwin:                                                        */
640         /* LA + TRACE_ARGS_NUM u8 args + methodinfo + LR                      */
641         /* LA_SIZE(=6*4) + 8*8         + 4          + 4  + 0(Padding)         */
642         /* 6 * 4 + 8 * 8 + 2 * 4 = 12 * 8 = 6 * 16                            */
643         /* For Linux:                                                         */
644         /* LA + (TRACE_ARGS_NUM - INT_ARG_CNT/2) u8 args + methodinfo         */
645         /* + INT_ARG_CNT * 4 ( save integer registers) + LR + 8 + 8 (Padding) */
646         /* LA_SIZE(=2*4) + 4 * 8 + 4 + 8 * 4 + 4 + 8                          */
647         /* 2 * 4 + 4 * 8 + 10 * 4 + 1 * 8 + 8= 12 * 8 = 6 * 16                */
648         
649         /* in nativestubs no Place to save the LR (Link Register) would be needed */
650         /* but since the stack frame has to be aligned the 4 Bytes would have to  */
651         /* be padded again */
652
653 #if defined(__DARWIN__)
654         stack_size = LA_SIZE + (TRACE_ARGS_NUM + 1) * 8;
655 #else
656         stack_size = 6 * 16;
657 #endif
658
659         /* mark trace code */
660
661         M_NOP;
662
663         M_MFLR(REG_ZERO);
664         M_AST(REG_ZERO, REG_SP, LA_LR_OFFSET);
665         M_STWU(REG_SP, REG_SP, -stack_size);
666
667         M_CLR(REG_ITMP1);    /* clear help register */
668
669         /* save up to TRACE_ARGS_NUM arguments into the reserved stack space */
670 #if defined(__DARWIN__)
671         /* Copy Params starting from first to Stack                          */
672         /* since TRACE_ARGS == INT_ARG_CNT all used integer argument regs    */ 
673         /* are saved                                                         */
674         p = 0;
675 #else
676         /* Copy Params starting from fifth to Stack (INT_ARG_CNT/2) are in   */
677         /* integer argument regs                                             */
678         /* all integer argument registers have to be saved                   */
679         for (p = 0; p < 8; p++) {
680                 d = rd->argintregs[p];
681                 /* save integer argument registers */
682                 M_IST(d, REG_SP, LA_SIZE + 4 * 8 + 4 + p * 4);
683         }
684         p = 4;
685 #endif
686         stack_off = LA_SIZE;
687         for (; p < md->paramcount && p < TRACE_ARGS_NUM; p++, stack_off += 8) {
688                 t = md->paramtypes[p].type;
689                 if (IS_INT_LNG_TYPE(t)) {
690                         if (!md->params[p].inmemory) { /* Param in Arg Reg */
691                                 if (IS_2_WORD_TYPE(t)) {
692                                         M_IST(rd->argintregs[GET_HIGH_REG(md->params[p].regoff)]
693                                                   , REG_SP, stack_off);
694                                         M_IST(rd->argintregs[GET_LOW_REG(md->params[p].regoff)]
695                                                   , REG_SP, stack_off + 4);
696                                 } else {
697                                         M_IST(REG_ITMP1, REG_SP, stack_off);
698                                         M_IST(rd->argintregs[md->params[p].regoff]
699                                                   , REG_SP, stack_off + 4);
700                                 }
701                         } else { /* Param on Stack */
702                                 s1 = (md->params[p].regoff + cd->stackframesize) * 4 
703                                         + stack_size;
704                                 if (IS_2_WORD_TYPE(t)) {
705                                         M_ILD(REG_ITMP2, REG_SP, s1);
706                                         M_IST(REG_ITMP2, REG_SP, stack_off);
707                                         M_ILD(REG_ITMP2, REG_SP, s1 + 4);
708                                         M_IST(REG_ITMP2, REG_SP, stack_off + 4);
709                                 } else {
710                                         M_IST(REG_ITMP1, REG_SP, stack_off);
711                                         M_ILD(REG_ITMP2, REG_SP, s1);
712                                         M_IST(REG_ITMP2, REG_SP, stack_off + 4);
713                                 }
714                         }
715                 } else { /* IS_FLT_DBL_TYPE(t) */
716                         if (!md->params[p].inmemory) { /* in Arg Reg */
717                                 s1 = rd->argfltregs[md->params[p].regoff];
718                                 if (!IS_2_WORD_TYPE(t)) {
719                                         M_IST(REG_ITMP1, REG_SP, stack_off);
720                                         M_FST(s1, REG_SP, stack_off + 4);
721                                 } else {
722                                         M_DST(s1, REG_SP, stack_off);
723                                 }
724                         } else { /* on Stack */
725                                 /* this should not happen */
726                         }
727                 }
728         }
729
730         /* load first 4 (==INT_ARG_CNT/2) arguments into integer registers */
731 #if defined(__DARWIN__)
732         for (p = 0; p < 8; p++) {
733                 d = rd->argintregs[p];
734                 M_ILD(d, REG_SP, LA_SIZE + p * 4);
735         }
736 #else
737         /* LINUX */
738         /* Set integer and float argument registers vor trace_args call */
739         /* offset to saved integer argument registers                   */
740         stack_off = LA_SIZE + 4 * 8 + 4;
741         for (p = 0; (p < 4) && (p < md->paramcount); p++) {
742                 t = md->paramtypes[p].type;
743                 if (IS_INT_LNG_TYPE(t)) {
744                         /* "stretch" int types */
745                         if (!IS_2_WORD_TYPE(t)) {
746                                 M_CLR(rd->argintregs[2 * p]);
747                                 M_ILD(rd->argintregs[2 * p + 1], REG_SP,stack_off);
748                                 stack_off += 4;
749                         } else {
750                                 M_ILD(rd->argintregs[2 * p + 1], REG_SP,stack_off + 4);
751                                 M_ILD(rd->argintregs[2 * p], REG_SP,stack_off);
752                                 stack_off += 8;
753                         }
754                 } else { /* Float/Dbl */
755                         if (!md->params[p].inmemory) { /* Param in Arg Reg */
756                                 /* use reserved Place on Stack (sp + 5 * 16) to copy  */
757                                 /* float/double arg reg to int reg                    */
758                                 s1 = rd->argfltregs[md->params[p].regoff];
759                                 if (!IS_2_WORD_TYPE(t)) {
760                                         M_FST(s1, REG_SP, 5 * 16);
761                                         M_ILD(rd->argintregs[2 * p + 1], REG_SP, 5 * 16);
762                                         M_CLR(rd->argintregs[2 * p]);
763                                 } else {
764                                         M_DST(s1, REG_SP, 5 * 16);
765                                         M_ILD(rd->argintregs[2 * p + 1], REG_SP,  5 * 16 + 4);
766                                         M_ILD(rd->argintregs[2 * p], REG_SP, 5 * 16);
767                                 }
768                         }
769                 }
770         }
771 #endif
772
773         /* put methodinfo pointer on Stackframe */
774         p = dseg_add_address(cd, m);
775         M_ALD(REG_ITMP1, REG_PV, p);
776 #if defined(__DARWIN__)
777         M_AST(REG_ITMP1, REG_SP, LA_SIZE + TRACE_ARGS_NUM * 8); 
778 #else
779         M_AST(REG_ITMP1, REG_SP, LA_SIZE + 4 * 8);
780 #endif
781         p = dseg_add_functionptr(cd, builtin_verbosecall_enter);
782         M_ALD(REG_ITMP2, REG_PV, p);
783         M_MTCTR(REG_ITMP2);
784         M_JSR;
785
786 #if defined(__DARWIN__)
787         /* restore integer argument registers from the reserved stack space */
788
789         stack_off = LA_SIZE;
790         for (p = 0; p < md->paramcount && p < TRACE_ARGS_NUM; 
791                  p++, stack_off += 8) {
792                 t = md->paramtypes[p].type;
793
794                 if (IS_INT_LNG_TYPE(t)) {
795                         if (!md->params[p].inmemory) {
796                                 if (IS_2_WORD_TYPE(t)) {
797                                         M_ILD(rd->argintregs[GET_HIGH_REG(md->params[p].regoff)]
798                                                   , REG_SP, stack_off);
799                                         M_ILD(rd->argintregs[GET_LOW_REG(md->params[p].regoff)]
800                                                   , REG_SP, stack_off + 4);
801                                 } else {
802                                         M_ILD(rd->argintregs[md->params[p].regoff]
803                                                   , REG_SP, stack_off + 4);
804                                 }
805                         }
806                 }
807         }
808 #else
809         /* LINUX */
810         for (p = 0; p < 8; p++) {
811                 d = rd->argintregs[p];
812                 /* save integer argument registers */
813                 M_ILD(d, REG_SP, LA_SIZE + 4 * 8 + 4 + p * 4);
814         }
815 #endif
816
817         M_ALD(REG_ZERO, REG_SP, stack_size + LA_LR_OFFSET);
818         M_MTLR(REG_ZERO);
819         M_LDA(REG_SP, REG_SP, stack_size);
820
821         /* mark trace code */
822
823         M_NOP;
824 #endif /* !defined(NDEBUG) */
825 }
826
827
828 /* emit_verbosecall_exit *******************************************************
829
830    Generates the code for the call trace.
831
832    void builtin_verbosecall_exit(s8 l, double d, float f, methodinfo *m);
833
834 *******************************************************************************/
835
836 void emit_verbosecall_exit(jitdata *jd)
837 {
838 #if !defined(NDEBUG)
839         methodinfo   *m;
840         codegendata  *cd;
841         registerdata *rd;
842         methoddesc   *md;
843         s4            disp;
844
845         if (!JITDATA_HAS_FLAG_VERBOSECALL(jd))
846                 return;
847
848         /* get required compiler data */
849
850         m  = jd->m;
851         cd = jd->cd;
852         rd = jd->rd;
853
854         md = m->parseddesc;
855         
856         /* mark trace code */
857
858         M_NOP;
859
860         M_MFLR(REG_ZERO);
861         M_AST(REG_ZERO, REG_SP, LA_LR_OFFSET);
862         M_STWU(REG_SP, REG_SP, -(LA_SIZE + (1 + 2 + 2 + 1 + 4) * 4));
863
864         /* save return registers */
865
866         M_LST(REG_RESULT_PACKED, REG_SP, LA_SIZE + (1 + 2 + 2 + 1 + 0) * 4);
867         M_DST(REG_FRESULT, REG_SP, LA_SIZE + (1 + 2 + 2 + 1 + 2) * 4);
868
869         /* keep this order */
870         switch (md->returntype.type) {
871         case TYPE_INT:
872         case TYPE_ADR:
873                 M_INTMOVE(REG_RESULT, REG_A1);
874                 M_CLR(REG_A0);
875                 break;
876
877         case TYPE_LNG:
878                 M_LNGMOVE(REG_RESULT_PACKED, REG_A0_A1_PACKED);
879                 break;
880         }
881
882         M_FLTMOVE(REG_FRESULT, REG_FA0);
883         M_FLTMOVE(REG_FRESULT, REG_FA1);
884
885         disp = dseg_add_address(cd, m);
886         M_ALD(REG_A2, REG_PV, disp);
887
888         disp = dseg_add_functionptr(cd, builtin_verbosecall_exit);
889         M_ALD(REG_ITMP2, REG_PV, disp);
890         M_MTCTR(REG_ITMP2);
891         M_JSR;
892
893         /* restore return registers */
894
895         M_LLD(REG_RESULT_PACKED, REG_SP, LA_SIZE + (1 + 2 + 2 + 1 + 0) * 4);
896         M_DLD(REG_FRESULT, REG_SP, LA_SIZE + (1 + 2 + 2 + 1 + 2) * 4);
897
898         M_ALD(REG_ZERO, REG_SP, LA_SIZE + (1 + 2 + 2 + 1 + 4) * 4 + LA_LR_OFFSET);
899         M_MTLR(REG_ZERO);
900         M_LDA(REG_SP, REG_SP, LA_SIZE + (1 + 2 + 2 + 1 + 4) * 4);
901
902         /* mark trace code */
903
904         M_NOP;
905 #endif /* !defined(NDEBUG) */
906 }
907
908
909 /*
910  * These are local overrides for various environment variables in Emacs.
911  * Please do not remove this and leave it at the end of the file, where
912  * Emacs will automagically detect them.
913  * ---------------------------------------------------------------------
914  * Local variables:
915  * mode: c
916  * indent-tabs-mode: t
917  * c-basic-offset: 4
918  * tab-width: 4
919  * End:
920  * vim:noexpandtab:sw=4:ts=4:
921  */