Added some missing vim modelines.
[cacao.git] / src / vm / jit / mips / md-abi.c
index 08aa28aa7e6834e748c53fcf7a72e2d50b6db97c..d20d0d19e90a68dd57a83c9024981050930ad9a7 100644 (file)
@@ -1,9 +1,7 @@
 /* src/vm/jit/mips/md-abi.c - functions for MIPS ABI
 
-   Copyright (C) 1996-2005, 2006 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
+   Copyright (C) 1996-2005, 2006, 2007, 2008
+   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
 
    This file is part of CACAO.
 
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
 
-   Contact: cacao@cacaojvm.org
-
-   Authors: Christian Thalinger
-
-   Changes: Christian Ullrich
-
-   $Id: md-abi.c 5634 2006-10-02 14:18:04Z edwin $
-
 */
 
 
 #include "config.h"
+
+#include <stdarg.h>
+#include <stdint.h>
+
 #include "vm/types.h"
 
 #include "vm/jit/mips/md-abi.h"
 
-#include "vm/descriptor.h"
+#include "mm/memory.hpp"
+
+#include "vm/descriptor.hpp"
 #include "vm/global.h"
+#include "vm/method.hpp"
+
 #include "vm/jit/abi.h"
+#include "vm/jit/stack.h"
 
 
 /* register descripton array **************************************************/
@@ -57,6 +56,44 @@ s4 nregdescint[] = {
        REG_END
 };
 
