Merged revisions 8245-8298 via svnmerge from
[cacao.git] / src / vm / jit / emit-common.c
index 2810994f58a5973d3e900710a3f99c6defff4091..5639853ef8d333c4becb5368bc80a1af78523dc2 100644 (file)
@@ -22,7 +22,7 @@
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
 
-   $Id: emitfuncs.c 4398 2006-01-31 23:43:08Z twisti $
+   $Id: emit-common.c 8265 2007-08-06 16:10:42Z 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"
@@ -246,13 +249,61 @@ void emit_store_dst(jitdata *jd, instruction *iptr, s4 d)
 }
 
 
-/* emit_bxx ********************************************************************
+/* 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). */
 
-   Wrappers for conditional branch instructions.
+               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_bc(codegendata *cd, basicblock *target, s4 condition)
+void emit_bccz(codegendata *cd, basicblock *target, s4 condition, s4 reg, u4 options)
 {
        s4 branchmpc;
        s4 disp;
@@ -268,90 +319,409 @@ void emit_bc(codegendata *cd, basicblock *target, s4 condition)
                branchmpc = cd->mcodeptr - cd->mcodebase;
                disp      = target->mpc - branchmpc;
 
-#if 0
-               emit_branch(cd, disp, condition);
+#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 */
 
-#if 0
-               codegen_add_branch_ref(cd, target, condition);
-#endif
+               codegen_add_branch_ref(cd, target, condition, reg, options);
 
                /* generate NOPs as placeholder for branch code */
-               /* XXX if recompile-with-long-branches */
 
                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_bc(cd, target, BRANCH_UNCONDITIONAL);
+       emit_bcc(cd, target, BRANCH_UNCONDITIONAL, BRANCH_OPT_NONE);
 }
 
 
-void emit_beq(codegendata *cd, basicblock *target)
+/* 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_bc(cd, target, BRANCH_EQ);
+       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_bne(codegendata *cd, basicblock *target)
+void emit_bltz(codegendata *cd, basicblock *target, s4 reg)
 {
-       emit_bc(cd, target, BRANCH_NE);
+       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_blt(codegendata *cd, basicblock *target)
+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_bc(cd, target, BRANCH_LT);
+       emit_bccz(cd, target, BRANCH_LE, reg, BRANCH_OPT_NONE);
 }
 
+#endif /* SUPPORT_BRANCH_CONDITIONAL_ONE_INTEGER_REGISTER */
 
-void emit_bge(codegendata *cd, basicblock *target)
+
+/* 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_bc(cd, target, BRANCH_GE);
+       emit_bccz(cd, target, BRANCH_NE, PACK_REGS(s1, s2), BRANCH_OPT_NONE);
 }
 
+#endif /* SUPPORT_BRANCH_CONDITIONAL_TWO_INTEGER_REGISTERS */
 
-void emit_bgt(codegendata *cd, basicblock *target)
+
+/* emit_bxx ********************************************************************
+
+   Wrappers for branches on condition codes.
+
+*******************************************************************************/
+
+#if SUPPORT_BRANCH_CONDITIONAL_CONDITION_REGISTER
+
+void emit_beq(codegendata *cd, basicblock *target)
 {
-       emit_bc(cd, target, BRANCH_GT);
+       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_bc(cd, target, BRANCH_LE);
+       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_bc(cd, target, BRANCH_NAN);
+       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 = 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_array_checks ***********************************************************
+/* emit_label ******************************************************************
 
-   Emit exception checks for array accesses, if they need to be
-   emitted.
+   Emit a label for a branch.  Possibly emit the branch, if it is a
+   forward branch.
 
 *******************************************************************************/
 
-void emit_array_checks(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
+void emit_label(codegendata *cd, s4 label)
 {
-       if (INSTRUCTION_MUST_CHECK(iptr)) {
-               emit_nullpointer_check(cd, iptr, s1);
-               emit_arrayindexoutofbounds_check(cd, iptr, s1, s2);
+       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.
  * Please do not remove this and leave it at the end of the file, where