-/* jit/mips/codegen.h - code generation macros and definitions for mips
+/* vm/jit/mips/codegen.h - code generation macros and definitions for mips
- Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
- Institut f. Computersprachen, TU Wien
- R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
- M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
- P. Tomsich, J. Wenninger
+ Copyright (C) 1996-2005 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
This file is part of CACAO.
Authors: Andreas Krall
- $Id: codegen.h 564 2003-11-03 15:47:13Z twisti $
+ $Id: codegen.h 1735 2004-12-07 14:33:27Z twisti $
*/
#ifndef _CODEGEN_H
#define _CODEGEN_H
-#include "jit.h"
+#include "vm/jit/mips/types.h"
-/* see also file calling.doc for explanation of calling conventions */
+/* additional functions and macros to generate code ***************************/
-/* preallocated registers *****************************************************/
+/* #define BlockPtrOfPC(pc) block+block_index[pc] */
+#define BlockPtrOfPC(pc) ((basicblock *) iptr->target)
-/* integer registers */
-
-#define REG_ZERO 0 /* allways zero */
-
-#define REG_RESULT 2 /* to deliver method results */
-
-#define REG_ITMP1 1 /* temporary register */
-#define REG_ITMP2 3 /* temporary register and method pointer */
-#define REG_ITMP3 25 /* temporary register */
-
-#define REG_ARG_0 4 /* argument register */
-#define REG_ARG_1 5 /* argument register */
-#define REG_ARG_2 6 /* argument register */
-#define REG_ARG_3 7 /* argument register */
-#define REG_ARG_4 8 /* argument register */
-#define REG_ARG_5 9 /* argument register */
-
-#define REG_RA 31 /* return address */
-#define REG_SP 29 /* stack pointer */
-#define REG_GP 28 /* global pointer */
-
-#define REG_PV 30 /* procedure vector, must be provided by caller */
-#define REG_METHODPTR 25 /* pointer to the place from where the procedure */
- /* vector has been fetched */
-#define REG_ITMP1_XPTR 1 /* exception pointer = temporary register 1 */
-#define REG_ITMP2_XPC 3 /* exception pc = temporary register 2 */
-
-/* floating point registers */
-
-#define REG_FRESULT 0 /* to deliver floating point method results */
-#define REG_FTMP1 1 /* temporary floating point register */
-#define REG_FTMP2 2 /* temporary floating point register */
-#define REG_FTMP3 3 /* temporary floating point register */
-
-#define REG_IFTMP 1 /* temporary integer and floating point register */
-
-/* register descripton - array ************************************************/
-
-/* #define REG_RES 0 reserved register for OS or code generator */
-/* #define REG_RET 1 return value register */
-/* #define REG_EXC 2 exception value register (only old jit) */
-/* #define REG_SAV 3 (callee) saved register */
-/* #define REG_TMP 4 scratch temporary register (caller saved) */
-/* #define REG_ARG 5 argument register (caller saved) */
-
-/* #define REG_END -1 last entry in tables */
-
-int nregdescint[] = {
- REG_RES, REG_RES, REG_RET, REG_RES, REG_ARG, REG_ARG, REG_ARG, REG_ARG,
- REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_TMP, REG_TMP, REG_TMP, REG_TMP,
- REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV,
- REG_TMP, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES,
- REG_END };
-
-#define INT_SAV_CNT 8 /* number of int callee saved registers */
-#define INT_ARG_CNT 8 /* number of int argument registers */
-
-/* for use of reserved registers, see comment above */
-
-int nregdescfloat[] = {
- REG_RET, REG_RES, REG_RES, REG_RES, REG_TMP, REG_TMP, REG_TMP, REG_TMP,
- REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_ARG, REG_ARG, REG_ARG, REG_ARG,
- REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_TMP, REG_TMP, REG_TMP, REG_TMP,
- REG_SAV, REG_TMP, REG_SAV, REG_TMP, REG_SAV, REG_TMP, REG_SAV, REG_TMP,
- REG_END };
-
-#define FLT_SAV_CNT 4 /* number of flt callee saved registers */
-#define FLT_ARG_CNT 8 /* number of flt argument registers */
-
-/* for use of reserved registers, see comment above */
-
-
-/* parameter allocation mode */
-
-int nreg_parammode = PARAMMODE_NUMBERED;
-
- /* parameter-registers will be allocated by assigning the
- 1. parameter: int/float-reg a0
- 2. parameter: int/float-reg a1
- 3. parameter: int/float-reg a2 ....
- */
+#ifdef STATISTICS
+#define COUNT_SPILLS count_spills++
+#else
+#define COUNT_SPILLS
+#endif
-/* stackframe-infos ***********************************************************/
-int parentargs_base; /* offset in stackframe for the parameter from the caller*/
+/* gen_nullptr_check(objreg) */
+
+#define gen_nullptr_check(objreg) \
+ if (checknull) { \
+ M_BEQZ((objreg), 0); \
+ codegen_addxnullrefs(cd, mcodeptr); \
+ M_NOP; \
+ }
+
+#define gen_bound_check \
+ if (checkbounds) { \
+ M_ILD(REG_ITMP3, s1, OFFSET(java_arrayheader, size)); \
+ M_CMPULT(s2, REG_ITMP3, REG_ITMP3); \
+ M_BEQZ(REG_ITMP3, 0); \
+ codegen_addxboundrefs(cd, mcodeptr, s2); \
+ M_NOP; \
+ }
+
+
+/* MCODECHECK(icnt) */
+
+#define MCODECHECK(icnt) \
+ if ((mcodeptr + (icnt)) > cd->mcodeend) \
+ mcodeptr = codegen_increase(cd, (u1 *) mcodeptr)
+
+
+#define ALIGNCODENOP \
+ if ((int) ((long) mcodeptr & 7)) { \
+ M_NOP; \
+ }
+
+
+/* M_INTMOVE:
+ generates an integer-move from register a to b.
+ if a and b are the same int-register, no code will be generated.
+*/
+
+#define M_INTMOVE(a,b) if (a != b) { M_MOV(a, b); }
+
+
+/* M_FLTMOVE:
+ generates a floating-point-move from register a to b.
+ if a and b are the same float-register, no code will be generated
+*/
+
+#define M_FLTMOVE(a,b) if (a != b) { M_DMOV(a, b); }
+
+#define M_TFLTMOVE(t,a,b) \
+ {if(a!=b) \
+ if ((t)==TYPE_DBL) \
+ {M_DMOV(a,b);} \
+ else {M_FMOV(a,b);} \
+ }
+
+#define M_TFLD(t,a,b,disp) \
+ if ((t)==TYPE_DBL) \
+ {M_DLD(a,b,disp);} \
+ else \
+ {M_FLD(a,b,disp);}
+
+#define M_TFST(t,a,b,disp) \
+ if ((t)==TYPE_DBL) \
+ {M_DST(a,b,disp);} \
+ else \
+ {M_FST(a,b,disp);}
+
+#define M_CCFLTMOVE(t1,t2,a,b) \
+ if ((t1)==(t2)) \
+ {M_TFLTMOVE(t1,a,b);} \
+ else \
+ if ((t1)==TYPE_DBL) \
+ {M_CVTDF(a,b);} \
+ else \
+ {M_CVTFD(a,b);}
+
+#define M_CCFLD(t1,t2,a,b,disp) \
+ if ((t1)==(t2)) \
+ {M_DLD(a,b,disp);} \
+ else { \
+ M_DLD(REG_FTMP1,b,disp); \
+ if ((t1)==TYPE_DBL) \
+ {M_CVTDF(REG_FTMP1,a);} \
+ else \
+ {M_CVTFD(REG_FTMP1,a);} \
+ }
+
+#define M_CCFST(t1,t2,a,b,disp) \
+ if ((t1)==(t2)) \
+ {M_DST(a,b,disp);} \
+ else { \
+ if ((t1)==TYPE_DBL) \
+ {M_CVTDF(a,REG_FTMP1);} \
+ else \
+ {M_CVTFD(a,REG_FTMP1);} \
+ M_DST(REG_FTMP1,b,disp); \
+ }
+
+
+/* var_to_reg_xxx:
+ this function generates code to fetch data from a pseudo-register
+ into a real register.
+ If the pseudo-register has actually been assigned to a real
+ register, no code will be emitted, since following operations
+ can use this register directly.
+
+ v: pseudoregister to be fetched from
+ tempregnum: temporary register to be used if v is actually spilled to ram
+
+ return: the register number, where the operand can be found after
+ fetching (this wil be either tempregnum or the register
+ number allready given to v)
+*/
-/* -> see file 'calling.doc' */
+#define var_to_reg_int(regnr,v,tempnr) { \
+ if ((v)->flags & INMEMORY) { \
+ COUNT_SPILLS; \
+ M_LLD(tempnr, REG_SP, 8 * (v)->regoff); \
+ regnr = tempnr; \
+ } else regnr = (v)->regoff; \
+}
+
+
+#define var_to_reg_flt(regnr,v,tempnr) { \
+ if ((v)->flags & INMEMORY) { \
+ COUNT_SPILLS; \
+ M_DLD(tempnr, REG_SP, 8 * (v)->regoff); \
+ regnr = tempnr; \
+ } else regnr = (v)->regoff; \
+}
+
+
+/* store_reg_to_var_xxx:
+ 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.
+
+ v ............ Pseudovariable
+ tempregnum ... Number of the temporary registers as returned by
+ reg_of_var.
+*/
+
+#define store_reg_to_var_int(sptr, tempregnum) { \
+ if ((sptr)->flags & INMEMORY) { \
+ COUNT_SPILLS; \
+ M_LST(tempregnum, REG_SP, 8 * (sptr)->regoff); \
+ } \
+ }
+
+#define store_reg_to_var_flt(sptr, tempregnum) { \
+ if ((sptr)->flags & INMEMORY) { \
+ COUNT_SPILLS; \
+ M_DST(tempregnum, REG_SP, 8 * (sptr)->regoff); \
+ } \
+ }
+
+
+#define M_COPY(from,to) \
+ d = reg_of_var(rd, to, REG_IFTMP); \
+ if ((from->regoff != to->regoff) || \
+ ((from->flags ^ to->flags) & INMEMORY)) { \
+ if (IS_FLT_DBL_TYPE(from->type)) { \
+ var_to_reg_flt(s1, from, d); \
+ M_TFLTMOVE(from->type, s1, d); \
+ store_reg_to_var_flt(to, d); \
+ } else { \
+ var_to_reg_int(s1, from, d); \
+ M_INTMOVE(s1, d); \
+ store_reg_to_var_int(to, d); \
+ } \
+ }
+
+
+#define ICONST(r,c) \
+ if ((c) >= -32768 && (c) <= 32767) { \
+ M_IADD_IMM(REG_ZERO, (c), (r)); \
+ } else if ((c) >= 0 && (c) <= 0xffff) { \
+ M_OR_IMM(REG_ZERO, (c), (r)); \
+ } else { \
+ a = dseg_adds4(cd, (c)); \
+ M_ILD((r), REG_PV, a); \
+ }
+
+#define LCONST(r,c) \
+ if ((c) >= -32768 && (c) <= 32767) { \
+ M_LADD_IMM(REG_ZERO, (c), (r)); \
+ } else if ((c) >= 0 && (c) <= 0xffff) { \
+ M_OR_IMM(REG_ZERO, (c), (r)); \
+ } else { \
+ a = dseg_adds8(cd, (c)); \
+ M_LLD((r), REG_PV, a); \
+ }
/* macros to create code ******************************************************/
#define M_MOVID(i,d) M_FP3(0,4,d,i,0) /* d = i */
#define M_MOVLD(l,d) M_FP3(0,5,d,l,0) /* d = l */
-#define M_DMFC1(l,f) M_FP3(0,1,f,l,0)
-#define M_DMTC1(l,f) M_FP3(0,5,f,l,0)
+#define M_DMFC1(l,f) M_FP3(0,1,f,l,0)
+#define M_DMTC1(l,f) M_FP3(0,5,f,l,0)
#define M_FCMPFF(a,b) M_FP3(0x30,FMT_F,a,b,0) /* c = a == b */
#define M_FCMPFD(a,b) M_FP3(0x30,FMT_D,a,b,0) /* c = a == b */
#define M_FCMPOLEF(a,b) M_FP3(0x36,FMT_F,a,b,0) /* c = a <= b */
#define M_FCMPOLED(a,b) M_FP3(0x36,FMT_D,a,b,0) /* c = a <= b */
#define M_FCMPULEF(a,b) M_FP3(0x37,FMT_F,a,b,0) /* c = a <= b */
-#define M_FCMPULE(a,b) M_FP3(0x37,FMT_D,a,b,0) /* c = a <= b */
+#define M_FCMPULED(a,b) M_FP3(0x37,FMT_D,a,b,0) /* c = a <= b */
#define M_FBF(disp) M_ITYPE(0x11,8,0,disp) /* br false */
#define M_FBT(disp) M_ITYPE(0x11,8,1,disp) /* br true */
#define M_FBFL(disp) M_ITYPE(0x11,8,2,disp) /* br false */
#define M_FBTL(disp) M_ITYPE(0x11,8,3,disp) /* br true */
+#define M_CMOVF(a,b) M_RTYPE(0x00,a,0,b,0,1)
+#define M_CMOVT(a,b) M_RTYPE(0x00,a,1,b,0,1)
+
/*
* Load Address pseudo instruction:
* -n32 addressing mode -> 32 bit addrs, -64 addressing mode -> 64 bit addrs
*******************************************************************************/
-#define gen_resolvebranch(ip,so,to) ((s4*)(ip))[-1]|=((s4)(to)-(so))>>2&0xffff
+#define gen_resolvebranch(ip,so,to) \
+ ((s4 *) (ip))[-1] |= ((s4) (to) - (so)) >> 2 & 0xffff
+
+
+/* function prototypes */
-#define SOFTNULLPTRCHECK /* soft null pointer check supportet as option */
+void docacheflush(u1 *p, long bytelen);
#endif /* _CODEGEN_H */