1 /* src/vm/jit/arm/codegen.h - code generation macros and definitions for ARM
3 Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
4 C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5 E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6 J. Wenninger, 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., 51 Franklin Street, Fifth Floor, Boston, MA
25 Contact: cacao@cacaojvm.org
27 Authors: Michael Starzinger
30 $Id: codegen.h 7511 2007-03-13 16:32:56Z michi $
41 /* helper macros for generating code ******************************************/
43 /* load_var_to_reg_xxx:
44 this function generates code to fetch data from a pseudo-register
46 If the pseudo-register has actually been assigned to a real
47 register, no code will be emitted, since following operations
48 can use this register directly.
49 v: pseudoregister to be fetched from
50 tempnr: temporary register to be used if v is actually spilled to ram
51 regnr: the register number, where the operand can be found after
52 fetching (this wil be either tempregnum or the register
53 number allready given to v)
56 #if defined(__ARMEL__)
57 #define load_var_to_reg_lng(regnr,v,tempnr) { \
58 if ((v)->flags & INMEMORY) { \
60 M_STACK_LOAD_LNG(tempnr, (v)->regoff); \
62 } else if (GET_HIGH_REG((v)->regoff)==REG_SPLIT) { \
63 M_LDR_INTERN(GET_HIGH_REG(tempnr), REG_SP, 0); /* TODO: where to load? */ \
64 regnr = PACK_REGS(GET_LOW_REG((v)->regoff), GET_HIGH_REG(tempnr)); \
65 } else regnr = (v)->regoff; \
67 #else /* defined(__ARMEB__) */
68 #define load_var_to_reg_lng(regnr,v,tempnr) { \
69 if ((v)->flags & INMEMORY) { \
71 M_STACK_LOAD_LNG(tempnr, (v)->regoff); \
73 } else if (GET_LOW_REG((v)->regoff)==REG_SPLIT) { \
74 M_LDR_INTERN(GET_LOW_REG(tempnr), REG_SP, 0); /* TODO: where to load? */ \
75 regnr = PACK_REGS(GET_LOW_REG(tempnr), GET_HIGH_REG((v)->regoff)); \
76 } else regnr = (v)->regoff; \
81 /* store_reg_to_var_xxx:
82 This function generates the code to store the result of an operation
83 back into a spilled pseudo-variable.
84 If the pseudo-variable has not been spilled in the first place, this
85 function will generate nothing.
87 tempnr: Number of the temporary registers as returned by
91 #if defined(__ARMEL__)
92 #define store_reg_to_var_lng(v,tempnr) { \
93 if ((v)->flags & INMEMORY) { \
95 M_STACK_STORE_LNG(tempnr, (v)->regoff); \
96 } else if (GET_HIGH_REG((v)->regoff)==REG_SPLIT) { \
97 M_STR_INTERN(GET_HIGH_REG(tempnr), REG_SP, 0); /* TODO: where to store? */ \
100 #else /* defined(__ARMEB__) */
101 #define store_reg_to_var_lng(v,tempnr) { \
102 if ((v)->flags & INMEMORY) { \
104 M_STACK_STORE_LNG(tempnr, (v)->regoff); \
105 } else if (GET_LOW_REG((v)->regoff)==REG_SPLIT) { \
106 M_STR_INTERN(GET_LOW_REG(tempnr), REG_SP, 0); /* TODO: where to store? */ \
111 #if defined(__ARMEL__)
112 #define SPLIT_OPEN(type, reg, tmpreg) \
113 if (IS_2_WORD_TYPE(type) && GET_HIGH_REG(reg)==REG_SPLIT) { \
114 /*dolog("SPLIT_OPEN({R%d;SPL} > {R%d;R%d})", GET_LOW_REG(reg), GET_LOW_REG(reg), tmpreg);*/ \
115 /*assert(GET_LOW_REG(reg) == 3);*/ \
116 (reg) = PACK_REGS(GET_LOW_REG(reg), tmpreg); \
118 #define SPLIT_LOAD(type, reg, offset) \
119 if (IS_2_WORD_TYPE(type) && GET_LOW_REG(reg)==3) { \
120 /*dolog("SPLIT_LOAD({R%d;R%d} from [%x])", GET_LOW_REG(reg), GET_HIGH_REG(reg), offset);*/ \
121 M_LDR(GET_HIGH_REG(reg), REG_SP, 4 * (offset)); \
123 #define SPLIT_STORE_AND_CLOSE(type, reg, offset) \
124 if (IS_2_WORD_TYPE(type) && GET_LOW_REG(reg)==3) { \
125 /*dolog("SPLIT_STORE({R%d;R%d} to [%x])", GET_LOW_REG(reg), GET_HIGH_REG(reg), offset);*/ \
126 M_STR(GET_HIGH_REG(reg), REG_SP, 4 * (offset)); \
127 (reg) = PACK_REGS(GET_LOW_REG(reg), REG_SPLIT); \
129 #else /* defined(__ARMEB__) */
130 #define SPLIT_OPEN(type, reg, tmpreg) \
131 if (IS_2_WORD_TYPE(type) && GET_LOW_REG(reg)==REG_SPLIT) { \
132 /*dolog("SPLIT_OPEN({SPL;R%d} > {R%d;R%d})", GET_HIGH_REG(reg), tmpreg, GET_HIGH_REG(reg));*/ \
133 /*assert(GET_HIGH_REG(reg) == 3);*/ \
134 (reg) = PACK_REGS(tmpreg, GET_HIGH_REG(reg)); \
136 #define SPLIT_LOAD(type, reg, offset) \
137 if (IS_2_WORD_TYPE(type) && GET_HIGH_REG(reg)==3) { \
138 /*dolog("SPLIT_LOAD({R%d;R%d} from [%x])", GET_LOW_REG(reg), GET_HIGH_REG(reg), offset);*/ \
139 M_LDR(GET_LOW_REG(reg), REG_SP, 4 * (offset)); \
141 #define SPLIT_STORE_AND_CLOSE(type, reg, offset) \
142 if (IS_2_WORD_TYPE(type) && GET_HIGH_REG(reg)==3) { \
143 /*dolog("SPLIT_STORE({R%d;R%d} to [%x])", GET_LOW_REG(reg), GET_HIGH_REG(reg), offset);*/ \
144 M_STR(GET_LOW_REG(reg), REG_SP, 4 * (offset)); \
145 (reg) = PACK_REGS(REG_SPLIT, GET_HIGH_REG(reg)); \
150 #define MCODECHECK(icnt) \
152 if ((cd->mcodeptr + (icnt) * 4) > cd->mcodeend) \
153 codegen_increase(cd); \
157 /* TODO: correct this! */
158 #define IS_IMM(val) ( ((val) >= 0) && ((val) <= 255) )
159 #define IS_OFFSET(off,max) ((s4)(off) <= (max) && (s4)(off) >= -(max))
162 # define CHECK_INT_REG(r) if ((r)<0 || (r)>15) printf("CHECK_INT_REG: this is not an integer register: %d\n", r); assert((r)>=0 && (r)<=15)
163 # define CHECK_FLT_REG(r) if ((r)<0 || (r)>7) printf("CHECK_FLT_REG: this is not an float register: %d\n", r); assert((r)>=0 && (r)<=7)
164 # define CHECK_OFFSET(off,max) \
165 if (!IS_OFFSET(off,max)) printf("CHECK_OFFSET: offset out of range: %x (>%x) SEVERE ERROR!!!\n", ((off)<0)?-(off):off, max); \
166 assert(IS_OFFSET(off,max))
168 # define CHECK_INT_REG(r)
169 # define CHECK_FLT_REG(r)
170 # define CHECK_OFFSET(off,max)
174 /* branch defines *************************************************************/
176 #define BRANCH_NOPS \
182 /* patcher defines ************************************************************/
184 #define PATCHER_CALL_SIZE 1 * 4 /* an instruction is 4-bytes long */
186 #define PATCHER_NOPS \
192 /* lazy debugger **************************************************************/
195 void asm_debug(int a1, int a2, int a3, int a4);
196 void asm_debug_intern(int a1, int a2, int a3, int a4);
198 /* if called with this macros, it can be placed nearly anywhere */
199 /* almost all registers are saved and restored afterwards */
200 /* it uses a long branch to call the asm_debug_intern (no exit) */
201 #define ASM_DEBUG_PREPARE \
202 M_STMFD(0x7fff, REG_SP)
203 #define ASM_DEBUG_EXECUTE \
204 M_LONGBRANCH(asm_debug_intern); \
205 M_LDMFD(0x7fff, REG_SP)
209 /* macros to create code ******************************************************/
211 /* the condition field */
212 #define COND_EQ 0x0 /* Equal Z set */
213 #define COND_NE 0x1 /* Not equal Z clear */
214 #define COND_CS 0x2 /* Carry set C set */
215 #define COND_CC 0x3 /* Carry clear C clear */
216 #define COND_MI 0x4 /* Negative N set */
217 #define COND_PL 0x5 /* Positive N clear */
218 #define COND_VS 0x6 /* Overflow V set */
219 #define COND_VC 0x7 /* No overflow V clear */
220 #define COND_HI 0x8 /* Unsigned higher */
221 #define COND_LS 0x9 /* Unsigned lower, same */
222 #define COND_GE 0xA /* Sig. greater, equal */
223 #define COND_LT 0xB /* Sig. less than */
224 #define COND_GT 0xC /* Sig. greater than */
225 #define COND_LE 0xD /* Sig. less, equal */
226 #define COND_AL 0xE /* Always */
227 #define CONDNV 0xF /* Special (see A3-5) */
228 #define UNCOND COND_AL
230 /* data processing operation: M_DAT
231 cond ... conditional execution
233 d ...... destination reg
235 S ...... update condition codes
236 I ...... switch to immediate mode
237 shift .. shifter operand
240 #define M_DAT(cond,op,d,n,S,I,shift) \
242 *((u4 *) cd->mcodeptr) = (((cond) << 28) | ((op) << 21) | ((d) << 12) | ((n) << 16) | ((I) << 25) | ((S) << 20) | ((shift) & 0x00000fff)); \
247 /* load and store instruction: M_MEM
248 cond ... conditional execution
249 L ...... load (L=1) or store (L=0)
250 B ...... unsigned byte (B=1) or word (B=0)
251 d ...... destination reg
252 n ...... base reg for addressing
253 adr .... addressing mode specific
256 #define M_MEM(cond,L,B,d,n,adr,I,P,U,W) \
258 *((u4 *) cd->mcodeptr) = (((cond) << 28) | (1 << 26) | ((L) << 20) | ((B) << 22) | ((d) << 12) | ((n) << 16) | ((adr) & 0x0fff) | ((I) << 25) | ((P) << 24) | ((U) << 23) | ((W) << 21)); \
263 /* load and store instruction: M_MEM2
264 cond ... conditional execution
265 L ...... load (L=1) or store (L=0)
266 H ...... halfword (H=1) or signed byte (H=0)
267 S ...... signed (S=1) or unsigned (S=0) halfword
268 d ...... destination reg
269 n ...... base reg for addressing
270 adr .... addressing mode specific
273 #define M_MEM2(cond,L,H,S,d,n,adr,I,P,U,W) \
275 *((u4 *) cd->mcodeptr) = (((cond) << 28) | (1 << 22) | (0x9 << 4) | ((L) << 20) | ((H) << 5) | ((S) << 6) | ((d) << 12) | ((n) << 16) | ((adr) & 0x0f) | (((adr) & 0xf0) << (8-4)) | ((I) << 22) | ((P) << 24) | ((U) << 23) | ((W) << 21)); \
280 /* load and store multiple instruction: M_MEM_MULTI
281 cond ... conditional execution
282 L ...... load (L=1) or store (L=0)
283 S ...... special (see "The ARM ARM A3-21")
284 regs ... register list
285 n ...... base reg for addressing
288 #define M_MEM_MULTI(cond,L,S,regs,n,P,U,W) \
290 *((u4 *) cd->mcodeptr) = (((cond) << 28) | (1 << 27) | ((L) << 20) | ((S) << 22) | ((n) << 16) | ((regs) & 0xffff) | ((P) << 24) | ((U) << 23) | ((W) << 21)); \
295 /* branch and branch with link: M_BRA
296 cond ... conditional execution
297 L ...... branch with link (L=1)
298 offset . 24bit offset
301 #define M_BRA(cond,L,offset) \
303 *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x5 << 25) | ((L) << 24) | ((offset) & 0x00ffffff)); \
308 /* multiplies: M_MULT
309 cond ... conditional execution
310 d ...... destination register
311 n, m ... source registers
312 S ...... update conditional codes
313 A ...... accumulate flag (enables third source)
314 s ...... third source register
317 #define M_MULT(cond,d,n,m,S,A,s) \
319 *((u4 *) cd->mcodeptr) = (((cond) << 28) | ((d) << 16) | ((n) << 8) | (m) | (0x09 << 4) | ((S) << 20) | ((A) << 21) | ((s) << 12)); \
324 /* no operation (mov r0,r0): M_NOP */
328 *((u4 *) cd->mcodeptr) = (0xe1a00000); \
333 /* software breakpoint (only v5 and above): M_BREAKPOINT */
335 #define M_BREAKPOINT(imm) \
337 *((u4 *) cd->mcodeptr) = (0x0e12 << 20) | (0x07 << 4) | (((imm) & 0xfff0) << (8-4)) | ((imm) & 0x0f); \
342 #if !defined(ENABLE_SOFTFLOAT)
344 /* M_CPDO **********************************************************************
346 Floating-Point Coprocessor Data Operations
348 cond ... conditional execution
350 D ...... dyadic (D=0) or monadic (D=1) instruction
351 Fd ..... destination float-register
352 Fn ..... source float-register
353 Fm ..... source float-register or immediate
355 *******************************************************************************/
357 #define M_CPDOS(cond,op,D,Fd,Fn,Fm) \
359 *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0e << 24) | (1 << 8) | ((op) << 20) | ((D) << 15) | ((Fd) << 12) | ((Fn) << 16) | ((Fm) & 0x0f)); \
364 #define M_CPDOD(cond,op,D,Fd,Fn,Fm) \
366 *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0e << 24) | (1 << 8) | ((op) << 20) | ((D) << 15) | ((Fd) << 12) | ((Fn) << 16) | ((Fm) & 0x0f) | (1 << 7)); \
371 /* M_CPDT **********************************************************************
373 Floating-Point Coprocessor Data Transfer
375 cond ... conditional execution
376 L ...... load (L=1) or store (L=0)
377 Fd ..... destination float-register
378 n ...... base reg for addressing
380 *******************************************************************************/
382 #define M_CPDT(cond,L,T1,T0,Fd,n,off,P,U,W) \
384 *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0c << 24) | (1 << 8) | ((L) << 20) | ((T1) << 22) | ((T0) << 15) | ((Fd) << 12) | ((n) << 16) | ((off) & 0xff) | ((P) << 24) | ((U) << 23) | ((W) << 21)); \
389 /* M_CPRT **********************************************************************
391 Floating-Point Coprocessor Register Transfer
395 *******************************************************************************/
397 #define M_CPRTS(cond,L,d,Fn,Fm) \
399 *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0e << 24) | (1 << 8) | (1 << 4) | ((L) << 20) | ((d) << 12) | ((Fn) << 16) | (Fm)); \
404 #define M_CPRTD(cond,L,d,Fn,Fm) \
406 *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0e << 24) | (1 << 8) | (1 << 4) | ((L) << 20) | ((d) << 12) | ((Fn) << 16) | (Fm) | (1 << 7)); \
411 #define M_CPRTI(cond,L,d,Fn,Fm) \
413 *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0e << 24) | (1 << 8) | (1 << 4) | ((L) << 20) | ((d) << 12) | ((Fn) << 16) | (Fm) | (3 << 5)); \
418 /* XXX TWISTI: replace X by something useful */
420 #define M_CPRTX(cond,L,d,Fn,Fm) \
422 *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0e << 24) | (1 << 8) | (1 << 4) | ((L) << 20) | ((d) << 12) | ((Fn) << 16) | (Fm) | (1 << 23)); \
426 #endif /* !defined(ENABLE_SOFTFLOAT) */
429 /* used to store values! */
432 *((u4 *) cd->mcodeptr) = val; \
437 /* used to directly access shifter; insert this as shifter operand! */
438 #define REG_LSL(reg, shift) ( (((shift) & 0x1f) << 7) | ((reg) & 0x0f) )
439 #define REG_LSR(reg, shift) ( (((shift) & 0x1f) << 7) | ((reg) & 0x0f) | (1 << 5) )
440 #define REG_ASR(reg, shift) ( (((shift) & 0x1f) << 7) | ((reg) & 0x0f) | (1 << 6) )
441 #define REG_LSL_REG(reg, s) ( (((s) & 0x0f) << 8) | ((reg) & 0x0f) | (1 << 4) )
442 #define REG_LSR_REG(reg, s) ( (((s) & 0x0f) << 8) | ((reg) & 0x0f) | (1 << 4) | (1 << 5) )
443 #define REG_ASR_REG(reg, s) ( (((s) & 0x0f) << 8) | ((reg) & 0x0f) | (1 << 4) | (1 << 6) )
445 /* used to directly rotate immediate values; insert this as immediate! */
446 /* ATTENTION: this rotates the immediate right by (2 * rot) bits */
447 #define IMM_ROTR(imm, rot) ( ((imm) & 0xff) | (((rot) & 0x0f) << 8) )
448 #define IMM_ROTL(imm, rot) IMM_ROTR(imm, 16-(rot))
450 /* macros for all arm instructions ********************************************/
452 #define M_ADD(d,a,b) M_DAT(UNCOND,0x04,d,a,0,0,b) /* d = a + b */
453 #define M_ADC(d,a,b) M_DAT(UNCOND,0x05,d,a,0,0,b) /* d = a + b (with Carry) */
454 #define M_SUB(d,a,b) M_DAT(UNCOND,0x02,d,a,0,0,b) /* d = a - b */
455 #define M_SBC(d,a,b) M_DAT(UNCOND,0x06,d,a,0,0,b) /* d = a - b (with Carry) */
456 #define M_AND(a,b,d) M_DAT(UNCOND,0x00,d,a,0,0,b) /* d = a & b */
457 #define M_ORR(a,b,d) M_DAT(UNCOND,0x0c,d,a,0,0,b) /* d = a | b */
458 #define M_EOR(a,b,d) M_DAT(UNCOND,0x01,d,a,0,0,b) /* d = a ^ b */
459 #define M_TST(a,b) M_DAT(UNCOND,0x08,0,a,1,0,b) /* TST a & b */
460 #define M_TEQ(a,b) M_DAT(UNCOND,0x09,0,a,1,0,b) /* TST a ^ b */
461 #define M_CMP(a,b) M_DAT(UNCOND,0x0a,0,a,1,0,b) /* TST a - b */
462 #define M_MOV(d,b) M_DAT(UNCOND,0x0d,d,0,0,0,b) /* d = b */
463 #define M_ADD_S(d,a,b) M_DAT(UNCOND,0x04,d,a,1,0,b) /* d = a + b (update Flags) */
464 #define M_SUB_S(d,a,b) M_DAT(UNCOND,0x02,d,a,1,0,b) /* d = a - b (update Flags) */
465 #define M_ORR_S(a,b,d) M_DAT(UNCOND,0x0c,d,a,1,0,b) /* d = a | b (update flags) */
466 #define M_MOV_S(d,b) M_DAT(UNCOND,0x0d,d,0,1,0,b) /* d = b (update Flags) */
468 #define M_ADD_IMM(d,a,i) M_DAT(UNCOND,0x04,d,a,0,1,i) /* d = a + i */
469 #define M_ADC_IMM(d,a,i) M_DAT(UNCOND,0x05,d,a,0,1,i) /* d = a + i (with Carry) */
470 #define M_SUB_IMM(d,a,i) M_DAT(UNCOND,0x02,d,a,0,1,i) /* d = a - i */
471 #define M_SBC_IMM(d,a,i) M_DAT(UNCOND,0x06,d,a,0,1,i) /* d = a - i (with Carry) */
472 #define M_RSB_IMM(d,a,i) M_DAT(UNCOND,0x03,d,a,0,1,i) /* d = -a + i */
473 #define M_RSC_IMM(d,a,i) M_DAT(UNCOND,0x07,d,a,0,1,i) /* d = -a + i (with Carry) */
474 #define M_AND_IMM(a,i,d) M_DAT(UNCOND,0x00,d,a,0,1,i) /* d = a & i */
475 #define M_TST_IMM(a,i) M_DAT(UNCOND,0x08,0,a,1,1,i) /* TST a & i */
476 #define M_TEQ_IMM(a,i) M_DAT(UNCOND,0x09,0,a,1,1,i) /* TST a ^ i */
477 #define M_CMP_IMM(a,i) M_DAT(UNCOND,0x0a,0,a,1,1,i) /* TST a - i */
478 #define M_CMN_IMM(a,i) M_DAT(UNCOND,0x0b,0,a,1,1,i) /* TST a + i */
479 #define M_MOV_IMM(d,i) M_DAT(UNCOND,0x0d,d,0,0,1,i) /* d = i */
480 #define M_ADD_IMMS(d,a,i) M_DAT(UNCOND,0x04,d,a,1,1,i) /* d = a + i (update Flags) */
481 #define M_SUB_IMMS(d,a,i) M_DAT(UNCOND,0x02,d,a,1,1,i) /* d = a - i (update Flags) */
482 #define M_RSB_IMMS(d,a,i) M_DAT(UNCOND,0x03,d,a,1,1,i) /* d = -a + i (update Flags) */
484 #define M_ADDSUB_IMM(d,a,i) if((i)>=0) M_ADD_IMM(d,a,i); else M_SUB_IMM(d,a,-(i))
485 #define M_MOVEQ(a,d) M_DAT(COND_EQ,0x0d,d,0,0,0,a)
487 #define M_MOVVS_IMM(i,d) M_DAT(COND_VS,0x0d,d,0,0,1,i)
488 #define M_MOVEQ_IMM(i,d) M_DAT(COND_EQ,0x0d,d,0,0,1,i)
489 #define M_MOVNE_IMM(i,d) M_DAT(COND_NE,0x0d,d,0,0,1,i)
490 #define M_MOVLT_IMM(i,d) M_DAT(COND_LT,0x0d,d,0,0,1,i)
491 #define M_MOVGT_IMM(i,d) M_DAT(COND_GT,0x0d,d,0,0,1,i)
492 #define M_MOVLS_IMM(i,d) M_DAT(COND_LS,0x0d,d,0,0,1,i)
494 #define M_ADDHI_IMM(d,a,i) M_DAT(COND_HI,0x04,d,a,0,1,i)
495 #define M_ADDLT_IMM(d,a,i) M_DAT(COND_LT,0x04,d,a,0,1,i)
496 #define M_ADDGT_IMM(d,a,i) M_DAT(COND_GT,0x04,d,a,0,1,i)
497 #define M_SUBLO_IMM(d,a,i) M_DAT(COND_CC,0x02,d,a,0,1,i)
498 #define M_SUBLT_IMM(d,a,i) M_DAT(COND_LT,0x02,d,a,0,1,i)
499 #define M_SUBGT_IMM(d,a,i) M_DAT(COND_GT,0x02,d,a,0,1,i)
500 #define M_RSBMI_IMM(d,a,i) M_DAT(COND_MI,0x03,d,a,0,1,i)
501 #define M_ADCMI_IMM(d,a,i) M_DAT(COND_MI,0x05,d,a,0,1,i)
503 #define M_CMPEQ(a,b) M_DAT(COND_EQ,0x0a,0,a,1,0,b) /* TST a - b */
504 #define M_CMPLE(a,b) M_DAT(COND_LE,0x0a,0,a,1,0,b) /* TST a - b */
506 #define M_CMPEQ_IMM(a,i) M_DAT(COND_EQ,0x0a,0,a,1,1,i)
508 #define M_MUL(d,a,b) M_MULT(UNCOND,d,a,b,0,0,0x0) /* d = a * b */
511 #define M_LDMFD(regs,base) M_MEM_MULTI(UNCOND,1,0,regs,base,0,1,1)
512 #define M_STMFD(regs,base) M_MEM_MULTI(UNCOND,0,0,regs,base,1,0,1)
514 #define M_LDR_INTERN(d,base,off) \
516 CHECK_OFFSET(off, 0x0fff); \
517 M_MEM(UNCOND,1,0,d,base,(((off) < 0) ? -(off) : off),0,1,(((off) < 0) ? 0 : 1),0); \
520 #define M_STR_INTERN(d,base,off) \
522 CHECK_OFFSET(off, 0x0fff); \
523 M_MEM(UNCOND,0,0,d,base,(((off) < 0) ? -(off) : off),0,1,(((off) < 0) ? 0 : 1),0); \
526 #define M_LDR_UPDATE(d,base,off) \
528 CHECK_OFFSET(off, 0x0fff); \
529 M_MEM(UNCOND,1,0,d,base,(((off) < 0) ? -(off) : off),0,0,(((off) < 0) ? 0 : 1),0); \
532 #define M_STR_UPDATE(d,base,off) \
534 CHECK_OFFSET(off,0x0fff); \
535 M_MEM(UNCOND,0,0,d,base,(((off) < 0) ? -(off) : off),0,1,(((off) < 0) ? 0 : 1),1); \
539 #define M_LDRH(d,base,off) \
541 CHECK_OFFSET(off, 0x00ff); \
543 M_MEM2(UNCOND,1,1,0,d,base,off,1,1,1,0); \
546 #define M_LDRSH(d,base,off) \
548 CHECK_OFFSET(off, 0x00ff); \
550 M_MEM2(UNCOND,1,1,1,d,base,off,1,1,1,0); \
553 #define M_LDRSB(d,base,off) \
555 CHECK_OFFSET(off, 0x00ff); \
557 M_MEM2(UNCOND,1,0,1,d,base,off,1,1,1,0); \
560 #define M_STRH(d,base,off) \
562 CHECK_OFFSET(off, 0x00ff); \
564 M_MEM2(UNCOND,0,1,0,d,base,off,1,1,1,0); \
567 #define M_STRB(d,base,off) \
569 CHECK_OFFSET(off, 0x0fff); \
571 M_MEM(UNCOND,0,1,d,base,off,0,1,1,0); \
575 #if !defined(ENABLE_SOFTFLOAT)
577 #define M_LDFS_INTERN(d,base,off) \
579 CHECK_OFFSET(off, 0x03ff); \
580 M_CPDT(UNCOND,1,0,0,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),1,(((off) < 0) ? 0 : 1),0); \
583 #define M_LDFD_INTERN(d,base,off) \
585 CHECK_OFFSET(off, 0x03ff); \
586 M_CPDT(UNCOND,1,0,1,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),1,(((off) < 0) ? 0 : 1),0); \
589 #define M_STFS_INTERN(d,base,off) \
591 CHECK_OFFSET(off, 0x03ff); \
592 M_CPDT(UNCOND,0,0,0,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),1,(((off) < 0) ? 0 : 1),0); \
595 #define M_STFD_INTERN(d,base,off) \
597 CHECK_OFFSET(off, 0x03ff); \
598 M_CPDT(UNCOND,0,0,1,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),1,(((off) < 0) ? 0 : 1),0); \
601 #define M_LDFS_UPDATE(d,base,off) \
603 CHECK_OFFSET(off, 0x03ff); \
604 M_CPDT(UNCOND,1,0,0,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),0,(((off) < 0) ? 0 : 1),1); \
607 #define M_LDFD_UPDATE(d,base,off) \
609 CHECK_OFFSET(off, 0x03ff); \
610 M_CPDT(UNCOND,1,0,1,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),0,(((off) < 0) ? 0 : 1),1); \
613 #define M_STFS_UPDATE(d,base,off) \
615 CHECK_OFFSET(off, 0x03ff); \
616 M_CPDT(UNCOND,0,0,0,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),1,(((off) < 0) ? 0 : 1),1); \
619 #define M_STFD_UPDATE(d,base,off) \
621 CHECK_OFFSET(off, 0x03ff); \
622 M_CPDT(UNCOND,0,0,1,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),1,(((off) < 0) ? 0 : 1),1); \
625 #define M_ADFS(d,a,b) M_CPDOS(UNCOND,0x00,0,d,a,b) /* d = a + b */
626 #define M_SUFS(d,a,b) M_CPDOS(UNCOND,0x02,0,d,a,b) /* d = a - b */
627 #define M_RSFS(d,a,b) M_CPDOS(UNCOND,0x03,0,d,a,b) /* d = b - a */
628 #define M_MUFS(d,a,b) M_CPDOS(UNCOND,0x01,0,d,a,b) /* d = a * b */
629 #define M_DVFS(d,a,b) M_CPDOS(UNCOND,0x04,0,d,a,b) /* d = a / b */
630 #define M_RMFS(d,a,b) M_CPDOS(UNCOND,0x08,0,d,a,b) /* d = a % b */
631 #define M_ADFD(d,a,b) M_CPDOD(UNCOND,0x00,0,d,a,b) /* d = a + b */
632 #define M_SUFD(d,a,b) M_CPDOD(UNCOND,0x02,0,d,a,b) /* d = a - b */
633 #define M_RSFD(d,a,b) M_CPDOD(UNCOND,0x03,0,d,a,b) /* d = b - a */
634 #define M_MUFD(d,a,b) M_CPDOD(UNCOND,0x01,0,d,a,b) /* d = a * b */
635 #define M_DVFD(d,a,b) M_CPDOD(UNCOND,0x04,0,d,a,b) /* d = a / b */
636 #define M_RMFD(d,a,b) M_CPDOD(UNCOND,0x08,0,d,a,b) /* d = a % b */
637 #define M_MVFS(d,a) M_CPDOS(UNCOND,0x00,1,d,0,a) /* d = a */
638 #define M_MVFD(d,a) M_CPDOD(UNCOND,0x00,1,d,0,a) /* d = a */
639 #define M_MNFS(d,a) M_CPDOS(UNCOND,0x01,1,d,0,a) /* d = - a */
640 #define M_MNFD(d,a) M_CPDOD(UNCOND,0x01,1,d,0,a) /* d = - a */
641 #define M_CMF(a,b) M_CPRTX(UNCOND,1,0x0f,a,b) /* COMPARE a; b */
642 #define M_FLTS(d,a) M_CPRTS(UNCOND,0,a,d,0) /* d = (float) a */
643 #define M_FLTD(d,a) M_CPRTD(UNCOND,0,a,d,0) /* d = (float) a */
644 #define M_FIX(d,a) M_CPRTI(UNCOND,1,d,0,a) /* d = (int) a */
646 #endif /* !defined(ENABLE_SOFTFLOAT) */
649 #define M_B(off) M_BRA(UNCOND,0,off) /* unconditional branch */
650 #define M_BL(off) M_BRA(UNCOND,1,off) /* branch and link */
651 #define M_BEQ(off) M_BRA(COND_EQ,0,off) /* conditional branches */
652 #define M_BNE(off) M_BRA(COND_NE,0,off)
653 #define M_BGE(off) M_BRA(COND_GE,0,off)
654 #define M_BGT(off) M_BRA(COND_GT,0,off)
655 #define M_BLT(off) M_BRA(COND_LT,0,off)
656 #define M_BLE(off) M_BRA(COND_LE,0,off)
657 #define M_BHI(off) M_BRA(COND_HI,0,off) /* unsigned conditional */
658 #define M_BHS(off) M_BRA(COND_CS,0,off)
659 #define M_BLO(off) M_BRA(COND_CC,0,off)
660 #define M_BLS(off) M_BRA(COND_LS,0,off)
663 #define M_FMOV(a,b) M_MVFS(b,a)
664 #define M_DMOV(a,b) M_MVFD(b,a)
667 /* if we do not have double-word load/store command, we can fake them */
668 /* ATTENTION: the original LDRD/STRD of ARMv5e would always use (Rd/Rd+1),
669 so these faked versions are more "powerful" */
671 #if defined(__ARMEL__)
673 #define M_LDRD_INTERN(d,base,off) \
675 M_LDR_INTERN(GET_LOW_REG(d), base, off); \
676 M_LDR_INTERN(GET_HIGH_REG(d), base, (off) + 4); \
679 #define M_STRD_INTERN(d,base,off) \
681 M_STR_INTERN(GET_LOW_REG(d), base, off); \
682 M_STR_INTERN(GET_HIGH_REG(d), base, (off) + 4); \
685 #define M_LDRD_ALTERN(d,base,off) \
687 M_LDR_INTERN(GET_HIGH_REG(d), base, (off) + 4); \
688 M_LDR_INTERN(GET_LOW_REG(d), base, off); \
691 #define M_LDRD_UPDATE(d,base,off) \
693 assert((off) == +8); \
694 M_LDR_UPDATE(GET_LOW_REG(d), base, 4); \
695 M_LDR_UPDATE(GET_HIGH_REG(d), base, 4); \
698 #define M_STRD_UPDATE(d,base,off) \
700 assert((off) == -8); \
701 M_STR_UPDATE(GET_HIGH_REG(d), base, -4); \
702 M_STR_UPDATE(GET_LOW_REG(d), base, -4); \
705 #define GET_FIRST_REG(d) GET_LOW_REG(d)
706 #define GET_SECOND_REG(d) GET_HIGH_REG(d)
708 #else /* defined(__ARMEB__) */
710 #define M_LDRD_INTERN(d,base,off) \
712 M_LDR_INTERN(GET_HIGH_REG(d), base, off); \
713 M_LDR_INTERN(GET_LOW_REG(d), base, (off) + 4); \
716 #define M_STRD_INTERN(d,base,off) \
718 M_STR_INTERN(GET_HIGH_REG(d), base, off); \
719 M_STR_INTERN(GET_LOW_REG(d), base, (off) + 4); \
722 #define M_LDRD_ALTERN(d,base,off) \
724 M_LDR_INTERN(GET_LOW_REG(d), base, (off) + 4); \
725 M_LDR_INTERN(GET_HIGH_REG(d), base, off); \
728 #define M_LDRD_UPDATE(d,base,off) \
730 assert((off) == +8); \
731 M_LDR_UPDATE(GET_HIGH_REG(d), base, 4); \
732 M_LDR_UPDATE(GET_LOW_REG(d), base, 4); \
735 #define M_STRD_UPDATE(d,base,off) \
737 assert((off) == -8); \
738 M_STR_UPDATE(GET_LOW_REG(d), base, -4); \
739 M_STR_UPDATE(GET_HIGH_REG(d) ,base, -4); \
742 #define GET_FIRST_REG(d) GET_HIGH_REG(d)
743 #define GET_SECOND_REG(d) GET_LOW_REG(d)
745 #endif /* defined(__ARMEB__) */
749 these are replacements for the original LDR/STR instructions, which can
750 handle longer offsets (up to 20bits). the original functions are now
753 /* ATTENTION: We use ITMP3 here, take into account that it gets destroyed.
754 This means that only ITMP1 and ITMP2 can be used in reg_of_var()!!!
756 /* ATTENTION2: It is possible to use ITMP3 as base reg. Remember that when
757 changing these macros!!!
760 #define M_LDR(d, base, offset) \
762 CHECK_OFFSET(offset, 0x0fffff); \
763 if (IS_OFFSET(offset, 0x000fff)) { \
764 M_LDR_INTERN(d, base, offset); \
766 /* we cannot handle REG_PC here */ \
767 assert((d) != REG_PC); \
768 if ((offset) > 0) { \
769 M_ADD_IMM(d, base, IMM_ROTL((offset) >> 12, 6)); \
770 M_LDR_INTERN(d, d, (offset) & 0x000fff); \
772 M_SUB_IMM(d, base, IMM_ROTL((-(offset)) >> 12, 6)); \
773 M_LDR_INTERN(d, d, -(-(offset) & 0x000fff)); \
778 #define M_LDR_NEGATIVE(d, base, offset) { \
779 /*assert((offset) <= 0);*/ \
780 if (IS_OFFSET(offset, 0x000fff)) { \
781 M_LDR_INTERN(d, base, offset); \
783 /* we cannot handle REG_PC here */ \
784 assert((d) != REG_PC); \
785 M_SUB_IMM(d, base, IMM_ROTL((-(offset)) >> 12, 6)); \
786 M_LDR_INTERN(d, d, -(-(offset) & 0x000fff)); \
790 #define M_LDRD(d, base, offset) \
792 CHECK_OFFSET(offset, 0x0fffff - 4); \
793 if (IS_OFFSET(offset, 0x000fff - 4)) { \
794 if (GET_FIRST_REG(d) != (base)) { \
795 M_LDRD_INTERN(d, base, offset); \
797 M_LDRD_ALTERN(d, base, offset); \
799 } else if (IS_OFFSET(offset, 0x000fff)) { \
800 dolog("M_LDRD: this offset seems to be complicated (%d)", offset); \
803 if ((offset) > 0) { \
804 M_ADD_IMM(GET_SECOND_REG(d), base, IMM_ROTL((offset) >> 12, 6)); \
805 M_LDRD_INTERN(d, GET_SECOND_REG(d), (offset) & 0x000fff); \
807 M_SUB_IMM(GET_SECOND_REG(d), base, IMM_ROTL((-(offset)) >> 12, 6)); \
808 M_LDRD_INTERN(d, GET_SECOND_REG(d), -(-(offset) & 0x000fff)); \
813 #if !defined(ENABLE_SOFTFLOAT)
814 #define M_LDFS(d, base, offset) \
816 CHECK_OFFSET(offset, 0x03ffff); \
817 if (IS_OFFSET(offset, 0x03ff)) { \
818 M_LDFS_INTERN(d, base, offset); \
820 if ((offset) > 0) { \
821 M_ADD_IMM(REG_ITMP3, base, IMM_ROTL((offset) >> 10, 5)); \
822 M_LDFS_INTERN(d, REG_ITMP3, (offset) & 0x03ff); \
824 M_SUB_IMM(REG_ITMP3, base, IMM_ROTL((-(offset)) >> 10, 5)); \
825 M_LDFS_INTERN(d, REG_ITMP3, -(-(offset) & 0x03ff)); \
830 #define M_LDFD(d, base, offset) \
832 CHECK_OFFSET(offset, 0x03ffff); \
833 if (IS_OFFSET(offset, 0x03ff)) { \
834 M_LDFD_INTERN(d, base, offset); \
836 if ((offset) > 0) { \
837 M_ADD_IMM(REG_ITMP3, base, IMM_ROTL((offset) >> 10, 5)); \
838 M_LDFD_INTERN(d, REG_ITMP3, (offset) & 0x03ff); \
840 M_SUB_IMM(REG_ITMP3, base, IMM_ROTL((-(offset)) >> 10, 5)); \
841 M_LDFD_INTERN(d, REG_ITMP3, -(-(offset) & 0x03ff)); \
846 #endif /* !defined(ENABLE_SOFTFLOAT) */
848 #define M_STR(d, base, offset) \
850 assert((d) != REG_ITMP3); \
851 CHECK_OFFSET(offset, 0x0fffff); \
852 if (IS_OFFSET(offset, 0x000fff)) { \
853 M_STR_INTERN(d, base, offset); \
855 if ((offset) > 0) { \
856 M_ADD_IMM(REG_ITMP3, base, IMM_ROTL((offset) >> 12, 6)); \
857 M_STR_INTERN(d, REG_ITMP3, (offset) & 0x000fff); \
859 M_SUB_IMM(REG_ITMP3, base, IMM_ROTL((-(offset)) >> 12, 6)); \
860 M_STR_INTERN(d, REG_ITMP3, -(-(offset) & 0x000fff)); \
865 #define M_STRD(d, base, offset) \
867 assert(GET_LOW_REG(d) != REG_ITMP3); \
868 assert(GET_HIGH_REG(d) != REG_ITMP3); \
869 CHECK_OFFSET(offset, 0x0fffff - 4); \
870 if (IS_OFFSET(offset, 0x000fff - 4)) { \
871 M_STRD_INTERN(d,base,offset); \
872 } else if (IS_OFFSET(offset, 0x000fff)) { \
873 dolog("M_STRD: this offset seems to be complicated (%d)", offset); \
876 if ((offset) > 0) { \
877 M_ADD_IMM(REG_ITMP3, base, IMM_ROTL((offset) >> 12, 6)); \
878 M_STRD_INTERN(d, REG_ITMP3, (offset) & 0x000fff); \
880 M_SUB_IMM(REG_ITMP3, base, IMM_ROTL((-(offset)) >> 12, 6)); \
881 M_STRD_INTERN(d, REG_ITMP3, -(-(offset) & 0x000fff)); \
886 #if !defined(ENABLE_SOFTFLOAT)
888 #define M_STFS(d, base, offset) \
890 CHECK_OFFSET(offset, 0x03ffff); \
891 if (IS_OFFSET(offset, 0x03ff)) { \
892 M_STFS_INTERN(d, base, offset); \
894 if ((offset) > 0) { \
895 M_ADD_IMM(REG_ITMP3, base, IMM_ROTL((offset) >> 10, 5)); \
896 M_STFS_INTERN(d, REG_ITMP3, (offset) & 0x03ff); \
898 M_SUB_IMM(REG_ITMP3, base, IMM_ROTL((-(offset)) >> 10, 5)); \
899 M_STFS_INTERN(d, REG_ITMP3, -(-(offset) & 0x03ff)); \
904 #define M_STFD(d, base, offset) \
906 CHECK_OFFSET(offset, 0x03ffff); \
907 if (IS_OFFSET(offset, 0x03ff)) { \
908 M_STFD_INTERN(d, base, offset); \
910 if ((offset) > 0) { \
911 M_ADD_IMM(REG_ITMP3, base, IMM_ROTL((offset) >> 10, 5)); \
912 M_STFD_INTERN(d, REG_ITMP3, (offset) & 0x03ff); \
914 M_SUB_IMM(REG_ITMP3, base, IMM_ROTL((-(offset)) >> 10, 5)); \
915 M_STFD_INTERN(d, REG_ITMP3, -(-(offset) & 0x03ff)); \
920 #endif /* !defined(ENABLE_SOFTFLOAT) */
922 /* M_???_IMM_EXT_MUL4:
923 extended immediate operations, to handle immediates lager than 8bit.
924 ATTENTION: the immediate is rotatet left by 2 (multiplied by 4)!!!
927 #define M_ADD_IMM_EXT_MUL4(d,n,imm) \
929 assert(d != REG_PC); \
930 assert((imm) >= 0 && (imm) <= 0x00ffffff); \
931 M_ADD_IMM(d, n, IMM_ROTL(imm, 1)); \
932 if ((imm) > 0x000000ff) M_ADD_IMM(d, d, IMM_ROTL((imm) >> 8, 5)); \
933 if ((imm) > 0x0000ffff) M_ADD_IMM(d, d, IMM_ROTL((imm) >> 16, 9)); \
936 #define M_SUB_IMM_EXT_MUL4(d,n,imm) \
938 assert(d != REG_PC); \
939 assert((imm) >= 0 && (imm) <= 0x00ffffff); \
940 M_SUB_IMM(d, n, IMM_ROTL(imm, 1)); \
941 if ((imm) > 0x000000ff) M_SUB_IMM(d, d, IMM_ROTL((imm) >> 8, 5)); \
942 if ((imm) > 0x0000ffff) M_SUB_IMM(d, d, IMM_ROTL((imm) >> 16, 9)); \
947 loads the integer/long value const into register d.
950 #define ICONST(d,c) emit_iconst(cd, (d), (c))
952 #define ICONST_CONDITIONAL(cond,d,const) \
953 if (IS_IMM(const)) { \
954 /* M_MOV_IMM */ M_DAT(cond,0x0d,d,0,0,1,const); \
956 disp = dseg_adds4(cd, const); \
957 /* TODO: implement this using M_DSEG_LOAD!!! */ \
958 /* M_LDR_INTERN */ CHECK_OFFSET(disp,0x0fff); M_MEM(cond,1,0,d,REG_PV,(disp<0)?-disp:disp,0,1,(disp<0)?0:1,0); \
961 #define LCONST(d,c) \
962 if (IS_IMM((c) >> 32)) { \
963 M_MOV_IMM(GET_HIGH_REG(d), (s4) ((s8) (c) >> 32)); \
964 ICONST(GET_LOW_REG(d), (s4) ((s8) (c) & 0xffffffff)); \
965 } else if (IS_IMM((c) & 0xffffffff)) { \
966 M_MOV_IMM(GET_LOW_REG(d), (s4) ((s8) (c) & 0xffffffff)); \
967 ICONST(GET_HIGH_REG(d), (s4) ((s8) (c) >> 32)); \
969 disp = dseg_add_s8(cd, (c)); \
970 M_LDRD(d, REG_PV, disp); \
974 #if !defined(ENABLE_SOFTFLOAT)
976 #define FCONST(d,c) \
978 disp = dseg_add_float(cd, (c)); \
979 M_LDFS(d, REG_PV, disp); \
982 #define DCONST(d,c) \
984 disp = dseg_add_double(cd, (c)); \
985 M_LDFD(d, REG_PV, disp); \
988 #endif /* !defined(ENABLE_SOFTFLOAT) */
992 used to recompute our PV (we use the IP for this) out of the current PC
993 ATTENTION: if you change this, you have to look at other functions as well!
994 Following things depend on it: asm_call_jit_compiler(); codegen_findmethod();
996 #define M_RECOMPUTE_PV(disp) \
997 disp += 8; /* we use PC relative addr. */ \
998 assert((disp & 0x03) == 0); \
999 assert(disp >= 0 && disp <= 0x03ffffff); \
1000 M_SUB_IMM(REG_PV, REG_PC, IMM_ROTL(disp >> 2, 1)); \
1001 if (disp > 0x000003ff) M_SUB_IMM(REG_PV, REG_PV, IMM_ROTL(disp >> 10, 5)); \
1002 if (disp > 0x0003ffff) M_SUB_IMM(REG_PV, REG_PV, IMM_ROTL(disp >> 18, 9)); \
1005 generates an integer-move from register a to b.
1006 if a and b are the same int-register, no code will be generated.
1009 #define M_INTMOVE(a,b) \
1015 #define M_LNGMOVE(a,b) \
1017 if (GET_HIGH_REG(a) == GET_LOW_REG(b)) { \
1018 assert((GET_LOW_REG(a) != GET_HIGH_REG(b))); \
1019 M_INTMOVE(GET_HIGH_REG(a), GET_HIGH_REG(b)); \
1020 M_INTMOVE(GET_LOW_REG(a), GET_LOW_REG(b)); \
1022 M_INTMOVE(GET_LOW_REG(a), GET_LOW_REG(b)); \
1023 M_INTMOVE(GET_HIGH_REG(a), GET_HIGH_REG(b)); \
1028 #if !defined(ENABLE_SOFTFLOAT)
1031 generates a floating-point-move from register a to b.
1032 if a and b are the same float-register, no code will be generated.
1035 #define M_FLTMOVE(a,b) \
1041 #define M_DBLMOVE(a,b) \
1049 #if !defined(ENABLE_SOFTFLOAT)
1050 /* M_CAST_INT_TO_FLT_TYPED:
1051 loads the value of the integer-register a (argument or result) into
1052 float-register Fb. (and vice versa)
1054 #define M_CAST_INT_TO_FLT_TYPED(t,a,Fb) \
1055 CHECK_FLT_REG(Fb); \
1056 if ((t) == TYPE_FLT) { \
1058 M_STR_UPDATE(a, REG_SP, -4); \
1059 M_LDFS_UPDATE(Fb, REG_SP, 4); \
1061 CHECK_INT_REG(GET_LOW_REG(a)); \
1062 CHECK_INT_REG(GET_HIGH_REG(a)); \
1063 M_STRD_UPDATE(a, REG_SP, -8); \
1064 M_LDFD_UPDATE(Fb, REG_SP, 8); \
1066 #define M_CAST_FLT_TO_INT_TYPED(t,Fa,b) \
1067 CHECK_FLT_REG(Fa); \
1068 if ((t) == TYPE_FLT) { \
1070 M_STFS_UPDATE(Fa, REG_SP, -4); \
1071 M_LDR_UPDATE(b, REG_SP, 4); \
1073 CHECK_INT_REG(GET_LOW_REG(b)); \
1074 CHECK_INT_REG(GET_HIGH_REG(b)); \
1075 M_STFD_UPDATE(Fa, REG_SP, -8); \
1076 M_LDRD_UPDATE(b, REG_SP, 8); \
1078 #endif /* !defined(ENABLE_SOFTFLOAT) */
1082 generates the compare part of an if-sequece
1083 uses M_CMP or M_CMP_IMM to do the compare
1084 ATTENTION: uses REG_ITMP3 as intermediate register
1086 #define M_COMPARE(reg, val) \
1087 if (IS_IMM(val)) { \
1088 M_CMP_IMM(reg, (val)); \
1089 } else if(IS_IMM(-(val))) { \
1090 M_CMN_IMM(reg, -(val)); \
1092 ICONST(REG_ITMP3, (val)); \
1093 M_CMP(reg, REG_ITMP3); \
1097 performs a long branch to an absolute address with return address in LR
1098 takes up 3 bytes of code space; address is hard-coded into code
1100 #define M_LONGBRANCH(adr) \
1101 M_ADD_IMM(REG_LR, REG_PC, 4); \
1102 M_LDR_INTERN(REG_PC, REG_PC, -4); \
1105 /* M_DSEG_LOAD/BRANCH:
1107 ATTENTION: if you change this, you have to look at the asm_call_jit_compiler!
1108 ATTENTION: we use M_LDR, so the same restrictions apply to us!
1110 #define M_DSEG_LOAD(reg, offset) \
1111 M_LDR_NEGATIVE(reg, REG_PV, offset)
1113 #define M_DSEG_BRANCH(offset) \
1114 if (IS_OFFSET(offset, 0x0fff)) { \
1115 M_MOV(REG_LR, REG_PC); \
1116 M_LDR_INTERN(REG_PC, REG_PV, offset); \
1118 /*assert((offset) <= 0);*/ \
1119 CHECK_OFFSET(offset,0x0fffff); \
1120 M_SUB_IMM(REG_ITMP3, REG_PV, ((-(offset) >> 12) & 0xff) | (((10) & 0x0f) << 8)); /*TODO: more to go*/ \
1121 M_MOV(REG_LR, REG_PC); \
1122 M_LDR_INTERN(REG_PC, REG_ITMP3, -(-(offset) & 0x0fff)); /*TODO: this looks ugly*/ \
1125 /* M_STACK_LOAD/STORE:
1126 loads or stores integer values from register to stack or from stack to register
1127 ATTENTION: we use M_LDR and M_STR, so the same restrictions apply to us!
1130 #define M_STACK_LOAD_LNG(reg, offset) { \
1131 CHECK_INT_REG(GET_LOW_REG(reg)); \
1132 CHECK_INT_REG(GET_HIGH_REG(reg)); \
1133 M_LDRD(reg, REG_SP, (offset) * 4); \
1137 #define M_ILD(a,b,c) M_LDR(a,b,c)
1138 #define M_LLD(a,b,c) M_LDRD(a,b,c)
1140 #define M_ILD_INTERN(a,b,c) M_LDR_INTERN(a,b,c)
1141 #define M_LLD_INTERN(a,b,c) M_LDRD_INTERN(a,b,c)
1143 #define M_ALD(a,b,c) M_ILD(a,b,c)
1144 #define M_ALD_INTERN(a,b,c) M_ILD_INTERN(a,b,c)
1147 #define M_IST(a,b,c) M_STR(a,b,c)
1148 #define M_LST(a,b,c) M_STRD(a,b,c)
1150 #define M_IST_INTERN(a,b,c) M_STR_INTERN(a,b,c)
1151 #define M_LST_INTERN(a,b,c) M_STRD_INTERN(a,b,c)
1153 #define M_AST(a,b,c) M_IST(a,b,c)
1154 #define M_AST_INTERN(a,b,c) M_IST_INTERN(a,b,c)
1157 #if !defined(ENABLE_SOFTFLOAT)
1159 #define M_FLD(a,b,c) M_LDFS(a,b,c)
1160 #define M_DLD(a,b,c) M_LDFD(a,b,c)
1162 #define M_FLD_INTERN(a,b,c) M_LDFS_INTERN(a,b,c)
1163 #define M_DLD_INTERN(a,b,c) M_LDFD_INTERN(a,b,c)
1166 #define M_FST(a,b,c) M_STFS(a,b,c)
1167 #define M_DST(a,b,c) M_STFD(a,b,c)
1169 #define M_FST_INTERN(a,b,c) M_STFS_INTERN(a,b,c)
1170 #define M_DST_INTERN(a,b,c) M_STFD_INTERN(a,b,c)
1172 #endif /* !defined(ENABLE_SOFTFLOAT) */
1175 /* function gen_resolvebranch **************************************************
1176 ip ... pointer to instruction after branch (void*)
1177 so ... offset of instruction after branch (s4)
1178 to ... offset of branch target (s4) */
1180 #define gen_resolvebranch(ip,so,to) \
1181 assert((((s4*) (ip))[-1] & 0x0e000000) == 0x0a000000); \
1182 ((s4*) (ip))[-1] |= ((s4) (to) - (so) - 1) >> 2 & 0x0ffffff
1185 /* function gen_nullptr_check *************************************************/
1187 #define gen_nullptr_check_intern(objreg) { \
1188 M_TST((objreg), (objreg)); \
1190 codegen_add_nullpointerexception_ref(cd); \
1193 #define gen_nullptr_check(objreg) \
1195 gen_nullptr_check_intern(objreg)
1198 /* function gen_div_check *****************************************************/
1200 #define gen_div_check(type,reg) \
1202 if (IS_2_WORD_TYPE(type)) { \
1203 M_TEQ_IMM(GET_LOW_REG(reg), 0); \
1204 /* M_TEQ_EQ_IMM(GET_HIGH_REG(reg), 0) */ M_DAT(COND_EQ,0x09,0,GET_HIGH_REG(reg),1,1,0); \
1207 M_TEQ_IMM((reg), 0); \
1210 codegen_add_arithmeticexception_ref(cd); \
1213 /* function gen_bound_check ***************************************************
1214 ATTENTION: uses REG_ITMP3 as intermediate register */
1215 /* TODO: maybe use another reg instead of REG_ITMP3! */
1217 #define gen_bound_check(arrayref,index) \
1218 if (checkbounds) { \
1219 M_LDR_INTERN(REG_ITMP3, (arrayref), OFFSET(java_arrayheader, size)); \
1220 M_CMP((index), REG_ITMP3); \
1222 codegen_add_arrayindexoutofboundsexception_ref(cd, index); \
1226 #endif /* _CODEGEN_H */
1230 * These are local overrides for various environment variables in Emacs.
1231 * Please do not remove this and leave it at the end of the file, where
1232 * Emacs will automagically detect them.
1233 * ---------------------------------------------------------------------
1236 * indent-tabs-mode: t
1240 * vim:noexpandtab:sw=4:ts=4: