1 /* src/vm/jit/s390/emit.c - s390 code emitter functions
3 Copyright (C) 1996-2005, 2006, 2007, 2008
4 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
6 This file is part of CACAO.
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2, or (at
11 your option) any later version.
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
30 #include "vm/jit/s390/codegen.h"
31 #include "vm/jit/s390/emit.h"
32 #include "vm/jit/s390/md-abi.h"
34 #include "mm/memory.h"
36 #include "threads/lock-common.h"
38 #include "vm/builtin.h"
39 #include "vm/exceptions.h"
40 #include "vm/global.h"
43 #include "vm/jit/abi.h"
44 #include "vm/jit/abi-asm.h"
45 #include "vm/jit/asmpart.h"
46 #include "vm/jit/codegen-common.h"
47 #include "vm/jit/emit-common.h"
48 #include "vm/jit/jit.h"
49 #include "vm/jit/patcher-common.h"
50 #include "vm/jit/replace.h"
51 #include "vm/jit/trace.h"
52 #include "vm/jit/trap.h"
54 #include "vmcore/options.h"
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 (IS_INMEMORY(src->flags)) {
76 disp = src->vv.regoff;
78 if (IS_FLT_DBL_TYPE(src->type)) {
79 if (IS_2_WORD_TYPE(src->type))
80 M_DLD(tempreg, REG_SP, disp);
82 M_FLD(tempreg, REG_SP, disp);
85 if (IS_2_WORD_TYPE(src->type))
86 M_LLD(tempreg, REG_SP, disp);
88 M_ILD(tempreg, REG_SP, disp);
100 /* emit_store ******************************************************************
102 This function generates the code to store the result of an
103 operation back into a spilled pseudo-variable. If the
104 pseudo-variable has not been spilled in the first place, this
105 function will generate nothing.
107 *******************************************************************************/
109 void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
113 /* get required compiler data */
117 if (IS_INMEMORY(dst->flags)) {
120 if (IS_FLT_DBL_TYPE(dst->type)) {
121 if (IS_2_WORD_TYPE(dst->type))
122 M_DST(d, REG_SP, dst->vv.regoff);
124 M_FST(d, REG_SP, dst->vv.regoff);
127 if (IS_2_WORD_TYPE(dst->type))
128 M_LST(d, REG_SP, dst->vv.regoff);
130 M_IST(d, REG_SP, dst->vv.regoff);
136 /* emit_copy *******************************************************************
138 Generates a register/memory to register/memory copy.
140 *******************************************************************************/
142 void emit_copy(jitdata *jd, instruction *iptr)
149 /* get required compiler data */
153 /* get source and destination variables */
155 src = VAROP(iptr->s1);
156 dst = VAROP(iptr->dst);
158 if ((src->vv.regoff != dst->vv.regoff) ||
159 ((src->flags ^ dst->flags) & INMEMORY)) {
161 if ((src->type == TYPE_RET) || (dst->type == TYPE_RET)) {
162 /* emit nothing, as the value won't be used anyway */
166 if (IS_INMEMORY(src->flags) && IS_INMEMORY(dst->flags)) {
167 if (IS_2_WORD_TYPE(src->type)) {
168 N_MVC(dst->vv.regoff, 8, REG_SP, src->vv.regoff, REG_SP);
170 N_MVC(dst->vv.regoff, 4, REG_SP, src->vv.regoff, REG_SP);
174 /* If one of the variables resides in memory, we can eliminate
175 the register move from/to the temporary register with the
176 order of getting the destination register and the load. */
178 if (IS_INMEMORY(src->flags)) {
179 if (IS_FLT_DBL_TYPE(dst->type)) {
180 d = codegen_reg_of_var(iptr->opc, dst, REG_FTMP1);
182 if (IS_2_WORD_TYPE(dst->type)) {
183 d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP12_PACKED);
185 d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP1);
188 s1 = emit_load(jd, iptr, src, d);
191 if (IS_FLT_DBL_TYPE(src->type)) {
192 s1 = emit_load(jd, iptr, src, REG_FTMP1);
194 if (IS_2_WORD_TYPE(src->type)) {
195 s1 = emit_load(jd, iptr, src, REG_ITMP12_PACKED);
197 s1 = emit_load(jd, iptr, src, REG_ITMP1);
200 d = codegen_reg_of_var(iptr->opc, dst, s1);
204 if (IS_FLT_DBL_TYPE(src->type)) {
207 if (IS_2_WORD_TYPE(src->type)) {
215 emit_store(jd, iptr, dst, d);
220 /* emit_trap *******************************************************************
222 Emit a trap instruction and return the original machine code.
224 *******************************************************************************/
226 uint32_t emit_trap(codegendata *cd)
230 /* Get machine code which is patched back in later. The
231 trap is 2 bytes long. */
233 mcode = *((u2 *) cd->mcodeptr);
241 /* emit_verbosecall_enter ******************************************************
243 Generates the code for the call trace.
245 *******************************************************************************/
248 void emit_verbosecall_enter(jitdata *jd)
263 /* mark trace code */
267 /* allocate stack frame */
269 stackframesize = 96 + (md->paramcount * 8);
271 /* for leaf methods we need to store unused argument and temporary registers */
273 if (code_is_leafmethod(code)) {
274 stackframesize += (ARG_CNT + TMP_CNT) * 8;
277 /* allocate stack frame */
279 M_ASUB_IMM(stackframesize, REG_SP);
281 /* store argument registers in array */
285 for (i = 0; i < md->paramcount; i++) {
286 if (! md->params[i].inmemory) {
287 s = md->params[i].regoff;
288 switch (md->paramtypes[i].type) {
291 M_IST(s, REG_SP, off);
294 M_LST(s, REG_SP, off);
297 M_FST(s, REG_SP, off);
300 M_DST(s, REG_SP, off);
307 /* save unused (currently all) argument registers for leaf methods */
308 /* save temporary registers for leaf methods */
310 if (code_is_leafmethod(code)) {
312 for (i = 0; i < INT_ARG_CNT; ++i, off += 8) {
313 M_IST(abi_registers_integer_argument[i], REG_SP, off);
316 for (i = 0; i < FLT_ARG_CNT; ++i, off += 8) {
317 M_DST(abi_registers_float_argument[i], REG_SP, off);
320 for (i = 0; i < INT_TMP_CNT; ++i, off += 8) {
321 M_IST(abi_registers_integer_temporary[i], REG_SP, off);
324 for (i = 0; i < FLT_TMP_CNT; ++i, off += 8) {
325 M_DST(abi_registers_float_temporary[i], REG_SP, off);
329 /* load arguments for trace_java_call_enter */
333 disp = dseg_add_address(cd, m);
334 M_ALD_DSEG(REG_A0, disp);
335 /* pointer to argument registers array */
336 M_LDA(REG_A1, REG_SP, 96);
337 /* pointer to on stack arguments */
338 M_LDA(REG_A2, REG_SP, stackframesize + (cd->stackframesize * 8));
340 /* call trace_java_call_enter */
342 disp = dseg_add_functionptr(cd, trace_java_call_enter);
343 M_ALD_DSEG(REG_ITMP2, disp);
346 /* restore used argument registers */
347 /* for leaf methods restore all argument and temporary registers */
349 if (code_is_leafmethod(code)) {
350 off = 96 + (8 * md->paramcount);
352 for (i = 0; i < INT_ARG_CNT; ++i, off += 8) {
353 M_ILD(abi_registers_integer_argument[i], REG_SP, off);
356 for (i = 0; i < FLT_ARG_CNT; ++i, off += 8) {
357 M_DLD(abi_registers_float_argument[i], REG_SP, off);
360 for (i = 0; i < INT_TMP_CNT; ++i, off += 8) {
361 M_ILD(abi_registers_integer_temporary[i], REG_SP, off);
364 for (i = 0; i < FLT_TMP_CNT; ++i, off += 8) {
365 M_DLD(abi_registers_float_temporary[i], REG_SP, off);
370 for (i = 0; i < md->paramcount; i++) {
371 if (! md->params[i].inmemory) {
372 s = md->params[i].regoff;
373 switch (md->paramtypes[i].type) {
376 M_ILD(s, REG_SP, off);
379 M_LLD(s, REG_SP, off);
382 M_FLD(s, REG_SP, off);
385 M_DLD(s, REG_SP, off);
393 /* remove stack frame */
395 M_AADD_IMM(stackframesize, REG_SP);
397 /* mark trace code */
402 #endif /* !defined(NDEBUG) */
405 /* emit_verbosecall_exit *******************************************************
407 Generates the code for the call trace.
409 *******************************************************************************/
412 void emit_verbosecall_exit(jitdata *jd)
423 t = m->parseddesc->returntype.type;
425 /* mark trace code */
429 /* allocate stackframe */
431 stackframesize = 96 + (1 * 8);
432 M_ASUB_IMM(stackframesize, REG_SP);
436 /* store return values in array */
438 if (IS_INT_LNG_TYPE(t)) {
439 if (IS_2_WORD_TYPE(t)) {
440 M_LST(REG_RESULT_PACKED, REG_SP, off);
442 M_IST(REG_RESULT, REG_SP, off);
445 M_DST(REG_FRESULT, REG_SP, off);
448 /* call trace_java_call_exit */
450 disp = dseg_add_address(cd, m);
451 M_ALD_DSEG(REG_A0, disp);
452 M_LDA(REG_A1, REG_SP, off);
453 disp = dseg_add_functionptr(cd, trace_java_call_exit);
454 M_ALD_DSEG(REG_ITMP2, disp);
457 /* restore return value */
459 if (IS_INT_LNG_TYPE(t)) {
460 if (IS_2_WORD_TYPE(t)) {
461 M_LLD(REG_RESULT_PACKED, REG_SP, off);
463 M_ILD(REG_RESULT, REG_SP, off);
466 M_DLD(REG_FRESULT, REG_SP, off);
469 /* remove stackframe */
471 M_AADD_IMM(stackframesize, REG_SP);
473 /* mark trace code */
477 #endif /* !defined(NDEBUG) */
480 /* emit_load_high **************************************************************
482 Emits a possible load of the high 32-bits of an operand.
484 *******************************************************************************/
486 s4 emit_load_high(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
492 assert(src->type == TYPE_LNG);
494 /* get required compiler data */
498 if (IS_INMEMORY(src->flags)) {
501 disp = src->vv.regoff;
503 M_ILD(tempreg, REG_SP, disp);
508 reg = GET_HIGH_REG(src->vv.regoff);
513 /* emit_load_low ***************************************************************
515 Emits a possible load of the low 32-bits of an operand.
517 *******************************************************************************/
519 s4 emit_load_low(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
525 assert(src->type == TYPE_LNG);
527 /* get required compiler data */
531 if (IS_INMEMORY(src->flags)) {
534 disp = src->vv.regoff;
536 M_ILD(tempreg, REG_SP, disp + 4);
541 reg = GET_LOW_REG(src->vv.regoff);
546 s4 emit_load_s1_but(jitdata *jd, instruction *iptr, s4 tempreg, s4 notreg) {
547 codegendata *cd = jd->cd;
548 s4 reg = emit_load_s1(jd, iptr, tempreg);
550 if (IS_FLT_DBL_TYPE(VAROP(iptr->s1)->type)) {
551 M_FMOV(reg, tempreg);
561 s4 emit_load_s2_but(jitdata *jd, instruction *iptr, s4 tempreg, s4 notreg) {
562 codegendata *cd = jd->cd;
563 s4 reg = emit_load_s2(jd, iptr, tempreg);
565 if (IS_FLT_DBL_TYPE(VAROP(iptr->sx.s23.s2)->type)) {
566 M_FMOV(reg, tempreg);
576 void emit_copy_dst(jitdata *jd, instruction *iptr, s4 dtmpreg) {
580 dst = VAROP(iptr->dst);
581 if (! IS_INMEMORY(dst->flags)) {
582 if (dst->vv.regoff != dtmpreg) {
583 if (IS_FLT_DBL_TYPE(dst->type)) {
584 M_FLTMOVE(dtmpreg, dst->vv.regoff);
585 } else if (IS_2_WORD_TYPE(dst->type)) {
586 M_LNGMOVE(dtmpreg, dst->vv.regoff);
588 M_INTMOVE(dtmpreg, dst->vv.regoff);
594 void emit_branch(codegendata *cd, s4 disp, s4 condition, s4 reg, u4 opt) {
596 s4 branchdisp = disp;
600 if (N_VALID_BRANCH(branchdisp)) {
602 /* valid displacement */
623 case BRANCH_UNCONDITIONAL:
627 vm_abort("emit_branch: unknown condition %d", condition);
631 /* If LONGBRANCHES is not set, the flag and the error flag */
633 if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
634 cd->flags |= (CODEGENDATA_FLAG_ERROR |
635 CODEGENDATA_FLAG_LONGBRANCHES);
638 /* If error flag is set, do nothing. The method has to be recompiled. */
640 if (CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd) && CODEGENDATA_HAS_FLAG_ERROR(cd)) {
644 /* Patch the displacement to branch over the actual branch manually
645 * to not get yet more nops.
648 branchmpc = cd->mcodeptr - cd->mcodebase;
670 case BRANCH_UNCONDITIONAL:
671 /* fall through, no displacement to patch */
675 vm_abort("emit_branch: unknown condition %d", condition);
678 /* The actual long branch */
680 disp = dseg_add_s4(cd, branchmpc + disp - N_PV_OFFSET);
681 M_ILD_DSEG(REG_ITMP2, disp);
682 M_AADD(REG_PV, REG_ITMP2);
683 M_JMP(RN, REG_ITMP2);
685 /* Patch back the displacement */
687 N_BRC_BACK_PATCH(ref);
691 void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg)
693 if (INSTRUCTION_MUST_CHECK(iptr)) {
695 M_BNE(SZ_BRC + SZ_ILL);
696 M_ILL(TRAP_ArithmeticException);
700 /* emit_arrayindexoutofbounds_check ********************************************
702 Emit a ArrayIndexOutOfBoundsException check.
704 *******************************************************************************/
706 void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
708 if (INSTRUCTION_MUST_CHECK(iptr)) {
710 * Do unsigned comparison to catch negative indexes.
712 N_CL(s2, OFFSET(java_array_t, size), RN, s1);
713 M_BLT(SZ_BRC + SZ_ILL);
714 M_ILL2(s2, TRAP_ArrayIndexOutOfBoundsException);
719 /* emit_arraystore_check *******************************************************
721 Emit an ArrayStoreException check.
723 *******************************************************************************/
725 void emit_arraystore_check(codegendata *cd, instruction *iptr)
727 if (INSTRUCTION_MUST_CHECK(iptr)) {
729 M_BNE(SZ_BRC + SZ_ILL);
730 M_ILL(TRAP_ArrayStoreException);
735 void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 reg, s4 s1) {
736 if (INSTRUCTION_MUST_CHECK(iptr)) {
742 M_BGT(SZ_BRC + SZ_ILL);
745 M_BNE(SZ_BRC + SZ_ILL);
748 M_BLE(SZ_BRC + SZ_ILL);
751 vm_abort("emit_classcast_check: unknown condition %d", condition);
753 M_ILL2(s1, TRAP_ClassCastException);
757 void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg)
759 if (INSTRUCTION_MUST_CHECK(iptr)) {
761 M_BNE(SZ_BRC + SZ_ILL);
762 M_ILL(TRAP_NullPointerException);
766 void emit_exception_check(codegendata *cd, instruction *iptr)
768 if (INSTRUCTION_MUST_CHECK(iptr)) {
770 M_BNE(SZ_BRC + SZ_ILL);
771 M_ILL(TRAP_CHECK_EXCEPTION);
775 void emit_restore_pv(codegendata *cd) {
776 s4 offset, offset_imm;
780 disp = (s4) (cd->mcodeptr - cd->mcodebase);
781 M_ASUB_IMM32(disp, REG_ITMP1, REG_PV);
784 /* If the offset from the method start does not fit into an immediate
785 * value, we can't put it into the data segment!
788 /* Displacement from start of method to here */
790 offset = (s4) (cd->mcodeptr - cd->mcodebase);
791 offset_imm = -offset - SZ_BASR + N_PV_OFFSET;
793 if (N_VALID_IMM(offset_imm)) {
794 /* Get program counter */
796 /* Substract displacement */
797 M_AADD_IMM(offset_imm, REG_PV);
799 /* Save program counter and jump over displacement in instruction flow */
800 N_BRAS(REG_PV, SZ_BRAS + SZ_LONG);
801 /* Place displacement here */
802 /* REG_PV points now exactly to this position */
803 N_LONG(-offset - SZ_BRAS + N_PV_OFFSET);
804 /* Substract *(REG_PV) from REG_PV */
805 N_A(REG_PV, 0, RN, REG_PV);
809 /* emit_trap_compiler **********************************************************
811 Emit a trap instruction which calls the JIT compiler.
813 *******************************************************************************/
815 void emit_trap_compiler(codegendata *cd)
817 M_ILL2(REG_METHODPTR, TRAP_COMPILER);
821 * These are local overrides for various environment variables in Emacs.
822 * Please do not remove this and leave it at the end of the file, where
823 * Emacs will automagically detect them.
824 * ---------------------------------------------------------------------
827 * indent-tabs-mode: t