1 /* src/vm/jit/i386/codegen.h - code generation macros and definitions for i386
3 Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
4 R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
5 C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
6 Institut f. Computersprachen - TU Wien
8 This file is part of CACAO.
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2, or (at
13 your option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
25 Contact: cacao@complang.tuwien.ac.at
27 Authors: Andreas Krall
32 $Id: codegen.h 2339 2005-04-22 13:31:01Z twisti $
43 /* let LSRA allocate reserved registers (REG_ITMP[1|2|3]) */
44 #define LSRA_USES_REG_RES
47 /* SET_ARG_STACKSLOTS ***************************************************
48 Macro for stack.c to set Argument Stackslots
50 Sets the first call_argcount stackslots of curstack to varkind ARGVAR, if
51 they to not have the SAVEDVAR flag set. According to the calling
52 conventions these stackslots are assigned argument registers or memory
56 i: Number of arguments for this method
57 curstack: instack of the method invokation
63 copy: Points to first stackslot after the parameters
64 rd->ifmemuse: max. number of stackslots used for spilling parameters
66 ************************************************************************/
67 #define SET_ARG_STACKSLOTS { \
69 if (i > rd->ifmemuse) \
72 if (!(copy->flags & SAVEDVAR)) { \
73 copy->varkind = ARGVAR; \
75 copy->flags |= INMEMORY; \
83 /* additional functions and macros to generate code ***************************/
85 #define BlockPtrOfPC(pc) ((basicblock *) iptr->target)
89 #define COUNT_SPILLS count_spills++
95 #define CALCOFFSETBYTES(var, reg, val) \
96 if ((s4) (val) < -128 || (s4) (val) > 127) (var) += 4; \
97 else if ((s4) (val) != 0) (var) += 1; \
98 else if ((reg) == EBP) (var) += 1;
101 #define CALCIMMEDIATEBYTES(var, val) \
102 if ((s4) (val) < -128 || (s4) (val) > 127) (var) += 4; \
106 /* gen_nullptr_check(objreg) */
108 #define gen_nullptr_check(objreg) \
110 i386_test_reg_reg(cd, (objreg), (objreg)); \
111 i386_jcc(cd, I386_CC_E, 0); \
112 codegen_addxnullrefs(cd, cd->mcodeptr); \
115 #define gen_bound_check \
117 i386_alu_membase_reg(cd, I386_CMP, s1, OFFSET(java_arrayheader, size), s2); \
118 i386_jcc(cd, I386_CC_AE, 0); \
119 codegen_addxboundrefs(cd, cd->mcodeptr, s2); \
122 #define gen_div_check(v) \
124 if ((v)->flags & INMEMORY) { \
125 i386_alu_imm_membase(cd, I386_CMP, 0, REG_SP, src->regoff * 8); \
127 i386_test_reg_reg(cd, src->regoff, src->regoff); \
129 i386_jcc(cd, I386_CC_E, 0); \
130 codegen_addxdivrefs(cd, cd->mcodeptr); \
134 /* MCODECHECK(icnt) */
136 #define MCODECHECK(icnt) \
137 if ((cd->mcodeptr + (icnt)) > (u1 *) cd->mcodeend) \
138 cd->mcodeptr = (u1 *) codegen_increase(cd, cd->mcodeptr)
141 /* XXX Do we need code padding on i386? */
142 /* #define ALIGNCODENOP {if((int)((long)cd->mcodeptr&7)){M_NOP;}} */
147 generates an integer-move from register a to b.
148 if a and b are the same int-register, no code will be generated.
151 #define M_INTMOVE(reg,dreg) \
152 if ((reg) != (dreg)) { \
153 i386_mov_reg_reg(cd, (reg),(dreg)); \
158 generates a floating-point-move from register a to b.
159 if a and b are the same float-register, no code will be generated
162 #define M_FLTMOVE(reg,dreg) panic("M_FLTMOVE");
164 #define M_LNGMEMMOVE(reg,dreg) \
166 i386_mov_membase_reg(cd, REG_SP, (reg) * 8, REG_ITMP1); \
167 i386_mov_reg_membase(cd, REG_ITMP1, REG_SP, (dreg) * 8); \
168 i386_mov_membase_reg(cd, REG_SP, (reg) * 8 + 4, REG_ITMP1); \
169 i386_mov_reg_membase(cd, REG_ITMP1, REG_SP, (dreg) * 8 + 4); \
174 this function generates code to fetch data from a pseudo-register
175 into a real register.
176 If the pseudo-register has actually been assigned to a real
177 register, no code will be emitted, since following operations
178 can use this register directly.
180 v: pseudoregister to be fetched from
181 tempregnum: temporary register to be used if v is actually spilled to ram
183 return: the register number, where the operand can be found after
184 fetching (this wil be either tempregnum or the register
185 number allready given to v)
188 #define var_to_reg_int(regnr,v,tempnr) \
189 if ((v)->flags & INMEMORY) { \
191 i386_mov_membase_reg(cd, REG_SP, (v)->regoff * 8, tempnr); \
194 regnr = (v)->regoff; \
199 #define var_to_reg_flt(regnr,v,tempnr) \
200 if ((v)->type == TYPE_FLT) { \
201 if ((v)->flags & INMEMORY) { \
203 i386_flds_membase(cd, REG_SP, (v)->regoff * 8); \
207 i386_fld_reg(cd, (v)->regoff + fpu_st_offset); \
209 regnr = (v)->regoff; \
212 if ((v)->flags & INMEMORY) { \
214 i386_fldl_membase(cd, REG_SP, (v)->regoff * 8); \
218 i386_fld_reg(cd, (v)->regoff + fpu_st_offset); \
220 regnr = (v)->regoff; \
224 #define NEW_var_to_reg_flt(regnr,v,tempnr) \
225 if ((v)->type == TYPE_FLT) { \
226 if ((v)->flags & INMEMORY) { \
228 i386_flds_membase(cd, REG_SP, (v)->regoff * 8); \
232 regnr = (v)->regoff; \
235 if ((v)->flags & INMEMORY) { \
237 i386_fldl_membase(cd, REG_SP, (v)->regoff * 8); \
241 regnr = (v)->regoff; \
246 /* store_reg_to_var_xxx:
247 This function generates the code to store the result of an operation
248 back into a spilled pseudo-variable.
249 If the pseudo-variable has not been spilled in the first place, this
250 function will generate nothing.
252 v ............ Pseudovariable
253 tempregnum ... Number of the temporary registers as returned by
257 #define store_reg_to_var_int(sptr, tempregnum) \
258 if ((sptr)->flags & INMEMORY) { \
260 i386_mov_reg_membase(cd, tempregnum, REG_SP, (sptr)->regoff * 8); \
264 #define store_reg_to_var_flt(sptr, tempregnum) \
265 if ((sptr)->type == TYPE_FLT) { \
266 if ((sptr)->flags & INMEMORY) { \
268 i386_fstps_membase(cd, REG_SP, (sptr)->regoff * 8); \
271 /* i386_fxch_reg((sptr)->regoff);*/ \
272 i386_fstp_reg(cd, (sptr)->regoff + fpu_st_offset); \
276 if ((sptr)->flags & INMEMORY) { \
278 i386_fstpl_membase(cd, REG_SP, (sptr)->regoff * 8); \
281 /* i386_fxch_reg((sptr)->regoff);*/ \
282 i386_fstp_reg(cd, (sptr)->regoff + fpu_st_offset); \
288 #define M_COPY(from,to) \
289 d = reg_of_var(rd, to, REG_ITMP1); \
290 if ((from->regoff != to->regoff) || \
291 ((from->flags ^ to->flags) & INMEMORY)) { \
292 if (IS_FLT_DBL_TYPE(from->type)) { \
293 var_to_reg_flt(s1, from, d); \
294 /*M_FLTMOVE(s1, d);*/ \
295 store_reg_to_var_flt(to, d); \
297 if (!IS_2_WORD_TYPE(from->type)) { \
298 if (to->flags & INMEMORY) { \
299 if (from->flags & INMEMORY) { \
300 i386_mov_membase_reg(cd, REG_SP, from->regoff * 8, REG_ITMP1); \
301 i386_mov_reg_membase(cd, REG_ITMP1, REG_SP, to->regoff * 8); \
303 i386_mov_reg_membase(cd, from->regoff, REG_SP, to->regoff * 8); \
306 if (from->flags & INMEMORY) { \
307 i386_mov_membase_reg(cd, REG_SP, from->regoff * 8, to->regoff); \
309 i386_mov_reg_reg(cd, from->regoff, to->regoff); \
313 M_LNGMEMMOVE(from->regoff, to->regoff); \
318 /* macros to create code ******************************************************/
333 /* opcodes for alu instructions */
361 I386_CC_B = 2, I386_CC_C = 2, I386_CC_NAE = 2,
362 I386_CC_BE = 6, I386_CC_NA = 6,
363 I386_CC_AE = 3, I386_CC_NB = 3, I386_CC_NC = 3,
364 I386_CC_E = 4, I386_CC_Z = 4,
365 I386_CC_NE = 5, I386_CC_NZ = 5,
366 I386_CC_A = 7, I386_CC_NBE = 7,
367 I386_CC_S = 8, I386_CC_LZ = 8,
368 I386_CC_NS = 9, I386_CC_GEZ = 9,
369 I386_CC_P = 0x0a, I386_CC_PE = 0x0a,
370 I386_CC_NP = 0x0b, I386_CC_PO = 0x0b,
371 I386_CC_L = 0x0c, I386_CC_NGE = 0x0c,
372 I386_CC_GE = 0x0d, I386_CC_NL = 0x0d,
373 I386_CC_LE = 0x0e, I386_CC_NG = 0x0e,
374 I386_CC_G = 0x0f, I386_CC_NLE = 0x0f,
379 /* modrm and stuff */
381 #define i386_address_byte(mod,reg,rm) \
382 *(cd->mcodeptr++) = ((((mod) & 0x03) << 6) | (((reg) & 0x07) << 3) | (((rm) & 0x07)));
385 #define i386_emit_reg(reg,rm) \
386 i386_address_byte(3,(reg),(rm));
389 #define i386_is_imm8(imm) \
390 (((int)(imm) >= -128 && (int)(imm) <= 127))
393 #define i386_emit_imm8(imm) \
394 *(cd->mcodeptr++) = (u1) ((imm) & 0xff);
397 #define i386_emit_imm16(imm) \
400 imb.i = (int) (imm); \
401 *(cd->mcodeptr++) = imb.b[0]; \
402 *(cd->mcodeptr++) = imb.b[1]; \
406 #define i386_emit_imm32(imm) \
409 imb.i = (int) (imm); \
410 *(cd->mcodeptr++) = imb.b[0]; \
411 *(cd->mcodeptr++) = imb.b[1]; \
412 *(cd->mcodeptr++) = imb.b[2]; \
413 *(cd->mcodeptr++) = imb.b[3]; \
417 #define i386_emit_mem(r,mem) \
419 i386_address_byte(0,(r),5); \
420 i386_emit_imm32((mem)); \
424 #define i386_emit_membase(basereg,disp,dreg) \
426 if ((basereg) == ESP) { \
428 i386_address_byte(0, (dreg), ESP); \
429 i386_address_byte(0, ESP, ESP); \
430 } else if (i386_is_imm8((disp))) { \
431 i386_address_byte(1, (dreg), ESP); \
432 i386_address_byte(0, ESP, ESP); \
433 i386_emit_imm8((disp)); \
435 i386_address_byte(2, (dreg), ESP); \
436 i386_address_byte(0, ESP, ESP); \
437 i386_emit_imm32((disp)); \
442 if ((disp) == 0 && (basereg) != EBP) { \
443 i386_address_byte(0, (dreg), (basereg)); \
447 if (i386_is_imm8((disp))) { \
448 i386_address_byte(1, (dreg), (basereg)); \
449 i386_emit_imm8((disp)); \
451 i386_address_byte(2, (dreg), (basereg)); \
452 i386_emit_imm32((disp)); \
457 #define i386_emit_membase32(basereg,disp,dreg) \
459 if ((basereg) == ESP) { \
460 i386_address_byte(2, (dreg), ESP); \
461 i386_address_byte(0, ESP, ESP); \
462 i386_emit_imm32((disp)); \
464 i386_address_byte(2, (dreg), (basereg)); \
465 i386_emit_imm32((disp)); \
470 #define i386_emit_memindex(reg,disp,basereg,indexreg,scale) \
472 if ((basereg) == -1) { \
473 i386_address_byte(0, (reg), 4); \
474 i386_address_byte((scale), (indexreg), 5); \
475 i386_emit_imm32((disp)); \
477 } else if ((disp) == 0 && (basereg) != EBP) { \
478 i386_address_byte(0, (reg), 4); \
479 i386_address_byte((scale), (indexreg), (basereg)); \
481 } else if (i386_is_imm8((disp))) { \
482 i386_address_byte(1, (reg), 4); \
483 i386_address_byte((scale), (indexreg), (basereg)); \
484 i386_emit_imm8 ((disp)); \
487 i386_address_byte(2, (reg), 4); \
488 i386_address_byte((scale), (indexreg), (basereg)); \
489 i386_emit_imm32((disp)); \
494 /* function gen_resolvebranch **************************************************
496 backpatches a branch instruction
498 parameters: ip ... pointer to instruction after branch (void*)
499 so ... offset of instruction after branch (s4)
500 to ... offset of branch target (s4)
502 *******************************************************************************/
504 #define gen_resolvebranch(ip,so,to) \
505 *((void **) ((ip) - 4)) = (void **) ((to) - (so));
508 /* function prototypes */
510 void thread_restartcriticalsection(ucontext_t *);
512 #endif /* _CODEGEN_H */
516 * These are local overrides for various environment variables in Emacs.
517 * Please do not remove this and leave it at the end of the file, where
518 * Emacs will automagically detect them.
519 * ---------------------------------------------------------------------
522 * indent-tabs-mode: t