* Removed all Id tags.
[cacao.git] / src / vm / jit / emit-common.c
index 8bd270b0478e860f2781c479bbf970d4c08ad240..aa2f38997165a63b4ce578f3b4a9e64b36c51db3 100644 (file)
@@ -1,6 +1,6 @@
 /* src/vm/jit/emit-common.c - common code emitter functions
 
-   Copyright (C) 2006 R. Grafl, A. Krall, C. Kruegel, C. Oates,
+   Copyright (C) 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates,
    R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
    C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
    Institut f. Computersprachen - TU Wien
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
 
-   Contact: cacao@cacaojvm.org
-
-   Authors: Christian Thalinger
-            Edwin Steiner
-
-   $Id: emitfuncs.c 4398 2006-01-31 23:43:08Z twisti $
-
 */
 
 
 #include "config.h"
 
 #include <assert.h>
+#include <stdint.h>
 
 #include "vm/types.h"
 
+#include "arch.h"
+#include "codegen.h"
+
 #include "vm/jit/emit-common.h"
 #include "vm/jit/jit.h"
+#include "vm/jit/patcher-common.h"
+
+#include "vmcore/options.h"
+#include "vmcore/statistics.h"
 
 
 /* emit_load_s1 ****************************************************************
@@ -246,23 +247,478 @@ void emit_store_dst(jitdata *jd, instruction *iptr, s4 d)
 }
 
 
-/* emit_array_checks ***********************************************************
+/* 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 = list_first_unsynced(code->patchers); pr != NULL; pr = list_next_unsynced(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 exception checks for array accesses, if they need to be
-   emitted.
+   Emit a branch to a label.  Possibly emit the branch, if it is a
+   backward branch.
 
 *******************************************************************************/
 
-#if defined(__ALPHA__) || defined(__POWERPC__)
-void emit_array_checks(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
+void emit_label_bccz(codegendata *cd, s4 label, s4 condition, s4 reg, u4 options)
 {
-       if (INSTRUCTION_MUST_CHECK(iptr)) {
-               emit_nullpointer_check(cd, s1);
-               emit_arrayindexoutofbounds_check(cd, s1, s2);
+       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 = list_first_unsynced(list); br != NULL;
+                br = list_next_unsynced(list, br)) {
+               /* is this entry the correct label? */
+
+               if (br->label == label)
+                       break;
+       }
+
+       /* a branch reference was found */
+
+       if (br != NULL) {
+               /* 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_unsynced(list, br);
+       }
+       else {
+               /* 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;
        }
 }
+
+
+/* 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 = list_first_unsynced(list); br != NULL;
+                br = list_next_unsynced(list, br)) {
+               /* is this entry the correct label? */
+
+               if (br->label == label)
+                       break;
+       }
+
+       /* a branch reference was found */
+
+       if (br != NULL) {
+               /* 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_unsynced(list, br);
+       }
+       else {
+               /* add the label to the list (use invalid values for condition
+                  and register) */
+
+               codegen_branch_label_add(cd, label, -1, -1, BRANCH_OPT_NONE );
+       }
+}
+
+
+/* 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.