1 /* src/vm/jit/powerpc/emit.c - PowerPC 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/powerpc/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/exceptions.h"
49 #include "vm/jit/asmpart.h"
50 #include "vm/jit/codegen-common.h"
51 #include "vm/jit/dseg.h"
52 #include "vm/jit/emit-common.h"
53 #include "vm/jit/jit.h"
54 #include "vm/jit/replace.h"
56 #include "vmcore/options.h"
59 /* emit_load *******************************************************************
61 Emits a possible load of an operand.
63 *******************************************************************************/
65 s4 emit_load(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
71 /* get required compiler data */
75 if (IS_INMEMORY(src->flags)) {
78 disp = src->vv.regoff * 4;
83 M_ILD(tempreg, REG_SP, disp);
86 M_LLD(tempreg, REG_SP, disp);
89 M_FLD(tempreg, REG_SP, disp);
92 M_DLD(tempreg, REG_SP, disp);
95 vm_abort("emit_load: unknown type %d", src->type);
101 reg = src->vv.regoff;
107 /* emit_load_low ***************************************************************
109 Emits a possible load of the low 32-bits of an 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 (IS_INMEMORY(src->flags)) {
128 disp = src->vv.regoff * 4;
130 M_ILD(tempreg, REG_SP, disp + 4);
135 reg = GET_LOW_REG(src->vv.regoff);
141 /* emit_load_high **************************************************************
143 Emits a possible load of the high 32-bits of an operand.
145 *******************************************************************************/
147 s4 emit_load_high(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
153 assert(src->type == TYPE_LNG);
155 /* get required compiler data */
159 if (IS_INMEMORY(src->flags)) {
162 disp = src->vv.regoff * 4;
164 M_ILD(tempreg, REG_SP, disp);
169 reg = GET_HIGH_REG(src->vv.regoff);
175 /* emit_store ******************************************************************
177 Emit a possible store for the given variable.
179 *******************************************************************************/
181 void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
186 /* get required compiler data */
190 if (IS_INMEMORY(dst->flags)) {
193 disp = dst->vv.regoff * 4;
198 M_IST(d, REG_SP, disp);
201 M_LST(d, REG_SP, disp);
204 M_FST(d, REG_SP, disp);
207 M_DST(d, REG_SP, disp);
210 vm_abort("emit_store: unknown type %d", dst->type);
216 /* emit_copy *******************************************************************
218 Generates a register/memory to register/memory copy.
220 *******************************************************************************/
222 void emit_copy(jitdata *jd, instruction *iptr, varinfo *src, varinfo *dst)
227 /* get required compiler data */
231 if ((src->vv.regoff != dst->vv.regoff) ||
232 (IS_INMEMORY(src->flags ^ dst->flags))) {
234 /* If one of the variables resides in memory, we can eliminate
235 the register move from/to the temporary register with the
236 order of getting the destination register and the load. */
238 if (IS_INMEMORY(src->flags)) {
239 if (IS_LNG_TYPE(src->type))
240 d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP12_PACKED);
242 d = codegen_reg_of_var(iptr->opc, dst, REG_IFTMP);
244 s1 = emit_load(jd, iptr, src, d);
247 if (IS_LNG_TYPE(src->type))
248 s1 = emit_load(jd, iptr, src, REG_ITMP12_PACKED);
250 s1 = emit_load(jd, iptr, src, REG_IFTMP);
252 d = codegen_reg_of_var(iptr->opc, dst, s1);
262 M_MOV(GET_LOW_REG(s1), GET_LOW_REG(d));
263 M_MOV(GET_HIGH_REG(s1), GET_HIGH_REG(d));
270 vm_abort("emit_copy: unknown type %d", dst->type);
274 emit_store(jd, iptr, dst, d);
279 /* emit_iconst *****************************************************************
283 *******************************************************************************/
285 void emit_iconst(codegendata *cd, s4 d, s4 value)
289 if ((value >= -32768) && (value <= 32767))
290 M_LDA_INTERN(d, REG_ZERO, value);
292 disp = dseg_add_s4(cd, value);
293 M_ILD(d, REG_PV, disp);
298 /* emit_branch *****************************************************************
300 Emits the code for conditional and unconditional branchs.
302 *******************************************************************************/
304 void emit_branch(codegendata *cd, s4 disp, s4 condition, s4 reg, u4 opt)
309 /* calculate the different displacements */
311 checkdisp = disp + 4;
312 branchdisp = (disp - 4) >> 2;
314 /* check which branch to generate */
316 if (condition == BRANCH_UNCONDITIONAL) {
317 /* check displacement for overflow */
319 if ((checkdisp < (s4) 0xfe000000) || (checkdisp > (s4) 0x01fffffc)) {
320 /* if the long-branches flag isn't set yet, do it */
322 if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
323 cd->flags |= (CODEGENDATA_FLAG_ERROR |
324 CODEGENDATA_FLAG_LONGBRANCHES);
327 vm_abort("emit_branch: emit unconditional long-branch code");
334 /* and displacement for overflow */
336 if ((checkdisp < (s4) 0xffff8000) || (checkdisp > (s4) 0x00007fff)) {
337 /* if the long-branches flag isn't set yet, do it */
339 if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
340 cd->flags |= (CODEGENDATA_FLAG_ERROR |
341 CODEGENDATA_FLAG_LONGBRANCHES);
370 vm_abort("emit_branch: long BRANCH_NAN");
373 vm_abort("emit_branch: unknown condition %d", condition);
400 vm_abort("emit_branch: unknown condition %d", condition);
407 /* emit_arithmetic_check *******************************************************
409 Emit an ArithmeticException check.
411 *******************************************************************************/
413 void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg)
415 if (INSTRUCTION_MUST_CHECK(iptr)) {
418 M_ALD_INTERN(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_ARITHMETIC);
423 /* emit_arrayindexoutofbounds_check ********************************************
425 Emit a ArrayIndexOutOfBoundsException check.
427 *******************************************************************************/
429 void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
431 if (INSTRUCTION_MUST_CHECK(iptr)) {
432 M_ILD(REG_ITMP3, s1, OFFSET(java_arrayheader, size));
433 M_TRAPGEU(s2, REG_ITMP3);
438 /* emit_classcast_check ********************************************************
440 Emit a ClassCastException check.
442 *******************************************************************************/
444 void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 reg, s4 s1)
446 if (INSTRUCTION_MUST_CHECK(iptr)) {
458 vm_abort("emit_classcast_check: unknown condition %d", condition);
460 M_ALD_INTERN(s1, REG_ZERO, EXCEPTION_HARDWARE_CLASSCAST);
465 /* emit_nullpointer_check ******************************************************
467 Emit a NullPointerException check.
469 *******************************************************************************/
471 void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg)
473 if (INSTRUCTION_MUST_CHECK(iptr)) {
476 M_ALD_INTERN(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_NULLPOINTER);
481 /* emit_exception_check ********************************************************
483 Emit an Exception check.
485 *******************************************************************************/
487 void emit_exception_check(codegendata *cd, instruction *iptr)
489 if (INSTRUCTION_MUST_CHECK(iptr)) {
492 M_ALD_INTERN(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_EXCEPTION);
497 /* emit_patcher_stubs **********************************************************
499 Generates the code for the patcher stubs.
501 *******************************************************************************/
503 void emit_patcher_stubs(jitdata *jd)
513 /* get required compiler data */
517 /* generate code patching stub call code */
521 for (pref = cd->patchrefs; pref != NULL; pref = pref->next) {
522 /* check code segment size */
526 /* Get machine code which is patched back in later. The
527 call is 1 instruction word long. */
529 tmpmcodeptr = (u1 *) (cd->mcodebase + pref->branchpos);
531 mcode = *((u4 *) tmpmcodeptr);
533 /* Patch in the call to call the following code (done at
536 savedmcodeptr = cd->mcodeptr; /* save current mcodeptr */
537 cd->mcodeptr = tmpmcodeptr; /* set mcodeptr to patch position */
539 disp = ((u4 *) savedmcodeptr) - (((u4 *) tmpmcodeptr) + 1);
542 cd->mcodeptr = savedmcodeptr; /* restore the current mcodeptr */
544 /* create stack frame - keep stack 16-byte aligned */
546 M_AADD_IMM(REG_SP, -8 * 4, REG_SP);
548 /* calculate return address and move it onto the stack */
550 M_LDA(REG_ITMP3, REG_PV, pref->branchpos);
551 M_AST_INTERN(REG_ITMP3, REG_SP, 5 * 4);
553 /* move pointer to java_objectheader onto stack */
555 #if defined(ENABLE_THREADS)
556 /* order reversed because of data segment layout */
558 (void) dseg_add_unique_address(cd, NULL); /* flcword */
559 (void) dseg_add_unique_address(cd, lock_get_initial_lock_word());
560 disp = dseg_add_unique_address(cd, NULL); /* vftbl */
562 M_LDA(REG_ITMP3, REG_PV, disp);
563 M_AST_INTERN(REG_ITMP3, REG_SP, 4 * 4);
568 /* move machine code onto stack */
570 disp = dseg_add_s4(cd, mcode);
571 M_ILD(REG_ITMP3, REG_PV, disp);
572 M_IST_INTERN(REG_ITMP3, REG_SP, 3 * 4);
574 /* move class/method/field reference onto stack */
576 disp = dseg_add_address(cd, pref->ref);
577 M_ALD(REG_ITMP3, REG_PV, disp);
578 M_AST_INTERN(REG_ITMP3, REG_SP, 2 * 4);
580 /* move data segment displacement onto stack */
582 disp = dseg_add_s4(cd, pref->disp);
583 M_ILD(REG_ITMP3, REG_PV, disp);
584 M_IST_INTERN(REG_ITMP3, REG_SP, 1 * 4);
586 /* move patcher function pointer onto stack */
588 disp = dseg_add_functionptr(cd, pref->patcher);
589 M_ALD(REG_ITMP3, REG_PV, disp);
590 M_AST_INTERN(REG_ITMP3, REG_SP, 0 * 4);
592 if (targetdisp == 0) {
593 targetdisp = ((u4 *) cd->mcodeptr) - ((u4 *) cd->mcodebase);
595 disp = dseg_add_functionptr(cd, asm_patcher_wrapper);
596 M_ALD(REG_ITMP3, REG_PV, disp);
601 disp = (((u4 *) cd->mcodebase) + targetdisp) -
602 (((u4 *) cd->mcodeptr) + 1);
609 /* emit_replacement_stubs ******************************************************
611 Generates the code for the replacement stubs.
613 *******************************************************************************/
615 #if defined(ENABLE_REPLACEMENT)
616 void emit_replacement_stubs(jitdata *jd)
627 /* get required compiler data */
632 rplp = code->rplpoints;
634 /* store beginning of replacement stubs */
636 code->replacementstubs = (u1*) (cd->mcodeptr - cd->mcodebase);
638 for (i = 0; i < code->rplpointcount; ++i, ++rplp) {
639 /* do not generate stubs for non-trappable points */
641 if (rplp->flags & RPLPOINT_FLAG_NOTRAP)
644 /* check code segment size */
649 savedmcodeptr = cd->mcodeptr;
652 /* create stack frame - keep 16-byte aligned */
654 M_AADD_IMM(REG_SP, -4 * 4, REG_SP);
656 /* push address of `rplpoint` struct */
658 disp = dseg_add_address(cd, rplp);
659 M_ALD(REG_ITMP3, REG_PV, disp);
660 M_AST_INTERN(REG_ITMP3, REG_SP, 0 * 4);
662 /* jump to replacement function */
664 disp = dseg_add_functionptr(cd, asm_replacement_out);
665 M_ALD(REG_ITMP3, REG_PV, disp);
669 assert((cd->mcodeptr - savedmcodeptr) == 4*REPLACEMENT_STUB_SIZE);
672 #endif /* defined(ENABLE_REPLACEMENT) */
675 /* emit_verbosecall_enter ******************************************************
677 Generates the code for the call trace.
679 *******************************************************************************/
681 void emit_verbosecall_enter(jitdata *jd)
692 if (!JITDATA_HAS_FLAG_VERBOSECALL(jd))
695 /* get required compiler data */
703 /* Build up Stackframe for builtin_trace_args call (a multiple of 16) */
705 /* LA + TRACE_ARGS_NUM u8 args + methodinfo + LR */
706 /* LA_SIZE(=6*4) + 8*8 + 4 + 4 + 0(Padding) */
707 /* 6 * 4 + 8 * 8 + 2 * 4 = 12 * 8 = 6 * 16 */
709 /* LA + (TRACE_ARGS_NUM - INT_ARG_CNT/2) u8 args + methodinfo */
710 /* + INT_ARG_CNT * 4 ( save integer registers) + LR + 8 + 8 (Padding) */
711 /* LA_SIZE(=2*4) + 4 * 8 + 4 + 8 * 4 + 4 + 8 */
712 /* 2 * 4 + 4 * 8 + 10 * 4 + 1 * 8 + 8= 12 * 8 = 6 * 16 */
714 /* in nativestubs no Place to save the LR (Link Register) would be needed */
715 /* but since the stack frame has to be aligned the 4 Bytes would have to */
716 /* be padded again */
718 #if defined(__DARWIN__)
719 stack_size = LA_SIZE + (TRACE_ARGS_NUM + 1) * 8;
724 /* mark trace code */
729 M_AST(REG_ZERO, REG_SP, LA_LR_OFFSET);
730 M_STWU(REG_SP, REG_SP, -stack_size);
732 M_CLR(REG_ITMP1); /* clear help register */
734 /* save up to TRACE_ARGS_NUM arguments into the reserved stack space */
735 #if defined(__DARWIN__)
736 /* Copy Params starting from first to Stack */
737 /* since TRACE_ARGS == INT_ARG_CNT all used integer argument regs */
741 /* Copy Params starting from fifth to Stack (INT_ARG_CNT/2) are in */
742 /* integer argument regs */
743 /* all integer argument registers have to be saved */
744 for (p = 0; p < 8; p++) {
745 d = rd->argintregs[p];
746 /* save integer argument registers */
747 M_IST(d, REG_SP, LA_SIZE + 4 * 8 + 4 + p * 4);
752 for (; p < md->paramcount && p < TRACE_ARGS_NUM; p++, stack_off += 8) {
753 t = md->paramtypes[p].type;
754 if (IS_INT_LNG_TYPE(t)) {
755 if (!md->params[p].inmemory) { /* Param in Arg Reg */
756 if (IS_2_WORD_TYPE(t)) {
757 M_IST(rd->argintregs[GET_HIGH_REG(md->params[p].regoff)]
758 , REG_SP, stack_off);
759 M_IST(rd->argintregs[GET_LOW_REG(md->params[p].regoff)]
760 , REG_SP, stack_off + 4);
762 M_IST(REG_ITMP1, REG_SP, stack_off);
763 M_IST(rd->argintregs[md->params[p].regoff]
764 , REG_SP, stack_off + 4);
766 } else { /* Param on Stack */
767 s1 = (md->params[p].regoff + cd->stackframesize) * 4
769 if (IS_2_WORD_TYPE(t)) {
770 M_ILD(REG_ITMP2, REG_SP, s1);
771 M_IST(REG_ITMP2, REG_SP, stack_off);
772 M_ILD(REG_ITMP2, REG_SP, s1 + 4);
773 M_IST(REG_ITMP2, REG_SP, stack_off + 4);
775 M_IST(REG_ITMP1, REG_SP, stack_off);
776 M_ILD(REG_ITMP2, REG_SP, s1);
777 M_IST(REG_ITMP2, REG_SP, stack_off + 4);
780 } else { /* IS_FLT_DBL_TYPE(t) */
781 if (!md->params[p].inmemory) { /* in Arg Reg */
782 s1 = rd->argfltregs[md->params[p].regoff];
783 if (!IS_2_WORD_TYPE(t)) {
784 M_IST(REG_ITMP1, REG_SP, stack_off);
785 M_FST(s1, REG_SP, stack_off + 4);
787 M_DST(s1, REG_SP, stack_off);
789 } else { /* on Stack */
790 /* this should not happen */
795 /* load first 4 (==INT_ARG_CNT/2) arguments into integer registers */
796 #if defined(__DARWIN__)
797 for (p = 0; p < 8; p++) {
798 d = rd->argintregs[p];
799 M_ILD(d, REG_SP, LA_SIZE + p * 4);
803 /* Set integer and float argument registers vor trace_args call */
804 /* offset to saved integer argument registers */
805 stack_off = LA_SIZE + 4 * 8 + 4;
806 for (p = 0; (p < 4) && (p < md->paramcount); p++) {
807 t = md->paramtypes[p].type;
808 if (IS_INT_LNG_TYPE(t)) {
809 /* "stretch" int types */
810 if (!IS_2_WORD_TYPE(t)) {
811 M_CLR(rd->argintregs[2 * p]);
812 M_ILD(rd->argintregs[2 * p + 1], REG_SP,stack_off);
815 M_ILD(rd->argintregs[2 * p + 1], REG_SP,stack_off + 4);
816 M_ILD(rd->argintregs[2 * p], REG_SP,stack_off);
819 } else { /* Float/Dbl */
820 if (!md->params[p].inmemory) { /* Param in Arg Reg */
821 /* use reserved Place on Stack (sp + 5 * 16) to copy */
822 /* float/double arg reg to int reg */
823 s1 = rd->argfltregs[md->params[p].regoff];
824 if (!IS_2_WORD_TYPE(t)) {
825 M_FST(s1, REG_SP, 5 * 16);
826 M_ILD(rd->argintregs[2 * p + 1], REG_SP, 5 * 16);
827 M_CLR(rd->argintregs[2 * p]);
829 M_DST(s1, REG_SP, 5 * 16);
830 M_ILD(rd->argintregs[2 * p + 1], REG_SP, 5 * 16 + 4);
831 M_ILD(rd->argintregs[2 * p], REG_SP, 5 * 16);
838 /* put methodinfo pointer on Stackframe */
839 p = dseg_add_address(cd, m);
840 M_ALD(REG_ITMP1, REG_PV, p);
841 #if defined(__DARWIN__)
842 M_AST(REG_ITMP1, REG_SP, LA_SIZE + TRACE_ARGS_NUM * 8);
844 M_AST(REG_ITMP1, REG_SP, LA_SIZE + 4 * 8);
846 p = dseg_add_functionptr(cd, builtin_verbosecall_enter);
847 M_ALD(REG_ITMP2, REG_PV, p);
851 #if defined(__DARWIN__)
852 /* restore integer argument registers from the reserved stack space */
855 for (p = 0; p < md->paramcount && p < TRACE_ARGS_NUM;
856 p++, stack_off += 8) {
857 t = md->paramtypes[p].type;
859 if (IS_INT_LNG_TYPE(t)) {
860 if (!md->params[p].inmemory) {
861 if (IS_2_WORD_TYPE(t)) {
862 M_ILD(rd->argintregs[GET_HIGH_REG(md->params[p].regoff)]
863 , REG_SP, stack_off);
864 M_ILD(rd->argintregs[GET_LOW_REG(md->params[p].regoff)]
865 , REG_SP, stack_off + 4);
867 M_ILD(rd->argintregs[md->params[p].regoff]
868 , REG_SP, stack_off + 4);
875 for (p = 0; p < 8; p++) {
876 d = rd->argintregs[p];
877 /* save integer argument registers */
878 M_ILD(d, REG_SP, LA_SIZE + 4 * 8 + 4 + p * 4);
882 M_ALD(REG_ZERO, REG_SP, stack_size + LA_LR_OFFSET);
884 M_LDA(REG_SP, REG_SP, stack_size);
886 /* mark trace code */
889 #endif /* !defined(NDEBUG) */
893 /* emit_verbosecall_exit *******************************************************
895 Generates the code for the call trace.
897 void builtin_verbosecall_exit(s8 l, double d, float f, methodinfo *m);
899 *******************************************************************************/
901 void emit_verbosecall_exit(jitdata *jd)
910 if (!JITDATA_HAS_FLAG_VERBOSECALL(jd))
913 /* get required compiler data */
921 /* mark trace code */
926 M_AST(REG_ZERO, REG_SP, LA_LR_OFFSET);
927 M_STWU(REG_SP, REG_SP, -(LA_SIZE + (1 + 2 + 2 + 1 + 4) * 4));
929 /* save return registers */
931 M_LST(REG_RESULT_PACKED, REG_SP, LA_SIZE + (1 + 2 + 2 + 1 + 0) * 4);
932 M_DST(REG_FRESULT, REG_SP, LA_SIZE + (1 + 2 + 2 + 1 + 2) * 4);
934 /* keep this order */
935 switch (md->returntype.type) {
938 M_INTMOVE(REG_RESULT, REG_A1);
943 M_LNGMOVE(REG_RESULT_PACKED, REG_A0_A1_PACKED);
947 M_FLTMOVE(REG_FRESULT, REG_FA0);
948 M_FLTMOVE(REG_FRESULT, REG_FA1);
950 disp = dseg_add_address(cd, m);
951 M_ALD(REG_A2, REG_PV, disp);
953 disp = dseg_add_functionptr(cd, builtin_verbosecall_exit);
954 M_ALD(REG_ITMP2, REG_PV, disp);
958 /* restore return registers */
960 M_LLD(REG_RESULT_PACKED, REG_SP, LA_SIZE + (1 + 2 + 2 + 1 + 0) * 4);
961 M_DLD(REG_FRESULT, REG_SP, LA_SIZE + (1 + 2 + 2 + 1 + 2) * 4);
963 M_ALD(REG_ZERO, REG_SP, LA_SIZE + (1 + 2 + 2 + 1 + 4) * 4 + LA_LR_OFFSET);
965 M_LDA(REG_SP, REG_SP, LA_SIZE + (1 + 2 + 2 + 1 + 4) * 4);
967 /* mark trace code */
970 #endif /* !defined(NDEBUG) */
975 * These are local overrides for various environment variables in Emacs.
976 * Please do not remove this and leave it at the end of the file, where
977 * Emacs will automagically detect them.
978 * ---------------------------------------------------------------------
981 * indent-tabs-mode: t
985 * vim:noexpandtab:sw=4:ts=4: