* Merged in twisti-branch.
[cacao.git] / src / vm / jit / m68k / emit.c
1 /* src/vm/jit/m68k/emit.c
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: arch.h 5330 2006-09-05 18:43:12Z edwin $
26
27 */
28 #include "config.h"
29
30 #include <assert.h>
31
32 #include "emit.h"
33 #include "vm/jit/emit-common.h"
34 #include "vm/exceptions.h"
35 #include "vm/jit/asmpart.h"
36
37 #include "vm/builtin.h"
38 #include "mm/memory.h"
39
40 #include "codegen.h"
41
42 /*
43  *      Loads an immededat operand into data register
44  */
45 void emit_mov_imm_reg (codegendata *cd, s4 imm, s4 dreg)
46 {
47         if ((imm & 0x000000FF) == imm)  {
48                 /* use byte form */
49                 *((s2*)cd->mcodeptr) = 0x7000 | (dreg << 9) | imm;      /* MOVEQ.L */
50                 cd->mcodeptr += 2;
51         } else if ((imm  & 0xFFFF0000) != 0)    {
52                 /* use long form */
53                 OPWORD( ((2<<6) | (dreg << 3) | 0), 7, 4);
54                 *((s4*)cd->mcodeptr) = (s4)imm;
55                 cd->mcodeptr += 4;
56         } else {
57                 /* use word form */
58                 OPWORD( ((3<<6) | (dreg << 3) | 0), 7, 4);
59                 *((s2*)cd->mcodeptr) = (s2)imm;
60                 cd->mcodeptr += 2;
61         }
62 }
63
64 /* emit_copy *******************************************************************
65
66    Generates a register/memory to register/memory copy.
67
68 *******************************************************************************/
69 void emit_copy(jitdata *jd, instruction *iptr, varinfo *src, varinfo *dst)
70 {
71         codegendata  *cd;
72         s4            s1, d;
73
74         /* get required compiler data */
75
76         cd = jd->cd;
77
78         if ((src->vv.regoff != dst->vv.regoff) ||
79                 (IS_INMEMORY(src->flags ^ dst->flags))) {
80
81                 /* If one of the variables resides in memory, we can eliminate
82                    the register move from/to the temporary register with the
83                    order of getting the destination register and the load. */
84
85                 if (IS_INMEMORY(src->flags)) {
86                         if (IS_LNG_TYPE(src->type))
87                                 d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP12_PACKED);
88                         else
89                                 d = codegen_reg_of_var(iptr->opc, dst, REG_IFTMP);
90
91                         s1 = emit_load(jd, iptr, src, d);
92                 } else {
93                         if (IS_LNG_TYPE(src->type))
94                                 s1 = emit_load(jd, iptr, src, REG_ITMP12_PACKED);
95                         else
96                                 s1 = emit_load(jd, iptr, src, REG_IFTMP);
97
98                         d = codegen_reg_of_var(iptr->opc, dst, s1);
99                 }
100
101                 if (s1 != d) {
102                         switch(src->type)       {
103                                 case TYPE_INT: M_INTMOVE(s1, d); break;
104                                 case TYPE_ADR: M_ADRMOVE(s1, d); break;
105                                 case TYPE_LNG: M_LNGMOVE(s1, d); break;
106 #if !defined(ENABLE_SOFTFLOAT)
107                                 case TYPE_FLT: M_FLTMOVE(s1, d); break;
108                                 case TYPE_DBL: M_DBLMOVE(s1, d); break;
109 #else
110                                 case TYPE_FLT: M_INTMOVE(s1, d); break;
111                                 case TYPE_DBL: M_LNGMOVE(s1, d); break;
112 #endif
113                                 default: assert(0);
114                         }
115                 }
116                 emit_store(jd, iptr, dst, d);
117         }
118 }
119 /* emit_store ******************************************************************
120
121    Emits a possible store of the destination operand.
122
123 *******************************************************************************/
124
125 inline void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
126 {
127         codegendata  *cd;
128
129         /* get required compiler data */
130
131         cd = jd->cd;
132
133         if (IS_INMEMORY(dst->flags)) {
134                 COUNT_SPILLS;
135         
136                 switch(dst->type)       {
137 #if defined(ENABLE_SOFTFLOAT)
138                         case TYPE_DBL:
139 #endif
140                         case TYPE_LNG:
141                                 M_LST(d, REG_SP, dst->vv.regoff * 4);
142                                 break;
143 #if defined(ENABLE_SOFTFLOAT)
144                         case TYPE_FLT:
145 #endif
146                         case TYPE_INT:
147                                 M_IST(d, REG_SP, dst->vv.regoff * 4);
148                                 break;
149                         case TYPE_ADR:
150                                 M_AST(d, REG_SP, dst->vv.regoff * 4);
151                                 break;
152 #if !defined(ENABLE_SOFTFLOAT)
153                         case TYPE_DBL:
154                                 M_DST(d, REG_SP, dst->vv.regoff * 4);
155                                 break;
156                         case TYPE_FLT:
157                                 M_FST(d, REG_SP, dst->vv.regoff * 4);
158                                 break;
159 #endif
160                         default:
161                                 assert(0);
162                 }
163         }
164 }
165 /* emit_load *******************************************************************
166
167    Emits a possible load of an operand.
168
169 *******************************************************************************/
170 s4 emit_load(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
171 {
172         codegendata *cd;
173         s4           disp;
174         s4           reg;
175
176         /* get required compiler data */
177
178         cd = jd->cd;
179
180         if (IS_INMEMORY(src->flags)) {
181                 COUNT_SPILLS;
182
183                 disp = src->vv.regoff * 4;
184         
185                 switch (src->type)      {
186 #if defined(ENABLE_SOFTFLOAT)
187                         case TYPE_FLT:
188 #endif
189                         case TYPE_INT: 
190                                 M_ILD(tempreg, REG_SP, disp);
191                                 break;
192 #if defined(ENABLE_SOFTFLOAT)
193                         case TYPE_DBL:
194 #endif
195                         case TYPE_LNG:
196                                 M_LLD(tempreg, REG_SP, disp);
197                                 break;
198                         case TYPE_ADR:
199                                 M_ALD(tempreg, REG_SP, disp);
200                                 break;
201 #if !defined(ENABLE_SOFTFLOAT)
202                         case TYPE_FLT:
203                                 M_FLD(tempreg, REG_SP, disp);
204                                 break;
205                         case TYPE_DBL:
206                                 M_DLD(tempreg, REG_SP, disp);
207                                 break;
208 #endif
209                         default: assert(0);
210                 }
211                 #if 0
212                 if (IS_FLT_DBL_TYPE(src->type)) {
213                         if (IS_2_WORD_TYPE(src->type)) {
214                                 M_DLD(tempreg, REG_SP, disp);
215                          } else {
216                                 M_FLD(tempreg, REG_SP, disp);
217                         }
218                 } else {
219                         if (IS_2_WORD_TYPE(src->type)) {
220                                 M_LLD(tempreg, REG_SP, disp);
221                         } else {
222                                 M_ILD(tempreg, REG_SP, disp);
223                         }
224                 }
225                 #endif
226
227                 reg = tempreg;
228         }
229         else
230                 reg = src->vv.regoff;
231
232         return reg;
233 }
234
235
236 /* emit_patcher_stubs **********************************************************
237
238    Generates the code for the patcher stubs.
239
240 *******************************************************************************/
241 void emit_patcher_stubs(jitdata *jd)
242 {
243         codegendata *cd;
244         patchref    *pref;
245         u8           mcode;
246         u1          *savedmcodeptr;
247         u1          *tmpmcodeptr;
248         s4           targetdisp;
249         s4           disp;
250
251         /* get required compiler data */
252
253         cd = jd->cd;
254
255         /* generate code patching stub call code */
256
257         targetdisp = 0;
258
259         for (pref = cd->patchrefs; pref != NULL; pref = pref->next) {
260                 /* check code segment size */
261
262                 MCODECHECK(512);
263
264                 /* Get machine code which is patched back in later. A
265                    `bsr.l' is 6 bytes long. */
266
267                 savedmcodeptr = cd->mcodebase + pref->branchpos;
268                 mcode = *((u8 *) savedmcodeptr);
269
270                 /* patch in `bsr.l' to call the following code */
271
272                 tmpmcodeptr  = cd->mcodeptr;    /* save current mcodeptr              */
273                 cd->mcodeptr = savedmcodeptr;   /* set mcodeptr to patch position     */
274
275                 M_BSR_IMM(tmpmcodeptr - (savedmcodeptr + PATCHER_CALL_SIZE) + 4);
276
277                 cd->mcodeptr = tmpmcodeptr;     /* restore the current mcodeptr       */
278
279                 /* save REG_ITMP3 */
280                 M_IPUSH(REG_ITMP3);     /* FIXME why, and restore where ? */
281
282                 /* move pointer to java_objectheader onto stack */
283
284 #if defined(ENABLE_THREADS)
285                 (void) dseg_add_unique_address(cd, NULL);                  /* flcword */
286                 (void) dseg_add_unique_address(cd, lock_get_initial_lock_word());
287                 disp = dseg_add_unique_address(cd, NULL);                  /* vftbl   */
288
289                 assert(0); /* The next lines are wrong */
290                 M_MOV_IMM(0, REG_ITMP3);
291                 dseg_adddata(cd);
292                 M_AADD_IMM(REG_ITMP3, disp);
293                 M_IPUSH(REG_ITMP3);
294 #else
295                 M_IPUSH_IMM(0);
296 #endif
297
298                 /* push move machine code bytes and classinfo pointer */
299
300                 M_IPUSH_IMM(mcode >> 32);
301                 M_IPUSH_IMM(mcode);
302                 M_IPUSH_IMM(pref->ref);
303                 M_IPUSH_IMM(pref->patcher);
304
305                 M_JMP_IMM(asm_patcher_wrapper);
306         }
307 }
308 s4 emit_load_low(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg) 
309 {
310         codegendata  *cd;
311         s4            disp;
312         s4            reg;
313
314         assert(src->type == TYPE_LNG);
315
316         /* get required compiler data */
317         cd = jd->cd;
318
319         if (IS_INMEMORY(src->flags)) {
320                 COUNT_SPILLS;
321
322                 disp = src->vv.regoff * 4;
323                 M_ILD(tempreg, REG_SP, disp + 4);
324                 reg = tempreg;
325         } else {
326                 reg = GET_LOW_REG(src->vv.regoff);
327         }
328         return reg;
329 }
330 s4 emit_load_high(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
331 {
332         codegendata  *cd;
333         s4            disp;
334         s4            reg;
335
336         assert(src->type == TYPE_LNG);
337
338         /* get required compiler data */
339         cd = jd->cd;
340
341         if (IS_INMEMORY(src->flags)) {
342                 COUNT_SPILLS;
343                 disp = src->vv.regoff * 4;
344                 M_ILD(tempreg, REG_SP, disp);
345                 reg = tempreg;
346         } else {
347                 reg = GET_HIGH_REG(src->vv.regoff);
348         }
349         return reg;
350 }
351 /* emit_branch *****************************************************************
352
353    Emits the code for conditional and unconditional branchs.
354
355 *******************************************************************************/
356 void emit_branch(codegendata *cd, s4 disp, s4 condition, s4 reg, u4 opt) 
357
358         /* calculate the different displacements */
359         /* PC is a at branch instruction + 2 */
360         /* coditional and uncondition branching work the same way */
361         /* short branches have signed 16 bit offset */
362         /* long branches are signed 32 bit */
363         /* the 8 bit offset branching instructions are not used */
364
365         disp  =  disp - 2;
366
367         /* check displacement for overflow */
368         if ((disp & 0x0000FFFF) != disp)        {
369                 if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
370                         cd->flags |= (CODEGENDATA_FLAG_ERROR | CODEGENDATA_FLAG_LONGBRANCHES);
371                 }
372         }
373
374         /* check which branch to generate */
375
376         if (condition == BRANCH_UNCONDITIONAL) {
377                 if (CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd))      {
378                         M_BR_32(disp);
379                 } else  {
380                         M_BR_16(disp);
381                 }
382         } else {
383                 if (CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
384                         switch (condition) {
385                         case BRANCH_EQ:
386                                 M_BEQ_32(disp);
387                                 break;
388                         case BRANCH_NE:
389                                 M_BNE_32(disp);
390                                 break;
391                         case BRANCH_LT:
392                                 M_BLT_32(disp);
393                                 break;
394                         case BRANCH_GE:
395                                 M_BGE_32(disp);
396                                 break;
397                         case BRANCH_GT:
398                                 M_BGT_32(disp);
399                                 break;
400                         case BRANCH_LE:
401                                 M_BLE_32(disp);
402                                 break;
403                         case BRANCH_NAN:
404                                 M_BNAN_32(disp);
405                                 break;
406                         case BRANCH_UGT:
407                                 M_BHI_32(disp);
408                                 break;
409
410                         default:
411                                 vm_abort("emit_branch: unknown condition %d", condition);
412                         }
413                 } else {
414                         switch (condition) {
415                         case BRANCH_EQ:
416                                 M_BEQ_16(disp);
417                                 break;
418                         case BRANCH_NE:
419                                 M_BNE_16(disp);
420                                 break;
421                         case BRANCH_LT:
422                                 M_BLT_16(disp);
423                                 break;
424                         case BRANCH_GE:
425                                 M_BGE_16(disp);
426                                 break;
427                         case BRANCH_GT:
428                                 M_BGT_16(disp);
429                                 break;
430                         case BRANCH_LE:
431                                 M_BLE_16(disp);
432                                 break;
433                         case BRANCH_NAN:
434                                 M_BNAN_16(disp);
435                                 break;
436                         case BRANCH_UGT:
437                                 M_BHI_16(disp);
438                                 break;
439                         default:
440                                 vm_abort("emit_branch: unknown condition %d", condition);
441                         }
442                 }
443         }
444 }
445
446
447 #if !defined(NDEBUG)
448 /*
449  *      Trace functions. Implement -verbose:call flag
450  *      code marked by real NOP, but performance is no matter when using -verbose:call :)
451  */
452 void emit_verbosecall_enter(jitdata* jd) 
453
454         methodinfo   *m;
455         codegendata  *cd;
456         registerdata *rd;
457         methoddesc   *md;
458         s4      disp,i,t;
459
460
461         if (!JITDATA_HAS_FLAG_VERBOSECALL(jd))
462                 return;
463         
464         /* get required compiler data */
465         m  = jd->m;
466         cd = jd->cd;
467         rd = jd->rd;
468         md = m->parseddesc;
469
470         /* mark trace code */
471         M_NOP;
472
473         M_LINK(REG_FP, -16*4);  
474         M_PUSHALL;
475
476         /* builtin_verbosecall_enter takes all args as s8 type */
477         /* TRACE_ARGS_NUM is the number of args the builtin_verbosecall_enter expects */
478         M_IPUSH_IMM(m);
479         
480         disp = 16*4 + 4 + 4;    /* points to old argument stack initially */
481
482         /* travel up stack to the first argument of the function which needs to be copied */
483         for (i=0; (i < md->paramcount) && (i < TRACE_ARGS_NUM); i++)    {
484                 disp += 4;
485                 if (IS_2_WORD_TYPE(md->paramtypes[i].type)) {   
486                         disp += 4;
487                 }
488         }
489
490         /* disp now points to the first arg which gets copied to the trace stack, relative to REG_SP! */
491         for (i=TRACE_ARGS_NUM-1; i>=0; --i) {
492                 if (i < md->paramcount) {
493                         /* traced function has such an argument */
494                         t = md->paramtypes[i].type;
495                         
496                         if (IS_2_WORD_TYPE(t))  {
497                                 /* copy from original argument stack */
498                                 M_ILD(REG_ITMP1, REG_SP, disp);
499                                 M_IPUSH(REG_ITMP1);
500                                 M_ILD(REG_ITMP1, REG_SP, disp);
501                                 M_IPUSH(REG_ITMP1);
502                         } else  {
503                                 /* displacment is increased as 4 byte on original stack but 8 byte on trace stack */
504                                 M_ILD(REG_ITMP1, REG_SP, disp);
505                                 M_IPUSH(REG_ITMP1);
506                                 M_IPUSH_IMM(0);
507                                 disp += 4;
508                         }
509                 } else  {
510                         /* function has no arg here, push nothing and adapt displacement */
511                         M_IPUSH_IMM(0);
512                         M_IPUSH_IMM(0);
513                         disp += 8;
514                 }
515         }
516         M_JSR_IMM(builtin_verbosecall_enter);
517         /* pop arguments off stack */
518         M_AADD_IMM(TRACE_ARGS_NUM*8+4, REG_SP);
519
520         M_POPALL;
521         M_UNLK(REG_FP);
522         M_NOP;
523 }
524 void emit_verbosecall_exit(jitdata* jd) 
525
526         methodinfo   *m;
527         codegendata  *cd;
528         registerdata *rd;
529         methoddesc   *md;
530
531         if (!JITDATA_HAS_FLAG_VERBOSECALL(jd))
532                 return;
533
534         /* get required compiler data */
535         m  = jd->m;
536         cd = jd->cd;
537         rd = jd->rd;
538         md = m->parseddesc;
539
540         /* void builtin_verbosecall_exit(s8 l, double d, float f, methodinfo *m); */
541
542
543         /* mark trace code */
544         M_NOP;
545         M_LINK(REG_FP, 0);
546
547         M_IPUSH_IMM(m);                                 /* push methodinfo */
548
549         M_IPUSH_IMM(0);                                 /* TODO push float result */
550
551         M_IPUSH_IMM(0);                                 /* TODO push double result */
552         M_IPUSH_IMM(0);                                 /* TODO push double result */
553
554         M_IPUSH(GET_HIGH_REG(REG_RESULT_PACKED))
555         M_IPUSH(GET_LOW_REG(REG_RESULT_PACKED))         /* push long result */
556
557
558         M_JSR_IMM(builtin_verbosecall_exit);
559
560         /* poping result registers from stack */
561         M_IPOP(GET_LOW_REG(REG_RESULT_PACKED))
562         M_IPOP(GET_HIGH_REG(REG_RESULT_PACKED))
563
564 #if 0
565         /* that is wrong of course, overwrites registers and stuff */
566         M_IPOP(0);      /* TODO: pop double result */
567         M_IPOP(0);      /* TODO: pop double result */
568
569         M_IPOP(0);      /* TODO: pop float result */
570 #else
571         M_AADD_IMM(3*4, REG_SP);
572 #endif
573         M_AADD_IMM(4, REG_SP);                          /* remove rest of stack */
574         M_UNLK(REG_FP);
575         M_NOP;
576 }
577 #endif
578
579 /* emit_classcast_check ********************************************************
580
581    Emit a ClassCastException check.
582
583 *******************************************************************************/
584
585 void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 reg, s4 s1)
586 {
587         if (INSTRUCTION_MUST_CHECK(iptr)) {
588                 switch (condition) {
589                 case BRANCH_LE:
590                         M_BGT(4);
591                         break;
592                 case BRANCH_EQ:
593                         M_BNE(4);
594                         break;
595                 case BRANCH_GT:
596                         M_BLE(4);
597                         break;
598                 case BRANCH_UGT:
599                         M_BHI(4);
600                         break;
601                 default:
602                         vm_abort("emit_classcast_check: unknown condition %d", condition);
603                 }
604                 M_TRAP_SETREGISTER(s1);
605                 M_TRAP(EXCEPTION_HARDWARE_CLASSCAST);
606         }
607 }
608
609 /* emit_arrayindexoutofbounds_check ********************************************
610
611    Emit a ArrayIndexOutOfBoundsException check.
612
613 *******************************************************************************/
614 void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
615 {
616         if (INSTRUCTION_MUST_CHECK(iptr)) {
617                 M_ILD(REG_ITMP3, s1, OFFSET(java_arrayheader, size));
618                 M_ICMP(REG_ITMP3, s2);
619                 M_BLT(2);
620                 /*M_ALD_INTERN(s2, REG_ZERO, EXCEPTION_LOAD_DISP_ARRAYINDEXOUTOFBOUNDS);*/
621                 M_ILLEGAL; /*FIXME */
622         }
623 }
624
625 /* emit_nullpointer_check ******************************************************
626
627    Emit a NullPointerException check.
628
629 *******************************************************************************/
630 void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg)
631 {
632         if (INSTRUCTION_MUST_CHECK(iptr)) {
633                 /* did like to assert on TYPE_ADR, but not possible in here */
634                 /* so assert before each emit_nullpointer_check */
635                 M_ATST(reg);
636                 M_BNE(2);
637                 /*M_ALD_INTERN(REG_ZERO, REG_ZERO, EXCEPTION_LOAD_DISP_NULLPOINTER);*/
638                 M_ILLEGAL;
639         }
640 }
641
642 /* emit_arithmetic_check *******************************************************
643
644    Emit an ArithmeticException check.
645
646 *******************************************************************************/
647
648 void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg)
649 {
650         if (INSTRUCTION_MUST_CHECK(iptr)) {
651                 M_ITST(reg);
652                 M_BNE(2);
653                 /*M_ALD_INTERN(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_ARITHMETIC);*/
654                 M_ILLEGAL; /* FIXME */
655         }
656 }
657
658 /* emit_exception_check_areg **************************************************
659  *
660    Emit an Exception check, tested register is address REG_RESULT
661
662 *******************************************************************************/
663 void emit_exception_check_areg(codegendata *cd, instruction *iptr)
664 {
665         if (INSTRUCTION_MUST_CHECK(iptr)) {
666                 M_ATST(REG_RESULT);
667                 M_BNE(2);
668                 /*M_ALD_INTERN(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_EXCEPTION);*/
669                 M_ILLEGAL; /*FIXME*/
670         }
671 }
672 /* emit_exception_check_ireg **************************************************
673
674    Emit an Exception check. Teste register is integer REG_RESULT
675
676 *******************************************************************************/
677 void emit_exception_check_ireg(codegendata *cd, instruction *iptr)
678 {
679         if (INSTRUCTION_MUST_CHECK(iptr)) {
680                 M_ITST(REG_RESULT);
681                 M_BNE(2);
682                 /*M_ALD_INTERN(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_EXCEPTION);*/
683                 M_ILLEGAL; /*FIXME*/
684         }
685 }
686