-/* jit/alpha/codegen.h - code generation macros and definitions for alpha
+/* vm/jit/alpha/codegen.h - code generation macros and definitions for Alpha
- Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
- 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, 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
This file is part of CACAO.
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., 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA.
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
- Contact: cacao@complang.tuwien.ac.at
-
- Authors: Andreas Krall
- Reinhard Grafl
-
- $Id: codegen.h 557 2003-11-02 22:51:59Z twisti $
+ $Id: codegen.h 7596 2007-03-28 21:05:53Z twisti $
*/
#ifndef _CODEGEN_H
#define _CODEGEN_H
-#include "jit.h"
+#include "config.h"
+#include "vm/types.h"
+#include "vm/jit/jit.h"
-/* see also file calling.doc for explanation of calling conventions */
-/* preallocated registers *****************************************************/
+/* additional functions and macros to generate code ***************************/
-/* integer registers */
-
-#define REG_RESULT 0 /* to deliver method results */
+#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_add_arrayindexoutofboundsexception_ref(cd, s2); \
+ }
-#define REG_RA 26 /* return address */
-#define REG_PV 27 /* procedure vector, must be provided by caller */
-#define REG_METHODPTR 28 /* pointer to the place from where the procedure */
- /* vector has been fetched */
-#define REG_ITMP1 25 /* temporary register */
-#define REG_ITMP2 28 /* temporary register and method pointer */
-#define REG_ITMP3 29 /* temporary register */
-#define REG_ITMP1_XPTR 25 /* exception pointer = temporary register 1 */
-#define REG_ITMP2_XPC 28 /* exception pc = temporary register 2 */
+/* MCODECHECK(icnt) */
-#define REG_SP 30 /* stack pointer */
-#define REG_ZERO 31 /* allways zero */
+#define MCODECHECK(icnt) \
+ do { \
+ if ((cd->mcodeptr + (icnt) * 4) > cd->mcodeend) \
+ codegen_increase(cd); \
+ } while (0)
-/* floating point registers */
-#define REG_FRESULT 0 /* to deliver floating point method results */
-#define REG_FTMP1 28 /* temporary floating point register */
-#define REG_FTMP2 29 /* temporary floating point register */
-#define REG_FTMP3 30 /* temporary floating point register */
+#define ALIGNCODENOP \
+ if ((s4) ((ptrint) cd->mcodeptr & 7)) { \
+ M_NOP; \
+ }
-#define REG_IFTMP 28 /* 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) */
+/* 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 REG_END -1 last entry in tables */
-
-int nregdescint[] = {
- REG_RET, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP,
- REG_TMP, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV,
- REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_TMP, REG_TMP,
- REG_TMP, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES,
- REG_END };
+#define M_INTMOVE(a,b) \
+ do { \
+ if ((a) != (b)) \
+ M_MOV(a, b); \
+ } while (0)
-#define INT_SAV_CNT 7 /* number of int callee saved registers */
-#define INT_ARG_CNT 6 /* number of int argument registers */
-/* for use of reserved registers, see comment above */
-
-int nregdescfloat[] = {
- REG_RET, REG_TMP, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV,
- REG_SAV, REG_SAV, 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_TMP, REG_TMP,
- REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_RES, REG_RES, REG_RES, REG_RES,
- REG_END };
+/* 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 FLT_SAV_CNT 8 /* number of flt callee saved registers */
-#define FLT_ARG_CNT 6 /* number of flt argument registers */
+#define M_FLTMOVE(a,b) \
+ do { \
+ if ((a) != (b)) \
+ M_FMOV(a, b); \
+ } while (0)
-/* for use of reserved registers, see comment above */
+#define ICONST(d,c) emit_iconst(cd, (d), (c))
+#define LCONST(d,c) emit_lconst(cd, (d), (c))
-/* parameter allocation mode */
-int nreg_parammode = PARAMMODE_NUMBERED;
+/* branch defines *************************************************************/
- /* parameter-registers will be allocated by assigning the
- 1. parameter: int/float-reg 16
- 2. parameter: int/float-reg 17
- 3. parameter: int/float-reg 18 ....
- */
+#define BRANCH_NOPS \
+ do { \
+ M_NOP; \
+ } while (0)
-/* stackframe-infos ***********************************************************/
+/* patcher defines ************************************************************/
-int parentargs_base; /* offset in stackframe for the parameter from the caller*/
+#define PATCHER_CALL_SIZE 1 * 4 /* an instruction is 4-bytes long */
-/* -> see file 'calling.doc' */
+#define PATCHER_NOPS \
+ do { \
+ M_NOP; \
+ } while (0)
/* macros to create code ******************************************************/
(REG means: use b as register number)
(CONST means: use b as constant 8-bit-integer)
*/
+
#define M_OP3(op,fu,a,b,c,const) \
- *(mcodeptr++) = ( (((s4)(op))<<26)|((a)<<21)|((b)<<(16-3*(const)))| \
- ((const)<<12)|((fu)<<5)|((c)) )
+ do { \
+ *((u4 *) cd->mcodeptr) = ((((s4) (op)) << 26) | ((a) << 21) | ((b) << (16 - 3 * (const))) | ((const) << 12) | ((fu) << 5) | ((c))); \
+ cd->mcodeptr += 4; \
+ } while (0)
+
/* 3-address-floating-point-operation: M_FOP3
op .... opcode
a,b ... source floating-point registers
c ..... destination register
*/
+
#define M_FOP3(op,fu,a,b,c) \
- *(mcodeptr++) = ( (((s4)(op))<<26)|((a)<<21)|((b)<<16)|((fu)<<5)|(c) )
+ do { \
+ *((u4 *) cd->mcodeptr) = ((((s4) (op)) << 26) | ((a) << 21) | ((b) << 16) | ((fu) << 5) | (c)); \
+ cd->mcodeptr += 4; \
+ } while (0)
+
/* branch instructions: M_BRA
op ..... opcode
a ...... register to be tested
disp ... relative address to be jumped to (divided by 4)
*/
+
#define M_BRA(op,a,disp) \
- *(mcodeptr++) = ( (((s4)(op))<<26)|((a)<<21)|((disp)&0x1fffff) )
+ do { \
+ *((u4 *) cd->mcodeptr) = ((((s4) (op)) << 26) | ((a) << 21) | ((disp) & 0x1fffff)); \
+ cd->mcodeptr += 4; \
+ } while (0)
/* memory operations: M_MEM
b ...... base register
disp ... displacement (16 bit signed) to be added to b
*/
+
#define M_MEM(op,a,b,disp) \
- *(mcodeptr++) = ( (((s4)(op))<<26)|((a)<<21)|((b)<<16)|((disp)&0xffff) )
+ do { \
+ *((u4 *) cd->mcodeptr) = ((((s4) (op)) << 26) | ((a) << 21) | ((b) << 16) | ((disp) & 0xffff)); \
+ cd->mcodeptr += 4; \
+ } while (0)
+
+#define M_MEM_GET_A(x) (((x) >> 21) & 0x1f )
+#define M_MEM_GET_B(x) (((x) >> 16) & 0x1f )
+#define M_MEM_GET_DISP(x) ( (x) & 0xffff)
+
+/* macros for all used commands (see an Alpha-manual for description) *********/
-/* macros for all used commands (see an Alpha-manual for description) *********/
+#define M_LDA_INTERN(a,b,disp) M_MEM(0x08,a,b,disp) /* low const */
+
+#define M_LDA(a,b,disp) \
+ do { \
+ s4 lo = (short) (disp); \
+ s4 hi = (short) (((disp) - lo) >> 16); \
+ if (hi == 0) { \
+ M_LDA_INTERN(a,b,lo); \
+ } else { \
+ M_LDAH(a,b,hi); \
+ M_LDA_INTERN(a,a,lo); \
+ } \
+ } while (0)
-#define M_LDA(a,b,disp) M_MEM (0x08,a,b,disp) /* low const */
#define M_LDAH(a,b,disp) M_MEM (0x09,a,b,disp) /* high const */
+
#define M_BLDU(a,b,disp) M_MEM (0x0a,a,b,disp) /* 8 load */
#define M_SLDU(a,b,disp) M_MEM (0x0c,a,b,disp) /* 16 load */
-#define M_ILD(a,b,disp) M_MEM (0x28,a,b,disp) /* 32 load */
-#define M_LLD(a,b,disp) M_MEM (0x29,a,b,disp) /* 64 load */
-#define M_ALD(a,b,disp) M_MEM (0x29,a,b,disp) /* addr load */
-#define M_BST(a,b,disp) M_MEM (0x0e,a,b,disp) /* 8 store */
-#define M_SST(a,b,disp) M_MEM (0x0d,a,b,disp) /* 16 store */
-#define M_IST(a,b,disp) M_MEM (0x2c,a,b,disp) /* 32 store */
-#define M_LST(a,b,disp) M_MEM (0x2d,a,b,disp) /* 64 store */
-#define M_AST(a,b,disp) M_MEM (0x2d,a,b,disp) /* addr store */
+
+#define M_ILD_INTERN(a,b,disp) M_MEM(0x28,a,b,disp) /* 32 load */
+#define M_LLD_INTERN(a,b,disp) M_MEM(0x29,a,b,disp) /* 64 load */
+
+#define M_ILD(a,b,disp) \
+ do { \
+ s4 lo = (short) (disp); \
+ s4 hi = (short) (((disp) - lo) >> 16); \
+ if (hi == 0) { \
+ M_ILD_INTERN(a,b,lo); \
+ } else { \
+ M_LDAH(a,b,hi); \
+ M_ILD_INTERN(a,a,lo); \
+ } \
+ } while (0)
+
+#define M_LLD(a,b,disp) \
+ do { \
+ s4 lo = (short) (disp); \
+ s4 hi = (short) (((disp) - lo) >> 16); \
+ if (hi == 0) { \
+ M_LLD_INTERN(a,b,lo); \
+ } else { \
+ M_LDAH(a,b,hi); \
+ M_LLD_INTERN(a,a,lo); \
+ } \
+ } while (0)
+
+#define M_ALD_INTERN(a,b,disp) M_LLD_INTERN(a,b,disp)
+#define M_ALD(a,b,disp) M_LLD(a,b,disp) /* addr load */
+
+#define M_BST(a,b,disp) M_MEM(0x0e,a,b,disp) /* 8 store */
+#define M_SST(a,b,disp) M_MEM(0x0d,a,b,disp) /* 16 store */
+
+#define M_IST_INTERN(a,b,disp) M_MEM(0x2c,a,b,disp) /* 32 store */
+#define M_LST_INTERN(a,b,disp) M_MEM(0x2d,a,b,disp) /* 64 store */
+
+/* Stores with displacement overflow should only happen with PUTFIELD or on */
+/* the stack. The PUTFIELD instruction does not use REG_ITMP3 and a */
+/* reg_of_var call should not use REG_ITMP3!!! */
+
+#define M_IST(a,b,disp) \
+ do { \
+ s4 lo = (short) (disp); \
+ s4 hi = (short) (((disp) - lo) >> 16); \
+ if (hi == 0) { \
+ M_IST_INTERN(a,b,lo); \
+ } else { \
+ M_LDAH(REG_ITMP3,b,hi); \
+ M_IST_INTERN(a,REG_ITMP3,lo); \
+ } \
+ } while (0)
+
+#define M_LST(a,b,disp) \
+ do { \
+ s4 lo = (short) (disp); \
+ s4 hi = (short) (((disp) - lo) >> 16); \
+ if (hi == 0) { \
+ M_LST_INTERN(a,b,lo); \
+ } else { \
+ M_LDAH(REG_ITMP3,b,hi); \
+ M_LST_INTERN(a,REG_ITMP3,lo); \
+ } \
+ } while (0)
+
+#define M_AST(a,b,disp) M_LST(a,b,disp) /* addr store */
#define M_BSEXT(b,c) M_OP3 (0x1c,0x0,REG_ZERO,b,c,0) /* 8 signext */
#define M_SSEXT(b,c) M_OP3 (0x1c,0x1,REG_ZERO,b,c,0) /* 16 signext */
#define M_IMUL_IMM(a,b,c) M_OP3 (0x13,0x00, a,b,c,1) /* 32 mul */
#define M_LMUL_IMM(a,b,c) M_OP3 (0x13,0x20, a,b,c,1) /* 64 mul */
+#define M_AADD_IMM(a,b,c) M_LADD_IMM(a,b,c)
+#define M_ASUB_IMM(a,b,c) M_LSUB_IMM(a,b,c)
+
#define M_CMPEQ(a,b,c) M_OP3 (0x10,0x2d, a,b,c,0) /* c = a == b */
#define M_CMPLT(a,b,c) M_OP3 (0x10,0x4d, a,b,c,0) /* c = a < b */
#define M_CMPLE(a,b,c) M_OP3 (0x10,0x6d, a,b,c,0) /* c = a <= b */
#define M_SRA_IMM(a,b,c) M_OP3 (0x12,0x3c, a,b,c,1) /* c = a >> b */
#define M_SRL_IMM(a,b,c) M_OP3 (0x12,0x34, a,b,c,1) /* c = a >>>b */
-#define M_FLD(a,b,disp) M_MEM (0x22,a,b,disp) /* load flt */
-#define M_DLD(a,b,disp) M_MEM (0x23,a,b,disp) /* load dbl */
-#define M_FST(a,b,disp) M_MEM (0x26,a,b,disp) /* store flt */
-#define M_DST(a,b,disp) M_MEM (0x27,a,b,disp) /* store dbl */
+#define M_FLD_INTERN(a,b,disp) M_MEM(0x22,a,b,disp) /* load flt */
+#define M_DLD_INTERN(a,b,disp) M_MEM(0x23,a,b,disp) /* load dbl */
+
+#define M_FLD(a,b,disp) \
+ do { \
+ s4 lo = (short) (disp); \
+ s4 hi = (short) (((disp) - lo) >> 16); \
+ if (hi == 0) { \
+ M_FLD_INTERN(a,b,lo); \
+ } else { \
+ M_LDAH(REG_ITMP3,b,hi); \
+ M_FLD_INTERN(a,REG_ITMP3,lo); \
+ } \
+ } while (0)
+
+#define M_DLD(a,b,disp) \
+ do { \
+ s4 lo = (short) (disp); \
+ s4 hi = (short) (((disp) - lo) >> 16); \
+ if (hi == 0) { \
+ M_DLD_INTERN(a,b,lo); \
+ } else { \
+ M_LDAH(REG_ITMP3,b,hi); \
+ M_DLD_INTERN(a,REG_ITMP3,lo); \
+ } \
+ } while (0)
+
+#define M_FST_INTERN(a,b,disp) M_MEM(0x26,a,b,disp) /* store flt */
+#define M_DST_INTERN(a,b,disp) M_MEM(0x27,a,b,disp) /* store dbl */
+
+/* Stores with displacement overflow should only happen with PUTFIELD or on */
+/* the stack. The PUTFIELD instruction does not use REG_ITMP3 and a */
+/* reg_of_var call should not use REG_ITMP3!!! */
+
+#define M_FST(a,b,disp) \
+ do { \
+ s4 lo = (short) (disp); \
+ s4 hi = (short) (((disp) - lo) >> 16); \
+ if (hi == 0) { \
+ M_FST_INTERN(a,b,lo); \
+ } else { \
+ M_LDAH(REG_ITMP3,b,hi); \
+ M_FST_INTERN(a,REG_ITMP3,lo); \
+ } \
+ } while (0)
+
+#define M_DST(a,b,disp) \
+ do { \
+ s4 lo = (short) (disp); \
+ s4 hi = (short) (((disp) - lo) >> 16); \
+ if (hi == 0) { \
+ M_DST_INTERN(a,b,lo); \
+ } else { \
+ M_LDAH(REG_ITMP3,b,hi); \
+ M_DST_INTERN(a,REG_ITMP3,lo); \
+ } \
+ } while (0)
+
#define M_FADD(a,b,c) M_FOP3 (0x16, 0x080, a,b,c) /* flt add */
#define M_DADD(a,b,c) M_FOP3 (0x16, 0x0a0, a,b,c) /* dbl add */
#define M_FDIVS(a,b,c) M_FOP3 (0x16, 0x583, a,b,c) /* flt div */
#define M_DDIVS(a,b,c) M_FOP3 (0x16, 0x5a3, a,b,c) /* dbl div */
-#define M_CVTDF(b,c) M_FOP3 (0x16, 0x0ac, 31,b,c) /* dbl2long */
+#define M_CVTDF(b,c) M_FOP3 (0x16, 0x0ac, 31,b,c) /* dbl2flt */
#define M_CVTLF(b,c) M_FOP3 (0x16, 0x0bc, 31,b,c) /* long2flt */
#define M_CVTLD(b,c) M_FOP3 (0x16, 0x0be, 31,b,c) /* long2dbl */
#define M_CVTDL(b,c) M_FOP3 (0x16, 0x1af, 31,b,c) /* dbl2long */
#define M_CVTDL_C(b,c) M_FOP3 (0x16, 0x12f, 31,b,c) /* dbl2long */
#define M_CVTLI(b,c) M_FOP3 (0x17, 0x130, 31,b,c) /* long2int */
-#define M_CVTDFS(b,c) M_FOP3 (0x16, 0x5ac, 31,b,c) /* dbl2long */
+#define M_CVTDFS(b,c) M_FOP3 (0x16, 0x5ac, 31,b,c) /* dbl2flt */
+#define M_CVTFDS(b,c) M_FOP3 (0x16, 0x6ac, 31,b,c) /* flt2dbl */
#define M_CVTDLS(b,c) M_FOP3 (0x16, 0x5af, 31,b,c) /* dbl2long */
#define M_CVTDL_CS(b,c) M_FOP3 (0x16, 0x52f, 31,b,c) /* dbl2long */
#define M_CVTLIS(b,c) M_FOP3 (0x17, 0x530, 31,b,c) /* long2int */
#define M_CMOVLE_IMM(a,b,c) M_OP3 (0x11,0x64, a,b,c,1) /* a<=0 ? c=b */
#define M_CMOVGT_IMM(a,b,c) M_OP3 (0x11,0x66, a,b,c,1) /* a> 0 ? c=b */
-/* macros for unused commands (see an Alpha-manual for description) ***********/
+/* macros for unused commands (see an Alpha-manual for description) ***********/
#define M_ANDNOT(a,b,c,const) M_OP3 (0x11,0x08, a,b,c,const) /* c = a &~ b */
#define M_ORNOT(a,b,c,const) M_OP3 (0x11,0x28, a,b,c,const) /* c = a |~ b */
#define M_JMP_CO(a,b) M_MEM (0x1a,a,b,0xc000) /* call cosub */
-
-/* function gen_resolvebranch **************************************************
-
- backpatches a branch instruction; Alpha branch instructions are very
- regular, so it is only necessary to overwrite some fixed bits in the
- instruction.
-
- parameters: ip ... pointer to instruction after branch (void*)
- so ... offset of instruction after branch (s4)
- to ... offset of branch target (s4)
-
-*******************************************************************************/
-
-#define gen_resolvebranch(ip,so,to) ((s4*)(ip))[-1]|=((s4)(to)-(so))>>2&0x1fffff
-
-#define SOFTNULLPTRCHECK /* soft null pointer check supportet as option */
-
#endif /* _CODEGEN_H */