-/* jit/i386/codegen.h - code generation macros and definitions for i386
+/* vm/jit/i386/codegen.h - code generation macros and definitions for i386
- 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 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
Christian Thalinger
- $Id: codegen.h 776 2003-12-14 13:38:14Z twisti $
+ $Id: codegen.h 1735 2004-12-07 14:33:27Z twisti $
*/
#ifndef _CODEGEN_H
#define _CODEGEN_H
-#include "global.h"
-#include "jit.h"
+#include <ucontext.h>
-/* define x86 register numbers */
-#define EAX 0
-#define ECX 1
-#define EDX 2
-#define EBX 3
-#define ESP 4
-#define EBP 5
-#define ESI 6
-#define EDI 7
+/* additional functions and macros to generate code ***************************/
+#define BlockPtrOfPC(pc) ((basicblock *) iptr->target)
-/* preallocated registers *****************************************************/
-/* integer registers */
-
-#define REG_RESULT EAX /* to deliver method results */
-#define REG_RESULT2 EDX /* to deliver long method results */
+#ifdef STATISTICS
+#define COUNT_SPILLS count_spills++
+#else
+#define COUNT_SPILLS
+#endif
-#define REG_ITMP1 EAX /* temporary register */
-#define REG_ITMP2 ECX /* temporary register */
-#define REG_ITMP3 EDX /* temporary register */
-#define REG_NULL -1 /* used for reg_of_var where d is not needed */
+#define CALCOFFSETBYTES(var, reg, val) \
+ if ((s4) (val) < -128 || (s4) (val) > 127) (var) += 4; \
+ else if ((s4) (val) != 0) (var) += 1; \
+ else if ((reg) == EBP) (var) += 1;
-#define REG_ITMP1_XPTR EAX /* exception pointer = temporary register 1 */
-#define REG_ITMP2_XPC ECX /* exception pc = temporary register 2 */
-#define REG_SP ESP /* stack pointer */
+#define CALCIMMEDIATEBYTES(var, val) \
+ if ((s4) (val) < -128 || (s4) (val) > 127) (var) += 4; \
+ else (var) += 1;
-/* floating point registers */
-#define REG_FRESULT 0 /* to deliver floating point method results */
-#define REG_FTMP1 6 /* temporary floating point register */
-#define REG_FTMP2 7 /* temporary floating point register */
-#define REG_FTMP3 7 /* temporary floating point register */
+/* gen_nullptr_check(objreg) */
+#define gen_nullptr_check(objreg) \
+ if (checknull) { \
+ i386_test_reg_reg(cd, (objreg), (objreg)); \
+ i386_jcc(cd, I386_CC_E, 0); \
+ codegen_addxnullrefs(cd, cd->mcodeptr); \
+ }
-static u1 fpu_in_24bit_mode = 0;
+#define gen_bound_check \
+ if (checkbounds) { \
+ i386_alu_membase_reg(cd, I386_CMP, s1, OFFSET(java_arrayheader, size), s2); \
+ i386_jcc(cd, I386_CC_AE, 0); \
+ codegen_addxboundrefs(cd, cd->mcodeptr, s2); \
+ }
-static u2 fpu_ctrlwrd_24bit = 0x007f; /* Round to nearest, 24-bit mode, exceptions masked */
-static u2 fpu_ctrlwrd_53bit = 0x027f; /* Round to nearest, 53-bit mode, exceptions masked */
+#define gen_div_check(v) \
+ if (checknull) { \
+ if ((v)->flags & INMEMORY) { \
+ i386_alu_imm_membase(cd, I386_CMP, 0, REG_SP, src->regoff * 8); \
+ } else { \
+ i386_test_reg_reg(cd, src->regoff, src->regoff); \
+ } \
+ i386_jcc(cd, I386_CC_E, 0); \
+ codegen_addxdivrefs(cd, cd->mcodeptr); \
+ }
+
+
+/* MCODECHECK(icnt) */
+
+#define MCODECHECK(icnt) \
+ if ((cd->mcodeptr + (icnt)) > (u1 *) cd->mcodeend) \
+ cd->mcodeptr = (u1 *) codegen_increase(cd, cd->mcodeptr)
+
+
+/* XXX Do we need code padding on i386? */
+/* #define ALIGNCODENOP {if((int)((long)cd->mcodeptr&7)){M_NOP;}} */
+#define ALIGNCODENOP
+
+
+/* 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(reg,dreg) \
+ if ((reg) != (dreg)) { \
+ i386_mov_reg_reg(cd, (reg),(dreg)); \
+ }
-static u4 subnormal_bias1[3] = { 0x00000000, 0x80000000, 0x03ff }; /* 2^(-15360) */
-static u4 subnormal_bias2[3] = { 0x00000000, 0x80000000, 0x7bff }; /* 2^(+15360) */
+/* 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(reg,dreg) panic("M_FLTMOVE");
+
+#define M_LNGMEMMOVE(reg,dreg) \
+ do { \
+ i386_mov_membase_reg(cd, REG_SP, (reg) * 8, REG_ITMP1); \
+ i386_mov_reg_membase(cd, REG_ITMP1, REG_SP, (dreg) * 8); \
+ i386_mov_membase_reg(cd, REG_SP, (reg) * 8 + 4, REG_ITMP1); \
+ i386_mov_reg_membase(cd, REG_ITMP1, REG_SP, (dreg) * 8 + 4); \
+ } while (0)
+
+
+/* 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)
+*/
+
+#define var_to_reg_int(regnr,v,tempnr) \
+ if ((v)->flags & INMEMORY) { \
+ COUNT_SPILLS; \
+ i386_mov_membase_reg(cd, REG_SP, (v)->regoff * 8, tempnr); \
+ regnr = tempnr; \
+ } else { \
+ regnr = (v)->regoff; \
+ }
+
+
+
+#define var_to_reg_flt(regnr,v,tempnr) \
+ if ((v)->type == TYPE_FLT) { \
+ if ((v)->flags & INMEMORY) { \
+ COUNT_SPILLS; \
+ i386_flds_membase(cd, REG_SP, (v)->regoff * 8); \
+ fpu_st_offset++; \
+ regnr = tempnr; \
+ } else { \
+ i386_fld_reg(cd, (v)->regoff + fpu_st_offset); \
+ fpu_st_offset++; \
+ regnr = (v)->regoff; \
+ } \
+ } else { \
+ if ((v)->flags & INMEMORY) { \
+ COUNT_SPILLS; \
+ i386_fldl_membase(cd, REG_SP, (v)->regoff * 8); \
+ fpu_st_offset++; \
+ regnr = tempnr; \
+ } else { \
+ i386_fld_reg(cd, (v)->regoff + fpu_st_offset); \
+ fpu_st_offset++; \
+ regnr = (v)->regoff; \
+ } \
+ }
+
+#define NEW_var_to_reg_flt(regnr,v,tempnr) \
+ if ((v)->type == TYPE_FLT) { \
+ if ((v)->flags & INMEMORY) { \
+ COUNT_SPILLS; \
+ i386_flds_membase(cd, REG_SP, (v)->regoff * 8); \
+ fpu_st_offset++; \
+ regnr = tempnr; \
+ } else { \
+ regnr = (v)->regoff; \
+ } \
+ } else { \
+ if ((v)->flags & INMEMORY) { \
+ COUNT_SPILLS; \
+ i386_fldl_membase(cd, REG_SP, (v)->regoff * 8); \
+ fpu_st_offset++; \
+ 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; \
+ i386_mov_reg_membase(cd, tempregnum, REG_SP, (sptr)->regoff * 8); \
+ }
+
+
+#define store_reg_to_var_flt(sptr, tempregnum) \
+ if ((sptr)->type == TYPE_FLT) { \
+ if ((sptr)->flags & INMEMORY) { \
+ COUNT_SPILLS; \
+ i386_fstps_membase(cd, REG_SP, (sptr)->regoff * 8); \
+ fpu_st_offset--; \
+ } else { \
+/* i386_fxch_reg((sptr)->regoff);*/ \
+ i386_fstp_reg(cd, (sptr)->regoff + fpu_st_offset); \
+ fpu_st_offset--; \
+ } \
+ } else { \
+ if ((sptr)->flags & INMEMORY) { \
+ COUNT_SPILLS; \
+ i386_fstpl_membase(cd, REG_SP, (sptr)->regoff * 8); \
+ fpu_st_offset--; \
+ } else { \
+/* i386_fxch_reg((sptr)->regoff);*/ \
+ i386_fstp_reg(cd, (sptr)->regoff + fpu_st_offset); \
+ fpu_st_offset--; \
+ } \
+ }
+
+
+#define M_COPY(from,to) \
+ d = reg_of_var(rd, to, REG_ITMP1); \
+ 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_FLTMOVE(s1, d);*/ \
+ store_reg_to_var_flt(to, d); \
+ } else { \
+ if (!IS_2_WORD_TYPE(from->type)) { \
+ if (to->flags & INMEMORY) { \
+ if (from->flags & INMEMORY) { \
+ i386_mov_membase_reg(cd, REG_SP, from->regoff * 8, REG_ITMP1); \
+ i386_mov_reg_membase(cd, REG_ITMP1, REG_SP, to->regoff * 8); \
+ } else { \
+ i386_mov_reg_membase(cd, from->regoff, REG_SP, to->regoff * 8); \
+ } \
+ } else { \
+ if (from->flags & INMEMORY) { \
+ i386_mov_membase_reg(cd, REG_SP, from->regoff * 8, to->regoff); \
+ } else { \
+ i386_mov_reg_reg(cd, from->regoff, to->regoff); \
+ } \
+ } \
+ } else { \
+ M_LNGMEMMOVE(from->regoff, to->regoff); \
+ } \
+ } \
+ }
/* macros to create code ******************************************************/
/* modrm and stuff */
-#define i386_address_byte(mod, reg, rm) \
- *(mcodeptr++) = ((((mod) & 0x03) << 6) | (((reg) & 0x07) << 3) | (((rm) & 0x07)));
+#define i386_address_byte(mod,reg,rm) \
+ *(cd->mcodeptr++) = ((((mod) & 0x03) << 6) | (((reg) & 0x07) << 3) | (((rm) & 0x07)));
#define i386_emit_reg(reg,rm) \
#define i386_emit_imm8(imm) \
- *(mcodeptr++) = (u1) ((imm) & 0xff);
+ *(cd->mcodeptr++) = (u1) ((imm) & 0xff);
#define i386_emit_imm16(imm) \
do { \
imm_union imb; \
imb.i = (int) (imm); \
- *(mcodeptr++) = imb.b[0]; \
- *(mcodeptr++) = imb.b[1]; \
+ *(cd->mcodeptr++) = imb.b[0]; \
+ *(cd->mcodeptr++) = imb.b[1]; \
} while (0)
do { \
imm_union imb; \
imb.i = (int) (imm); \
- *(mcodeptr++) = imb.b[0]; \
- *(mcodeptr++) = imb.b[1]; \
- *(mcodeptr++) = imb.b[2]; \
- *(mcodeptr++) = imb.b[3]; \
+ *(cd->mcodeptr++) = imb.b[0]; \
+ *(cd->mcodeptr++) = imb.b[1]; \
+ *(cd->mcodeptr++) = imb.b[2]; \
+ *(cd->mcodeptr++) = imb.b[3]; \
} while (0)
} while (0)
-/* code generation prototypes */
-
-void i386_emit_ialu(s4 alu_op, stackptr src, instruction *iptr);
-void i386_emit_ialuconst(s4 alu_op, stackptr src, instruction *iptr);
-void i386_emit_lalu(s4 alu_op, stackptr src, instruction *iptr);
-void i386_emit_laluconst(s4 alu_op, stackptr src, instruction *iptr);
-void i386_emit_ishift(s4 shift_op, stackptr src, instruction *iptr);
-void i386_emit_ishiftconst(s4 shift_op, stackptr src, instruction *iptr);
-void i386_emit_ifcc_iconst(s4 if_op, stackptr src, instruction *iptr);
-
-
-/* integer instructions */
-
-void i386_mov_reg_reg(s4 reg, s4 dreg);
-void i386_mov_imm_reg(s4 imm, s4 dreg);
-void i386_movb_imm_reg(s4 imm, s4 dreg);
-void i386_mov_membase_reg(s4 basereg, s4 disp, s4 reg);
-void i386_mov_membase32_reg(s4 basereg, s4 disp, s4 reg);
-void i386_mov_reg_membase(s4 reg, s4 basereg, s4 disp);
-void i386_mov_memindex_reg(s4 disp, s4 basereg, s4 indexreg, s4 scale, s4 reg);
-void i386_mov_reg_memindex(s4 reg, s4 disp, s4 basereg, s4 indexreg, s4 scale);
-void i386_mov_mem_reg(s4 mem, s4 dreg);
-void i386_movw_reg_memindex(s4 reg, s4 disp, s4 basereg, s4 indexreg, s4 scale);
-void i386_movb_reg_memindex(s4 reg, s4 disp, s4 basereg, s4 indexreg, s4 scale);
-void i386_mov_imm_membase(s4 imm, s4 basereg, s4 disp);
-void i386_movsbl_memindex_reg(s4 disp, s4 basereg, s4 indexreg, s4 scale, s4 reg);
-void i386_movswl_memindex_reg(s4 disp, s4 basereg, s4 indexreg, s4 scale, s4 reg);
-void i386_movzwl_memindex_reg(s4 disp, s4 basereg, s4 indexreg, s4 scale, s4 reg);
-void i386_alu_reg_reg(s4 opc, s4 reg, s4 dreg);
-void i386_alu_reg_membase(s4 opc, s4 reg, s4 basereg, s4 disp);
-void i386_alu_membase_reg(s4 opc, s4 basereg, s4 disp, s4 reg);
-void i386_alu_imm_reg(s4 opc, s4 imm, s4 reg);
-void i386_alu_imm_membase(s4 opc, s4 imm, s4 basereg, s4 disp);
-void i386_test_reg_reg(s4 reg, s4 dreg);
-void i386_test_imm_reg(s4 imm, s4 dreg);
-void i386_inc_reg(s4 reg);
-void i386_inc_membase(s4 basereg, s4 disp);
-void i386_dec_reg(s4 reg);
-void i386_dec_membase(s4 basereg, s4 disp);
-void i386_cltd();
-void i386_imul_reg_reg(s4 reg, s4 dreg);
-void i386_imul_membase_reg(s4 basereg, s4 disp, s4 dreg);
-void i386_imul_imm_reg(s4 imm, s4 reg);
-void i386_imul_imm_reg_reg(s4 imm, s4 reg, s4 dreg);
-void i386_imul_imm_membase_reg(s4 imm, s4 basereg, s4 disp, s4 dreg);
-void i386_mul_membase(s4 basereg, s4 disp);
-void i386_idiv_reg(s4 reg);
-void i386_ret();
-void i386_shift_reg(s4 opc, s4 reg);
-void i386_shift_membase(s4 opc, s4 basereg, s4 disp);
-void i386_shift_imm_reg(s4 opc, s4 imm, s4 reg);
-void i386_shift_imm_membase(s4 opc, s4 imm, s4 basereg, s4 disp);
-void i386_shld_reg_reg(s4 reg, s4 dreg);
-void i386_shld_imm_reg_reg(s4 imm, s4 reg, s4 dreg);
-void i386_shld_reg_membase(s4 reg, s4 basereg, s4 disp);
-void i386_shrd_reg_reg(s4 reg, s4 dreg);
-void i386_shrd_imm_reg_reg(s4 imm, s4 reg, s4 dreg);
-void i386_shrd_reg_membase(s4 reg, s4 basereg, s4 disp);
-void i386_jmp_imm(s4 imm);
-void i386_jmp_reg(s4 reg);
-void i386_jcc(s4 opc, s4 imm);
-void i386_setcc_reg(s4 opc, s4 reg);
-void i386_setcc_membase(s4 opc, s4 basereg, s4 disp);
-void i386_xadd_reg_mem(s4 reg, s4 mem);
-void i386_neg_reg(s4 reg);
-void i386_neg_membase(s4 basereg, s4 disp);
-void i386_push_imm(s4 imm);
-void i386_pop_reg(s4 reg);
-void i386_nop();
-void i386_lock();
-void i386_call_reg(s4 reg);
-void i386_call_imm(s4 imm);
-
-
-/* floating point instructions */
-
-void i386_fld1();
-void i386_fldz();
-void i386_fld_reg(s4 reg);
-void i386_flds_membase(s4 basereg, s4 disp);
-void i386_fldl_membase(s4 basereg, s4 disp);
-void i386_fldt_membase(s4 basereg, s4 disp);
-void i386_flds_memindex(s4 disp, s4 basereg, s4 indexreg, s4 scale);
-void i386_fldl_memindex(s4 disp, s4 basereg, s4 indexreg, s4 scale);
-void i386_fildl_membase(s4 basereg, s4 disp);
-void i386_fildll_membase(s4 basereg, s4 disp);
-void i386_fst_reg(s4 reg);
-void i386_fsts_membase(s4 basereg, s4 disp);
-void i386_fstl_membase(s4 basereg, s4 disp);
-void i386_fsts_memindex(s4 disp, s4 basereg, s4 indexreg, s4 scale);
-void i386_fstl_memindex(s4 disp, s4 basereg, s4 indexreg, s4 scale);
-void i386_fstp_reg(s4 reg);
-void i386_fstps_membase(s4 basereg, s4 disp);
-void i386_fstpl_membase(s4 basereg, s4 disp);
-void i386_fstpt_membase(s4 basereg, s4 disp);
-void i386_fstps_memindex(s4 disp, s4 basereg, s4 indexreg, s4 scale);
-void i386_fstpl_memindex(s4 disp, s4 basereg, s4 indexreg, s4 scale);
-void i386_fistl_membase(s4 basereg, s4 disp);
-void i386_fistpl_membase(s4 basereg, s4 disp);
-void i386_fistpll_membase(s4 basereg, s4 disp);
-void i386_fchs();
-void i386_faddp();
-void i386_fadd_reg_st(s4 reg);
-void i386_fadd_st_reg(s4 reg);
-void i386_faddp_st_reg(s4 reg);
-void i386_fadds_membase(s4 basereg, s4 disp);
-void i386_faddl_membase(s4 basereg, s4 disp);
-void i386_fsub_reg_st(s4 reg);
-void i386_fsub_st_reg(s4 reg);
-void i386_fsubp_st_reg(s4 reg);
-void i386_fsubp();
-void i386_fsubs_membase(s4 basereg, s4 disp);
-void i386_fsubl_membase(s4 basereg, s4 disp);
-void i386_fmul_reg_st(s4 reg);
-void i386_fmul_st_reg(s4 reg);
-void i386_fmulp();
-void i386_fmulp_st_reg(s4 reg);
-void i386_fmuls_membase(s4 basereg, s4 disp);
-void i386_fmull_membase(s4 basereg, s4 disp);
-void i386_fdiv_reg_st(s4 reg);
-void i386_fdiv_st_reg(s4 reg);
-void i386_fdivp();
-void i386_fdivp_st_reg(s4 reg);
-void i386_fxch();
-void i386_fxch_reg(s4 reg);
-void i386_fprem();
-void i386_fprem1();
-void i386_fucom();
-void i386_fucom_reg(s4 reg);
-void i386_fucomp_reg(s4 reg);
-void i386_fucompp();
-void i386_fnstsw();
-void i386_sahf();
-void i386_finit();
-void i386_fldcw_mem(s4 mem);
-void i386_fldcw_membase(s4 basereg, s4 disp);
-void i386_wait();
-void i386_ffree_reg(s4 reg);
-void i386_fdecstp();
-void i386_fincstp();
-
-
/* function gen_resolvebranch **************************************************
backpatches a branch instruction
/* function prototypes */
-void codegen_init();
-void init_exceptions();
-void codegen();
-void codegen_close();
-void dseg_display(s4 *s4ptr);
+void thread_restartcriticalsection(ucontext_t *);
#endif /* _CODEGEN_H */