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