1 /* src/vm/jit/arm/emit.c - Arm code emitter functions
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
8 This file is part of CACAO.
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.
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.
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
25 $Id: emit.c 4398 2006-01-31 23:43:08Z twisti $
38 #include "vm/jit/arm/codegen.h"
40 #include "mm/memory.h"
42 #if defined(ENABLE_THREADS)
43 # include "threads/native/lock.h"
46 #include "vm/builtin.h"
47 #include "vm/global.h"
49 #include "vm/jit/asmpart.h"
50 #include "vm/jit/emit-common.h"
51 #include "vm/jit/jit.h"
52 #include "vm/jit/replace.h"
54 #include "toolbox/logging.h" /* XXX for debugging only */
57 /* emit_load *******************************************************************
59 Emits a possible load of an operand.
61 *******************************************************************************/
63 s4 emit_load(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
69 /* get required compiler data */
73 if (src->flags & INMEMORY) {
76 disp = src->vv.regoff * 4;
78 if (IS_FLT_DBL_TYPE(src->type)) {
79 #if defined(ENABLE_SOFTFLOAT)
80 if (IS_2_WORD_TYPE(src->type))
81 M_LLD(tempreg, REG_SP, disp);
83 M_ILD(tempreg, REG_SP, disp);
85 if (IS_2_WORD_TYPE(src->type))
86 M_DLD(tempreg, REG_SP, disp);
88 M_FLD(tempreg, REG_SP, disp);
92 if (IS_2_WORD_TYPE(src->type))
93 M_LLD(tempreg, REG_SP, disp);
95 M_ILD(tempreg, REG_SP, disp);
101 reg = src->vv.regoff;
107 /* emit_load_low ***************************************************************
109 Emits a possible load of the low 32-bits of a long source operand.
111 *******************************************************************************/
113 s4 emit_load_low(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
119 assert(src->type == TYPE_LNG);
121 /* get required compiler data */
125 if (src->flags & INMEMORY) {
128 disp = src->vv.regoff * 4;
130 #if defined(__ARMEL__)
131 M_ILD(tempreg, REG_SP, disp);
133 M_ILD(tempreg, REG_SP, disp + 4);
139 reg = GET_LOW_REG(src->vv.regoff);
145 /* emit_load_high **************************************************************
147 Emits a possible load of the high 32-bits of a long source operand.
149 *******************************************************************************/
151 s4 emit_load_high(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
157 assert(src->type == TYPE_LNG);
159 /* get required compiler data */
163 if (src->flags & INMEMORY) {
166 disp = src->vv.regoff * 4;
168 #if defined(__ARMEL__)
169 M_ILD(tempreg, REG_SP, disp + 4);
171 M_ILD(tempreg, REG_SP, disp);
177 reg = GET_HIGH_REG(src->vv.regoff);
183 /* emit_store ******************************************************************
185 Emits a possible store to a variable.
187 *******************************************************************************/
189 void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
194 /* get required compiler data */
198 if (dst->flags & INMEMORY) {
201 disp = dst->vv.regoff * 4;
203 if (IS_FLT_DBL_TYPE(dst->type)) {
204 #if defined(ENABLE_SOFTFLOAT)
205 if (IS_2_WORD_TYPE(dst->type))
206 M_LST(d, REG_SP, disp);
208 M_IST(d, REG_SP, disp);
210 if (IS_2_WORD_TYPE(dst->type))
211 M_DST(d, REG_SP, disp);
213 M_FST(d, REG_SP, disp);
217 if (IS_2_WORD_TYPE(dst->type))
218 M_LST(d, REG_SP, disp);
220 M_IST(d, REG_SP, disp);
223 else if (IS_LNG_TYPE(dst->type)) {
224 #if defined(__ARMEL__)
225 if (GET_HIGH_REG(dst->vv.regoff) == REG_SPLIT)
226 M_IST_INTERN(GET_HIGH_REG(d), REG_SP, 0 * 4);
228 if (GET_LOW_REG(dst->vv.regoff) == REG_SPLIT)
229 M_IST_INTERN(GET_LOW_REG(d), REG_SP, 0 * 4);
235 /* emit_copy *******************************************************************
239 *******************************************************************************/
241 void emit_copy(jitdata *jd, instruction *iptr, varinfo *src, varinfo *dst)
247 /* get required compiler data */
252 /* XXX dummy call, removed me!!! */
253 d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP1);
255 if ((src->vv.regoff != dst->vv.regoff) ||
256 ((src->flags ^ dst->flags) & INMEMORY)) {
258 /* If one of the variables resides in memory, we can eliminate
259 the register move from/to the temporary register with the
260 order of getting the destination register and the load. */
262 if (IS_INMEMORY(src->flags)) {
263 #if !defined(ENABLE_SOFTFLOAT)
264 if (IS_FLT_DBL_TYPE(src->type))
265 d = codegen_reg_of_var(iptr->opc, dst, REG_FTMP1);
269 if (IS_2_WORD_TYPE(src->type))
270 d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP12_PACKED);
272 d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP1);
275 s1 = emit_load(jd, iptr, src, d);
278 #if !defined(ENABLE_SOFTFLOAT)
279 if (IS_FLT_DBL_TYPE(src->type))
280 s1 = emit_load(jd, iptr, src, REG_FTMP1);
284 if (IS_2_WORD_TYPE(src->type))
285 s1 = emit_load(jd, iptr, src, REG_ITMP12_PACKED);
287 s1 = emit_load(jd, iptr, src, REG_ITMP1);
290 d = codegen_reg_of_var(iptr->opc, dst, s1);
294 if (IS_FLT_DBL_TYPE(src->type)) {
295 #if defined(ENABLE_SOFTFLOAT)
296 if (IS_2_WORD_TYPE(src->type))
299 /* XXX grrrr, wrong direction! */
302 if (IS_2_WORD_TYPE(src->type))
309 if (IS_2_WORD_TYPE(src->type))
312 /* XXX grrrr, wrong direction! */
317 emit_store(jd, iptr, dst, d);
322 /* emit_iconst *****************************************************************
326 *******************************************************************************/
328 void emit_iconst(codegendata *cd, s4 d, s4 value)
335 disp = dseg_add_s4(cd, value);
336 M_DSEG_LOAD(d, disp);
341 /* emit_nullpointer_check ******************************************************
343 Emit a NullPointerException check.
345 *******************************************************************************/
347 void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg)
349 if (INSTRUCTION_MUST_CHECK(iptr)) {
352 codegen_add_nullpointerexception_ref(cd);
357 /* emit_arrayindexoutofbounds_check ********************************************
359 Emit a ArrayIndexOutOfBoundsException check.
361 *******************************************************************************/
363 void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
365 if (INSTRUCTION_MUST_CHECK(iptr)) {
366 M_ILD_INTERN(REG_ITMP3, s1, OFFSET(java_arrayheader, size));
367 M_CMP(s2, REG_ITMP3);
369 codegen_add_arrayindexoutofboundsexception_ref(cd, s2);
374 /* emit_exception_stubs ********************************************************
376 Generates the code for the exception stubs.
378 *******************************************************************************/
380 void emit_exception_stubs(jitdata *jd)
390 /* get required compiler data */
395 /* generate exception stubs */
399 for (er = cd->exceptionrefs; er != NULL; er = er->next) {
400 /* back-patch the branch to this exception code */
402 branchmpc = er->branchpos;
403 targetmpc = cd->mcodeptr - cd->mcodebase;
405 md_codegen_patch_branch(cd, branchmpc, targetmpc);
409 /* Check if the exception is an
410 ArrayIndexOutOfBoundsException. If so, move index register
414 M_MOV(REG_ITMP1, er->reg);
416 /* calcuate exception address */
418 assert((er->branchpos - 4) % 4 == 0);
419 M_ADD_IMM_EXT_MUL4(REG_ITMP2_XPC, REG_PV, (er->branchpos - 4) / 4);
421 /* move function to call into REG_ITMP3 */
423 disp = dseg_add_functionptr(cd, er->function);
424 M_DSEG_LOAD(REG_ITMP3, disp);
426 if (targetdisp == 0) {
427 targetdisp = ((u4 *) cd->mcodeptr) - ((u4 *) cd->mcodebase);
429 M_MOV(rd->argintregs[0], REG_PV);
430 M_MOV(rd->argintregs[1], REG_SP);
432 if (jd->isleafmethod)
433 M_MOV(rd->argintregs[2], REG_LR);
435 M_LDR(rd->argintregs[2], REG_SP,
436 cd->stackframesize * 4 - SIZEOF_VOID_P);
438 M_MOV(rd->argintregs[3], REG_ITMP2_XPC);
441 /* TODO: we only need to save LR in leaf methods */
443 M_STMFD(BITMASK_ARGS | 1<<REG_PV | 1<<REG_LR, REG_SP);
445 /* move a3 to stack */
447 M_STR_UPDATE(REG_ITMP1, REG_SP, -4);
449 /* do the exception call */
451 M_MOV(REG_LR, REG_PC);
452 M_MOV(REG_PC, REG_ITMP3);
454 M_ADD_IMM(REG_SP, REG_SP, 4);
456 /* result of stacktrace is our XPTR */
458 M_MOV(REG_ITMP1_XPTR, REG_RESULT);
460 /* restore registers */
462 M_LDMFD(BITMASK_ARGS | 1<<REG_PV | 1<<REG_LR, REG_SP);
464 disp = dseg_add_functionptr(cd, asm_handle_exception);
465 M_DSEG_LOAD(REG_ITMP3, disp);
466 M_MOV(REG_PC, REG_ITMP3);
469 disp = (((u4 *) cd->mcodebase) + targetdisp) -
470 (((u4 *) cd->mcodeptr) + 2);
478 /* emit_patcher_stubs **********************************************************
480 Generates the code for the patcher stubs.
482 *******************************************************************************/
484 void emit_patcher_stubs(jitdata *jd)
494 /* get required compiler data */
498 /* generate patcher stub call code */
502 for (pref = cd->patchrefs; pref != NULL; pref = pref->next) {
503 /* check code segment size */
507 /* Get machine code which is patched back in later. The
508 call is 1 instruction word long. */
510 tmpmcodeptr = (u1 *) (cd->mcodebase + pref->branchpos);
512 mcode = *((u4 *) tmpmcodeptr);
514 /* Patch in the call to call the following code (done at
517 savedmcodeptr = cd->mcodeptr; /* save current mcodeptr */
518 cd->mcodeptr = tmpmcodeptr; /* set mcodeptr to patch position */
520 disp = ((u4 *) savedmcodeptr) - (((u4 *) tmpmcodeptr) + 2);
523 cd->mcodeptr = savedmcodeptr; /* restore the current mcodeptr */
525 /* create stack frame (align stack to 8-byte) */
527 M_SUB_IMM(REG_SP, REG_SP, 8 * 4);
529 /* save itmp3 onto stack */
531 M_STR_INTERN(REG_ITMP3, REG_SP, 6 * 4);
533 /* calculate return address and move it onto stack */
534 /* ATTENTION: we can not use BL to branch to patcher stub, */
535 /* ATTENTION: because we need to preserve LR for leaf methods */
537 disp = (s4) (((u4 *) cd->mcodeptr) - (((u4 *) tmpmcodeptr) + 1) + 2);
539 M_SUB_IMM_EXT_MUL4(REG_ITMP3, REG_PC, disp);
540 M_STR_INTERN(REG_ITMP3, REG_SP, 4 * 4);
542 /* move pointer to java_objectheader onto stack */
544 #if defined(ENABLE_THREADS)
545 /* order reversed because of data segment layout */
547 (void) dseg_add_unique_address(cd, NULL); /* flcword */
548 (void) dseg_add_unique_address(cd, lock_get_initial_lock_word());
549 disp = dseg_add_unique_address(cd, NULL); /* vftbl */
551 M_SUB_IMM_EXT_MUL4(REG_ITMP3, REG_PV, -disp / 4);
552 M_STR_INTERN(REG_ITMP3, REG_SP, 3 * 4);
554 M_EOR(REG_ITMP3, REG_ITMP3, REG_ITMP3);
555 M_STR_INTERN(REG_ITMP3, REG_SP, 3 * 4);
558 /* move machine code onto stack */
560 disp = dseg_add_unique_s4(cd, mcode);
561 M_DSEG_LOAD(REG_ITMP3, disp);
562 M_STR_INTERN(REG_ITMP3, REG_SP, 2 * 4);
564 /* move class/method/field reference onto stack */
566 disp = dseg_add_unique_address(cd, pref->ref);
567 M_DSEG_LOAD(REG_ITMP3, disp);
568 M_STR_INTERN(REG_ITMP3, REG_SP, 1 * 4);
570 /* move data segment displacement onto stack */
572 disp = dseg_add_unique_s4(cd, pref->disp);
573 M_DSEG_LOAD(REG_ITMP3, disp);
574 M_STR_INTERN(REG_ITMP3, REG_SP, 5 * 4);
576 /* move patcher function pointer onto stack */
578 disp = dseg_add_functionptr(cd, pref->patcher);
579 M_DSEG_LOAD(REG_ITMP3, disp);
580 M_STR_INTERN(REG_ITMP3, REG_SP, 0 * 4);
582 /* finally call the patcher via asm_patcher_wrapper */
583 /* ATTENTION: don't use REG_PV here, because some patchers need it */
585 if (targetdisp == 0) {
586 targetdisp = ((u4 *) cd->mcodeptr) - ((u4 *) cd->mcodebase);
588 disp = dseg_add_functionptr(cd, asm_patcher_wrapper);
589 /*M_DSEG_BRANCH_NOLINK(REG_PC, REG_PV, a);*/
590 /* TODO: this is only a hack */
591 M_DSEG_LOAD(REG_ITMP3, disp);
592 M_MOV(REG_PC, REG_ITMP3);
595 disp = (((u4 *) cd->mcodebase) + targetdisp) -
596 (((u4 *) cd->mcodeptr) + 2);
604 /* emit_replacement_stubs ******************************************************
606 Generates the code for the replacement stubs.
608 *******************************************************************************/
610 #if defined(ENABLE_REPLACEMENT)
611 void emit_replacement_stubs(jitdata *jd)
620 /* get required compiler data */
625 #endif /* defined(ENABLE_REPLACEMENT) */
628 /* emit_verbosecall_enter ******************************************************
630 Generates the code for the call trace.
632 *******************************************************************************/
635 void emit_verbosecall_enter(jitdata *jd)
645 /* get required compiler data */
653 /* stackframesize is changed below */
655 stackframesize = cd->stackframesize;
657 /* mark trace code */
661 /* Save argument registers to stack (including LR and PV). Keep
662 stack 8-byte aligned. */
664 M_STMFD(BITMASK_ARGS | (1<<REG_LR) | (1<<REG_PV), REG_SP);
665 M_SUB_IMM(REG_SP, REG_SP, (2 + 2 + 1 + 1) * 4); /* space for a3, a4 and m */
667 stackframesize += 6 + 2 + 2 + 1 + 1;
669 /* prepare args for tracer */
671 i = md->paramcount - 1;
676 for (; i >= 0; i--) {
677 t = md->paramtypes[i].type;
679 /* load argument into register (s1) and make it of TYPE_LNG */
681 if (!md->params[i].inmemory) {
682 s1 = md->params[i].regoff;
684 if (!IS_2_WORD_TYPE(t)) {
685 M_MOV_IMM(REG_ITMP1, 0);
686 s1 = PACK_REGS(s1, REG_ITMP1);
689 SPLIT_OPEN(t, s1, REG_ITMP1);
690 SPLIT_LOAD(t, s1, stackframesize);
694 s1 = REG_ITMP12_PACKED;
695 s2 = md->params[i].regoff + stackframesize;
697 if (IS_2_WORD_TYPE(t))
698 M_LLD(s1, REG_SP, s2 * 4);
700 M_ILD(GET_LOW_REG(s1), REG_SP, s2 * 4);
701 M_MOV_IMM(GET_HIGH_REG(s1), 0);
705 /* place argument for tracer */
708 #if defined(__ARMEL__)
709 s2 = PACK_REGS(rd->argintregs[i * 2], rd->argintregs[i * 2 + 1]);
710 #else /* defined(__ARMEB__) */
711 s2 = PACK_REGS(rd->argintregs[i * 2 + 1], rd->argintregs[i * 2]);
717 M_LST(s1, REG_SP, s2 * 4);
721 /* prepare methodinfo pointer for tracer */
723 disp = dseg_add_address(cd, m);
724 M_DSEG_LOAD(REG_ITMP1, disp);
725 M_STR_INTERN(REG_ITMP1, REG_SP, 16);
727 /* call tracer here (we use a long branch) */
729 M_LONGBRANCH(builtin_verbosecall_enter);
731 /* Restore argument registers from stack. Keep stack 8-byte
734 M_ADD_IMM(REG_SP, REG_SP, (2 + 2 + 1 + 1) * 4); /* free argument stack */
735 M_LDMFD(BITMASK_ARGS | (1<<REG_LR) | (1<<REG_PV), REG_SP);
737 /* mark trace code */
741 #endif /* !defined(NDEBUG) */
744 /* emit_verbosecall_exit *******************************************************
746 Generates the code for the call trace.
748 void builtin_verbosecall_exit(s8 l, double d, float f, methodinfo *m);
750 *******************************************************************************/
753 void emit_verbosecall_exit(jitdata *jd)
761 /* get required compiler data */
769 /* mark trace code */
773 /* Keep stack 8-byte aligned. */
775 M_STMFD(BITMASK_RESULT | (1<<REG_LR) | (1<<REG_PV), REG_SP);
776 M_SUB_IMM(REG_SP, REG_SP, (1 + 1) * 4); /* space for f and m */
778 switch (md->returntype.type) {
781 M_INTMOVE(REG_RESULT, GET_LOW_REG(REG_A0_A1_PACKED));
782 M_MOV_IMM(GET_HIGH_REG(REG_A0_A1_PACKED), 0);
786 M_LNGMOVE(REG_RESULT_PACKED, REG_A0_A1_PACKED);
790 M_IST(REG_RESULT, REG_SP, 0 * 4);
794 M_LNGMOVE(REG_RESULT_PACKED, REG_A2_A3_PACKED);
798 disp = dseg_add_address(cd, m);
799 M_DSEG_LOAD(REG_ITMP1, disp);
800 M_AST(REG_ITMP1, REG_SP, 1 * 4);
801 M_LONGBRANCH(builtin_verbosecall_exit);
803 /* Keep stack 8-byte aligned. */
805 M_ADD_IMM(REG_SP, REG_SP, (1 + 1) * 4); /* free argument stack */
806 M_LDMFD(BITMASK_RESULT | (1<<REG_LR) | (1<<REG_PV), REG_SP);
808 /* mark trace code */
812 #endif /* !defined(NDEBUG) */
816 * These are local overrides for various environment variables in Emacs.
817 * Please do not remove this and leave it at the end of the file, where
818 * Emacs will automagically detect them.
819 * ---------------------------------------------------------------------
822 * indent-tabs-mode: t
826 * vim:noexpandtab:sw=4:ts=4: