Killed panic's.
[cacao.git] / src / vm / jit / i386 / codegen.h
1 /* src/vm/jit/i386/codegen.h - code generation macros and definitions for i386
2
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
7
8    This file is part of CACAO.
9
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.
14
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.
19
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
23    02111-1307, USA.
24
25    Contact: cacao@complang.tuwien.ac.at
26
27    Authors: Andreas Krall
28             Christian Thalinger
29
30    Changes:
31
32    $Id: codegen.h 2496 2005-05-23 08:06:06Z twisti $
33
34 */
35
36
37 #ifndef _CODEGEN_H
38 #define _CODEGEN_H
39
40 #include <ucontext.h>
41
42 #ifdef LSRA
43 /* let LSRA allocate reserved registers (REG_ITMP[1|2|3]) */
44 #define LSRA_USES_REG_RES
45 #endif
46
47 /* SET_ARG_STACKSLOTS ***************************************************
48 Macro for stack.c to set Argument Stackslots
49
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
53 locations
54
55 --- in
56 i:                Number of arguments for this method
57 curstack:         instack of the method invokation
58
59 --- uses
60 i, copy
61
62 --- out
63 copy:             Points to first stackslot after the parameters
64 rd->ifmemuse:     max. number of stackslots used for spilling parameters
65                   so far
66 ************************************************************************/
67 #if defined(HAS_4BYTE_STACKSLOT)
68 #define SET_ARG_STACKSLOTS {                                                            \
69                 s4 stacksize = 0;                                                                       \
70                 copy = curstack;                                                                        \
71                 while (--i >= 0) {                                                                      \
72                         stacksize+=IS_2_WORD_TYPE(copy->type)?2:1;              \
73                         copy = copy->prev;                                                              \
74                 }                                                                                                       \
75                 i=call_argcount;                                                                        \
76                 copy=curstack;                                                                          \
77                 if (stacksize > rd->ifmemuse)                                           \
78                         rd->ifmemuse = stacksize;                                               \
79                 while (--i >= 0) {                                                                      \
80                         stacksize -= IS_2_WORD_TYPE(copy->type)?2:1;    \
81                         if (!(copy->flags & SAVEDVAR)) {                                \
82                                 copy->varkind = ARGVAR;                                         \
83                                 copy->varnum = i;                                                       \
84                                 copy->flags |= INMEMORY;                                        \
85                                 copy->regoff = stacksize;                                       \
86                         }                                                                                               \
87                         copy = copy->prev;                                                              \
88                 }                                                                                                       \
89         }
90 #else
91 #define SET_ARG_STACKSLOTS {                                    \
92                 copy = curstack;                                                \
93                 if (i > rd->ifmemuse)                                   \
94                         rd->ifmemuse = i;                                       \
95                 while (--i >= 0) {                                              \
96                         if (!(copy->flags & SAVEDVAR)) {        \
97                                 copy->varkind = ARGVAR;                 \
98                                 copy->varnum = i;                               \
99                                 copy->flags |= INMEMORY;                \
100                                 copy->regoff = i;                               \
101                         }                                                                       \
102                         copy = copy->prev;                                      \
103                 }                                                                               \
104         }
105 #endif /*  defined(HAS_4BYTE_STACKSLOTS) */
106
107 /* additional functions and macros to generate code ***************************/
108
109 #define BlockPtrOfPC(pc)  ((basicblock *) iptr->target)
110
111
112 #ifdef STATISTICS
113 #define COUNT_SPILLS count_spills++
114 #else
115 #define COUNT_SPILLS
116 #endif
117
118
119 #define CALCOFFSETBYTES(var, reg, val) \
120     if ((s4) (val) < -128 || (s4) (val) > 127) (var) += 4; \
121     else if ((s4) (val) != 0) (var) += 1; \
122     else if ((reg) == EBP) (var) += 1;
123
124
125 #define CALCIMMEDIATEBYTES(var, val) \
126     if ((s4) (val) < -128 || (s4) (val) > 127) (var) += 4; \
127     else (var) += 1;
128
129
130 /* gen_nullptr_check(objreg) */
131
132 #define gen_nullptr_check(objreg) \
133         if (checknull) { \
134         i386_test_reg_reg(cd, (objreg), (objreg)); \
135         i386_jcc(cd, I386_CC_E, 0); \
136             codegen_addxnullrefs(cd, cd->mcodeptr); \
137         }
138
139 #define gen_bound_check \
140     if (checkbounds) { \
141         i386_alu_membase_reg(cd, ALU_CMP, s1, OFFSET(java_arrayheader, size), s2); \
142         i386_jcc(cd, I386_CC_AE, 0); \
143         codegen_addxboundrefs(cd, cd->mcodeptr, s2); \
144     }
145
146 #define gen_div_check(v) \
147     if (checknull) { \
148         if ((v)->flags & INMEMORY) { \
149             i386_alu_imm_membase(cd, ALU_CMP, 0, REG_SP, src->regoff * 4); \
150         } else { \
151             i386_test_reg_reg(cd, src->regoff, src->regoff); \
152         } \
153         i386_jcc(cd, I386_CC_E, 0); \
154         codegen_addxdivrefs(cd, cd->mcodeptr); \
155     }
156
157
158 /* MCODECHECK(icnt) */
159
160 #define MCODECHECK(icnt) \
161         if ((cd->mcodeptr + (icnt)) > (u1 *) cd->mcodeend) \
162         cd->mcodeptr = (u1 *) codegen_increase(cd, cd->mcodeptr)
163
164
165 /* M_INTMOVE:
166      generates an integer-move from register a to b.
167      if a and b are the same int-register, no code will be generated.
168 */ 
169
170 #define M_INTMOVE(reg,dreg) \
171     if ((reg) != (dreg)) { \
172         i386_mov_reg_reg(cd, (reg),(dreg)); \
173     }
174
175
176 /* M_FLTMOVE:
177     generates a floating-point-move from register a to b.
178     if a and b are the same float-register, no code will be generated
179 */
180
181 #define M_FLTMOVE(reg,dreg) \
182     do { \
183         log_text("M_FLTMOVE"); \
184         assert(0); \
185     } while (0)
186
187
188 #define M_LNGMEMMOVE(reg,dreg) \
189     do { \
190         i386_mov_membase_reg(cd, REG_SP, (reg) * 4, REG_ITMP1); \
191         i386_mov_reg_membase(cd, REG_ITMP1, REG_SP, (dreg) * 4); \
192         i386_mov_membase_reg(cd, REG_SP, (reg) * 4 + 4, REG_ITMP1); \
193         i386_mov_reg_membase(cd, REG_ITMP1, REG_SP, (dreg) * 4 + 4); \
194     } while (0)
195
196
197 /* var_to_reg_xxx:
198     this function generates code to fetch data from a pseudo-register
199     into a real register. 
200     If the pseudo-register has actually been assigned to a real 
201     register, no code will be emitted, since following operations
202     can use this register directly.
203     
204     v: pseudoregister to be fetched from
205     tempregnum: temporary register to be used if v is actually spilled to ram
206
207     return: the register number, where the operand can be found after 
208             fetching (this wil be either tempregnum or the register
209             number allready given to v)
210 */
211
212 #define var_to_reg_int(regnr,v,tempnr) \
213     if ((v)->flags & INMEMORY) { \
214         COUNT_SPILLS; \
215         i386_mov_membase_reg(cd, REG_SP, (v)->regoff * 4, tempnr); \
216         regnr = tempnr; \
217     } else { \
218         regnr = (v)->regoff; \
219     }
220
221
222
223 #define var_to_reg_flt(regnr,v,tempnr) \
224     if ((v)->type == TYPE_FLT) { \
225         if ((v)->flags & INMEMORY) { \
226             COUNT_SPILLS; \
227             i386_flds_membase(cd, REG_SP, (v)->regoff * 4); \
228             fpu_st_offset++; \
229             regnr = tempnr; \
230         } else { \
231             i386_fld_reg(cd, (v)->regoff + fpu_st_offset); \
232             fpu_st_offset++; \
233             regnr = (v)->regoff; \
234         } \
235     } else { \
236         if ((v)->flags & INMEMORY) { \
237             COUNT_SPILLS; \
238             i386_fldl_membase(cd, REG_SP, (v)->regoff * 4); \
239             fpu_st_offset++; \
240             regnr = tempnr; \
241         } else { \
242             i386_fld_reg(cd, (v)->regoff + fpu_st_offset); \
243             fpu_st_offset++; \
244             regnr = (v)->regoff; \
245         } \
246     }
247
248 #define NEW_var_to_reg_flt(regnr,v,tempnr) \
249     if ((v)->type == TYPE_FLT) { \
250        if ((v)->flags & INMEMORY) { \
251             COUNT_SPILLS; \
252             i386_flds_membase(cd, REG_SP, (v)->regoff * 4); \
253             fpu_st_offset++; \
254             regnr = tempnr; \
255         } else { \
256             regnr = (v)->regoff; \
257         } \
258     } else { \
259         if ((v)->flags & INMEMORY) { \
260             COUNT_SPILLS; \
261             i386_fldl_membase(cd, REG_SP, (v)->regoff * 4); \
262             fpu_st_offset++; \
263             regnr = tempnr; \
264         } else { \
265             regnr = (v)->regoff; \
266         } \
267     }
268
269
270 /* store_reg_to_var_xxx:
271     This function generates the code to store the result of an operation
272     back into a spilled pseudo-variable.
273     If the pseudo-variable has not been spilled in the first place, this 
274     function will generate nothing.
275     
276     v ............ Pseudovariable
277     tempregnum ... Number of the temporary registers as returned by
278                    reg_of_var.
279 */      
280
281 #define store_reg_to_var_int(sptr, tempregnum) \
282     if ((sptr)->flags & INMEMORY) { \
283         COUNT_SPILLS; \
284         i386_mov_reg_membase(cd, tempregnum, REG_SP, (sptr)->regoff * 4); \
285     }
286
287
288 #define store_reg_to_var_flt(sptr, tempregnum) \
289     if ((sptr)->type == TYPE_FLT) { \
290         if ((sptr)->flags & INMEMORY) { \
291              COUNT_SPILLS; \
292              i386_fstps_membase(cd, REG_SP, (sptr)->regoff * 4); \
293              fpu_st_offset--; \
294         } else { \
295 /*                  i386_fxch_reg((sptr)->regoff);*/ \
296              i386_fstp_reg(cd, (sptr)->regoff + fpu_st_offset); \
297              fpu_st_offset--; \
298         } \
299     } else { \
300         if ((sptr)->flags & INMEMORY) { \
301             COUNT_SPILLS; \
302             i386_fstpl_membase(cd, REG_SP, (sptr)->regoff * 4); \
303             fpu_st_offset--; \
304         } else { \
305 /*                  i386_fxch_reg((sptr)->regoff);*/ \
306             i386_fstp_reg(cd, (sptr)->regoff + fpu_st_offset); \
307             fpu_st_offset--; \
308         } \
309     }
310
311
312 #define M_COPY(from,to) \
313     d = reg_of_var(rd, to, REG_ITMP1); \
314         if ((from->regoff != to->regoff) || \
315             ((from->flags ^ to->flags) & INMEMORY)) { \
316                 if (IS_FLT_DBL_TYPE(from->type)) { \
317                         var_to_reg_flt(s1, from, d); \
318                         /*M_FLTMOVE(s1, d);*/ \
319                         store_reg_to_var_flt(to, d); \
320                 } else { \
321             if (!IS_2_WORD_TYPE(from->type)) { \
322                 if (to->flags & INMEMORY) { \
323                      if (from->flags & INMEMORY) { \
324                          i386_mov_membase_reg(cd, REG_SP, from->regoff * 4, REG_ITMP1); \
325                          i386_mov_reg_membase(cd, REG_ITMP1, REG_SP, to->regoff * 4); \
326                      } else { \
327                          i386_mov_reg_membase(cd, from->regoff, REG_SP, to->regoff * 4); \
328                      } \
329                 } else { \
330                      if (from->flags & INMEMORY) { \
331                          i386_mov_membase_reg(cd, REG_SP, from->regoff * 4, to->regoff); \
332                      } else { \
333                          i386_mov_reg_reg(cd, from->regoff, to->regoff); \
334                      } \
335                 } \
336             } else { \
337                 M_LNGMEMMOVE(from->regoff, to->regoff); \
338             } \
339                 } \
340         }
341
342 /* macros to create code ******************************************************/
343
344 typedef enum {
345     REG_AL = 0,
346     REG_CL = 1,
347     REG_DL = 2,
348     REG_BL = 3,
349     REG_AH = 4,
350     REG_CH = 5,
351     REG_DH = 6,
352     REG_BH = 7,
353     REG_NREGB
354 } I386_RegB_No;
355
356
357 /* opcodes for alu instructions */
358
359 typedef enum {
360     ALU_ADD = 0,
361     ALU_OR  = 1,
362     ALU_ADC = 2,
363     ALU_SBB = 3,
364     ALU_AND = 4,
365     ALU_SUB = 5,
366     ALU_XOR = 6,
367     ALU_CMP = 7,
368     ALU_NALU
369 } I386_ALU_Opcode;
370
371 typedef enum {
372     I386_ROL = 0,
373     I386_ROR = 1,
374     I386_RCL = 2,
375     I386_RCR = 3,
376     I386_SHL = 4,
377     I386_SHR = 5,
378     I386_SAR = 7,
379     I386_NSHIFT = 8
380 } I386_Shift_Opcode;
381
382 typedef enum {
383     I386_CC_O = 0,
384     I386_CC_NO = 1,
385     I386_CC_B = 2, I386_CC_C = 2, I386_CC_NAE = 2,
386     I386_CC_BE = 6, I386_CC_NA = 6,
387     I386_CC_AE = 3, I386_CC_NB = 3, I386_CC_NC = 3,
388     I386_CC_E = 4, I386_CC_Z = 4,
389     I386_CC_NE = 5, I386_CC_NZ = 5,
390     I386_CC_A = 7, I386_CC_NBE = 7,
391     I386_CC_S = 8, I386_CC_LZ = 8,
392     I386_CC_NS = 9, I386_CC_GEZ = 9,
393     I386_CC_P = 0x0a, I386_CC_PE = 0x0a,
394     I386_CC_NP = 0x0b, I386_CC_PO = 0x0b,
395     I386_CC_L = 0x0c, I386_CC_NGE = 0x0c,
396     I386_CC_GE = 0x0d, I386_CC_NL = 0x0d,
397     I386_CC_LE = 0x0e, I386_CC_NG = 0x0e,
398     I386_CC_G = 0x0f, I386_CC_NLE = 0x0f,
399     I386_NCC
400 } I386_CC;
401
402
403 /* modrm and stuff */
404
405 #define i386_address_byte(mod,reg,rm) \
406     *(cd->mcodeptr++) = ((((mod) & 0x03) << 6) | (((reg) & 0x07) << 3) | (((rm) & 0x07)));
407
408
409 #define i386_emit_reg(reg,rm) \
410     i386_address_byte(3,(reg),(rm));
411
412
413 #define i386_is_imm8(imm) \
414     (((int)(imm) >= -128 && (int)(imm) <= 127))
415
416
417 #define i386_emit_imm8(imm) \
418     *(cd->mcodeptr++) = (u1) ((imm) & 0xff);
419
420
421 #define i386_emit_imm16(imm) \
422     do { \
423         imm_union imb; \
424         imb.i = (int) (imm); \
425         *(cd->mcodeptr++) = imb.b[0]; \
426         *(cd->mcodeptr++) = imb.b[1]; \
427     } while (0)
428
429
430 #define i386_emit_imm32(imm) \
431     do { \
432         imm_union imb; \
433         imb.i = (int) (imm); \
434         *(cd->mcodeptr++) = imb.b[0]; \
435         *(cd->mcodeptr++) = imb.b[1]; \
436         *(cd->mcodeptr++) = imb.b[2]; \
437         *(cd->mcodeptr++) = imb.b[3]; \
438     } while (0)
439
440
441 #define i386_emit_mem(r,mem) \
442     do { \
443         i386_address_byte(0,(r),5); \
444         i386_emit_imm32((mem)); \
445     } while (0)
446
447
448 #define i386_emit_membase(basereg,disp,dreg) \
449     do { \
450         if ((basereg) == ESP) { \
451             if ((disp) == 0) { \
452                 i386_address_byte(0, (dreg), ESP); \
453                 i386_address_byte(0, ESP, ESP); \
454             } else if (i386_is_imm8((disp))) { \
455                 i386_address_byte(1, (dreg), ESP); \
456                 i386_address_byte(0, ESP, ESP); \
457                 i386_emit_imm8((disp)); \
458             } else { \
459                 i386_address_byte(2, (dreg), ESP); \
460                 i386_address_byte(0, ESP, ESP); \
461                 i386_emit_imm32((disp)); \
462             } \
463             break; \
464         } \
465         \
466         if ((disp) == 0 && (basereg) != EBP) { \
467             i386_address_byte(0, (dreg), (basereg)); \
468             break; \
469         } \
470         \
471         if (i386_is_imm8((disp))) { \
472             i386_address_byte(1, (dreg), (basereg)); \
473             i386_emit_imm8((disp)); \
474         } else { \
475             i386_address_byte(2, (dreg), (basereg)); \
476             i386_emit_imm32((disp)); \
477         } \
478     } while (0)
479
480
481 #define i386_emit_membase32(basereg,disp,dreg) \
482     do { \
483         if ((basereg) == ESP) { \
484             i386_address_byte(2, (dreg), ESP); \
485             i386_address_byte(0, ESP, ESP); \
486             i386_emit_imm32((disp)); \
487         } else { \
488             i386_address_byte(2, (dreg), (basereg)); \
489             i386_emit_imm32((disp)); \
490         } \
491     } while (0)
492
493
494 #define i386_emit_memindex(reg,disp,basereg,indexreg,scale) \
495     do { \
496         if ((basereg) == -1) { \
497             i386_address_byte(0, (reg), 4); \
498             i386_address_byte((scale), (indexreg), 5); \
499             i386_emit_imm32((disp)); \
500         \
501         } else if ((disp) == 0 && (basereg) != EBP) { \
502             i386_address_byte(0, (reg), 4); \
503             i386_address_byte((scale), (indexreg), (basereg)); \
504         \
505         } else if (i386_is_imm8((disp))) { \
506             i386_address_byte(1, (reg), 4); \
507             i386_address_byte((scale), (indexreg), (basereg)); \
508             i386_emit_imm8 ((disp)); \
509         \
510         } else { \
511             i386_address_byte(2, (reg), 4); \
512             i386_address_byte((scale), (indexreg), (basereg)); \
513             i386_emit_imm32((disp)); \
514         }    \
515      } while (0)
516
517
518 /* macros to create code ******************************************************/
519
520 #define M_ILD(a,b,disp)         i386_mov_membase_reg(cd, (b), (disp), (a))
521
522 #define M_IST(a,b,disp)         i386_mov_reg_membase(cd, (a), (b), (disp))
523
524 #define M_IADD_IMM(a,b)         i386_alu_imm_reg(cd, ALU_ADD, (a), (b))
525 #define M_ISUB_IMM(a,b)         i386_alu_imm_reg(cd, ALU_SUB, (a), (b))
526
527 #define M_NOP                   i386_nop(cd)
528
529
530 /* function gen_resolvebranch **************************************************
531
532     backpatches a branch instruction
533
534     parameters: ip ... pointer to instruction after branch (void*)
535                 so ... offset of instruction after branch  (s4)
536                 to ... offset of branch target             (s4)
537
538 *******************************************************************************/
539
540 #define gen_resolvebranch(ip,so,to) \
541     *((void **) ((ip) - 4)) = (void **) ((to) - (so));
542
543
544 /* function prototypes */
545
546 void thread_restartcriticalsection(ucontext_t *);
547
548 #endif /* _CODEGEN_H */
549
550
551 /*
552  * These are local overrides for various environment variables in Emacs.
553  * Please do not remove this and leave it at the end of the file, where
554  * Emacs will automagically detect them.
555  * ---------------------------------------------------------------------
556  * Local variables:
557  * mode: c
558  * indent-tabs-mode: t
559  * c-basic-offset: 4
560  * tab-width: 4
561  * End:
562  */