1 /* src/vm/jit/s390/emit.c - s390 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
32 #include "mm/memory.h"
33 #if defined(ENABLE_THREADS)
34 # include "threads/native/lock.h"
36 #include "vm/builtin.h"
37 #include "vm/exceptions.h"
38 #include "vm/global.h"
39 #include "vm/jit/abi.h"
40 #include "vm/jit/abi-asm.h"
41 #include "vm/jit/asmpart.h"
42 #include "vm/jit/codegen-common.h"
43 #include "vm/jit/emit-common.h"
44 #include "vm/jit/jit.h"
45 #include "vm/jit/patcher-common.h"
46 #include "vm/jit/replace.h"
47 #include "vm/jit/s390/codegen.h"
48 #include "vm/jit/s390/emit.h"
49 #include "vm/jit/s390/md-abi.h"
51 #include "vmcore/options.h"
53 /* emit_load *******************************************************************
55 Emits a possible load of an operand.
57 *******************************************************************************/
59 s4 emit_load(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
65 /* get required compiler data */
69 if (IS_INMEMORY(src->flags)) {
72 disp = src->vv.regoff;
74 if (IS_FLT_DBL_TYPE(src->type)) {
75 if (IS_2_WORD_TYPE(src->type))
76 M_DLD(tempreg, REG_SP, disp);
78 M_FLD(tempreg, REG_SP, disp);
81 if (IS_2_WORD_TYPE(src->type))
82 M_LLD(tempreg, REG_SP, disp);
84 M_ILD(tempreg, REG_SP, disp);
96 /* emit_store ******************************************************************
98 This function generates the code to store the result of an
99 operation back into a spilled pseudo-variable. If the
100 pseudo-variable has not been spilled in the first place, this
101 function will generate nothing.
103 *******************************************************************************/
105 void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
109 /* get required compiler data */
113 if (IS_INMEMORY(dst->flags)) {
116 if (IS_FLT_DBL_TYPE(dst->type)) {
117 if (IS_2_WORD_TYPE(dst->type))
118 M_DST(d, REG_SP, dst->vv.regoff);
120 M_FST(d, REG_SP, dst->vv.regoff);
123 if (IS_2_WORD_TYPE(dst->type))
124 M_LST(d, REG_SP, dst->vv.regoff);
126 M_IST(d, REG_SP, dst->vv.regoff);
132 /* emit_copy *******************************************************************
134 Generates a register/memory to register/memory copy.
136 *******************************************************************************/
138 void emit_copy(jitdata *jd, instruction *iptr)
145 /* get required compiler data */
149 /* get source and destination variables */
151 src = VAROP(iptr->s1);
152 dst = VAROP(iptr->dst);
154 if ((src->vv.regoff != dst->vv.regoff) ||
155 ((src->flags ^ dst->flags) & INMEMORY)) {
157 if ((src->type == TYPE_RET) || (dst->type == TYPE_RET)) {
158 /* emit nothing, as the value won't be used anyway */
162 if (IS_INMEMORY(src->flags) && IS_INMEMORY(dst->flags)) {
163 if (IS_2_WORD_TYPE(src->type)) {
164 N_MVC(dst->vv.regoff, 8, REG_SP, src->vv.regoff, REG_SP);
166 N_MVC(dst->vv.regoff, 4, REG_SP, src->vv.regoff, REG_SP);
170 /* If one of the variables resides in memory, we can eliminate
171 the register move from/to the temporary register with the
172 order of getting the destination register and the load. */
174 if (IS_INMEMORY(src->flags)) {
175 if (IS_FLT_DBL_TYPE(dst->type)) {
176 d = codegen_reg_of_var(iptr->opc, dst, REG_FTMP1);
178 if (IS_2_WORD_TYPE(dst->type)) {
179 d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP12_PACKED);
181 d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP1);
184 s1 = emit_load(jd, iptr, src, d);
187 if (IS_FLT_DBL_TYPE(src->type)) {
188 s1 = emit_load(jd, iptr, src, REG_FTMP1);
190 if (IS_2_WORD_TYPE(src->type)) {
191 s1 = emit_load(jd, iptr, src, REG_ITMP12_PACKED);
193 s1 = emit_load(jd, iptr, src, REG_ITMP1);
196 d = codegen_reg_of_var(iptr->opc, dst, s1);
200 if (IS_FLT_DBL_TYPE(src->type)) {
203 if (IS_2_WORD_TYPE(src->type)) {
211 emit_store(jd, iptr, dst, d);
216 /* emit_trap *******************************************************************
218 Emit a trap instruction and return the original machine code.
220 *******************************************************************************/
222 uint32_t emit_trap(codegendata *cd)
226 /* Get machine code which is patched back in later. The
227 trap is 2 bytes long. */
229 mcode = *((u2 *) cd->mcodeptr);
231 M_ILL(EXCEPTION_HARDWARE_PATCHER);
237 /* emit_verbosecall_enter ******************************************************
239 Generates the code for the call trace.
241 *******************************************************************************/
244 #include "vm/jit/trace.h"
245 void emit_verbosecall_enter(jitdata *jd)
256 /* mark trace code */
260 /* allocate stack frame */
262 stackframesize = 96 + (ARG_CNT * 8) + (TMP_CNT * 8);
263 M_ASUB_IMM(stackframesize, REG_SP);
265 /* store argument registers in array */
269 for (i = 0; i < INT_ARG_CNT; ++i, off += 8) {
270 M_IST(abi_registers_integer_argument[i], REG_SP, off + 4);
271 /* high bytes are sign extension */
272 M_SRA_IMM(31, abi_registers_integer_argument[i]);
273 M_IST(abi_registers_integer_argument[i], REG_SP, off);
276 for (i = 0; i < FLT_ARG_CNT; ++i, off += 8) {
277 M_DST(abi_registers_float_argument[i], REG_SP, off);
280 /* save temporary registers for leaf methods */
282 if (jd->isleafmethod) {
283 for (i = 0; i < INT_TMP_CNT; ++i, off += 8) {
284 M_IST(abi_registers_integer_temporary[i], REG_SP, off);
287 for (i = 0; i < FLT_TMP_CNT; ++i, off += 8) {
288 M_DST(abi_registers_float_temporary[i], REG_SP, off);
292 /* load arguments for trace_java_call_enter */
295 disp = dseg_add_address(cd, m);
296 M_ALD_DSEG(REG_A0, disp);
297 /* pointer to argument registers array */
298 M_LDA(REG_A1, REG_SP, 96);
299 /* pointer to on stack arguments */
300 M_LDA(REG_A2, REG_SP, stackframesize + (cd->stackframesize * 8));
302 /* call trace_java_call_enter */
304 disp = dseg_add_functionptr(cd, trace_java_call_enter);
305 M_ALD_DSEG(REG_ITMP2, disp);
308 /* restore argument registers */
312 for (i = 0; i < INT_ARG_CNT; ++i, off += 8) {
313 M_ILD(abi_registers_integer_argument[i], REG_SP, off + 4);
316 for (i = 0; i < FLT_ARG_CNT; ++i, off += 8) {
317 M_DLD(abi_registers_float_argument[i], REG_SP, off);
320 /* restore temporary registers for leaf methods */
322 if (jd->isleafmethod) {
323 for (i = 0; i < INT_TMP_CNT; ++i, off += 8) {
324 M_ILD(abi_registers_integer_temporary[i], REG_SP, off);
327 for (i = 0; i < FLT_TMP_CNT; ++i, off += 8) {
328 M_DLD(abi_registers_float_temporary[i], REG_SP, off);
332 /* remove stack frame */
334 M_AADD_IMM(stackframesize, REG_SP);
336 /* mark trace code */
345 s4 stackframesize, off, foff, aoff, doff, t, iargctr, fargctr, disp;
347 /* get required compiler data */
354 /* mark trace code */
359 (6 * 8) + /* s8 on stack parameters x 6 */
360 (1 * 4) + /* methodinfo on stack parameter */
365 M_ASUB_IMM(stackframesize, REG_SP); /* allocate stackframe */
367 /* save argument registers */
369 off = (6 * 8) + (1 * 4);
371 for (i = 0; i < INT_ARG_CNT; i++, off += 8)
372 M_IST(abi_registers_integer_argument[i], REG_SP, off);
374 for (i = 0; i < FLT_ARG_CNT; i++, off += 8)
375 M_DST(abi_registers_float_argument[i], REG_SP, off);
377 /* save temporary registers for leaf methods */
379 if (jd->isleafmethod) {
380 for (i = 0; i < INT_TMP_CNT; i++, off += 8)
381 M_LST(abi_registers_integer_temporary[i], REG_SP, off);
383 for (i = 0; i < FLT_TMP_CNT; i++, off += 8)
384 M_DST(abi_registers_float_temporary[i], REG_SP, off);
387 /* Load arguments to new locations */
389 /* First move all arguments to stack
394 * (s8) a1 \ Auxilliary stack frame
399 M_ASUB_IMM(2 * 8, REG_SP);
401 /* offset to where first integer arg is saved on stack */
402 off = (2 * 8) + (6 * 8) + (1 * 4);
403 /* offset to where first float arg is saved on stack */
404 foff = off + (INT_ARG_CNT * 8);
405 /* offset to where first argument is passed on stack */
406 aoff = (2 * 8) + stackframesize + (cd->stackframesize * 8);
407 /* offset to destination on stack */
410 iargctr = fargctr = 0;
412 ICONST(REG_ITMP1, 0);
414 for (i = 0; i < md->paramcount && i < 8; i++) {
415 t = md->paramtypes[i].type;
417 M_IST(REG_ITMP1, REG_SP, doff);
418 M_IST(REG_ITMP1, REG_SP, doff + 4);
420 if (IS_FLT_DBL_TYPE(t)) {
421 if (fargctr < 2) { /* passed in register */
422 N_STD(abi_registers_float_argument[fargctr], doff, RN, REG_SP);
424 } else { /* passed on stack */
426 if (IS_2_WORD_TYPE(t)) {
427 N_MVC(doff, 8, REG_SP, aoff, REG_SP);
429 N_MVC(doff + 4, 4, REG_SP, aoff, REG_SP);
432 N_MVC(doff, 8, REG_SP, aoff, REG_SP);
436 if (IS_2_WORD_TYPE(t)) {
437 if (iargctr < 4) { /* passed in 2 registers */
438 N_STM(REG_A0 + iargctr, REG_A0 + iargctr + 1, doff, REG_SP);
440 } else { /* passed on stack */
441 N_MVC(doff, 8, REG_SP, aoff, REG_SP);
445 if (iargctr < 5) { /* passed in register */
446 N_ST(REG_A0 + iargctr, doff + 4, RN, REG_SP);
448 } else { /* passed on stack */
449 N_MVC(doff + 4, 4, REG_SP, aoff, REG_SP);
458 /* Now move a0 and a1 to registers
468 N_LM(REG_A0, REG_A1, 0, REG_SP);
469 N_LM(REG_A2, REG_A3, 8, REG_SP);
471 M_AADD_IMM(2 * 8, REG_SP);
473 /* Finally load methodinfo argument */
475 disp = dseg_add_address(cd, m);
476 M_ALD_DSEG(REG_ITMP2, disp);
477 M_AST(REG_ITMP2, REG_SP, 6 * 8);
479 /* Call builtin_verbosecall_enter */
481 disp = dseg_add_address(cd, builtin_verbosecall_enter);
482 M_ALD_DSEG(REG_ITMP2, disp);
483 M_ASUB_IMM(96, REG_SP);
485 M_AADD_IMM(96, REG_SP);
487 /* restore argument registers */
489 off = (6 * 8) + (1 * 4);
491 for (i = 0; i < INT_ARG_CNT; i++, off += 8)
492 M_ILD(abi_registers_integer_argument[i], REG_SP, off);
494 for (i = 0; i < FLT_ARG_CNT; i++, off += 8)
495 M_DLD(abi_registers_float_argument[i], REG_SP, off);
497 /* restore temporary registers for leaf methods */
499 if (jd->isleafmethod) {
500 for (i = 0; i < INT_TMP_CNT; i++, off += 8)
501 M_ILD(abi_registers_integer_temporary[i], REG_SP, off);
503 for (i = 0; i < FLT_TMP_CNT; i++, off += 8)
504 M_DLD(abi_registers_float_temporary[i], REG_SP, off);
507 /* remove stackframe */
509 M_AADD_IMM(stackframesize, REG_SP);
511 /* mark trace code */
516 #endif /* !defined(NDEBUG) */
519 /* emit_verbosecall_exit *******************************************************
521 Generates the code for the call trace.
523 *******************************************************************************/
526 void emit_verbosecall_exit(jitdata *jd)
537 /* mark trace code */
541 /* allocate stackframe */
543 stackframesize = 96 + (3 * 8);
544 M_ASUB_IMM(stackframesize, REG_SP);
546 /* store return values in array and sign extend them */
548 M_IST(REG_RESULT, REG_SP, 96 + (0 * 8) + 4);
549 M_SRA_IMM(31, REG_RESULT);
550 M_IST(REG_RESULT, REG_SP, 96 + (0 * 8));
552 M_IST(REG_RESULT2, REG_SP, 96 + (1 * 8) + 4);
553 M_SRA_IMM(31, REG_RESULT2);
554 M_IST(REG_RESULT2, REG_SP, 96 + (1 * 8));
556 M_DST(REG_FRESULT, REG_SP, 96 + (2 * 8));
558 /* call trace_java_call_exit */
560 disp = dseg_add_address(cd, m);
561 M_ALD_DSEG(REG_A0, disp);
562 M_LDA(REG_A1, REG_SP, 96);
563 disp = dseg_add_functionptr(cd, trace_java_call_exit);
564 M_ALD_DSEG(REG_ITMP2, disp);
567 /* restore return values */
569 M_ILD(REG_RESULT, REG_SP, 96 + (0 * 8) + 4);
570 M_ILD(REG_RESULT2, REG_SP, 96 + (1 * 8) + 4);
571 M_DLD(REG_FRESULT, REG_SP, 96 + (2 * 8));
573 /* remove stackframe */
575 M_AADD_IMM(stackframesize, REG_SP);
577 /* mark trace code */
588 /* get required compiler data */
594 /* mark trace code */
598 M_ASUB_IMM(2 * 8, REG_SP);
600 N_STM(REG_RESULT, REG_RESULT2, 0 * 8, REG_SP);
601 M_DST(REG_FRESULT, REG_SP, 1 * 8);
603 if (IS_2_WORD_TYPE(m->parseddesc->returntype.type)) {
604 /* (REG_A0, REG_A1) == (REG_RESULT, REG_RESULT2), se no need to move */
606 M_INTMOVE(REG_RESULT, REG_A1);
610 disp = dseg_add_address(cd, m);
611 M_ALD_DSEG(REG_A2, disp);
613 /* REG_FRESULT is REG_FA0, so no need to move */
614 M_FLTMOVE(REG_FRESULT, REG_FA1);
616 disp = dseg_add_address(cd, builtin_verbosecall_exit);
617 M_ALD_DSEG(REG_ITMP1, disp);
618 M_ASUB_IMM(96, REG_SP);
620 M_AADD_IMM(96, REG_SP);
622 N_LM(REG_RESULT, REG_RESULT2, 0 * 8, REG_SP);
623 M_DLD(REG_FRESULT, REG_SP, 1 * 8);
625 M_AADD_IMM(2 * 8, REG_SP);
627 /* mark trace code */
632 #endif /* !defined(NDEBUG) */
635 /* emit_load_high **************************************************************
637 Emits a possible load of the high 32-bits of an operand.
639 *******************************************************************************/
641 s4 emit_load_high(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
647 assert(src->type == TYPE_LNG);
649 /* get required compiler data */
653 if (IS_INMEMORY(src->flags)) {
656 disp = src->vv.regoff;
658 M_ILD(tempreg, REG_SP, disp);
663 reg = GET_HIGH_REG(src->vv.regoff);
668 /* emit_load_low ***************************************************************
670 Emits a possible load of the low 32-bits of an operand.
672 *******************************************************************************/
674 s4 emit_load_low(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
680 assert(src->type == TYPE_LNG);
682 /* get required compiler data */
686 if (IS_INMEMORY(src->flags)) {
689 disp = src->vv.regoff;
691 M_ILD(tempreg, REG_SP, disp + 4);
696 reg = GET_LOW_REG(src->vv.regoff);
701 s4 emit_load_s1_but(jitdata *jd, instruction *iptr, s4 tempreg, s4 notreg) {
702 codegendata *cd = jd->cd;
703 s4 reg = emit_load_s1(jd, iptr, tempreg);
705 if (IS_FLT_DBL_TYPE(VAROP(iptr->s1)->type)) {
706 M_FMOV(reg, tempreg);
716 s4 emit_load_s2_but(jitdata *jd, instruction *iptr, s4 tempreg, s4 notreg) {
717 codegendata *cd = jd->cd;
718 s4 reg = emit_load_s2(jd, iptr, tempreg);
720 if (IS_FLT_DBL_TYPE(VAROP(iptr->sx.s23.s2)->type)) {
721 M_FMOV(reg, tempreg);
731 void emit_copy_dst(jitdata *jd, instruction *iptr, s4 dtmpreg) {
735 dst = VAROP(iptr->dst);
736 if (! IS_INMEMORY(dst->flags)) {
737 if (dst->vv.regoff != dtmpreg) {
738 if (IS_FLT_DBL_TYPE(dst->type)) {
739 M_FLTMOVE(dtmpreg, dst->vv.regoff);
740 } else if (IS_2_WORD_TYPE(dst->type)) {
741 M_LNGMOVE(dtmpreg, dst->vv.regoff);
743 M_INTMOVE(dtmpreg, dst->vv.regoff);
749 void emit_branch(codegendata *cd, s4 disp, s4 condition, s4 reg, u4 opt) {
751 s4 branchdisp = disp;
755 if (N_VALID_BRANCH(branchdisp)) {
757 /* valid displacement */
778 case BRANCH_UNCONDITIONAL:
782 vm_abort("emit_branch: unknown condition %d", condition);
786 /* If LONGBRANCHES is not set, the flag and the error flag */
788 if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
789 cd->flags |= (CODEGENDATA_FLAG_ERROR |
790 CODEGENDATA_FLAG_LONGBRANCHES);
793 /* If error flag is set, do nothing. The method has to be recompiled. */
795 if (CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd) && CODEGENDATA_HAS_FLAG_ERROR(cd)) {
799 /* Patch the displacement to branch over the actual branch manually
800 * to not get yet more nops.
803 branchmpc = cd->mcodeptr - cd->mcodebase;
825 case BRANCH_UNCONDITIONAL:
826 /* fall through, no displacement to patch */
830 vm_abort("emit_branch: unknown condition %d", condition);
833 /* The actual long branch */
835 disp = dseg_add_s4(cd, branchmpc + disp - N_PV_OFFSET);
836 M_ILD_DSEG(REG_ITMP2, disp);
837 M_AADD(REG_PV, REG_ITMP2);
838 M_JMP(RN, REG_ITMP2);
840 /* Patch back the displacement */
843 *(u4 *)ref |= (u4)((cd->mcodeptr - ref) / 2);
848 void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg) {
849 if (INSTRUCTION_MUST_CHECK(iptr)) {
851 M_BNE(SZ_BRC + SZ_ILL);
852 M_ILL(EXCEPTION_HARDWARE_ARITHMETIC);
856 /* emit_arrayindexoutofbounds_check ********************************************
858 Emit a ArrayIndexOutOfBoundsException check.
860 *******************************************************************************/
862 void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
864 if (INSTRUCTION_MUST_CHECK(iptr)) {
866 * Do unsigned comparison to catch negative indexes.
868 N_CL(s2, OFFSET(java_array_t, size), RN, s1);
869 M_BLT(SZ_BRC + SZ_ILL);
870 M_ILL2(s2, EXCEPTION_HARDWARE_ARRAYINDEXOUTOFBOUNDS);
875 /* emit_arraystore_check *******************************************************
877 Emit an ArrayStoreException check.
879 *******************************************************************************/
881 void emit_arraystore_check(codegendata *cd, instruction *iptr)
883 if (INSTRUCTION_MUST_CHECK(iptr)) {
885 M_BNE(SZ_BRC + SZ_ILL);
886 M_ILL(EXCEPTION_HARDWARE_ARRAYSTORE);
891 void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 reg, s4 s1) {
892 if (INSTRUCTION_MUST_CHECK(iptr)) {
898 M_BGT(SZ_BRC + SZ_ILL);
901 M_BNE(SZ_BRC + SZ_ILL);
904 M_BLE(SZ_BRC + SZ_ILL);
907 vm_abort("emit_classcast_check: unknown condition %d", condition);
909 M_ILL2(s1, EXCEPTION_HARDWARE_CLASSCAST);
913 void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg) {
914 if (INSTRUCTION_MUST_CHECK(iptr)) {
916 M_BNE(SZ_BRC + SZ_ILL);
917 M_ILL(EXCEPTION_HARDWARE_NULLPOINTER);
921 void emit_exception_check(codegendata *cd, instruction *iptr) {
922 if (INSTRUCTION_MUST_CHECK(iptr)) {
924 M_BNE(SZ_BRC + SZ_ILL);
925 M_ILL(EXCEPTION_HARDWARE_EXCEPTION);
929 void emit_restore_pv(codegendata *cd) {
930 s4 offset, offset_imm;
934 disp = (s4) (cd->mcodeptr - cd->mcodebase);
935 M_ASUB_IMM32(disp, REG_ITMP1, REG_PV);
938 /* If the offset from the method start does not fit into an immediate
939 * value, we can't put it into the data segment!
942 /* Displacement from start of method to here */
944 offset = (s4) (cd->mcodeptr - cd->mcodebase);
945 offset_imm = -offset - SZ_BASR + N_PV_OFFSET;
947 if (N_VALID_IMM(offset_imm)) {
948 /* Get program counter */
950 /* Substract displacement */
951 M_AADD_IMM(offset_imm, REG_PV);
953 /* Save program counter and jump over displacement in instruction flow */
954 N_BRAS(REG_PV, SZ_BRAS + SZ_LONG);
955 /* Place displacement here */
956 /* REG_PV points now exactly to this position */
957 N_LONG(-offset - SZ_BRAS + N_PV_OFFSET);
958 /* Substract *(REG_PV) from REG_PV */
959 N_A(REG_PV, 0, RN, REG_PV);
964 * These are local overrides for various environment variables in Emacs.
965 * Please do not remove this and leave it at the end of the file, where
966 * Emacs will automagically detect them.
967 * ---------------------------------------------------------------------
970 * indent-tabs-mode: t