1 /* src/vm/jit/arm/codegen.h - code generation macros and definitions for ARM
3 Copyright (C) 1996-2005, 2006, 2007, 2008
4 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
6 This file is part of CACAO.
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2, or (at
11 your option) any later version.
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
32 /******************************************************************************/
33 /* register splitting stuff (ugly) ********************************************/
34 /******************************************************************************/
36 #if defined(__ARMEL__)
38 # define SPLIT_OPEN(type, reg, tmpreg) \
39 if (IS_2_WORD_TYPE(type) && GET_HIGH_REG(reg)==REG_SPLIT) { \
40 /*dolog("SPLIT_OPEN({R%d;SPL} > {R%d;R%d})", GET_LOW_REG(reg), GET_LOW_REG(reg), tmpreg);*/ \
41 /*assert(GET_LOW_REG(reg) == 3);*/ \
42 (reg) = PACK_REGS(GET_LOW_REG(reg), tmpreg); \
45 # define SPLIT_STORE_AND_CLOSE(type, reg, offset) \
46 if (IS_2_WORD_TYPE(type) && GET_LOW_REG(reg)==3) { \
47 /*dolog("SPLIT_STORE({R%d;R%d} to [%x])", GET_LOW_REG(reg), GET_HIGH_REG(reg), offset);*/ \
48 M_STR(GET_HIGH_REG(reg), REG_SP, 4 * (offset)); \
49 (reg) = PACK_REGS(GET_LOW_REG(reg), REG_SPLIT); \
52 #else /* defined(__ARMEB__) */
54 # define SPLIT_OPEN(type, reg, tmpreg) \
55 if (IS_2_WORD_TYPE(type) && GET_LOW_REG(reg)==REG_SPLIT) { \
56 /*dolog("SPLIT_OPEN({SPL;R%d} > {R%d;R%d})", GET_HIGH_REG(reg), tmpreg, GET_HIGH_REG(reg));*/ \
57 /*assert(GET_HIGH_REG(reg) == 3);*/ \
58 (reg) = PACK_REGS(tmpreg, GET_HIGH_REG(reg)); \
61 # define SPLIT_STORE_AND_CLOSE(type, reg, offset) \
62 if (IS_2_WORD_TYPE(type) && GET_HIGH_REG(reg)==3) { \
63 /*dolog("SPLIT_STORE({R%d;R%d} to [%x])", GET_LOW_REG(reg), GET_HIGH_REG(reg), offset);*/ \
64 M_STR(GET_LOW_REG(reg), REG_SP, 4 * (offset)); \
65 (reg) = PACK_REGS(REG_SPLIT, GET_HIGH_REG(reg)); \
71 /******************************************************************************/
72 /* checking macros ************************************************************/
73 /******************************************************************************/
75 #define MCODECHECK(icnt) \
77 if ((cd->mcodeptr + (icnt) * 4) > cd->mcodeend) \
78 codegen_increase(cd); \
82 /* TODO: correct this! */
83 #define IS_IMM(val) ( ((val) >= 0) && ((val) <= 255) )
84 #define IS_OFFSET(off,max) ((s4)(off) <= (max) && (s4)(off) >= -(max))
87 # 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)
88 # 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)
89 # define CHECK_OFFSET(off,max) \
90 if (!IS_OFFSET(off,max)) printf("CHECK_OFFSET: offset out of range: %x (>%x) SEVERE ERROR!!!\n", ((off)<0)?-(off):off, max); \
91 assert(IS_OFFSET(off,max))
93 # define CHECK_INT_REG(r)
94 # define CHECK_FLT_REG(r)
95 # define CHECK_OFFSET(off,max)
99 /* branch defines *************************************************************/
101 #define BRANCH_NOPS \
107 /* patcher defines ************************************************************/
109 #define PATCHER_CALL_SIZE 1 * 4 /* an instruction is 4-bytes long */
111 #define PATCHER_NOPS \
117 /* lazy debugger **************************************************************/
120 void asm_debug(int a1, int a2, int a3, int a4);
121 void asm_debug_intern(int a1, int a2, int a3, int a4);
123 /* if called with this macros, it can be placed nearly anywhere */
124 /* almost all registers are saved and restored afterwards */
125 /* it uses a long branch to call the asm_debug_intern (no exit) */
126 #define ASM_DEBUG_PREPARE \
127 M_STMFD(0x7fff, REG_SP)
128 #define ASM_DEBUG_EXECUTE \
129 M_LONGBRANCH(asm_debug_intern); \
130 M_LDMFD(0x7fff, REG_SP)
134 /******************************************************************************/
135 /* macros to create code ******************************************************/
136 /******************************************************************************/
138 /* the condition field */
139 #define COND_EQ 0x0 /* Equal Z set */
140 #define COND_NE 0x1 /* Not equal Z clear */
141 #define COND_CS 0x2 /* Carry set C set */
142 #define COND_CC 0x3 /* Carry clear C clear */
143 #define COND_MI 0x4 /* Negative N set */
144 #define COND_PL 0x5 /* Positive N clear */
145 #define COND_VS 0x6 /* Overflow V set */
146 #define COND_VC 0x7 /* No overflow V clear */
147 #define COND_HI 0x8 /* Unsigned higher */
148 #define COND_LS 0x9 /* Unsigned lower, same */
149 #define COND_GE 0xA /* Sig. greater, equal */
150 #define COND_LT 0xB /* Sig. less than */
151 #define COND_GT 0xC /* Sig. greater than */
152 #define COND_LE 0xD /* Sig. less, equal */
153 #define COND_AL 0xE /* Always */
154 #define CONDNV 0xF /* Special (see A3-5) */
155 #define UNCOND COND_AL
157 /* data processing operation: M_DAT
158 cond ... conditional execution
160 d ...... destination reg
162 S ...... update condition codes
163 I ...... switch to immediate mode
164 shift .. shifter operand
167 #define M_DAT(cond,op,d,n,S,I,shift) \
169 *((u4 *) cd->mcodeptr) = (((cond) << 28) | ((op) << 21) | ((d) << 12) | ((n) << 16) | ((I) << 25) | ((S) << 20) | ((shift) & 0x00000fff)); \
174 /* load and store instruction: M_MEM
175 cond ... conditional execution
176 L ...... load (L=1) or store (L=0)
177 B ...... unsigned byte (B=1) or word (B=0)
178 d ...... destination reg
179 n ...... base reg for addressing
180 adr .... addressing mode specific
183 #define M_MEM(cond,L,B,d,n,adr,I,P,U,W) \
185 *((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)); \
189 #define M_MEM_GET_Rd(mcode) (((mcode) >> 12) & 0x0f)
190 #define M_MEM_GET_Rbase(mcode) (((mcode) >> 16) & 0x0f)
193 /* load and store instruction: M_MEM2
194 cond ... conditional execution
195 L ...... load (L=1) or store (L=0)
196 H ...... halfword (H=1) or signed byte (H=0)
197 S ...... signed (S=1) or unsigned (S=0) halfword
198 d ...... destination reg
199 n ...... base reg for addressing
200 adr .... addressing mode specific
203 #define M_MEM2(cond,L,H,S,d,n,adr,I,P,U,W) \
205 *((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)); \
210 /* load and store multiple instruction: M_MEM_MULTI
211 cond ... conditional execution
212 L ...... load (L=1) or store (L=0)
213 S ...... special (see "The ARM ARM A3-21")
214 regs ... register list
215 n ...... base reg for addressing
218 #define M_MEM_MULTI(cond,L,S,regs,n,P,U,W) \
220 *((u4 *) cd->mcodeptr) = (((cond) << 28) | (1 << 27) | ((L) << 20) | ((S) << 22) | ((n) << 16) | ((regs) & 0xffff) | ((P) << 24) | ((U) << 23) | ((W) << 21)); \
225 /* branch and branch with link: M_BRA
226 cond ... conditional execution
227 L ...... branch with link (L=1)
228 offset . 24bit offset
231 #define M_BRA(cond,L,offset) \
233 *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x5 << 25) | ((L) << 24) | ((offset) & 0x00ffffff)); \
238 /* multiplies: M_MULT
239 cond ... conditional execution
240 d ...... destination register
241 n, m ... source registers
242 S ...... update conditional codes
243 A ...... accumulate flag (enables third source)
244 s ...... third source register
247 #define M_MULT(cond,d,n,m,S,A,s) \
249 *((u4 *) cd->mcodeptr) = (((cond) << 28) | ((d) << 16) | ((n) << 8) | (m) | (0x09 << 4) | ((S) << 20) | ((A) << 21) | ((s) << 12)); \
254 /* no operation (mov r0,r0): M_NOP */
258 *((u4 *) cd->mcodeptr) = (0xe1a00000); \
263 /* software breakpoint (only v5 and above): M_BREAKPOINT */
265 #define M_BREAKPOINT(imm) \
267 *((u4 *) cd->mcodeptr) = (0x0e12 << 20) | (0x07 << 4) | (((imm) & 0xfff0) << (8-4)) | ((imm) & 0x0f); \
272 /* undefined instruction used for hardware exceptions */
274 #define M_UNDEFINED(cond,imm,n) \
276 *((u4 *) cd->mcodeptr) = ((cond) << 28) | (0x7f << 20) | (((imm) & 0x0fff) << 8) | (0x0f << 4) | (n); \
281 #if !defined(ENABLE_SOFTFLOAT)
283 /* M_CPDO **********************************************************************
285 Floating-Point Coprocessor Data Operations
287 cond ... conditional execution
289 D ...... dyadic (D=0) or monadic (D=1) instruction
290 Fd ..... destination float-register
291 Fn ..... source float-register
292 Fm ..... source float-register or immediate
294 *******************************************************************************/
296 #define M_CPDOS(cond,op,D,Fd,Fn,Fm) \
298 *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0e << 24) | (1 << 8) | ((op) << 20) | ((D) << 15) | ((Fd) << 12) | ((Fn) << 16) | ((Fm) & 0x0f)); \
303 #define M_CPDOD(cond,op,D,Fd,Fn,Fm) \
305 *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0e << 24) | (1 << 8) | ((op) << 20) | ((D) << 15) | ((Fd) << 12) | ((Fn) << 16) | ((Fm) & 0x0f) | (1 << 7)); \
310 #define M_CPDP(cond,p,q,r,s,cp_num,D,N,M,Fd,Fn,Fm) \
312 *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0e << 24) | ((p) << 23) | ((q) << 21) | ((r) << 20) | ((s) << 6) | ((cp_num) << 8) | ((D) << 22) | ((N) << 7) | ((M) << 5) | ((Fd) << 12) | ((Fn) << 16) | ((Fm) & 0x0f)); \
317 /* M_CPDT **********************************************************************
319 Floating-Point Coprocessor Data Transfer
321 cond ... conditional execution
322 L ...... load (L=1) or store (L=0)
323 Fd ..... destination float-register
324 n ...... base reg for addressing
326 *******************************************************************************/
328 #define M_CPDT(cond,L,T1,T0,Fd,n,off,P,U,W) \
330 *((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)); \
334 #define M_CPLS(cond,L,P,U,W,cp_num,D,Fd,n,off) \
336 *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0c << 24) | ((P) << 24) | ((U) << 23) | ((W) << 21) | ((L) << 20) | ((cp_num) << 8) | ((D) << 22) | ((Fd) << 12) | ((n) << 16) | ((off) & 0xff)); \
341 /* M_CPRT **********************************************************************
343 Floating-Point Coprocessor Register Transfer
347 *******************************************************************************/
349 #define M_CPRT(cond,op,L,cp_num,N,Fn,n) \
351 *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0e << 24) | (1 << 4) | ((op) << 21) | ((L) << 20) | ((cp_num) << 8) | ((N) << 7) | ((Fn) << 16) | ((n) << 12)); \
355 #define M_CPRTS(cond,L,d,Fn,Fm) \
357 *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0e << 24) | (1 << 8) | (1 << 4) | ((L) << 20) | ((d) << 12) | ((Fn) << 16) | (Fm)); \
362 #define M_CPRTD(cond,L,d,Fn,Fm) \
364 *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0e << 24) | (1 << 8) | (1 << 4) | ((L) << 20) | ((d) << 12) | ((Fn) << 16) | (Fm) | (1 << 7)); \
369 #define M_CPRTI(cond,L,d,Fn,Fm) \
371 *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0e << 24) | (1 << 8) | (1 << 4) | ((L) << 20) | ((d) << 12) | ((Fn) << 16) | (Fm) | (3 << 5)); \
376 /* XXX TWISTI: replace X by something useful */
378 #define M_CPRTX(cond,L,d,Fn,Fm) \
380 *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0e << 24) | (1 << 8) | (1 << 4) | ((L) << 20) | ((d) << 12) | ((Fn) << 16) | (Fm) | (1 << 23)); \
384 #endif /* !defined(ENABLE_SOFTFLOAT) */
387 /* used to store values! */
390 *((u4 *) cd->mcodeptr) = val; \
395 /* used to directly access shifter; insert this as shifter operand! */
396 #define REG_LSL(reg, shift) ( (((shift) & 0x1f) << 7) | ((reg) & 0x0f) )
397 #define REG_LSR(reg, shift) ( (((shift) & 0x1f) << 7) | ((reg) & 0x0f) | (1 << 5) )
398 #define REG_ASR(reg, shift) ( (((shift) & 0x1f) << 7) | ((reg) & 0x0f) | (1 << 6) )
399 #define REG_LSL_REG(reg, s) ( (((s) & 0x0f) << 8) | ((reg) & 0x0f) | (1 << 4) )
400 #define REG_LSR_REG(reg, s) ( (((s) & 0x0f) << 8) | ((reg) & 0x0f) | (1 << 4) | (1 << 5) )
401 #define REG_ASR_REG(reg, s) ( (((s) & 0x0f) << 8) | ((reg) & 0x0f) | (1 << 4) | (1 << 6) )
403 /* used to directly rotate immediate values; insert this as immediate! */
404 /* ATTENTION: this rotates the immediate right by (2 * rot) bits */
405 #define IMM_ROTR(imm, rot) ( ((imm) & 0xff) | (((rot) & 0x0f) << 8) )
406 #define IMM_ROTL(imm, rot) IMM_ROTR(imm, 16-(rot))
409 /******************************************************************************/
410 /* macros for all basic arm instructions **************************************/
411 /******************************************************************************/
413 #define M_ADD(d,a,b) M_DAT(UNCOND,0x04,d,a,0,0,b) /* d = a + b */
414 #define M_ADC(d,a,b) M_DAT(UNCOND,0x05,d,a,0,0,b) /* d = a + b (with Carry) */
415 #define M_SUB(d,a,b) M_DAT(UNCOND,0x02,d,a,0,0,b) /* d = a - b */
416 #define M_SBC(d,a,b) M_DAT(UNCOND,0x06,d,a,0,0,b) /* d = a - b (with Carry) */
417 #define M_AND(a,b,d) M_DAT(UNCOND,0x00,d,a,0,0,b) /* d = a & b */
418 #define M_ORR(a,b,d) M_DAT(UNCOND,0x0c,d,a,0,0,b) /* d = a | b */
419 #define M_EOR(a,b,d) M_DAT(UNCOND,0x01,d,a,0,0,b) /* d = a ^ b */
420 #define M_TST(a,b) M_DAT(UNCOND,0x08,0,a,1,0,b) /* TST a & b */
421 #define M_TEQ(a,b) M_DAT(UNCOND,0x09,0,a,1,0,b) /* TST a ^ b */
422 #define M_CMP(a,b) M_DAT(UNCOND,0x0a,0,a,1,0,b) /* TST a - b */
423 #define M_MOV(d,b) M_DAT(UNCOND,0x0d,d,0,0,0,b) /* d = b */
424 #define M_ADD_S(d,a,b) M_DAT(UNCOND,0x04,d,a,1,0,b) /* d = a + b (update Flags) */
425 #define M_SUB_S(d,a,b) M_DAT(UNCOND,0x02,d,a,1,0,b) /* d = a - b (update Flags) */
426 #define M_ORR_S(a,b,d) M_DAT(UNCOND,0x0c,d,a,1,0,b) /* d = a | b (update flags) */
427 #define M_MOV_S(d,b) M_DAT(UNCOND,0x0d,d,0,1,0,b) /* d = b (update Flags) */
429 #define M_ADD_IMM(d,a,i) M_DAT(UNCOND,0x04,d,a,0,1,i) /* d = a + i */
430 #define M_ADC_IMM(d,a,i) M_DAT(UNCOND,0x05,d,a,0,1,i) /* d = a + i (with Carry) */
431 #define M_SUB_IMM(d,a,i) M_DAT(UNCOND,0x02,d,a,0,1,i) /* d = a - i */
432 #define M_SBC_IMM(d,a,i) M_DAT(UNCOND,0x06,d,a,0,1,i) /* d = a - i (with Carry) */
433 #define M_RSB_IMM(d,a,i) M_DAT(UNCOND,0x03,d,a,0,1,i) /* d = -a + i */
434 #define M_RSC_IMM(d,a,i) M_DAT(UNCOND,0x07,d,a,0,1,i) /* d = -a + i (with Carry) */
435 #define M_AND_IMM(a,i,d) M_DAT(UNCOND,0x00,d,a,0,1,i) /* d = a & i */
436 #define M_TST_IMM(a,i) M_DAT(UNCOND,0x08,0,a,1,1,i) /* TST a & i */
437 #define M_TEQ_IMM(a,i) M_DAT(UNCOND,0x09,0,a,1,1,i) /* TST a ^ i */
438 #define M_CMP_IMM(a,i) M_DAT(UNCOND,0x0a,0,a,1,1,i) /* TST a - i */
439 #define M_CMN_IMM(a,i) M_DAT(UNCOND,0x0b,0,a,1,1,i) /* TST a + i */
440 #define M_MOV_IMM(d,i) M_DAT(UNCOND,0x0d,d,0,0,1,i) /* d = i */
441 #define M_ADD_IMMS(d,a,i) M_DAT(UNCOND,0x04,d,a,1,1,i) /* d = a + i (update Flags) */
442 #define M_SUB_IMMS(d,a,i) M_DAT(UNCOND,0x02,d,a,1,1,i) /* d = a - i (update Flags) */
443 #define M_RSB_IMMS(d,a,i) M_DAT(UNCOND,0x03,d,a,1,1,i) /* d = -a + i (update Flags) */
445 #define M_ADDSUB_IMM(d,a,i) if((i)>=0) M_ADD_IMM(d,a,i); else M_SUB_IMM(d,a,-(i))
446 #define M_MOVEQ(a,d) M_DAT(COND_EQ,0x0d,d,0,0,0,a)
447 #define M_EORLE(d,a,b) M_DAT(COND_LE,0x01,d,a,0,0,b)
449 #define M_MOVVS_IMM(i,d) M_DAT(COND_VS,0x0d,d,0,0,1,i)
450 #define M_MOVEQ_IMM(i,d) M_DAT(COND_EQ,0x0d,d,0,0,1,i)
451 #define M_MOVNE_IMM(i,d) M_DAT(COND_NE,0x0d,d,0,0,1,i)
452 #define M_MOVLT_IMM(i,d) M_DAT(COND_LT,0x0d,d,0,0,1,i)
453 #define M_MOVGT_IMM(i,d) M_DAT(COND_GT,0x0d,d,0,0,1,i)
454 #define M_MOVLS_IMM(i,d) M_DAT(COND_LS,0x0d,d,0,0,1,i)
456 #define M_ADDHI_IMM(d,a,i) M_DAT(COND_HI,0x04,d,a,0,1,i)
457 #define M_ADDLT_IMM(d,a,i) M_DAT(COND_LT,0x04,d,a,0,1,i)
458 #define M_ADDGT_IMM(d,a,i) M_DAT(COND_GT,0x04,d,a,0,1,i)
459 #define M_SUBLO_IMM(d,a,i) M_DAT(COND_CC,0x02,d,a,0,1,i)
460 #define M_SUBLT_IMM(d,a,i) M_DAT(COND_LT,0x02,d,a,0,1,i)
461 #define M_SUBGT_IMM(d,a,i) M_DAT(COND_GT,0x02,d,a,0,1,i)
462 #define M_RSBMI_IMM(d,a,i) M_DAT(COND_MI,0x03,d,a,0,1,i)
463 #define M_ADCMI_IMM(d,a,i) M_DAT(COND_MI,0x05,d,a,0,1,i)
465 #define M_CMPEQ(a,b) M_DAT(COND_EQ,0x0a,0,a,1,0,b) /* TST a - b */
466 #define M_CMPLE(a,b) M_DAT(COND_LE,0x0a,0,a,1,0,b) /* TST a - b */
468 #define M_CMPEQ_IMM(a,i) M_DAT(COND_EQ,0x0a,0,a,1,1,i)
470 #define M_MUL(d,a,b) M_MULT(UNCOND,d,a,b,0,0,0x0) /* d = a * b */
472 #define M_B(off) M_BRA(UNCOND,0,off) /* unconditional branch */
473 #define M_BL(off) M_BRA(UNCOND,1,off) /* branch and link */
474 #define M_BEQ(off) M_BRA(COND_EQ,0,off) /* conditional branches */
475 #define M_BNE(off) M_BRA(COND_NE,0,off)
476 #define M_BGE(off) M_BRA(COND_GE,0,off)
477 #define M_BGT(off) M_BRA(COND_GT,0,off)
478 #define M_BLT(off) M_BRA(COND_LT,0,off)
479 #define M_BLE(off) M_BRA(COND_LE,0,off)
480 #define M_BHI(off) M_BRA(COND_HI,0,off) /* unsigned conditional */
481 #define M_BHS(off) M_BRA(COND_CS,0,off)
482 #define M_BLO(off) M_BRA(COND_CC,0,off)
483 #define M_BLS(off) M_BRA(COND_LS,0,off)
486 /******************************************************************************/
487 /* macros for load and store instructions *************************************/
488 /******************************************************************************/
490 #define M_LDMFD(regs,base) M_MEM_MULTI(UNCOND,1,0,regs,base,0,1,1)
491 #define M_STMFD(regs,base) M_MEM_MULTI(UNCOND,0,0,regs,base,1,0,1)
493 #define M_LDR_REG(d,base,offreg) M_MEM(UNCOND,1,0,d,base,offreg,1,1,1,0)
494 #define M_STR_REG(d,base,offreg) M_MEM(UNCOND,0,0,d,base,offreg,1,1,1,0)
496 #define M_LDR_INTERN(d,base,off) \
498 CHECK_OFFSET(off, 0x0fff); \
499 M_MEM(UNCOND,1,0,d,base,(((off) < 0) ? -(off) : off),0,1,(((off) < 0) ? 0 : 1),0); \
502 #define M_STR_INTERN(d,base,off) \
504 CHECK_OFFSET(off, 0x0fff); \
505 M_MEM(UNCOND,0,0,d,base,(((off) < 0) ? -(off) : off),0,1,(((off) < 0) ? 0 : 1),0); \
508 #define M_LDR_UPDATE(d,base,off) \
510 CHECK_OFFSET(off, 0x0fff); \
511 M_MEM(UNCOND,1,0,d,base,(((off) < 0) ? -(off) : off),0,0,(((off) < 0) ? 0 : 1),0); \
514 #define M_STR_UPDATE(d,base,off) \
516 CHECK_OFFSET(off,0x0fff); \
517 M_MEM(UNCOND,0,0,d,base,(((off) < 0) ? -(off) : off),0,1,(((off) < 0) ? 0 : 1),1); \
521 #define M_LDRH(d,base,off) \
523 CHECK_OFFSET(off, 0x00ff); \
525 M_MEM2(UNCOND,1,1,0,d,base,off,1,1,1,0); \
528 #define M_LDRSH(d,base,off) \
530 CHECK_OFFSET(off, 0x00ff); \
532 M_MEM2(UNCOND,1,1,1,d,base,off,1,1,1,0); \
535 #define M_LDRSB(d,base,off) \
537 CHECK_OFFSET(off, 0x00ff); \
539 M_MEM2(UNCOND,1,0,1,d,base,off,1,1,1,0); \
542 #define M_STRH(d,base,off) \
544 CHECK_OFFSET(off, 0x00ff); \
546 M_MEM2(UNCOND,0,1,0,d,base,off,1,1,1,0); \
549 #define M_STRB(d,base,off) \
551 CHECK_OFFSET(off, 0x0fff); \
553 M_MEM(UNCOND,0,1,d,base,off,0,1,1,0); \
557 #define M_TRAP(a,i) M_UNDEFINED(UNCOND,i,a);
558 #define M_TRAPEQ(a,i) M_UNDEFINED(COND_EQ,i,a);
559 #define M_TRAPNE(a,i) M_UNDEFINED(COND_NE,i,a);
560 #define M_TRAPLT(a,i) M_UNDEFINED(COND_LT,i,a);
561 #define M_TRAPLE(a,i) M_UNDEFINED(COND_LE,i,a);
562 #define M_TRAPHI(a,i) M_UNDEFINED(COND_HI,i,a);
563 #define M_TRAPHS(a,i) M_UNDEFINED(COND_CS,i,a);
566 /* if we do not have double-word load/store command, we can fake them */
567 /* ATTENTION: the original LDRD/STRD of ARMv5e would always use (Rd/Rd+1),
568 so these faked versions are more "powerful" */
570 #if defined(__ARMEL__)
572 #define M_LDRD_INTERN(d,base,off) \
574 M_LDR_INTERN(GET_LOW_REG(d), base, off); \
575 M_LDR_INTERN(GET_HIGH_REG(d), base, (off) + 4); \
578 #define M_STRD_INTERN(d,base,off) \
580 M_STR_INTERN(GET_LOW_REG(d), base, off); \
581 M_STR_INTERN(GET_HIGH_REG(d), base, (off) + 4); \
584 #define M_LDRD_ALTERN(d,base,off) \
586 M_LDR_INTERN(GET_HIGH_REG(d), base, (off) + 4); \
587 M_LDR_INTERN(GET_LOW_REG(d), base, off); \
590 #define M_LDRD_UPDATE(d,base,off) \
592 assert((off) == +8); \
593 M_LDR_UPDATE(GET_LOW_REG(d), base, 4); \
594 M_LDR_UPDATE(GET_HIGH_REG(d), base, 4); \
597 #define M_STRD_UPDATE(d,base,off) \
599 assert((off) == -8); \
600 M_STR_UPDATE(GET_HIGH_REG(d), base, -4); \
601 M_STR_UPDATE(GET_LOW_REG(d), base, -4); \
604 #define GET_FIRST_REG(d) GET_LOW_REG(d)
605 #define GET_SECOND_REG(d) GET_HIGH_REG(d)
607 #else /* defined(__ARMEB__) */
609 #define M_LDRD_INTERN(d,base,off) \
611 M_LDR_INTERN(GET_HIGH_REG(d), base, off); \
612 M_LDR_INTERN(GET_LOW_REG(d), base, (off) + 4); \
615 #define M_STRD_INTERN(d,base,off) \
617 M_STR_INTERN(GET_HIGH_REG(d), base, off); \
618 M_STR_INTERN(GET_LOW_REG(d), base, (off) + 4); \
621 #define M_LDRD_ALTERN(d,base,off) \
623 M_LDR_INTERN(GET_LOW_REG(d), base, (off) + 4); \
624 M_LDR_INTERN(GET_HIGH_REG(d), base, off); \
627 #define M_LDRD_UPDATE(d,base,off) \
629 assert((off) == +8); \
630 M_LDR_UPDATE(GET_HIGH_REG(d), base, 4); \
631 M_LDR_UPDATE(GET_LOW_REG(d), base, 4); \
634 #define M_STRD_UPDATE(d,base,off) \
636 assert((off) == -8); \
637 M_STR_UPDATE(GET_LOW_REG(d), base, -4); \
638 M_STR_UPDATE(GET_HIGH_REG(d) ,base, -4); \
641 #define GET_FIRST_REG(d) GET_HIGH_REG(d)
642 #define GET_SECOND_REG(d) GET_LOW_REG(d)
644 #endif /* defined(__ARMEB__) */
647 /******************************************************************************/
648 /* macros for all floating point instructions *********************************/
649 /******************************************************************************/
651 #if !defined(ENABLE_SOFTFLOAT)
653 #if defined(__VFP_FP__)
655 #define M_FADD(a,b,d) M_CPDP(UNCOND,0,1,1,0,10,0,0,0,d,a,b)/* d = a + b */
656 #define M_FSUB(a,b,d) M_CPDP(UNCOND,0,1,1,1,10,0,0,0,d,a,b)/* d = a - b */
657 #define M_FMUL(a,b,d) M_CPDP(UNCOND,0,1,0,0,10,0,0,0,d,a,b)/* d = a * b */
658 #define M_FDIV(a,b,d) M_CPDP(UNCOND,1,0,0,0,10,0,0,0,d,a,b)/* d = a / b */
659 #define M_DADD(a,b,d) M_CPDP(UNCOND,0,1,1,0,11,0,0,0,d,a,b)/* d = a + b */
660 #define M_DSUB(a,b,d) M_CPDP(UNCOND,0,1,1,1,11,0,0,0,d,a,b)/* d = a - b */
661 #define M_DMUL(a,b,d) M_CPDP(UNCOND,0,1,0,0,11,0,0,0,d,a,b)/* d = a * b */
662 #define M_DDIV(a,b,d) M_CPDP(UNCOND,1,0,0,0,11,0,0,0,d,a,b)/* d = a / b */
664 #define M_FMOV(a,d) M_CPDP(UNCOND,1,1,1,1,10,0,0,0,d,0x0,a)
665 #define M_DMOV(a,d) M_CPDP(UNCOND,1,1,1,1,11,0,0,0,d,0x0,a)
666 #define M_FNEG(a,d) M_CPDP(UNCOND,1,1,1,1,10,0,0,0,d,0x1,a)
667 #define M_DNEG(a,d) M_CPDP(UNCOND,1,1,1,1,11,0,0,0,d,0x1,a)
669 #define M_FCMP(a,b) M_CPDP(UNCOND,1,1,1,1,10,0,0,0,a,0x4,b)
670 #define M_DCMP(a,b) M_CPDP(UNCOND,1,1,1,1,11,0,0,0,a,0x4,b)
672 #define M_CVTDF(a,d) M_CPDP(UNCOND,1,1,1,1,11,0,1,0,d,0x7,a)
673 #define M_CVTFD(a,d) M_CPDP(UNCOND,1,1,1,1,10,0,1,0,d,0x7,a)
674 #define M_CVTIF(a,d) M_CPDP(UNCOND,1,1,1,1,10,0,1,0,d,0x8,a)
675 #define M_CVTID(a,d) M_CPDP(UNCOND,1,1,1,1,11,0,1,0,d,0x8,a)
676 #define M_CVTFI(a,d) M_CPDP(UNCOND,1,1,1,1,10,0,1,0,d,0xd,a) // ftosis
677 #define M_CVTDI(a,d) M_CPDP(UNCOND,1,1,1,1,11,0,1,0,d,0xd,a) // ftosid
679 #define M_FMSTAT M_CPRT(UNCOND,0x07,1,10,0,0x1,0xf)
681 #define M_FMSR(a,Fb) M_CPRT(UNCOND,0x00,0,10,0,Fb,a)
682 #define M_FMRS(Fa,b) M_CPRT(UNCOND,0x00,1,10,0,Fa,b)
683 #define M_FMDLR(a,Fb) M_CPRT(UNCOND,0x00,0,11,0,Fb,a)
684 #define M_FMRDL(Fa,b) M_CPRT(UNCOND,0x00,1,11,0,Fa,b)
685 #define M_FMDHR(a,Fb) M_CPRT(UNCOND,0x01,0,11,0,Fb,a)
686 #define M_FMRDH(Fa,b) M_CPRT(UNCOND,0x01,1,11,0,Fa,b)
690 #define M_FADD(a,b,d) M_CPDOS(UNCOND,0x00,0,d,a,b) /* d = a + b */
691 #define M_FSUB(a,b,d) M_CPDOS(UNCOND,0x02,0,d,a,b) /* d = a - b */
692 #define M_FMUL(a,b,d) M_CPDOS(UNCOND,0x01,0,d,a,b) /* d = a * b */
693 #define M_FDIV(a,b,d) M_CPDOS(UNCOND,0x04,0,d,a,b) /* d = a / b */
694 #define M_RMFS(d,a,b) M_CPDOS(UNCOND,0x08,0,d,a,b) /* d = a % b */
695 #define M_DADD(a,b,d) M_CPDOD(UNCOND,0x00,0,d,a,b) /* d = a + b */
696 #define M_DSUB(a,b,d) M_CPDOD(UNCOND,0x02,0,d,a,b) /* d = a - b */
697 #define M_DMUL(a,b,d) M_CPDOD(UNCOND,0x01,0,d,a,b) /* d = a * b */
698 #define M_DDIV(a,b,d) M_CPDOD(UNCOND,0x04,0,d,a,b) /* d = a / b */
699 #define M_RMFD(d,a,b) M_CPDOD(UNCOND,0x08,0,d,a,b) /* d = a % b */
701 #define M_FMOV(a,d) M_CPDOS(UNCOND,0x00,1,d,0,a) /* d = a */
702 #define M_DMOV(a,d) M_CPDOD(UNCOND,0x00,1,d,0,a) /* d = a */
703 #define M_FNEG(a,d) M_CPDOS(UNCOND,0x01,1,d,0,a) /* d = - a */
704 #define M_DNEG(a,d) M_CPDOD(UNCOND,0x01,1,d,0,a) /* d = - a */
706 #define M_FCMP(a,b) M_CPRTX(UNCOND,1,0x0f,a,b) /* COMPARE a; b */
707 #define M_DCMP(a,b) M_CPRTX(UNCOND,1,0x0f,a,b) /* COMPARE a; b */
709 #define M_CVTDF(a,b) M_FMOV(a,b)
710 #define M_CVTFD(a,b) M_DMOV(a,b)
711 #define M_CVTIF(a,d) M_CPRTS(UNCOND,0,a,d,0) /* d = (float) a */
712 #define M_CVTID(a,d) M_CPRTD(UNCOND,0,a,d,0) /* d = (float) a */
713 #define M_CVTFI(a,d) M_CPRTI(UNCOND,1,d,0,a) /* d = (int) a */
714 #define M_CVTDI(a,d) M_CPRTI(UNCOND,1,d,0,a) /* d = (int) a */
720 loads the value of the integer-register a (argument or result) into
721 float-register Fb. (and vice versa)
724 #if defined(__VFP_FP__)
726 #define M_CAST_I2F(a,Fb) M_FMSR(a,Fb)
728 #define M_CAST_F2I(Fa,b) M_FMRS(Fa,b)
730 #define M_CAST_L2D(a,Fb) \
732 M_FMDLR(GET_LOW_REG(a), Fb); \
733 M_FMDHR(GET_HIGH_REG(a), Fb); \
736 #define M_CAST_D2L(Fa,b) \
738 M_FMRDL(Fa, GET_LOW_REG(b)); \
739 M_FMRDH(Fa, GET_HIGH_REG(b)); \
744 #define M_CAST_I2F(a,Fb) \
748 M_STR_UPDATE(a, REG_SP, -4); \
749 M_FLD_UPDATE(Fb, REG_SP, 4); \
752 #define M_CAST_L2D(a,Fb) \
755 CHECK_INT_REG(GET_LOW_REG(a)); \
756 CHECK_INT_REG(GET_HIGH_REG(a)); \
757 M_STRD_UPDATE(a, REG_SP, -8); \
758 M_DLD_UPDATE(Fb, REG_SP, 8); \
761 #define M_CAST_F2I(Fa,b) \
765 M_FST_UPDATE(Fa, REG_SP, -4); \
766 M_LDR_UPDATE(b, REG_SP, 4); \
769 #define M_CAST_D2L(Fa,b) \
771 CHECK_INT_REG(GET_LOW_REG(b)); \
772 CHECK_INT_REG(GET_HIGH_REG(b)); \
773 M_DST_UPDATE(Fa, REG_SP, -8); \
774 M_LDRD_UPDATE(b, REG_SP, 8); \
779 /* M_xLD_xx & M_xST_xx:
783 #if defined(__VFP_FP__)
785 #define M_FLD_INTERN(d,base,off) \
787 CHECK_OFFSET(off, 0x03ff); \
788 M_CPLS(UNCOND,1,1,(((off) < 0) ? 0 : 1),0,10,0,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2)); \
791 #define M_DLD_INTERN(d,base,off) \
793 CHECK_OFFSET(off, 0x03ff); \
794 M_CPLS(UNCOND,1,1,(((off) < 0) ? 0 : 1),0,11,0,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2)); \
797 #define M_FST_INTERN(d,base,off) \
799 CHECK_OFFSET(off, 0x03ff); \
800 M_CPLS(UNCOND,0,1,(((off) < 0) ? 0 : 1),0,10,0,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2)); \
803 #define M_DST_INTERN(d,base,off) \
805 CHECK_OFFSET(off, 0x03ff); \
806 M_CPLS(UNCOND,0,1,(((off) < 0) ? 0 : 1),0,11,0,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2)); \
811 #define M_FLD_INTERN(d,base,off) \
813 CHECK_OFFSET(off, 0x03ff); \
814 M_CPDT(UNCOND,1,0,0,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),1,(((off) < 0) ? 0 : 1),0); \
817 #define M_DLD_INTERN(d,base,off) \
819 CHECK_OFFSET(off, 0x03ff); \
820 M_CPDT(UNCOND,1,0,1,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),1,(((off) < 0) ? 0 : 1),0); \
823 #define M_FST_INTERN(d,base,off) \
825 CHECK_OFFSET(off, 0x03ff); \
826 M_CPDT(UNCOND,0,0,0,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),1,(((off) < 0) ? 0 : 1),0); \
829 #define M_DST_INTERN(d,base,off) \
831 CHECK_OFFSET(off, 0x03ff); \
832 M_CPDT(UNCOND,0,0,1,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),1,(((off) < 0) ? 0 : 1),0); \
835 #define M_FLD_UPDATE(d,base,off) \
837 CHECK_OFFSET(off, 0x03ff); \
838 M_CPDT(UNCOND,1,0,0,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),0,(((off) < 0) ? 0 : 1),1); \
841 #define M_DLD_UPDATE(d,base,off) \
843 CHECK_OFFSET(off, 0x03ff); \
844 M_CPDT(UNCOND,1,0,1,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),0,(((off) < 0) ? 0 : 1),1); \
847 #define M_FST_UPDATE(d,base,off) \
849 CHECK_OFFSET(off, 0x03ff); \
850 M_CPDT(UNCOND,0,0,0,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),1,(((off) < 0) ? 0 : 1),1); \
853 #define M_DST_UPDATE(d,base,off) \
855 CHECK_OFFSET(off, 0x03ff); \
856 M_CPDT(UNCOND,0,0,1,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),1,(((off) < 0) ? 0 : 1),1); \
861 #endif /* !defined(ENABLE_SOFTFLOAT) */
864 /******************************************************************************/
865 /* wrapper macros for load and store instructions *****************************/
866 /******************************************************************************/
869 these are replacements for the original LDR/STR instructions, which can
870 handle longer offsets (up to 20bits). the original functions are now
873 /* ATTENTION: We use ITMP3 here, take into account that it gets destroyed.
874 This means that only ITMP1 and ITMP2 can be used in reg_of_var()!!!
876 /* ATTENTION2: It is possible to use ITMP3 as base reg. Remember that when
877 changing these macros!!!
880 #define M_LDR(d, base, offset) \
882 CHECK_OFFSET(offset, 0x0fffff); \
883 if (IS_OFFSET(offset, 0x000fff)) { \
884 M_LDR_INTERN(d, base, offset); \
886 /* we cannot handle REG_PC here */ \
887 assert((d) != REG_PC); \
888 if ((offset) > 0) { \
889 M_ADD_IMM(d, base, IMM_ROTL((offset) >> 12, 6)); \
890 M_LDR_INTERN(d, d, (offset) & 0x000fff); \
892 M_SUB_IMM(d, base, IMM_ROTL((-(offset)) >> 12, 6)); \
893 M_LDR_INTERN(d, d, -(-(offset) & 0x000fff)); \
898 #define M_LDR_NEGATIVE(d, base, offset) { \
899 /*assert((offset) <= 0);*/ \
900 if (IS_OFFSET(offset, 0x000fff)) { \
901 M_LDR_INTERN(d, base, offset); \
903 /* we cannot handle REG_PC here */ \
904 assert((d) != REG_PC); \
905 M_SUB_IMM(d, base, IMM_ROTL((-(offset)) >> 12, 6)); \
906 M_LDR_INTERN(d, d, -(-(offset) & 0x000fff)); \
910 #define M_LDRD(d, base, offset) \
912 CHECK_OFFSET(offset, 0x0fffff - 4); \
913 if (IS_OFFSET(offset, 0x000fff - 4)) { \
914 if (GET_FIRST_REG(d) != (base)) { \
915 M_LDRD_INTERN(d, base, offset); \
917 M_LDRD_ALTERN(d, base, offset); \
919 } else if (IS_OFFSET(offset, 0x000fff)) { \
920 dolog("M_LDRD: this offset seems to be complicated (%d)", offset); \
923 if ((offset) > 0) { \
924 M_ADD_IMM(GET_SECOND_REG(d), base, IMM_ROTL((offset) >> 12, 6)); \
925 M_LDRD_INTERN(d, GET_SECOND_REG(d), (offset) & 0x000fff); \
927 M_SUB_IMM(GET_SECOND_REG(d), base, IMM_ROTL((-(offset)) >> 12, 6)); \
928 M_LDRD_INTERN(d, GET_SECOND_REG(d), -(-(offset) & 0x000fff)); \
933 #if !defined(ENABLE_SOFTFLOAT)
935 #define M_LDFS(d, base, offset) \
937 CHECK_OFFSET(offset, 0x03ffff); \
938 if (IS_OFFSET(offset, 0x03ff)) { \
939 M_FLD_INTERN(d, base, offset); \
941 if ((offset) > 0) { \
942 M_ADD_IMM(REG_ITMP3, base, IMM_ROTL((offset) >> 10, 5)); \
943 M_FLD_INTERN(d, REG_ITMP3, (offset) & 0x03ff); \
945 M_SUB_IMM(REG_ITMP3, base, IMM_ROTL((-(offset)) >> 10, 5)); \
946 M_FLD_INTERN(d, REG_ITMP3, -(-(offset) & 0x03ff)); \
951 #define M_LDFD(d, base, offset) \
953 CHECK_OFFSET(offset, 0x03ffff); \
954 if (IS_OFFSET(offset, 0x03ff)) { \
955 M_DLD_INTERN(d, base, offset); \
957 if ((offset) > 0) { \
958 M_ADD_IMM(REG_ITMP3, base, IMM_ROTL((offset) >> 10, 5)); \
959 M_DLD_INTERN(d, REG_ITMP3, (offset) & 0x03ff); \
961 M_SUB_IMM(REG_ITMP3, base, IMM_ROTL((-(offset)) >> 10, 5)); \
962 M_DLD_INTERN(d, REG_ITMP3, -(-(offset) & 0x03ff)); \
967 #endif /* !defined(ENABLE_SOFTFLOAT) */
969 #define M_STR(d, base, offset) \
971 assert((d) != REG_ITMP3); \
972 CHECK_OFFSET(offset, 0x0fffff); \
973 if (IS_OFFSET(offset, 0x000fff)) { \
974 M_STR_INTERN(d, base, offset); \
976 if ((offset) > 0) { \
977 M_ADD_IMM(REG_ITMP3, base, IMM_ROTL((offset) >> 12, 6)); \
978 M_STR_INTERN(d, REG_ITMP3, (offset) & 0x000fff); \
980 M_SUB_IMM(REG_ITMP3, base, IMM_ROTL((-(offset)) >> 12, 6)); \
981 M_STR_INTERN(d, REG_ITMP3, -(-(offset) & 0x000fff)); \
986 #define M_STRD(d, base, offset) \
988 assert(GET_LOW_REG(d) != REG_ITMP3); \
989 assert(GET_HIGH_REG(d) != REG_ITMP3); \
990 CHECK_OFFSET(offset, 0x0fffff - 4); \
991 if (IS_OFFSET(offset, 0x000fff - 4)) { \
992 M_STRD_INTERN(d,base,offset); \
993 } else if (IS_OFFSET(offset, 0x000fff)) { \
994 dolog("M_STRD: this offset seems to be complicated (%d)", offset); \
997 if ((offset) > 0) { \
998 M_ADD_IMM(REG_ITMP3, base, IMM_ROTL((offset) >> 12, 6)); \
999 M_STRD_INTERN(d, REG_ITMP3, (offset) & 0x000fff); \
1001 M_SUB_IMM(REG_ITMP3, base, IMM_ROTL((-(offset)) >> 12, 6)); \
1002 M_STRD_INTERN(d, REG_ITMP3, -(-(offset) & 0x000fff)); \
1007 #if !defined(ENABLE_SOFTFLOAT)
1009 #define M_STFS(d, base, offset) \
1011 CHECK_OFFSET(offset, 0x03ffff); \
1012 if (IS_OFFSET(offset, 0x03ff)) { \
1013 M_FST_INTERN(d, base, offset); \
1015 if ((offset) > 0) { \
1016 M_ADD_IMM(REG_ITMP3, base, IMM_ROTL((offset) >> 10, 5)); \
1017 M_FST_INTERN(d, REG_ITMP3, (offset) & 0x03ff); \
1019 M_SUB_IMM(REG_ITMP3, base, IMM_ROTL((-(offset)) >> 10, 5)); \
1020 M_FST_INTERN(d, REG_ITMP3, -(-(offset) & 0x03ff)); \
1025 #define M_STFD(d, base, offset) \
1027 CHECK_OFFSET(offset, 0x03ffff); \
1028 if (IS_OFFSET(offset, 0x03ff)) { \
1029 M_DST_INTERN(d, base, offset); \
1031 if ((offset) > 0) { \
1032 M_ADD_IMM(REG_ITMP3, base, IMM_ROTL((offset) >> 10, 5)); \
1033 M_DST_INTERN(d, REG_ITMP3, (offset) & 0x03ff); \
1035 M_SUB_IMM(REG_ITMP3, base, IMM_ROTL((-(offset)) >> 10, 5)); \
1036 M_DST_INTERN(d, REG_ITMP3, -(-(offset) & 0x03ff)); \
1041 #endif /* !defined(ENABLE_SOFTFLOAT) */
1044 /******************************************************************************/
1045 /* additional helper macros ***************************************************/
1046 /******************************************************************************/
1048 /* M_???_IMM_EXT_MUL4:
1049 extended immediate operations, to handle immediates lager than 8bit.
1050 ATTENTION: the immediate is rotatet left by 2 (multiplied by 4)!!!
1053 #define M_ADD_IMM_EXT_MUL4(d,n,imm) \
1055 assert(d != REG_PC); \
1056 assert((imm) >= 0 && (imm) <= 0x00ffffff); \
1057 M_ADD_IMM(d, n, IMM_ROTL(imm, 1)); \
1058 if ((imm) > 0x000000ff) M_ADD_IMM(d, d, IMM_ROTL((imm) >> 8, 5)); \
1059 if ((imm) > 0x0000ffff) M_ADD_IMM(d, d, IMM_ROTL((imm) >> 16, 9)); \
1062 #define M_SUB_IMM_EXT_MUL4(d,n,imm) \
1064 assert(d != REG_PC); \
1065 assert((imm) >= 0 && (imm) <= 0x00ffffff); \
1066 M_SUB_IMM(d, n, IMM_ROTL(imm, 1)); \
1067 if ((imm) > 0x000000ff) M_SUB_IMM(d, d, IMM_ROTL((imm) >> 8, 5)); \
1068 if ((imm) > 0x0000ffff) M_SUB_IMM(d, d, IMM_ROTL((imm) >> 16, 9)); \
1073 loads the integer/long value const into register d.
1076 #define ICONST(d,c) emit_iconst(cd, (d), (c))
1078 #define LCONST(d,c) \
1079 if (IS_IMM((c) >> 32)) { \
1080 M_MOV_IMM(GET_HIGH_REG(d), (s4) ((s8) (c) >> 32)); \
1081 ICONST(GET_LOW_REG(d), (s4) ((s8) (c) & 0xffffffff)); \
1082 } else if (IS_IMM((c) & 0xffffffff)) { \
1083 M_MOV_IMM(GET_LOW_REG(d), (s4) ((s8) (c) & 0xffffffff)); \
1084 ICONST(GET_HIGH_REG(d), (s4) ((s8) (c) >> 32)); \
1086 disp = dseg_add_s8(cd, (c)); \
1087 M_LDRD(d, REG_PV, disp); \
1091 #if !defined(ENABLE_SOFTFLOAT)
1093 #define FCONST(d,c) \
1095 disp = dseg_add_float(cd, (c)); \
1096 M_LDFS(d, REG_PV, disp); \
1099 #define DCONST(d,c) \
1101 disp = dseg_add_double(cd, (c)); \
1102 M_LDFD(d, REG_PV, disp); \
1105 #endif /* !defined(ENABLE_SOFTFLOAT) */
1109 used to recompute our PV (we use the IP for this) out of the current PC
1110 ATTENTION: if you change this, you have to look at other functions as well!
1111 Following things depend on it: md_codegen_get_pv_from_pc();
1113 #define M_RECOMPUTE_PV(disp) \
1114 disp += 8; /* we use PC relative addr. */ \
1115 assert((disp & 0x03) == 0); \
1116 assert(disp >= 0 && disp <= 0x03ffffff); \
1117 if (disp > 0x0003ffff) { \
1118 M_SUB_IMM(REG_PV, REG_PC, IMM_ROTL(disp >> 18, 9)); \
1119 M_SUB_IMM(REG_PV, REG_PV, IMM_ROTL(disp >> 10, 5)); \
1120 M_SUB_IMM(REG_PV, REG_PV, IMM_ROTL(disp >> 2, 1)); \
1121 } else if (disp > 0x000003ff) { \
1122 M_SUB_IMM(REG_PV, REG_PC, IMM_ROTL(disp >> 10, 5)); \
1123 M_SUB_IMM(REG_PV, REG_PV, IMM_ROTL(disp >> 2, 1)); \
1125 M_SUB_IMM(REG_PV, REG_PC, IMM_ROTL(disp >> 2, 1)); \
1129 generates an integer-move from register a to b.
1130 if a and b are the same int-register, no code will be generated.
1133 #define M_INTMOVE(a,b) \
1139 #define M_LNGMOVE(a,b) \
1141 if (GET_HIGH_REG(a) == GET_LOW_REG(b)) { \
1142 assert((GET_LOW_REG(a) != GET_HIGH_REG(b))); \
1143 M_INTMOVE(GET_HIGH_REG(a), GET_HIGH_REG(b)); \
1144 M_INTMOVE(GET_LOW_REG(a), GET_LOW_REG(b)); \
1146 M_INTMOVE(GET_LOW_REG(a), GET_LOW_REG(b)); \
1147 M_INTMOVE(GET_HIGH_REG(a), GET_HIGH_REG(b)); \
1153 generates the compare part of an if-sequece
1154 uses M_CMP or M_CMP_IMM to do the compare
1155 ATTENTION: uses REG_ITMP3 as intermediate register
1157 #define M_COMPARE(reg, val) \
1158 if (IS_IMM(val)) { \
1159 M_CMP_IMM(reg, (val)); \
1160 } else if(IS_IMM(-(val))) { \
1161 M_CMN_IMM(reg, -(val)); \
1163 assert((reg) != REG_ITMP3); \
1164 ICONST(REG_ITMP3, (val)); \
1165 M_CMP(reg, REG_ITMP3); \
1169 performs a long branch to an absolute address with return address in LR
1170 takes up 3 bytes of code space; address is hard-coded into code
1172 #define M_LONGBRANCH(adr) \
1173 M_ADD_IMM(REG_LR, REG_PC, 4); \
1174 M_LDR_INTERN(REG_PC, REG_PC, -4); \
1177 /* M_DSEG_LOAD/BRANCH:
1179 ATTENTION: if you change this, you have to look at the asm_call_jit_compiler!
1180 ATTENTION: we use M_LDR, so the same restrictions apply to us!
1182 #define M_DSEG_LOAD(reg, offset) \
1183 M_LDR_NEGATIVE(reg, REG_PV, offset)
1185 #define M_DSEG_BRANCH(offset) \
1186 if (IS_OFFSET(offset, 0x0fff)) { \
1187 M_MOV(REG_LR, REG_PC); \
1188 M_LDR_INTERN(REG_PC, REG_PV, offset); \
1190 /*assert((offset) <= 0);*/ \
1191 CHECK_OFFSET(offset,0x0fffff); \
1192 M_SUB_IMM(REG_ITMP3, REG_PV, ((-(offset) >> 12) & 0xff) | (((10) & 0x0f) << 8)); /*TODO: more to go*/ \
1193 M_MOV(REG_LR, REG_PC); \
1194 M_LDR_INTERN(REG_PC, REG_ITMP3, -(-(offset) & 0x0fff)); /*TODO: this looks ugly*/ \
1198 #define M_ILD(a,b,c) M_LDR(a,b,c)
1199 #define M_LLD(a,b,c) M_LDRD(a,b,c)
1201 #define M_ILD_INTERN(a,b,c) M_LDR_INTERN(a,b,c)
1202 #define M_LLD_INTERN(a,b,c) M_LDRD_INTERN(a,b,c)
1204 #define M_ALD(a,b,c) M_ILD(a,b,c)
1205 #define M_ALD_INTERN(a,b,c) M_ILD_INTERN(a,b,c)
1208 #define M_IST(a,b,c) M_STR(a,b,c)
1209 #define M_LST(a,b,c) M_STRD(a,b,c)
1211 #define M_IST_INTERN(a,b,c) M_STR_INTERN(a,b,c)
1212 #define M_LST_INTERN(a,b,c) M_STRD_INTERN(a,b,c)
1214 #define M_AST(a,b,c) M_IST(a,b,c)
1215 #define M_AST_INTERN(a,b,c) M_IST_INTERN(a,b,c)
1218 #if !defined(ENABLE_SOFTFLOAT)
1220 #define M_FLD(a,b,c) M_LDFS(a,b,c)
1221 #define M_DLD(a,b,c) M_LDFD(a,b,c)
1223 #define M_FST(a,b,c) M_STFS(a,b,c)
1224 #define M_DST(a,b,c) M_STFD(a,b,c)
1226 #endif /* !defined(ENABLE_SOFTFLOAT) */
1229 #endif /* _CODEGEN_H */
1233 * These are local overrides for various environment variables in Emacs.
1234 * Please do not remove this and leave it at the end of the file, where
1235 * Emacs will automagically detect them.
1236 * ---------------------------------------------------------------------
1239 * indent-tabs-mode: t
1243 * vim:noexpandtab:sw=4:ts=4: