+/* 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 <assert.h>
+#include <stdint.h>
+
+#include "vm/types.h"
+
+#include "arch.h"
+#include "codegen.h"
+
+#include "vm/options.h"
+#include "vm/statistics.h"
+
+#include "vm/jit/emit-common.hpp"
+#include "vm/jit/jit.hpp"
+#include "vm/jit/patcher-common.h"
+
+
+/* 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;
+ patchref_t *pr;
+ u1 *savedmcodeptr;
+ u1 *tmpmcodeptr;
+ uint32_t mcode;
+
+ /* get required compiler data */
+
+ cd = jd->cd;
+ code = jd->code;
+
+ /* generate patcher traps code */
+
+ for (pr = (patchref_t*) list_first(code->patchers); pr != NULL; pr = (patchref_t*) list_next(code->patchers, pr)) {
+
+ /* 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)
+{
+ list_t *list;
+ branch_label_ref_t *br;
+ s4 mpc;
+ s4 disp;
+
+ /* get the label list */
+
+ list = cd->brancheslabel;
+
+ /* search if the label is already in the list */
+
+ for (br = (branch_label_ref_t*) list_first(list); br != NULL; br = (branch_label_ref_t*) list_next(list, br)) {
+ /* is this entry the correct label? */
+
+ if (br->label == label)
+ break;
+ }
+
+ if (br == NULL) {
+ /* 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. */
+
+ /* calculate the mpc of the branch instruction */
+
+ mpc = cd->mcodeptr - cd->mcodebase;
+ 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 */
+
+ list_remove(list, 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)
+{
+ list_t *list;
+ branch_label_ref_t *br;
+ s4 mpc;
+ s4 disp;
+ u1 *mcodeptr;
+
+ /* get the label list */
+
+ list = cd->brancheslabel;
+
+ /* search if the label is already in the list */
+
+ for (br = (branch_label_ref_t*) list_first(list); br != NULL; br = (branch_label_ref_t*) list_next(list, br)) {
+ /* is this entry the correct label? */
+
+ if (br->label == label)
+ break;
+ }
+
+ if (br == NULL) {
+ /* 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. */
+
+ /* calculate the mpc of the branch instruction */
+
+ mpc = cd->mcodeptr - cd->mcodebase;
+ 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 */
+
+ list_remove(list, 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);
+}
+
+#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:
+ */