+const char *abi_registers_integer_name[] = {
+       "zero",  "at",    "v0",    "v1",    "a0",    "a1",    "a2",    "a3",
+       "a4",    "a5",    "a6",    "a7",    "t0",    "t1",    "t2",    "t3",
+       "s0",    "s1",    "s2",    "s3",    "s4",    "s5",    "s6",    "s7",
+       "t8",    "t9",    "k0",    "k1",    "gp",    "sp",    "s8",    "ra"
+};
+
+const s4 abi_registers_integer_argument[] = {
+       4,  /* a0  */
+       5,  /* a1  */
+       6,  /* a2  */
+       7,  /* a3  */
+       8,  /* a4  */
+       9,  /* a5  */
+       10, /* a6  */
+       11, /* a7  */
+};
+
+const s4 abi_registers_integer_saved[] = {
+       16, /* s0  */
+       17, /* s1  */
+       18, /* s2  */
+       19, /* s3  */
+       20, /* s4  */
+       21, /* s5  */
+       22, /* s6  */
+       23, /* s7  */
+};
+
+const s4 abi_registers_integer_temporary[] = {
+       12, /* t0  */
+       13, /* t1  */
+       14, /* t2  */
+       15, /* t3  */
+       24, /* t4  */
+};
+
+
 s4 nregdescfloat[] = {
        /*  fv0,   ftmp1,   ftmp2,   ftmp3,     ft0,     ft1,     ft2,     ft3,   */
        REG_RET, REG_RES, REG_RES, REG_RES, REG_TMP, REG_TMP, REG_TMP, REG_TMP,
@@ -73,6 +110,43 @@ s4 nregdescfloat[] = {
        REG_END
 };
 
+const s4 abi_registers_float_argument[] = {
+       12, /* fa0  */
+       13, /* fa1  */
+       14, /* fa2  */
+       15, /* fa3  */
+       16, /* fa4  */
+       17, /* fa5  */
+       18, /* fa6  */
+       19, /* fa7  */
+};
+
+const s4 abi_registers_float_saved[] = {
+       24, /* fs0  */
+       26, /* fs1  */
+       28, /* fs2  */
+       30, /* fs3  */
+};
+
+const s4 abi_registers_float_temporary[] = {
+       4,  /* ft0  */
+       5,  /* ft1  */
+       6,  /* ft2  */
+       7,  /* ft3  */
+       8,  /* ft4  */
+       9,  /* ft5  */
+       10, /* ft6  */
+       11, /* ft7  */
+       20, /* ft8  */
+       21, /* ft9  */
+       22, /* ft10 */
+       23, /* ft11 */
+       25, /* ft12 */
+       27, /* ft13 */
+       29, /* ft14 */
+       31, /* ft15 */
+};
+
 #else /* SIZEOF_VOID_P == 8 */
 
 /* MIPS32 */
@@ -93,6 +167,43 @@ s4 nregdescint[] = {
        REG_END
 };
 
+const char *abi_registers_integer_name[] = {
+       "zero",  "at",    "v0",    "v1",    "a0",    "a1",    "a2",    "a3",
+       "a4",    "a5",    "a6",    "a7",    "t0",    "t1",    "t2",    "t3",
+       "s0",    "s1",    "s2",    "s3",    "s4",    "s5",    "s6",    "s7",
+       "t8",    "t9",    "k0",    "k1",    "gp",    "sp",    "s8",    "ra"
+};
+
+const s4 abi_registers_integer_argument[] = {
+       4,  /* a0  */
+       5,  /* a1  */
+       6,  /* a2  */
+       7,  /* a3  */
+};
+
+const s4 abi_registers_integer_saved[] = {
+       16, /* s0  */
+       17, /* s1  */
+       18, /* s2  */
+       19, /* s3  */
+       20, /* s4  */
+       21, /* s5  */
+       22, /* s6  */
+       23, /* s7  */
+};
+
+const s4 abi_registers_integer_temporary[] = {
+       8,  /* t0  */
+       9,  /* t1  */
+       10, /* t2  */
+       11, /* t3  */
+       12, /* t4  */
+       13, /* t5  */
+       14, /* t6  */
+       15, /* t7  */
+};
+
+
 #if !defined(ENABLE_SOFT_FLOAT)
 
 s4 nregdescfloat[] = {
@@ -111,6 +222,28 @@ s4 nregdescfloat[] = {
        REG_END
 };
 
+const s4 abi_registers_float_argument[] = {
+       12, /* fa0  */
+       14, /* fa1  */
+};
+
+const s4 abi_registers_float_saved[] = {
+       20, /* fs0  */
+       22, /* fs1  */
+       24, /* fs2  */
+       26, /* fs3  */
+       28, /* fs4  */
+       30, /* fs5  */
+};
+
+const s4 abi_registers_float_temporary[] = {
+       8,  /* ft0  */
+       10, /* ft1  */
+       16, /* ft2  */
+       18, /* ft3  */
+};
+
+
 #else /* !defined(ENABLE_SOFT_FLOAT) */
 
 s4 nregdescfloat[] = {
@@ -124,7 +257,7 @@ s4 nregdescfloat[] = {
 
 /* md_param_alloc **************************************************************
 
-   XXX
+   Pre-allocate arguments according to the internal JIT ABI.
 
 *******************************************************************************/
 
@@ -137,51 +270,357 @@ void md_param_alloc(methoddesc *md)
 
        /* set default values */
 
-       reguse = 0;
-       stacksize = 0;
+       reguse      = 0;
+       stacksize   = 0;
 
        /* get params field of methoddesc */
 
        pd = md->params;
 
+#if SIZEOF_VOID_P == 8
+
        for (i = 0; i < md->paramcount; i++, pd++) {
                switch (md->paramtypes[i].type) {
                case TYPE_INT:
                case TYPE_ADR:
                case TYPE_LNG:
-                       if (i < INT_ARG_CNT) {
+                       if (reguse < INT_ARG_CNT) {
+                               pd->inmemory = false;
+                               pd->regoff   = abi_registers_integer_argument[reguse];
+                               reguse++;
+                               md->argintreguse = reguse;
+                       }
+                       else {
+                               pd->inmemory = true;
+                               pd->regoff   = stacksize * 8;
+                               stacksize++;
+                       }
+                       break;
+
+               case TYPE_FLT:
+               case TYPE_DBL:
+                       if (reguse < FLT_ARG_CNT) {
                                pd->inmemory = false;
-                               pd->regoff = reguse;
+                               pd->regoff   = abi_registers_float_argument[reguse];
                                reguse++;
+                               md->argfltreguse = reguse;
+                       }
+                       else {
+                               pd->inmemory = true;
+                               pd->regoff   = stacksize * 8;
+                               stacksize++;
+                       }
+                       break;
+               }
+
+               /* register type is the same as java type */
+
+               pd->type = md->paramtypes[i].type;
+       }
+
+#else /* SIZEOF_VOID_P == 8 */
+
+# if !defined(ENABLE_SOFT_FLOAT)
+
+       /* Set stacksize to 2, as 4 32-bit argument registers can be
+          stored. */
+       /* XXX maybe this should be done in stack.c? */
+
+       stacksize = 2;
+
+       for (i = 0; i < md->paramcount; i++, pd++) {
+               switch (md->paramtypes[i].type) {
+               case TYPE_INT:
+               case TYPE_ADR:
+                       if (reguse < INT_ARG_CNT) {
+                               pd->inmemory = false;
+                               pd->index    = reguse;
+                               pd->regoff   = abi_registers_integer_argument[reguse];
+                               reguse++;
+                               md->argintreguse = reguse;
+                       }
+                       else {
+                               pd->inmemory = true;
+                               pd->index    = stacksize;
+                               pd->regoff   = stacksize * 8;
+                               stacksize++;
+                       }
+                       break;
+
+               case TYPE_LNG:
+                       ALIGN_2(reguse);
+
+                       if (reguse < INT_ARG_CNT) {
+                               pd->inmemory = false;
+#  if WORDS_BIGENDIAN == 1
+                               pd->index    = PACK_REGS(reguse + 1, reguse);
+                               pd->regoff   =
+                                       PACK_REGS(abi_registers_integer_argument[reguse + 1],
+                                                         abi_registers_integer_argument[reguse]);
+#  else
+                               pd->index    = PACK_REGS(reguse, reguse + 1);
+                               pd->regoff   =
+                                       PACK_REGS(abi_registers_integer_argument[reguse],
+                                                         abi_registers_integer_argument[reguse + 1]);
+#  endif
+                               reguse += 2;
                                md->argintreguse = reguse;
-                       } else {
+                       }
+                       else {
                                pd->inmemory = true;
-                               pd->regoff = stacksize;
+                               pd->index    = stacksize;
+                               pd->regoff   = stacksize * 8;
                                stacksize++;
                        }
                        break;
+
                case TYPE_FLT:
                case TYPE_DBL:
-                       if (i < FLT_ARG_CNT) {
+                       if (reguse < FLT_ARG_CNT) {
                                pd->inmemory = false;
-                               pd->regoff = reguse;
+                               pd->index    = reguse;
+                               pd->regoff   = abi_registers_float_argument[reguse];
                                reguse++;
                                md->argfltreguse = reguse;
-                       } else {
+                       }
+                       else {
                                pd->inmemory = true;
-                               pd->regoff = stacksize;
+                               pd->index    = stacksize;
+                               pd->regoff   = stacksize * 8;
                                stacksize++;
                        }
                        break;
                }
+
+               /* register type is the same as java type */
+
+               pd->type = md->paramtypes[i].type;
        }
 
+# else /* !defined(ENABLE_SOFT_FLOAT) */
+#  error never actually tested!
+
+       for (i = 0; i < md->paramcount; i++, pd++) {
+               switch (md->paramtypes[i].type) {
+               case TYPE_INT:
+               case TYPE_ADR:
+               case TYPE_FLT:
+                       pd->type = TYPE_INT;
+
+                       if (reguse < INT_ARG_CNT) {
+                               pd->inmemory = false;
+                               pd->regoff   = abi_registers_integer_argument[reguse];
+                               reguse++;
+                               md->argintreguse = reguse;
+                       }
+                       else {
+                               pd->inmemory = true;
+                               pd->regoff   = stacksize * 8;
+                       }
+                       stacksize++;
+                       break;
+
+               case TYPE_LNG:
+               case TYPE_DBL:
+                       pd->type = TYPE_LNG;
+
+                       if (reguse < INT_ARG_CNT) {
+                               pd->inmemory = false;
+#  if WORDS_BIGENDIAN == 1
+                               pd->regoff   =
+                                       PACK_REGS(abi_registers_integer_argument[reguse + 1],
+                                                         abi_registers_integer_argument[reguse]);
+#  else
+                               pd->regoff   =
+                                       PACK_REGS(abi_registers_integer_argument[reguse],
+                                                         abi_registers_integer_argument[reguse + 1]);
+#  endif
+                               reguse += 2;
+                               md->argintreguse = reguse;
+                       }
+                       else {
+                               pd->inmemory = true;
+                               pd->regoff   = stacksize * 8;
+                       }
+                       stacksize += 2;
+                       break;
+               }
+       }
+
+# endif /* !defined(ENABLE_SOFT_FLOAT) */
+#endif /* SIZEOF_VOID_P == 8 */
+
        /* fill register and stack usage */
 
        md->memuse = stacksize;
 }
 
 
+/* md_param_alloc_native *******************************************************
+
+   Pre-allocate arguments according the native ABI.
+
+*******************************************************************************/
+
+void md_param_alloc_native(methoddesc *md)
+{
+#if SIZEOF_VOID_P == 8
+
+       /* On MIPS n64 we use the same ABI for JIT method calls as for
+          native method calls. */
+
+       md_param_alloc(md);
+
+#else /* SIZEOF_VOID_P == 8 */
+
+       paramdesc *pd;
+       s4         i;
+       s4         reguse;
+       s4         stacksize;
+# if !defined(ENABLE_SOFT_FLOAT)
+       s4         t;
+       bool       a0_is_float;
+# endif
+
+       /* set default values */
+
+       reguse      = 0;
+       stacksize   = 0;
+# if !defined(ENABLE_SOFT_FLOAT)
+       a0_is_float = false;
+# endif
+
+       /* get params field of methoddesc */
+
+       pd = md->params;
+
+# if !defined(ENABLE_SOFT_FLOAT)
+
+       for (i = 0; i < md->paramcount; i++, pd++) {
+               t = md->paramtypes[i].type;
+
+               if (IS_FLT_DBL_TYPE(t) &&
+                       ((i == 0) ||
+                        ((i == 1) && IS_FLT_DBL_TYPE(md->paramtypes[0].type)))) {
+                       if (IS_2_WORD_TYPE(t)) {
+                               pd->type   = TYPE_DBL;
+                               pd->regoff = abi_registers_float_argument[reguse];
+                               reguse++;
+                               stacksize += 2;
+                       }
+                       else {
+                               pd->type   = TYPE_FLT;
+                               pd->regoff = abi_registers_float_argument[reguse];
+                               reguse++;
+                               stacksize++;
+                       }
+                       md->argfltreguse = reguse;
+                       a0_is_float = true;
+               }
+               else {
+                       if (IS_2_WORD_TYPE(t)) {
+                               ALIGN_2(reguse);
+                               pd->type = TYPE_LNG;
+
+                               if (reguse < INT_ARG_CNT) {
+                                       pd->inmemory = false;
+#  if WORDS_BIGENDIAN == 1
+                                       pd->regoff   =
+                                               PACK_REGS(abi_registers_integer_argument[reguse + 1],
+                                                                 abi_registers_integer_argument[reguse]);
+#  else
+                                       pd->regoff   =
+                                               PACK_REGS(abi_registers_integer_argument[reguse],
+                                                                 abi_registers_integer_argument[reguse + 1]);
+#  endif
+                                       reguse += 2;
+                                       md->argintreguse = reguse;
+                               }
+                               else {
+                                       ALIGN_2(stacksize);
+
+                                       pd->inmemory = true;
+                                       pd->regoff   = stacksize * 4;
+                               }
+                               stacksize += 2;
+                       }
+                       else {
+                               pd->type = TYPE_INT;
+
+                               if (reguse < INT_ARG_CNT) {
+                                       pd->inmemory = false;
+                                       pd->regoff   = abi_registers_integer_argument[reguse];
+                                       reguse++;
+                                       md->argintreguse = reguse;
+                               }
+                               else {
+                                       pd->inmemory = true;
+                                       pd->regoff   = stacksize * 4;
+                               }
+                               stacksize++;
+                       }
+               }
+       }
+
+# else /* !defined(ENABLE_SOFT_FLOAT) */
+#  error never actually tested!
+
+       for (i = 0; i < md->paramcount; i++, pd++) {
+               switch (md->paramtypes[i].type) {
+               case TYPE_INT:
+               case TYPE_ADR:
+               case TYPE_FLT:
+                       pd->type = TYPE_INT;
+
+                       if (i < INT_ARG_CNT) {
+                               pd->inmemory = false;
+                               pd->regoff   = abi_registers_integer_argument[reguse];
+                               reguse++;
+                               md->argintreguse = reguse;
+                       }
+                       else {
+                               pd->inmemory = true;
+                               pd->regoff   = stacksize * 4;
+                       }
+                       stacksize++;
+                       break;
+               case TYPE_LNG:
+               case TYPE_DBL:
+                       pd->type = TYPE_LNG;
+
+                       if (i < INT_ARG_CNT) {
+                               pd->inmemory = false;
+#  if WORDS_BIGENDIAN == 1
+                               pd->regoff   =
+                                       PACK_REGS(abi_registers_integer_argument[reguse + 1],
+                                                         abi_registers_integer_argument[reguse]);
+#  else
+                               pd->regoff   =
+                                       PACK_REGS(abi_registers_integer_argument[reguse],
+                                                         abi_registers_integer_argument[reguse + 1]);
+#  endif
+                               reguse += 2;
+                               md->argintreguse = reguse;
+                       }
+                       else {
+                               pd->inmemory = true;
+                               pd->regoff   = stacksize * 4;
+                       }
+                       stacksize += 2;
+                       break;
+               }
+       }
+
+# endif /* !defined(ENABLE_SOFT_FLOAT) */
+
+       /* fill register and stack usage */
+
+       md->memuse = stacksize;
+
+#endif /* SIZEOF_VOID_P == 8 */
+}
+
+
 /* md_return_alloc *************************************************************
 
    Precolor the Java Stackelement containing the Return Value. Since
@@ -201,7 +640,7 @@ void md_param_alloc(methoddesc *md)
 
 *******************************************************************************/
 
-void md_return_alloc(jitdata *jd, stackptr stackslot)
+void md_return_alloc(jitdata *jd, stackelement_t *stackslot)
 {
        methodinfo *m;
        methoddesc *md;
@@ -216,11 +655,16 @@ void md_return_alloc(jitdata *jd, stackptr stackslot)
           not to survive method invokations. */
 
        if (!(stackslot->flags & SAVEDVAR)) {
-
                VAR(stackslot->varnum)->flags = PREALLOC;
 
-               if (IS_INT_LNG_TYPE(md->returntype.type))
-                       VAR(stackslot->varnum)->vv.regoff = REG_RESULT;
+               if (IS_INT_LNG_TYPE(md->returntype.type)) {
+#if SIZEOF_VOID_P == 4
+                       if (IS_2_WORD_TYPE(md->returntype.type))
+                               VAR(stackslot->varnum)->vv.regoff = REG_RESULT_PACKED;
+                       else
+#endif
+                               VAR(stackslot->varnum)->vv.regoff = REG_RESULT;
+               }
                else
                        VAR(stackslot->varnum)->vv.regoff = REG_FRESULT;
        }
@@ -238,4 +682,5 @@ void md_return_alloc(jitdata *jd, stackptr stackslot)
  * c-basic-offset: 4
  * tab-width: 4
  * End:
+ * vim:noexpandtab:sw=4:ts=4:
  */