1 /* src/vm/jit/x86_64/codegen.h - code generation macros for x86_64
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
31 $Id: codegen.h 2415 2005-04-29 18:55:49Z twisti $
40 #include "vm/jit/x86_64/types.h"
42 /* SET_ARG_STACKSLOTS *************************************************
43 Macro for stack.c to set Argument Stackslots
45 Sets the first call_argcount stackslots of curstack to varkind ARGVAR, if
46 they to not have the SAVEDVAR flag set. According to the calling
47 conventions these stackslots are assigned argument registers or memory
51 i,call_argcount: Number of Parameters
52 curstack: stackptr to current instack
59 copy: points to first stackslot after the parameters
60 rd->ifmemuse: max. number of stackslots needed for spilled parameters so far
61 rd->argintreguse: max. number of used integer argument registers used so far
62 rd->fltintreguse: max. number of used float argument registers used so far
63 ************************************************************************/
64 #define SET_ARG_STACKSLOTS { \
67 s4 stacksize; /* Stackoffset for spilled arg */ \
70 (IS_FLT_DBL_TYPE(copy->type)) ? farg++ : iarg++; \
73 stacksize = (farg < rd->fltreg_argnum)? 0 : (farg - rd->fltreg_argnum); \
74 stacksize += (iarg < rd->intreg_argnum)? 0 : (iarg - rd->intreg_argnum); \
75 if (rd->argintreguse < iarg) \
76 rd->argintreguse = iarg; \
77 if (rd->argfltreguse < farg) \
78 rd->argfltreguse = farg; \
79 if (rd->ifmemuse < stacksize) \
80 rd->ifmemuse = stacksize; \
84 if (IS_FLT_DBL_TYPE(copy->type)) { \
86 if (!(copy->flags & SAVEDVAR)) { \
87 copy->varnum = farg; \
88 copy->varkind = ARGVAR; \
89 if (farg < rd->fltreg_argnum) { \
91 copy->regoff = rd->argfltregs[farg]; \
93 copy->flags = INMEMORY; \
94 copy->regoff = --stacksize; \
97 } else { /* int_arg */ \
99 if (!(copy->flags & SAVEDVAR)) { \
100 copy->varnum = iarg; \
101 copy->varkind = ARGVAR; \
102 if (iarg < rd->intreg_argnum) { \
104 copy->regoff = rd->argintregs[iarg]; \
106 copy->flags = INMEMORY; \
107 copy->regoff = --stacksize; \
116 /* macros to create code ******************************************************/
118 /* immediate data union */
130 /* opcodes for alu instructions */
154 } X86_64_Shift_Opcode;
160 X86_64_CC_B = 2, X86_64_CC_C = 2, X86_64_CC_NAE = 2,
161 X86_64_CC_BE = 6, X86_64_CC_NA = 6,
162 X86_64_CC_AE = 3, X86_64_CC_NB = 3, X86_64_CC_NC = 3,
163 X86_64_CC_E = 4, X86_64_CC_Z = 4,
164 X86_64_CC_NE = 5, X86_64_CC_NZ = 5,
165 X86_64_CC_A = 7, X86_64_CC_NBE = 7,
166 X86_64_CC_S = 8, X86_64_CC_LZ = 8,
167 X86_64_CC_NS = 9, X86_64_CC_GEZ = 9,
168 X86_64_CC_P = 0x0a, X86_64_CC_PE = 0x0a,
169 X86_64_CC_NP = 0x0b, X86_64_CC_PO = 0x0b,
170 X86_64_CC_L = 0x0c, X86_64_CC_NGE = 0x0c,
171 X86_64_CC_GE = 0x0d, X86_64_CC_NL = 0x0d,
172 X86_64_CC_LE = 0x0e, X86_64_CC_NG = 0x0e,
173 X86_64_CC_G = 0x0f, X86_64_CC_NLE = 0x0f,
178 #define IS_IMM8(imm) \
179 (((long) (imm) >= -128) && ((long) (imm) <= 127))
182 #define IS_IMM32(imm) \
183 (((long) (imm) >= (-2147483647-1)) && ((long) (imm) <= 2147483647))
186 /* modrm and stuff */
188 #define x86_64_address_byte(mod,reg,rm) \
189 *(cd->mcodeptr++) = ((((mod) & 0x03) << 6) | (((reg) & 0x07) << 3) | ((rm) & 0x07));
192 #define x86_64_emit_reg(reg,rm) \
193 x86_64_address_byte(3,(reg),(rm));
196 #define x86_64_emit_rex(size,reg,index,rm) \
197 if ((size) == 1 || (reg) > 7 || (index) > 7 || (rm) > 7) { \
198 *(cd->mcodeptr++) = (0x40 | (((size) & 0x01) << 3) | ((((reg) >> 3) & 0x01) << 2) | ((((index) >> 3) & 0x01) << 1) | (((rm) >> 3) & 0x01)); \
202 #define x86_64_emit_byte_rex(reg,index,rm) \
203 *(cd->mcodeptr++) = (0x40 | ((((reg) >> 3) & 0x01) << 2) | ((((index) >> 3) & 0x01) << 1) | (((rm) >> 3) & 0x01));
206 #define x86_64_emit_mem(r,disp) \
208 x86_64_address_byte(0,(r),5); \
209 x86_64_emit_imm32((disp)); \
213 #define x86_64_emit_membase(basereg,disp,dreg) \
215 if ((basereg) == REG_SP || (basereg) == R12) { \
217 x86_64_address_byte(0,(dreg),REG_SP); \
218 x86_64_address_byte(0,REG_SP,REG_SP); \
219 } else if (IS_IMM8((disp))) { \
220 x86_64_address_byte(1,(dreg),REG_SP); \
221 x86_64_address_byte(0,REG_SP,REG_SP); \
222 x86_64_emit_imm8((disp)); \
224 x86_64_address_byte(2,(dreg),REG_SP); \
225 x86_64_address_byte(0,REG_SP,REG_SP); \
226 x86_64_emit_imm32((disp)); \
230 if ((disp) == 0 && (basereg) != RBP && (basereg) != R13) { \
231 x86_64_address_byte(0,(dreg),(basereg)); \
235 if ((basereg) == RIP) { \
236 x86_64_address_byte(0,(dreg),RBP); \
237 x86_64_emit_imm32((disp)); \
241 if (IS_IMM8((disp))) { \
242 x86_64_address_byte(1,(dreg),(basereg)); \
243 x86_64_emit_imm8((disp)); \
245 x86_64_address_byte(2,(dreg),(basereg)); \
246 x86_64_emit_imm32((disp)); \
251 #define x86_64_emit_membase32(basereg,disp,dreg) \
253 if ((basereg) == REG_SP || (basereg) == R12) { \
254 x86_64_address_byte(2,(dreg),REG_SP); \
255 x86_64_address_byte(0,REG_SP,REG_SP); \
256 x86_64_emit_imm32((disp)); \
258 x86_64_address_byte(2,(dreg),(basereg)); \
259 x86_64_emit_imm32((disp)); \
264 #define x86_64_emit_memindex(reg,disp,basereg,indexreg,scale) \
266 if ((basereg) == -1) { \
267 x86_64_address_byte(0,(reg),4); \
268 x86_64_address_byte((scale),(indexreg),5); \
269 x86_64_emit_imm32((disp)); \
271 } else if ((disp) == 0 && (basereg) != RBP && (basereg) != R13) { \
272 x86_64_address_byte(0,(reg),4); \
273 x86_64_address_byte((scale),(indexreg),(basereg)); \
275 } else if (IS_IMM8((disp))) { \
276 x86_64_address_byte(1,(reg),4); \
277 x86_64_address_byte((scale),(indexreg),(basereg)); \
278 x86_64_emit_imm8 ((disp)); \
281 x86_64_address_byte(2,(reg),4); \
282 x86_64_address_byte((scale),(indexreg),(basereg)); \
283 x86_64_emit_imm32((disp)); \
288 #define x86_64_emit_imm8(imm) \
289 *(cd->mcodeptr++) = (u1) ((imm) & 0xff);
292 #define x86_64_emit_imm16(imm) \
294 x86_64_imm_buf imb; \
295 imb.i = (s4) (imm); \
296 *(cd->mcodeptr++) = imb.b[0]; \
297 *(cd->mcodeptr++) = imb.b[1]; \
301 #define x86_64_emit_imm32(imm) \
303 x86_64_imm_buf imb; \
304 imb.i = (s4) (imm); \
305 *(cd->mcodeptr++) = imb.b[0]; \
306 *(cd->mcodeptr++) = imb.b[1]; \
307 *(cd->mcodeptr++) = imb.b[2]; \
308 *(cd->mcodeptr++) = imb.b[3]; \
312 #define x86_64_emit_imm64(imm) \
314 x86_64_imm_buf imb; \
315 imb.l = (s8) (imm); \
316 *(cd->mcodeptr++) = imb.b[0]; \
317 *(cd->mcodeptr++) = imb.b[1]; \
318 *(cd->mcodeptr++) = imb.b[2]; \
319 *(cd->mcodeptr++) = imb.b[3]; \
320 *(cd->mcodeptr++) = imb.b[4]; \
321 *(cd->mcodeptr++) = imb.b[5]; \
322 *(cd->mcodeptr++) = imb.b[6]; \
323 *(cd->mcodeptr++) = imb.b[7]; \
327 /* additional functions and macros to generate code ***************************/
329 #define BlockPtrOfPC(pc) ((basicblock *) iptr->target)
333 #define COUNT_SPILLS count_spills++
339 #define CALCOFFSETBYTES(var, reg, val) \
340 if ((s4) (val) < -128 || (s4) (val) > 127) (var) += 4; \
341 else if ((s4) (val) != 0) (var) += 1; \
342 else if ((reg) == RBP || (reg) == RSP || (reg) == R12 || (reg) == R13) (var) += 1;
345 #define CALCIMMEDIATEBYTES(var, val) \
346 if ((s4) (val) < -128 || (s4) (val) > 127) (var) += 4; \
350 /* gen_nullptr_check(objreg) */
352 #define gen_nullptr_check(objreg) \
354 x86_64_test_reg_reg(cd, (objreg), (objreg)); \
355 x86_64_jcc(cd, X86_64_CC_E, 0); \
356 codegen_addxnullrefs(cd, cd->mcodeptr); \
360 #define gen_bound_check \
362 x86_64_alul_membase_reg(cd, X86_64_CMP, s1, OFFSET(java_arrayheader, size), s2); \
363 x86_64_jcc(cd, X86_64_CC_AE, 0); \
364 codegen_addxboundrefs(cd, cd->mcodeptr, s2); \
368 #define gen_div_check(v) \
370 if ((v)->flags & INMEMORY) { \
371 x86_64_alu_imm_membase(cd, X86_64_CMP, 0, REG_SP, src->regoff * 8); \
373 x86_64_test_reg_reg(cd, src->regoff, src->regoff); \
375 x86_64_jcc(cd, X86_64_CC_E, 0); \
376 codegen_addxdivrefs(cd, cd->mcodeptr); \
380 /* MCODECHECK(icnt) */
382 #define MCODECHECK(icnt) \
383 if ((cd->mcodeptr + (icnt)) > (u1 *) cd->mcodeend) \
384 cd->mcodeptr = (u1 *) codegen_increase(cd, cd->mcodeptr)
387 generates an integer-move from register a to b.
388 if a and b are the same int-register, no code will be generated.
391 #define M_INTMOVE(reg,dreg) \
392 if ((reg) != (dreg)) { \
393 x86_64_mov_reg_reg(cd, (reg),(dreg)); \
398 generates a floating-point-move from register a to b.
399 if a and b are the same float-register, no code will be generated
402 #define M_FLTMOVE(reg,dreg) \
403 if ((reg) != (dreg)) { \
404 x86_64_movq_reg_reg(cd, (reg),(dreg)); \
409 this function generates code to fetch data from a pseudo-register
410 into a real register.
411 If the pseudo-register has actually been assigned to a real
412 register, no code will be emitted, since following operations
413 can use this register directly.
415 v: pseudoregister to be fetched from
416 tempregnum: temporary register to be used if v is actually spilled to ram
418 return: the register number, where the operand can be found after
419 fetching (this wil be either tempregnum or the register
420 number allready given to v)
423 #define var_to_reg_int(regnr,v,tempnr) \
424 if ((v)->flags & INMEMORY) { \
426 if ((v)->type == TYPE_INT) { \
427 x86_64_movl_membase_reg(cd, REG_SP, (v)->regoff * 8, tempnr); \
429 x86_64_mov_membase_reg(cd, REG_SP, (v)->regoff * 8, tempnr); \
433 regnr = (v)->regoff; \
438 #define var_to_reg_flt(regnr,v,tempnr) \
439 if ((v)->flags & INMEMORY) { \
441 if ((v)->type == TYPE_FLT) { \
442 x86_64_movlps_membase_reg(cd, REG_SP, (v)->regoff * 8, tempnr); \
444 x86_64_movlpd_membase_reg(cd, REG_SP, (v)->regoff * 8, tempnr); \
446 /* x86_64_movq_membase_reg(REG_SP, (v)->regoff * 8, tempnr);*/ \
449 regnr = (v)->regoff; \
453 /* store_reg_to_var_xxx:
454 This function generates the code to store the result of an operation
455 back into a spilled pseudo-variable.
456 If the pseudo-variable has not been spilled in the first place, this
457 function will generate nothing.
459 v ............ Pseudovariable
460 tempregnum ... Number of the temporary registers as returned by
464 #define store_reg_to_var_int(sptr, tempregnum) \
465 if ((sptr)->flags & INMEMORY) { \
467 x86_64_mov_reg_membase(cd, tempregnum, REG_SP, (sptr)->regoff * 8); \
471 #define store_reg_to_var_flt(sptr, tempregnum) \
472 if ((sptr)->flags & INMEMORY) { \
474 x86_64_movq_reg_membase(cd, tempregnum, REG_SP, (sptr)->regoff * 8); \
478 #define M_COPY(from,to) \
479 d = reg_of_var(rd, to, REG_ITMP1); \
480 if ((from->regoff != to->regoff) || \
481 ((from->flags ^ to->flags) & INMEMORY)) { \
482 if (IS_FLT_DBL_TYPE(from->type)) { \
483 var_to_reg_flt(s1, from, d); \
485 store_reg_to_var_flt(to, d); \
487 var_to_reg_int(s1, from, d); \
489 store_reg_to_var_int(to, d); \
494 /* macros to create code ******************************************************/
496 #define M_LLD(a,b,disp) x86_64_mov_membase_reg(cd, (b), (disp), (a))
497 #define M_DLD(a,b,disp) x86_64_movq_membase_reg(cd, (b), (disp), (a))
499 #define M_LST(a,b,disp) x86_64_mov_reg_membase(cd, (a), (b), (disp))
500 #define M_DST(a,b,disp) x86_64_movq_reg_membase(cd, (a), (b), (disp))
502 #define M_LADD_IMM(a,b) x86_64_alu_imm_reg(cd, X86_64_ADD, (a), (b))
503 #define M_LSUB_IMM(a,b) x86_64_alu_imm_reg(cd, X86_64_SUB, (a), (b))
505 #define M_NOP x86_64_nop(cd)
508 /* function gen_resolvebranch **************************************************
510 backpatches a branch instruction
512 parameters: ip ... pointer to instruction after branch (void*)
513 so ... offset of instruction after branch (s8)
514 to ... offset of branch target (s8)
516 *******************************************************************************/
518 #define gen_resolvebranch(ip,so,to) \
519 *((s4*) ((ip) - 4)) = (s4) ((to) - (so));
522 /* function prototypes */
524 void thread_restartcriticalsection(ucontext_t *uc);
526 #endif /* _CODEGEN_H */
530 * These are local overrides for various environment variables in Emacs.
531 * Please do not remove this and leave it at the end of the file, where
532 * Emacs will automagically detect them.
533 * ---------------------------------------------------------------------
536 * indent-tabs-mode: t