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