/* src/vm/jit/emit-common.cpp - common code emitter functions Copyright (C) 2006, 2007, 2008 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO This file is part of CACAO. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "config.h" #include #include #include #include "vm/types.h" #include "arch.h" #include "codegen.h" #include "toolbox/list.hpp" #include "vm/options.h" #include "vm/statistics.h" #include "vm/jit/emit-common.hpp" #include "vm/jit/jit.hpp" #include "vm/jit/patcher-common.hpp" /* emit_load_s1 **************************************************************** Emits a possible load of the first source operand. *******************************************************************************/ s4 emit_load_s1(jitdata *jd, instruction *iptr, s4 tempreg) { varinfo *src; s4 reg; src = VAROP(iptr->s1); reg = emit_load(jd, iptr, src, tempreg); return reg; } /* emit_load_s2 **************************************************************** Emits a possible load of the second source operand. *******************************************************************************/ s4 emit_load_s2(jitdata *jd, instruction *iptr, s4 tempreg) { varinfo *src; s4 reg; src = VAROP(iptr->sx.s23.s2); reg = emit_load(jd, iptr, src, tempreg); return reg; } /* emit_load_s3 **************************************************************** Emits a possible load of the third source operand. *******************************************************************************/ s4 emit_load_s3(jitdata *jd, instruction *iptr, s4 tempreg) { varinfo *src; s4 reg; src = VAROP(iptr->sx.s23.s3); reg = emit_load(jd, iptr, src, tempreg); return reg; } /* emit_load_s1_low ************************************************************ Emits a possible load of the low 32-bits of the first long source operand. *******************************************************************************/ #if SIZEOF_VOID_P == 4 s4 emit_load_s1_low(jitdata *jd, instruction *iptr, s4 tempreg) { varinfo *src; s4 reg; src = VAROP(iptr->s1); reg = emit_load_low(jd, iptr, src, tempreg); return reg; } #endif /* emit_load_s2_low ************************************************************ Emits a possible load of the low 32-bits of the second long source operand. *******************************************************************************/ #if SIZEOF_VOID_P == 4 s4 emit_load_s2_low(jitdata *jd, instruction *iptr, s4 tempreg) { varinfo *src; s4 reg; src = VAROP(iptr->sx.s23.s2); reg = emit_load_low(jd, iptr, src, tempreg); return reg; } #endif /* emit_load_s3_low ************************************************************ Emits a possible load of the low 32-bits of the third long source operand. *******************************************************************************/ #if SIZEOF_VOID_P == 4 s4 emit_load_s3_low(jitdata *jd, instruction *iptr, s4 tempreg) { varinfo *src; s4 reg; src = VAROP(iptr->sx.s23.s3); reg = emit_load_low(jd, iptr, src, tempreg); return reg; } #endif /* emit_load_s1_high *********************************************************** Emits a possible load of the high 32-bits of the first long source operand. *******************************************************************************/ #if SIZEOF_VOID_P == 4 s4 emit_load_s1_high(jitdata *jd, instruction *iptr, s4 tempreg) { varinfo *src; s4 reg; src = VAROP(iptr->s1); reg = emit_load_high(jd, iptr, src, tempreg); return reg; } #endif /* emit_load_s2_high *********************************************************** Emits a possible load of the high 32-bits of the second long source operand. *******************************************************************************/ #if SIZEOF_VOID_P == 4 s4 emit_load_s2_high(jitdata *jd, instruction *iptr, s4 tempreg) { varinfo *src; s4 reg; src = VAROP(iptr->sx.s23.s2); reg = emit_load_high(jd, iptr, src, tempreg); return reg; } #endif /* emit_load_s3_high *********************************************************** Emits a possible load of the high 32-bits of the third long source operand. *******************************************************************************/ #if SIZEOF_VOID_P == 4 s4 emit_load_s3_high(jitdata *jd, instruction *iptr, s4 tempreg) { varinfo *src; s4 reg; src = VAROP(iptr->sx.s23.s3); reg = emit_load_high(jd, iptr, src, tempreg); return reg; } #endif /* emit_store_dst ************************************************************** This function generates the code to store the result of an operation back into a spilled pseudo-variable. If the pseudo-variable has not been spilled in the first place, this function will generate nothing. *******************************************************************************/ void emit_store_dst(jitdata *jd, instruction *iptr, s4 d) { emit_store(jd, iptr, VAROP(iptr->dst), d); } /* emit_patcher_traps ********************************************************** Generates the code for the patcher traps. *******************************************************************************/ void emit_patcher_traps(jitdata *jd) { codegendata *cd; codeinfo *code; u1 *savedmcodeptr; u1 *tmpmcodeptr; uint32_t mcode; /* get required compiler data */ cd = jd->cd; code = jd->code; // Generate patcher traps code. for (List::iterator it = code->patchers->begin(); it != code->patchers->end(); it++) { patchref_t& pr = *it; /* Calculate the patch position where the original machine code is located and the trap should be placed. */ tmpmcodeptr = (u1 *) (cd->mcodebase + pr.mpc); /* Patch in the trap to call the signal handler (done at compile time). */ savedmcodeptr = cd->mcodeptr; /* save current mcodeptr */ cd->mcodeptr = tmpmcodeptr; /* set mcodeptr to patch position */ mcode = emit_trap(cd); cd->mcodeptr = savedmcodeptr; /* restore the current mcodeptr */ /* Remember the original machine code which is patched back in later (done at runtime). */ pr.mcode = mcode; } } /* emit_bccz ******************************************************************* Emit conditional and unconditional branch instructions on integer regiseters. *******************************************************************************/ void emit_bccz(codegendata *cd, basicblock *target, s4 condition, s4 reg, u4 options) { s4 branchmpc; s4 disp; /* Target basic block already has an PC, so we can generate the branch immediately. */ if ((target->mpc >= 0)) { STATISTICS(count_branches_resolved++); /* calculate the mpc of the branch instruction */ branchmpc = cd->mcodeptr - cd->mcodebase; disp = target->mpc - branchmpc; #if defined(ENABLE_STATISTICS) count_emit_branch++; if ((int8_t)disp == disp) count_emit_branch_8bit++; else if ((int16_t)disp == disp) count_emit_branch_16bit++; else if ((int32_t)disp == disp) count_emit_branch_32bit++; # if SIZEOF_VOID_P == 8 else if ((int64_t)disp == disp) count_emit_branch_64bit++; # endif #endif emit_branch(cd, disp, condition, reg, options); } else { /* current mcodeptr is the correct position, afterwards emit the NOPs */ codegen_add_branch_ref(cd, target, condition, reg, options); /* generate NOPs as placeholder for branch code */ BRANCH_NOPS; } } /* emit_bcc ******************************************************************** Emit conditional and unconditional branch instructions on condition codes. *******************************************************************************/ void emit_bcc(codegendata *cd, basicblock *target, s4 condition, u4 options) { emit_bccz(cd, target, condition, -1, options); } /* emit_br ********************************************************************* Wrapper for unconditional branches. *******************************************************************************/ void emit_br(codegendata *cd, basicblock *target) { emit_bcc(cd, target, BRANCH_UNCONDITIONAL, BRANCH_OPT_NONE); } /* emit_bxxz ******************************************************************* Wrappers for branches on one integer register. *******************************************************************************/ #if SUPPORT_BRANCH_CONDITIONAL_ONE_INTEGER_REGISTER void emit_beqz(codegendata *cd, basicblock *target, s4 reg) { emit_bccz(cd, target, BRANCH_EQ, reg, BRANCH_OPT_NONE); } void emit_bnez(codegendata *cd, basicblock *target, s4 reg) { emit_bccz(cd, target, BRANCH_NE, reg, BRANCH_OPT_NONE); } void emit_bltz(codegendata *cd, basicblock *target, s4 reg) { emit_bccz(cd, target, BRANCH_LT, reg, BRANCH_OPT_NONE); } void emit_bgez(codegendata *cd, basicblock *target, s4 reg) { emit_bccz(cd, target, BRANCH_GE, reg, BRANCH_OPT_NONE); } void emit_bgtz(codegendata *cd, basicblock *target, s4 reg) { emit_bccz(cd, target, BRANCH_GT, reg, BRANCH_OPT_NONE); } void emit_blez(codegendata *cd, basicblock *target, s4 reg) { emit_bccz(cd, target, BRANCH_LE, reg, BRANCH_OPT_NONE); } #endif /* SUPPORT_BRANCH_CONDITIONAL_ONE_INTEGER_REGISTER */ /* emit_bxx ******************************************************************** Wrappers for branches on two integer registers. We use PACK_REGS here, so we don't have to change the branchref data structure and the emit_bccz function. *******************************************************************************/ #if SUPPORT_BRANCH_CONDITIONAL_TWO_INTEGER_REGISTERS void emit_beq(codegendata *cd, basicblock *target, s4 s1, s4 s2) { emit_bccz(cd, target, BRANCH_EQ, PACK_REGS(s1, s2), BRANCH_OPT_NONE); } void emit_bne(codegendata *cd, basicblock *target, s4 s1, s4 s2) { emit_bccz(cd, target, BRANCH_NE, PACK_REGS(s1, s2), BRANCH_OPT_NONE); } #endif /* SUPPORT_BRANCH_CONDITIONAL_TWO_INTEGER_REGISTERS */ /* emit_bxx ******************************************************************** Wrappers for branches on condition codes. *******************************************************************************/ #if SUPPORT_BRANCH_CONDITIONAL_CONDITION_REGISTER void emit_beq(codegendata *cd, basicblock *target) { emit_bcc(cd, target, BRANCH_EQ, BRANCH_OPT_NONE); } void emit_bne(codegendata *cd, basicblock *target) { emit_bcc(cd, target, BRANCH_NE, BRANCH_OPT_NONE); } void emit_blt(codegendata *cd, basicblock *target) { emit_bcc(cd, target, BRANCH_LT, BRANCH_OPT_NONE); } void emit_bge(codegendata *cd, basicblock *target) { emit_bcc(cd, target, BRANCH_GE, BRANCH_OPT_NONE); } void emit_bgt(codegendata *cd, basicblock *target) { emit_bcc(cd, target, BRANCH_GT, BRANCH_OPT_NONE); } void emit_ble(codegendata *cd, basicblock *target) { emit_bcc(cd, target, BRANCH_LE, BRANCH_OPT_NONE); } #if SUPPORT_BRANCH_CONDITIONAL_UNSIGNED_CONDITIONS void emit_bult(codegendata *cd, basicblock *target) { emit_bcc(cd, target, BRANCH_ULT, BRANCH_OPT_NONE); } void emit_bule(codegendata *cd, basicblock *target) { emit_bcc(cd, target, BRANCH_ULE, BRANCH_OPT_NONE); } void emit_buge(codegendata *cd, basicblock *target) { emit_bcc(cd, target, BRANCH_UGE, BRANCH_OPT_NONE); } void emit_bugt(codegendata *cd, basicblock *target) { emit_bcc(cd, target, BRANCH_UGT, BRANCH_OPT_NONE); } #endif #if defined(__POWERPC__) || defined(__POWERPC64__) void emit_bnan(codegendata *cd, basicblock *target) { emit_bcc(cd, target, BRANCH_NAN, BRANCH_OPT_NONE); } #endif #endif /* SUPPORT_BRANCH_CONDITIONAL_CONDITION_REGISTER */ /* emit_label_bccz ************************************************************* Emit a branch to a label. Possibly emit the branch, if it is a backward branch. *******************************************************************************/ void emit_label_bccz(codegendata *cd, s4 label, s4 condition, s4 reg, u4 options) { // Search if the label is already in the list. DumpList::iterator it; for (it = cd->brancheslabel->begin(); it != cd->brancheslabel->end(); it++) { branch_label_ref_t* br = *it; /* is this entry the correct label? */ if (br->label == label) break; } if (it == cd->brancheslabel->end()) { /* current mcodeptr is the correct position, afterwards emit the NOPs */ codegen_branch_label_add(cd, label, condition, reg, options); /* generate NOPs as placeholder for branch code */ BRANCH_NOPS; return; } // Branch reference was found. branch_label_ref_t* br = *it; /* calculate the mpc of the branch instruction */ int32_t mpc = cd->mcodeptr - cd->mcodebase; int32_t disp = br->mpc - mpc; #if defined(ENABLE_STATISTICS) count_emit_branch++; if ((int8_t)disp == disp) count_emit_branch_8bit++; else if ((int16_t)disp == disp) count_emit_branch_16bit++; else if ((int32_t)disp == disp) count_emit_branch_32bit++; # if SIZEOF_VOID_P == 8 else if ((int64_t)disp == disp) count_emit_branch_64bit++; # endif #endif emit_branch(cd, disp, condition, reg, options); // Now remove the branch reference. cd->brancheslabel->remove(br); } /* emit_label ****************************************************************** Emit a label for a branch. Possibly emit the branch, if it is a forward branch. *******************************************************************************/ void emit_label(codegendata *cd, s4 label) { u1* mcodeptr; // Search if the label is already in the list. DumpList::iterator it; for (it = cd->brancheslabel->begin(); it != cd->brancheslabel->end(); it++) { branch_label_ref_t* br = *it; /* is this entry the correct label? */ if (br->label == label) break; } if (it == cd->brancheslabel->end()) { /* No branch reference found, add the label to the list (use invalid values for condition and register). */ codegen_branch_label_add(cd, label, -1, -1, BRANCH_OPT_NONE ); return; } // Branch reference was found. branch_label_ref_t* br = *it; // Calculate the mpc of the branch instruction. int32_t mpc = cd->mcodeptr - cd->mcodebase; int32_t disp = mpc - br->mpc; /* temporary set the mcodeptr */ mcodeptr = cd->mcodeptr; cd->mcodeptr = cd->mcodebase + br->mpc; #if defined(ENABLE_STATISTICS) count_emit_branch++; if ((int8_t)disp == disp) count_emit_branch_8bit++; else if ((int16_t)disp == disp) count_emit_branch_16bit++; else if ((int32_t)disp == disp) count_emit_branch_32bit++; # if SIZEOF_VOID_P == 8 else if ((int64_t)disp == disp) count_emit_branch_64bit++; # endif #endif emit_branch(cd, disp, br->condition, br->reg, br->options); /* restore mcodeptr */ cd->mcodeptr = mcodeptr; // Now remove the branch reference. cd->brancheslabel->remove(br); } /* emit_label_bcc ************************************************************** Emit conditional and unconditional label-branch instructions on condition codes. *******************************************************************************/ void emit_label_bcc(codegendata *cd, s4 label, s4 condition, u4 options) { emit_label_bccz(cd, label, condition, -1, options); } /* emit_label_br *************************************************************** Wrapper for unconditional label-branches. *******************************************************************************/ void emit_label_br(codegendata *cd, s4 label) { emit_label_bcc(cd, label, BRANCH_UNCONDITIONAL, BRANCH_OPT_NONE); } /* emit_label_bxxz ************************************************************* Wrappers for label-branches on one integer register. *******************************************************************************/ #if SUPPORT_BRANCH_CONDITIONAL_ONE_INTEGER_REGISTER void emit_label_beqz(codegendata *cd, s4 label, s4 reg) { emit_label_bccz(cd, label, BRANCH_EQ, reg, BRANCH_OPT_NONE); } void emit_label_bnez(codegendata *cd, s4 label, s4 reg) { emit_label_bccz(cd, label, BRANCH_NE, reg, BRANCH_OPT_NONE); } #endif /* SUPPORT_BRANCH_CONDITIONAL_ONE_INTEGER_REGISTER */ /* emit_label_bxx ************************************************************** Wrappers for label-branches on condition codes. *******************************************************************************/ #if SUPPORT_BRANCH_CONDITIONAL_CONDITION_REGISTER void emit_label_beq(codegendata *cd, s4 label) { emit_label_bcc(cd, label, BRANCH_EQ, BRANCH_OPT_NONE); } void emit_label_bne(codegendata *cd, s4 label) { emit_label_bcc(cd, label, BRANCH_NE, BRANCH_OPT_NONE); } void emit_label_blt(codegendata *cd, s4 label) { emit_label_bcc(cd, label, BRANCH_LT, BRANCH_OPT_NONE); } void emit_label_bge(codegendata *cd, s4 label) { emit_label_bcc(cd, label, BRANCH_GE, BRANCH_OPT_NONE); } void emit_label_bgt(codegendata *cd, s4 label) { emit_label_bcc(cd, label, BRANCH_GT, BRANCH_OPT_NONE); } void emit_label_ble(codegendata *cd, s4 label) { emit_label_bcc(cd, label, BRANCH_LE, BRANCH_OPT_NONE); } #endif /* SUPPORT_BRANCH_CONDITIONAL_CONDITION_REGISTER */ /* * These are local overrides for various environment variables in Emacs. * Please do not remove this and leave it at the end of the file, where * Emacs will automagically detect them. * --------------------------------------------------------------------- * Local variables: * mode: c++ * indent-tabs-mode: t * c-basic-offset: 4 * tab-width: 4 * End: * vim:noexpandtab:sw=4:ts=4: */