CACAO
codegen.hpp
Go to the documentation of this file.
1 /* src/vm/jit/arm/codegen.hpp - code generation macros and definitions for ARM
2 
3  Copyright (C) 1996-2013
4  CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5 
6  This file is part of CACAO.
7 
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.
12 
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.
17 
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
21  02110-1301, USA.
22 
23 */
24 
25 
26 #ifndef CODEGEN_HPP_
27 #define CODEGEN_HPP_ 1
28 
29 #include "config.h"
30 
31 
32 /******************************************************************************/
33 /* register splitting stuff (ugly) ********************************************/
34 /******************************************************************************/
35 
36 #if defined(__ARMEL__)
37 
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); \
43  }
44 
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); \
50  }
51 
52 #else /* defined(__ARMEB__) */
53 
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)); \
59  }
60 
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)); \
66  }
67 
68 #endif
69 
70 
71 /******************************************************************************/
72 /* checking macros ************************************************************/
73 /******************************************************************************/
74 
75 #define MCODECHECK(icnt) \
76  do { \
77  if ((cd->mcodeptr + (icnt) * 4) > cd->mcodeend) \
78  codegen_increase(cd); \
79  } while (0)
80 
81 #define ALIGNCODENOP /* empty */
82 
83 /* TODO: correct this! */
84 #define IS_IMM(val) ( ((val) >= 0) && ((val) <= 255) )
85 #define IS_OFFSET(off,max) ((s4)(off) <= (max) && (s4)(off) >= -(max))
86 
87 #define CHECK_INT_REG(r) assert((r)>=0 && (r)<=15)
88 #define CHECK_FLT_REG(r) assert((r)>=0 && (r)<=15)
89 #define CHECK_OFFSET(off,max) assert(IS_OFFSET(off,max))
90 
91 
92 /* branch defines *************************************************************/
93 
94 #define BRANCH_NOPS \
95  do { \
96  M_NOP; \
97  } while (0)
98 
99 
100 /* patcher defines ************************************************************/
101 
102 #define PATCHER_CALL_SIZE 1 * 4 /* an instruction is 4-bytes long */
103 
104 #define PATCHER_NOPS \
105  do { \
106  M_NOP; \
107  } while (0)
108 
109 
110 /* lazy debugger **************************************************************/
111 
112 #if !defined(NDEBUG)
113 void asm_debug(int a1, int a2, int a3, int a4);
114 void asm_debug_intern(int a1, int a2, int a3, int a4);
115 
116 /* if called with this macros, it can be placed nearly anywhere */
117 /* almost all registers are saved and restored afterwards */
118 /* it uses a long branch to call the asm_debug_intern (no exit) */
119 #define ASM_DEBUG_PREPARE \
120  M_STMFD(0x7fff, REG_SP)
121 #define ASM_DEBUG_EXECUTE \
122  M_LONGBRANCH(asm_debug_intern); \
123  M_LDMFD(0x7fff, REG_SP)
124 #endif
125 
126 
127 /******************************************************************************/
128 /* macros to create code ******************************************************/
129 /******************************************************************************/
130 
131 /* the condition field */
132 #define COND_EQ 0x0 /* Equal Z set */
133 #define COND_NE 0x1 /* Not equal Z clear */
134 #define COND_CS 0x2 /* Carry set C set */
135 #define COND_CC 0x3 /* Carry clear C clear */
136 #define COND_MI 0x4 /* Negative N set */
137 #define COND_PL 0x5 /* Positive N clear */
138 #define COND_VS 0x6 /* Overflow V set */
139 #define COND_VC 0x7 /* No overflow V clear */
140 #define COND_HI 0x8 /* Unsigned higher */
141 #define COND_LS 0x9 /* Unsigned lower, same */
142 #define COND_GE 0xA /* Sig. greater, equal */
143 #define COND_LT 0xB /* Sig. less than */
144 #define COND_GT 0xC /* Sig. greater than */
145 #define COND_LE 0xD /* Sig. less, equal */
146 #define COND_AL 0xE /* Always */
147 #define CONDNV 0xF /* Special (see A3-5) */
148 #define UNCOND COND_AL
149 
150 /* data processing operation: M_DAT
151  cond ... conditional execution
152  op ..... opcode
153  d ...... destination reg
154  n ...... source reg
155  S ...... update condition codes
156  I ...... switch to immediate mode
157  shift .. shifter operand
158 */
159 
160 #define M_DAT(cond,op,d,n,S,I,shift) \
161  do { \
162  *((u4 *) cd->mcodeptr) = (((cond) << 28) | ((op) << 21) | ((d) << 12) | ((n) << 16) | ((I) << 25) | ((S) << 20) | ((shift) & 0x00000fff)); \
163  cd->mcodeptr += 4; \
164  } while (0)
165 
166 
167 /* load and store instruction: M_MEM
168  cond ... conditional execution
169  L ...... load (L=1) or store (L=0)
170  B ...... unsigned byte (B=1) or word (B=0)
171  d ...... destination reg
172  n ...... base reg for addressing
173  adr .... addressing mode specific
174 */
175 
176 #define M_MEM(cond,L,B,d,n,adr,I,P,U,W) \
177  do { \
178  *((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)); \
179  cd->mcodeptr += 4; \
180  } while (0)
181 
182 #define M_MEM_GET_Rd(mcode) (((mcode) >> 12) & 0x0f)
183 #define M_MEM_GET_Rbase(mcode) (((mcode) >> 16) & 0x0f)
184 
185 
186 /* load and store instruction: M_MEM2
187  cond ... conditional execution
188  L ...... load (L=1) or store (L=0)
189  H ...... halfword (H=1) or signed byte (H=0)
190  S ...... signed (S=1) or unsigned (S=0) halfword
191  d ...... destination reg
192  n ...... base reg for addressing
193  adr .... addressing mode specific
194 */
195 
196 #define M_MEM2(cond,L,H,S,d,n,adr,I,P,U,W) \
197  do { \
198  *((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)); \
199  cd->mcodeptr += 4; \
200  } while (0)
201 
202 
203 /* load and store multiple instruction: M_MEM_MULTI
204  cond ... conditional execution
205  L ...... load (L=1) or store (L=0)
206  S ...... special (see "The ARM ARM A3-21")
207  regs ... register list
208  n ...... base reg for addressing
209 */
210 
211 #define M_MEM_MULTI(cond,L,S,regs,n,P,U,W) \
212  do { \
213  *((u4 *) cd->mcodeptr) = (((cond) << 28) | (1 << 27) | ((L) << 20) | ((S) << 22) | ((n) << 16) | ((regs) & 0xffff) | ((P) << 24) | ((U) << 23) | ((W) << 21)); \
214  cd->mcodeptr += 4; \
215  } while (0)
216 
217 
218 /* branch and branch with link X (instruction set exchange)
219  cond ... conditional execution
220  L ...... branch with link (L=1)
221  reg .... register
222 */
223 
224 #define M_BRAX(cond,L,reg) \
225  do { \
226  *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x12 << 20) | (0xfff << 8) | (L << 5) | (1 << 4) | ((reg) & 0xf)); \
227  cd->mcodeptr += 4; \
228  } while (0)
229 
230 
231 /* branch and branch with link: M_BRA
232  cond ... conditional execution
233  L ...... branch with link (L=1)
234  offset . 24bit offset
235 */
236 
237 #define M_BRA(cond,L,offset) \
238  do { \
239  *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x5 << 25) | ((L) << 24) | ((offset) & 0x00ffffff)); \
240  cd->mcodeptr += 4; \
241  } while (0)
242 
243 
244 /* multiplies: M_MULT
245  cond ... conditional execution
246  d ...... destination register
247  n, m ... source registers
248  S ...... update conditional codes
249  A ...... accumulate flag (enables third source)
250  s ...... third source register
251 */
252 
253 #define M_MULT(cond,d,n,m,S,A,s) \
254  do { \
255  *((u4 *) cd->mcodeptr) = (((cond) << 28) | ((d) << 16) | ((n) << 8) | (m) | (0x09 << 4) | ((S) << 20) | ((A) << 21) | ((s) << 12)); \
256  cd->mcodeptr += 4; \
257  } while (0)
258 
259 
260 /* no operation (mov r0,r0): M_NOP */
261 
262 #define M_NOP \
263  do { \
264  *((u4 *) cd->mcodeptr) = (0xe1a00000); \
265  cd->mcodeptr += 4; \
266  } while (0)
267 
268 
269 /* software breakpoint (only v5 and above): M_BREAKPOINT */
270 
271 #define M_BREAKPOINT(imm) \
272  do { \
273  *((u4 *) cd->mcodeptr) = (0x0e12 << 20) | (0x07 << 4) | (((imm) & 0xfff0) << (8-4)) | ((imm) & 0x0f); \
274  cd->mcodeptr += 4; \
275  } while (0)
276 
277 
278 /* undefined instruction used for hardware exceptions */
279 
280 #define M_UNDEFINED(cond,imm,n) \
281  do { \
282  *((u4 *) cd->mcodeptr) = ((cond) << 28) | (0x7f << 20) | (((imm) & 0x0fff) << 8) | (0x0f << 4) | (n); \
283  cd->mcodeptr += 4; \
284  } while (0)
285 
286 
287 #if !defined(ENABLE_SOFTFLOAT)
288 
289 /* M_CPDO **********************************************************************
290 
291  Floating-Point Coprocessor Data Operations
292 
293  cond ... conditional execution
294  op ..... opcode
295  D ...... dyadic (D=0) or monadic (D=1) instruction
296  Fd ..... destination float-register
297  Fn ..... source float-register
298  Fm ..... source float-register or immediate
299 
300 *******************************************************************************/
301 
302 #define M_CPDOS(cond,op,D,Fd,Fn,Fm) \
303  do { \
304  *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0e << 24) | (1 << 8) | ((op) << 20) | ((D) << 15) | ((Fd) << 12) | ((Fn) << 16) | ((Fm) & 0x0f)); \
305  cd->mcodeptr += 4; \
306  } while (0)
307 
308 
309 #define M_CPDOD(cond,op,D,Fd,Fn,Fm) \
310  do { \
311  *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0e << 24) | (1 << 8) | ((op) << 20) | ((D) << 15) | ((Fd) << 12) | ((Fn) << 16) | ((Fm) & 0x0f) | (1 << 7)); \
312  cd->mcodeptr += 4; \
313  } while (0)
314 
315 
316 #define M_CPDP(cond,p,q,r,s,cp_num,D,N,M,Fd,Fn,Fm) \
317  do { \
318  *((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)); \
319  cd->mcodeptr += 4; \
320  } while (0)
321 
322 #define M_CPDPF(cond,p,q,r,s,cp_num,Fd,Fn,Fm) \
323  M_CPDP(cond,p,q,r,s,cp_num,(Fd)>>4,(Fn)>>4,(Fm)>>4,(Fd)&0xf,(Fn)&0xf,Fm)
324 
325 /* M_CPDT **********************************************************************
326 
327  Floating-Point Coprocessor Data Transfer
328 
329  cond ... conditional execution
330  L ...... load (L=1) or store (L=0)
331  Fd ..... destination float-register
332  n ...... base reg for addressing
333 
334 *******************************************************************************/
335 
336 #define M_CPDT(cond,L,T1,T0,Fd,n,off,P,U,W) \
337  do { \
338  *((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)); \
339  cd->mcodeptr += 4; \
340  } while (0)
341 
342 #define M_CPLS(cond,L,P,U,W,cp_num,D,Fd,n,off) \
343  do { \
344  *((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)); \
345  cd->mcodeptr += 4; \
346  } while (0)
347 
348 
349 /* M_CPRT **********************************************************************
350 
351  Floating-Point Coprocessor Register Transfer
352 
353  XXX
354 
355 *******************************************************************************/
356 
357 #define M_CPRT(cond,op,L,cp_num,N,Fn,n) \
358  do { \
359  *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0e << 24) | (1 << 4) | ((op) << 21) | ((L) << 20) | ((cp_num) << 8) | ((N) << 7) | ((Fn) << 16) | ((n) << 12)); \
360  cd->mcodeptr += 4; \
361  } while (0)
362 
363 #define M_CPRTS(cond,L,d,Fn,Fm) \
364  do { \
365  *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0e << 24) | (1 << 8) | (1 << 4) | ((L) << 20) | ((d) << 12) | ((Fn) << 16) | (Fm)); \
366  cd->mcodeptr += 4; \
367  } while (0)
368 
369 
370 #define M_CPRTD(cond,L,d,Fn,Fm) \
371  do { \
372  *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0e << 24) | (1 << 8) | (1 << 4) | ((L) << 20) | ((d) << 12) | ((Fn) << 16) | (Fm) | (1 << 7)); \
373  cd->mcodeptr += 4; \
374  } while (0)
375 
376 
377 #define M_CPRTI(cond,L,d,Fn,Fm) \
378  do { \
379  *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0e << 24) | (1 << 8) | (1 << 4) | ((L) << 20) | ((d) << 12) | ((Fn) << 16) | (Fm) | (3 << 5)); \
380  cd->mcodeptr += 4; \
381  } while (0)
382 
383 
384 /* XXX TWISTI: replace X by something useful */
385 
386 #define M_CPRTX(cond,L,d,Fn,Fm) \
387  do { \
388  *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0e << 24) | (1 << 8) | (1 << 4) | ((L) << 20) | ((d) << 12) | ((Fn) << 16) | (Fm) | (1 << 23)); \
389  cd->mcodeptr += 4; \
390  } while (0)
391 
392 #endif /* !defined(ENABLE_SOFTFLOAT) */
393 
394 
395 /* used to store values! */
396 #define DCD(val) \
397  do { \
398  *((u4 *) cd->mcodeptr) = val; \
399  cd->mcodeptr += 4; \
400  } while (0)
401 
402 
403 /* used to directly access shifter; insert this as shifter operand! */
404 #define REG_LSL(reg, shift) ( (((shift) & 0x1f) << 7) | ((reg) & 0x0f) )
405 #define REG_LSR(reg, shift) ( (((shift) & 0x1f) << 7) | ((reg) & 0x0f) | (1 << 5) )
406 #define REG_ASR(reg, shift) ( (((shift) & 0x1f) << 7) | ((reg) & 0x0f) | (1 << 6) )
407 #define REG_LSL_REG(reg, s) ( (((s) & 0x0f) << 8) | ((reg) & 0x0f) | (1 << 4) )
408 #define REG_LSR_REG(reg, s) ( (((s) & 0x0f) << 8) | ((reg) & 0x0f) | (1 << 4) | (1 << 5) )
409 #define REG_ASR_REG(reg, s) ( (((s) & 0x0f) << 8) | ((reg) & 0x0f) | (1 << 4) | (1 << 6) )
410 
411 /* used to directly rotate immediate values; insert this as immediate! */
412 /* ATTENTION: this rotates the immediate right by (2 * rot) bits */
413 #define IMM_ROTR(imm, rot) ( ((imm) & 0xff) | (((rot) & 0x0f) << 8) )
414 #define IMM_ROTL(imm, rot) IMM_ROTR(imm, 16-(rot))
415 
416 
417 /******************************************************************************/
418 /* macros for all basic arm instructions **************************************/
419 /******************************************************************************/
420 
421 #define M_ADD(d,a,b) M_DAT(UNCOND,0x04,d,a,0,0,b) /* d = a + b */
422 #define M_ADC(d,a,b) M_DAT(UNCOND,0x05,d,a,0,0,b) /* d = a + b (with Carry) */
423 #define M_SUB(d,a,b) M_DAT(UNCOND,0x02,d,a,0,0,b) /* d = a - b */
424 #define M_SBC(d,a,b) M_DAT(UNCOND,0x06,d,a,0,0,b) /* d = a - b (with Carry) */
425 #define M_AND(a,b,d) M_DAT(UNCOND,0x00,d,a,0,0,b) /* d = a & b */
426 #define M_ORR(a,b,d) M_DAT(UNCOND,0x0c,d,a,0,0,b) /* d = a | b */
427 #define M_EOR(a,b,d) M_DAT(UNCOND,0x01,d,a,0,0,b) /* d = a ^ b */
428 #define M_TST(a,b) M_DAT(UNCOND,0x08,0,a,1,0,b) /* TST a & b */
429 #define M_TEQ(a,b) M_DAT(UNCOND,0x09,0,a,1,0,b) /* TST a ^ b */
430 #define M_CMP(a,b) M_DAT(UNCOND,0x0a,0,a,1,0,b) /* TST a - b */
431 #define M_MOV(d,b) M_DAT(UNCOND,0x0d,d,0,0,0,b) /* d = b */
432 #define M_ADD_S(d,a,b) M_DAT(UNCOND,0x04,d,a,1,0,b) /* d = a + b (update Flags) */
433 #define M_SUB_S(d,a,b) M_DAT(UNCOND,0x02,d,a,1,0,b) /* d = a - b (update Flags) */
434 #define M_ORR_S(a,b,d) M_DAT(UNCOND,0x0c,d,a,1,0,b) /* d = a | b (update flags) */
435 #define M_MOV_S(d,b) M_DAT(UNCOND,0x0d,d,0,1,0,b) /* d = b (update Flags) */
436 
437 #define M_ADD_IMM(d,a,i) M_DAT(UNCOND,0x04,d,a,0,1,i) /* d = a + i */
438 #define M_ADC_IMM(d,a,i) M_DAT(UNCOND,0x05,d,a,0,1,i) /* d = a + i (with Carry) */
439 #define M_SUB_IMM(d,a,i) M_DAT(UNCOND,0x02,d,a,0,1,i) /* d = a - i */
440 #define M_SBC_IMM(d,a,i) M_DAT(UNCOND,0x06,d,a,0,1,i) /* d = a - i (with Carry) */
441 #define M_RSB_IMM(d,a,i) M_DAT(UNCOND,0x03,d,a,0,1,i) /* d = -a + i */
442 #define M_RSC_IMM(d,a,i) M_DAT(UNCOND,0x07,d,a,0,1,i) /* d = -a + i (with Carry) */
443 #define M_AND_IMM(a,i,d) M_DAT(UNCOND,0x00,d,a,0,1,i) /* d = a & i */
444 #define M_TST_IMM(a,i) M_DAT(UNCOND,0x08,0,a,1,1,i) /* TST a & i */
445 #define M_TEQ_IMM(a,i) M_DAT(UNCOND,0x09,0,a,1,1,i) /* TST a ^ i */
446 #define M_CMP_IMM(a,i) M_DAT(UNCOND,0x0a,0,a,1,1,i) /* TST a - i */
447 #define M_CMN_IMM(a,i) M_DAT(UNCOND,0x0b,0,a,1,1,i) /* TST a + i */
448 #define M_MOV_IMM(d,i) M_DAT(UNCOND,0x0d,d,0,0,1,i) /* d = i */
449 #define M_ADD_IMMS(d,a,i) M_DAT(UNCOND,0x04,d,a,1,1,i) /* d = a + i (update Flags) */
450 #define M_SUB_IMMS(d,a,i) M_DAT(UNCOND,0x02,d,a,1,1,i) /* d = a - i (update Flags) */
451 #define M_RSB_IMMS(d,a,i) M_DAT(UNCOND,0x03,d,a,1,1,i) /* d = -a + i (update Flags) */
452 
453 #define M_ADDSUB_IMM(d,a,i) if((i)>=0) M_ADD_IMM(d,a,i); else M_SUB_IMM(d,a,-(i))
454 #define M_MOVEQ(a,d) M_DAT(COND_EQ,0x0d,d,0,0,0,a)
455 #define M_EORLE(d,a,b) M_DAT(COND_LE,0x01,d,a,0,0,b)
456 
457 #define M_MOVVS_IMM(i,d) M_DAT(COND_VS,0x0d,d,0,0,1,i)
458 #define M_MOVEQ_IMM(i,d) M_DAT(COND_EQ,0x0d,d,0,0,1,i)
459 #define M_MOVNE_IMM(i,d) M_DAT(COND_NE,0x0d,d,0,0,1,i)
460 #define M_MOVLT_IMM(i,d) M_DAT(COND_LT,0x0d,d,0,0,1,i)
461 #define M_MOVGT_IMM(i,d) M_DAT(COND_GT,0x0d,d,0,0,1,i)
462 #define M_MOVLS_IMM(i,d) M_DAT(COND_LS,0x0d,d,0,0,1,i)
463 
464 #define M_ADDHI_IMM(d,a,i) M_DAT(COND_HI,0x04,d,a,0,1,i)
465 #define M_ADDLT_IMM(d,a,i) M_DAT(COND_LT,0x04,d,a,0,1,i)
466 #define M_ADDGT_IMM(d,a,i) M_DAT(COND_GT,0x04,d,a,0,1,i)
467 #define M_SUBLO_IMM(d,a,i) M_DAT(COND_CC,0x02,d,a,0,1,i)
468 #define M_SUBLT_IMM(d,a,i) M_DAT(COND_LT,0x02,d,a,0,1,i)
469 #define M_SUBGT_IMM(d,a,i) M_DAT(COND_GT,0x02,d,a,0,1,i)
470 #define M_RSBMI_IMM(d,a,i) M_DAT(COND_MI,0x03,d,a,0,1,i)
471 #define M_ADCMI_IMM(d,a,i) M_DAT(COND_MI,0x05,d,a,0,1,i)
472 
473 #define M_CMPEQ(a,b) M_DAT(COND_EQ,0x0a,0,a,1,0,b) /* TST a - b */
474 #define M_CMPLE(a,b) M_DAT(COND_LE,0x0a,0,a,1,0,b) /* TST a - b */
475 
476 #define M_CMPEQ_IMM(a,i) M_DAT(COND_EQ,0x0a,0,a,1,1,i)
477 
478 #define M_MUL(d,a,b) M_MULT(UNCOND,d,a,b,0,0,0x0) /* d = a * b */
479 
480 #define M_B(off) M_BRA(UNCOND,0,off) /* unconditional branch */
481 #define M_BL(off) M_BRA(UNCOND,1,off) /* branch and link */
482 #define M_BEQ(off) M_BRA(COND_EQ,0,off) /* conditional branches */
483 #define M_BNE(off) M_BRA(COND_NE,0,off)
484 #define M_BGE(off) M_BRA(COND_GE,0,off)
485 #define M_BGT(off) M_BRA(COND_GT,0,off)
486 #define M_BLT(off) M_BRA(COND_LT,0,off)
487 #define M_BLE(off) M_BRA(COND_LE,0,off)
488 #define M_BHI(off) M_BRA(COND_HI,0,off) /* unsigned conditional */
489 #define M_BHS(off) M_BRA(COND_CS,0,off)
490 #define M_BLO(off) M_BRA(COND_CC,0,off)
491 #define M_BLS(off) M_BRA(COND_LS,0,off)
492 
493 #define M_BX(a) M_BRAX(COND_AL,0,a)
494 #define M_BLX(a) M_BRAX(COND_AL,1,a)
495 
496 
497 /******************************************************************************/
498 /* macros for load and store instructions *************************************/
499 /******************************************************************************/
500 
501 #define M_LDMFD(regs,base) M_MEM_MULTI(UNCOND,1,0,regs,base,0,1,1)
502 #define M_STMFD(regs,base) M_MEM_MULTI(UNCOND,0,0,regs,base,1,0,1)
503 
504 #define M_LDR_REG(d,base,offreg) M_MEM(UNCOND,1,0,d,base,offreg,1,1,1,0)
505 #define M_STR_REG(d,base,offreg) M_MEM(UNCOND,0,0,d,base,offreg,1,1,1,0)
506 
507 #define M_LDR_INTERN(d,base,off) \
508  do { \
509  CHECK_OFFSET(off, 0x0fff); \
510  M_MEM(UNCOND,1,0,d,base,(((off) < 0) ? -(off) : off),0,1,(((off) < 0) ? 0 : 1),0); \
511  } while (0)
512 
513 #define M_STR_INTERN(d,base,off) \
514  do { \
515  CHECK_OFFSET(off, 0x0fff); \
516  M_MEM(UNCOND,0,0,d,base,(((off) < 0) ? -(off) : off),0,1,(((off) < 0) ? 0 : 1),0); \
517  } while (0)
518 
519 #define M_LDR_UPDATE(d,base,off) \
520  do { \
521  CHECK_OFFSET(off, 0x0fff); \
522  M_MEM(UNCOND,1,0,d,base,(((off) < 0) ? -(off) : off),0,0,(((off) < 0) ? 0 : 1),0); \
523  } while (0)
524 
525 #define M_STR_UPDATE(d,base,off) \
526  do { \
527  CHECK_OFFSET(off,0x0fff); \
528  M_MEM(UNCOND,0,0,d,base,(((off) < 0) ? -(off) : off),0,1,(((off) < 0) ? 0 : 1),1); \
529  } while (0)
530 
531 
532 #define M_LDRH(d,base,off) \
533  do { \
534  CHECK_OFFSET(off, 0x00ff); \
535  assert(off >= 0); \
536  M_MEM2(UNCOND,1,1,0,d,base,off,1,1,1,0); \
537  } while (0)
538 
539 #define M_LDRSH(d,base,off) \
540  do { \
541  CHECK_OFFSET(off, 0x00ff); \
542  assert(off >= 0); \
543  M_MEM2(UNCOND,1,1,1,d,base,off,1,1,1,0); \
544  } while (0)
545 
546 #define M_LDRSB(d,base,off) \
547  do { \
548  CHECK_OFFSET(off, 0x00ff); \
549  assert(off >= 0); \
550  M_MEM2(UNCOND,1,0,1,d,base,off,1,1,1,0); \
551  } while (0)
552 
553 #define M_STRH(d,base,off) \
554  do { \
555  CHECK_OFFSET(off, 0x00ff); \
556  assert(off >= 0); \
557  M_MEM2(UNCOND,0,1,0,d,base,off,1,1,1,0); \
558  } while (0)
559 
560 #define M_STRB(d,base,off) \
561  do { \
562  CHECK_OFFSET(off, 0x0fff); \
563  assert(off >= 0); \
564  M_MEM(UNCOND,0,1,d,base,off,0,1,1,0); \
565  } while (0)
566 
567 
568 #define M_TRAP(a,i) M_UNDEFINED(UNCOND,i,a);
569 #define M_TRAPEQ(a,i) M_UNDEFINED(COND_EQ,i,a);
570 #define M_TRAPNE(a,i) M_UNDEFINED(COND_NE,i,a);
571 #define M_TRAPLT(a,i) M_UNDEFINED(COND_LT,i,a);
572 #define M_TRAPLE(a,i) M_UNDEFINED(COND_LE,i,a);
573 #define M_TRAPHI(a,i) M_UNDEFINED(COND_HI,i,a);
574 #define M_TRAPHS(a,i) M_UNDEFINED(COND_CS,i,a);
575 
576 
577 /* if we do not have double-word load/store command, we can fake them */
578 /* ATTENTION: the original LDRD/STRD of ARMv5e would always use (Rd/Rd+1),
579  so these faked versions are more "powerful" */
580 
581 #if defined(__ARMEL__)
582 
583 #define M_LDRD_INTERN(d,base,off) \
584  do { \
585  M_LDR_INTERN(GET_LOW_REG(d), base, off); \
586  M_LDR_INTERN(GET_HIGH_REG(d), base, (off) + 4); \
587  } while (0)
588 
589 #define M_STRD_INTERN(d,base,off) \
590  do { \
591  M_STR_INTERN(GET_LOW_REG(d), base, off); \
592  M_STR_INTERN(GET_HIGH_REG(d), base, (off) + 4); \
593  } while (0)
594 
595 #define M_LDRD_ALTERN(d,base,off) \
596  do { \
597  M_LDR_INTERN(GET_HIGH_REG(d), base, (off) + 4); \
598  M_LDR_INTERN(GET_LOW_REG(d), base, off); \
599  } while (0)
600 
601 #define M_LDRD_UPDATE(d,base,off) \
602  do { \
603  assert((off) == +8); \
604  M_LDR_UPDATE(GET_LOW_REG(d), base, 4); \
605  M_LDR_UPDATE(GET_HIGH_REG(d), base, 4); \
606  } while (0)
607 
608 #define M_STRD_UPDATE(d,base,off) \
609  do { \
610  assert((off) == -8); \
611  M_STR_UPDATE(GET_HIGH_REG(d), base, -4); \
612  M_STR_UPDATE(GET_LOW_REG(d), base, -4); \
613  } while (0)
614 
615 #define GET_FIRST_REG(d) GET_LOW_REG(d)
616 #define GET_SECOND_REG(d) GET_HIGH_REG(d)
617 
618 #else /* defined(__ARMEB__) */
619 
620 #define M_LDRD_INTERN(d,base,off) \
621  do { \
622  M_LDR_INTERN(GET_HIGH_REG(d), base, off); \
623  M_LDR_INTERN(GET_LOW_REG(d), base, (off) + 4); \
624  } while (0)
625 
626 #define M_STRD_INTERN(d,base,off) \
627  do { \
628  M_STR_INTERN(GET_HIGH_REG(d), base, off); \
629  M_STR_INTERN(GET_LOW_REG(d), base, (off) + 4); \
630  } while (0)
631 
632 #define M_LDRD_ALTERN(d,base,off) \
633  do { \
634  M_LDR_INTERN(GET_LOW_REG(d), base, (off) + 4); \
635  M_LDR_INTERN(GET_HIGH_REG(d), base, off); \
636  } while (0)
637 
638 #define M_LDRD_UPDATE(d,base,off) \
639  do { \
640  assert((off) == +8); \
641  M_LDR_UPDATE(GET_HIGH_REG(d), base, 4); \
642  M_LDR_UPDATE(GET_LOW_REG(d), base, 4); \
643  } while (0)
644 
645 #define M_STRD_UPDATE(d,base,off) \
646  do { \
647  assert((off) == -8); \
648  M_STR_UPDATE(GET_LOW_REG(d), base, -4); \
649  M_STR_UPDATE(GET_HIGH_REG(d) ,base, -4); \
650  } while (0)
651 
652 #define GET_FIRST_REG(d) GET_HIGH_REG(d)
653 #define GET_SECOND_REG(d) GET_LOW_REG(d)
654 
655 #endif /* defined(__ARMEB__) */
656 
657 
658 /******************************************************************************/
659 /* macros for all floating point instructions *********************************/
660 /******************************************************************************/
661 
662 #if !defined(ENABLE_SOFTFLOAT)
663 
664 #if defined(__VFP_FP__)
665 
666 #define M_FADD(a,b,d) M_CPDPF(UNCOND,0,1,1,0,10,d,a,b)/* d = a + b */
667 #define M_FSUB(a,b,d) M_CPDPF(UNCOND,0,1,1,1,10,d,a,b)/* d = a - b */
668 #define M_FMUL(a,b,d) M_CPDPF(UNCOND,0,1,0,0,10,d,a,b)/* d = a * b */
669 #define M_FDIV(a,b,d) M_CPDPF(UNCOND,1,0,0,0,10,d,a,b)/* d = a / b */
670 #define M_DADD(a,b,d) M_CPDP(UNCOND,0,1,1,0,11,0,0,0,d,a,b)/* d = a + b */
671 #define M_DSUB(a,b,d) M_CPDP(UNCOND,0,1,1,1,11,0,0,0,d,a,b)/* d = a - b */
672 #define M_DMUL(a,b,d) M_CPDP(UNCOND,0,1,0,0,11,0,0,0,d,a,b)/* d = a * b */
673 #define M_DDIV(a,b,d) M_CPDP(UNCOND,1,0,0,0,11,0,0,0,d,a,b)/* d = a / b */
674 
675 #define M_FMOV(a,d) M_CPDPF(UNCOND,1,1,1,1,10,d,0x0,a)
676 #define M_DMOV(a,d) M_CPDP(UNCOND,1,1,1,1,11,0,0,0,d,0x0,a)
677 #define M_FNEG(a,d) M_CPDPF(UNCOND,1,1,1,1,10,d,0x1,a)
678 #define M_DNEG(a,d) M_CPDP(UNCOND,1,1,1,1,11,0,0,0,d,0x1,a)
679 
680 #define M_FCMP(a,b) M_CPDPF(UNCOND,1,1,1,1,10,a,0x4,b)
681 #define M_DCMP(a,b) M_CPDP(UNCOND,1,1,1,1,11,0,0,0,a,0x4,b)
682 
683 #define M_CVTDF(a,d) M_CPDP(UNCOND,1,1,1,1,11,(d)>>4,1,0,(d)&0xf,0x7,a)
684 #define M_CVTFD(a,d) M_CPDP(UNCOND,1,1,1,1,10,0,1,0,d,0x7,a)
685 #define M_CVTIF(a,d) M_CPDP(UNCOND,1,1,1,1,10,(d)>>4,1,0,(d)&0xf,0x8,a)
686 #define M_CVTID(a,d) M_CPDP(UNCOND,1,1,1,1,11,0,1,0,d,0x8,a)
687 #define M_CVTFI(a,d) M_CPDP(UNCOND,1,1,1,1,10,0,1,(a)>>4,d,0xd,a) // ftosis
688 #define M_CVTDI(a,d) M_CPDP(UNCOND,1,1,1,1,11,0,1,0,d,0xd,a) // ftosid
689 
690 #define M_FMSTAT M_CPRT(UNCOND,0x07,1,10,0,0x1,0xf)
691 
692 #define M_FMSR(a,Fb) M_CPRT(UNCOND,0x00,0,10,0,Fb,a)
693 #define M_FMRS(Fa,b) M_CPRT(UNCOND,0x00,1,10,0,Fa,b)
694 #define M_FMDLR(a,Fb) M_CPRT(UNCOND,0x00,0,11,0,Fb,a)
695 #define M_FMRDL(Fa,b) M_CPRT(UNCOND,0x00,1,11,0,Fa,b)
696 #define M_FMDHR(a,Fb) M_CPRT(UNCOND,0x01,0,11,0,Fb,a)
697 #define M_FMRDH(Fa,b) M_CPRT(UNCOND,0x01,1,11,0,Fa,b)
698 
699 #else
700 
701 #define M_FADD(a,b,d) M_CPDOS(UNCOND,0x00,0,d,a,b) /* d = a + b */
702 #define M_FSUB(a,b,d) M_CPDOS(UNCOND,0x02,0,d,a,b) /* d = a - b */
703 #define M_FMUL(a,b,d) M_CPDOS(UNCOND,0x01,0,d,a,b) /* d = a * b */
704 #define M_FDIV(a,b,d) M_CPDOS(UNCOND,0x04,0,d,a,b) /* d = a / b */
705 #define M_RMFS(d,a,b) M_CPDOS(UNCOND,0x08,0,d,a,b) /* d = a % b */
706 #define M_DADD(a,b,d) M_CPDOD(UNCOND,0x00,0,d,a,b) /* d = a + b */
707 #define M_DSUB(a,b,d) M_CPDOD(UNCOND,0x02,0,d,a,b) /* d = a - b */
708 #define M_DMUL(a,b,d) M_CPDOD(UNCOND,0x01,0,d,a,b) /* d = a * b */
709 #define M_DDIV(a,b,d) M_CPDOD(UNCOND,0x04,0,d,a,b) /* d = a / b */
710 #define M_RMFD(d,a,b) M_CPDOD(UNCOND,0x08,0,d,a,b) /* d = a % b */
711 
712 #define M_FMOV(a,d) M_CPDOS(UNCOND,0x00,1,d,0,a) /* d = a */
713 #define M_DMOV(a,d) M_CPDOD(UNCOND,0x00,1,d,0,a) /* d = a */
714 #define M_FNEG(a,d) M_CPDOS(UNCOND,0x01,1,d,0,a) /* d = - a */
715 #define M_DNEG(a,d) M_CPDOD(UNCOND,0x01,1,d,0,a) /* d = - a */
716 
717 #define M_FCMP(a,b) M_CPRTX(UNCOND,1,0x0f,a,b) /* COMPARE a; b */
718 #define M_DCMP(a,b) M_CPRTX(UNCOND,1,0x0f,a,b) /* COMPARE a; b */
719 
720 #define M_CVTDF(a,b) M_FMOV(a,b)
721 #define M_CVTFD(a,b) M_DMOV(a,b)
722 #define M_CVTIF(a,d) M_CPRTS(UNCOND,0,a,d,0) /* d = (float) a */
723 #define M_CVTID(a,d) M_CPRTD(UNCOND,0,a,d,0) /* d = (float) a */
724 #define M_CVTFI(a,d) M_CPRTI(UNCOND,1,d,0,a) /* d = (int) a */
725 #define M_CVTDI(a,d) M_CPRTI(UNCOND,1,d,0,a) /* d = (int) a */
726 
727 #endif
728 
729 
730 /* M_CAST_x2x:
731  loads the value of the integer-register a (argument or result) into
732  float-register Fb. (and vice versa)
733 */
734 
735 #if defined(__VFP_FP__)
736 
737 #define M_CAST_I2F(a,Fb) M_FMSR(a,Fb)
738 
739 #define M_CAST_F2I(Fa,b) M_FMRS(Fa,b)
740 
741 #define M_CAST_L2D(a,Fb) \
742  do { \
743  M_FMDLR(GET_LOW_REG(a), Fb); \
744  M_FMDHR(GET_HIGH_REG(a), Fb); \
745  } while (0)
746 
747 #define M_CAST_D2L(Fa,b) \
748  do { \
749  M_FMRDL(Fa, GET_LOW_REG(b)); \
750  M_FMRDH(Fa, GET_HIGH_REG(b)); \
751  } while (0)
752 
753 #else
754 
755 #define M_CAST_I2F(a,Fb) \
756  do { \
757  CHECK_FLT_REG(Fb); \
758  CHECK_INT_REG(a); \
759  M_STR_UPDATE(a, REG_SP, -4); \
760  M_FLD_UPDATE(Fb, REG_SP, 4); \
761  } while (0)
762 
763 #define M_CAST_L2D(a,Fb) \
764  do { \
765  CHECK_FLT_REG(Fb); \
766  CHECK_INT_REG(GET_LOW_REG(a)); \
767  CHECK_INT_REG(GET_HIGH_REG(a)); \
768  M_STRD_UPDATE(a, REG_SP, -8); \
769  M_DLD_UPDATE(Fb, REG_SP, 8); \
770  } while (0)
771 
772 #define M_CAST_F2I(Fa,b) \
773  do { \
774  CHECK_FLT_REG(Fa); \
775  CHECK_INT_REG(b); \
776  M_FST_UPDATE(Fa, REG_SP, -4); \
777  M_LDR_UPDATE(b, REG_SP, 4); \
778  } while (0)
779 
780 #define M_CAST_D2L(Fa,b) \
781  do { \
782  CHECK_INT_REG(GET_LOW_REG(b)); \
783  CHECK_INT_REG(GET_HIGH_REG(b)); \
784  M_DST_UPDATE(Fa, REG_SP, -8); \
785  M_LDRD_UPDATE(b, REG_SP, 8); \
786  } while (0)
787 
788 #endif
789 
790 /* M_xLD_xx & M_xST_xx:
791  XXX document me!
792 */
793 
794 #if defined(__VFP_FP__)
795 
796 #define M_FLD_INTERN(d,base,off) \
797  do { \
798  CHECK_OFFSET(off, 0x03ff); \
799  M_CPLS(UNCOND,1,1,(((off) < 0) ? 0 : 1),0,10,(d)>>4,(d)&0xf,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2)); \
800  } while (0)
801 
802 #define M_DLD_INTERN(d,base,off) \
803  do { \
804  CHECK_OFFSET(off, 0x03ff); \
805  M_CPLS(UNCOND,1,1,(((off) < 0) ? 0 : 1),0,11,0,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2)); \
806  } while (0)
807 
808 #define M_FST_INTERN(d,base,off) \
809  do { \
810  CHECK_OFFSET(off, 0x03ff); \
811  M_CPLS(UNCOND,0,1,(((off) < 0) ? 0 : 1),0,10,(d)>>4,(d)&0xf,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2)); \
812  } while (0)
813 
814 #define M_DST_INTERN(d,base,off) \
815  do { \
816  CHECK_OFFSET(off, 0x03ff); \
817  M_CPLS(UNCOND,0,1,(((off) < 0) ? 0 : 1),0,11,0,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2)); \
818  } while (0)
819 
820 #else
821 
822 #define M_FLD_INTERN(d,base,off) \
823  do { \
824  CHECK_OFFSET(off, 0x03ff); \
825  M_CPDT(UNCOND,1,0,0,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),1,(((off) < 0) ? 0 : 1),0); \
826  } while (0)
827 
828 #define M_DLD_INTERN(d,base,off) \
829  do { \
830  CHECK_OFFSET(off, 0x03ff); \
831  M_CPDT(UNCOND,1,0,1,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),1,(((off) < 0) ? 0 : 1),0); \
832  } while (0)
833 
834 #define M_FST_INTERN(d,base,off) \
835  do { \
836  CHECK_OFFSET(off, 0x03ff); \
837  M_CPDT(UNCOND,0,0,0,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),1,(((off) < 0) ? 0 : 1),0); \
838  } while (0)
839 
840 #define M_DST_INTERN(d,base,off) \
841  do { \
842  CHECK_OFFSET(off, 0x03ff); \
843  M_CPDT(UNCOND,0,0,1,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),1,(((off) < 0) ? 0 : 1),0); \
844  } while (0)
845 
846 #define M_FLD_UPDATE(d,base,off) \
847  do { \
848  CHECK_OFFSET(off, 0x03ff); \
849  M_CPDT(UNCOND,1,0,0,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),0,(((off) < 0) ? 0 : 1),1); \
850  } while (0)
851 
852 #define M_DLD_UPDATE(d,base,off) \
853  do { \
854  CHECK_OFFSET(off, 0x03ff); \
855  M_CPDT(UNCOND,1,0,1,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),0,(((off) < 0) ? 0 : 1),1); \
856  } while (0)
857 
858 #define M_FST_UPDATE(d,base,off) \
859  do { \
860  CHECK_OFFSET(off, 0x03ff); \
861  M_CPDT(UNCOND,0,0,0,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),1,(((off) < 0) ? 0 : 1),1); \
862  } while (0)
863 
864 #define M_DST_UPDATE(d,base,off) \
865  do { \
866  CHECK_OFFSET(off, 0x03ff); \
867  M_CPDT(UNCOND,0,0,1,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),1,(((off) < 0) ? 0 : 1),1); \
868  } while (0)
869 
870 #endif
871 
872 #endif /* !defined(ENABLE_SOFTFLOAT) */
873 
874 
875 /******************************************************************************/
876 /* wrapper macros for load and store instructions *****************************/
877 /******************************************************************************/
878 
879 /* M_LDR/M_STR:
880  these are replacements for the original LDR/STR instructions, which can
881  handle longer offsets (up to 20bits). the original functions are now
882  called M_xxx_INTERN.
883 */
884 /* ATTENTION: We use ITMP3 here, take into account that it gets destroyed.
885  This means that only ITMP1 and ITMP2 can be used in reg_of_var()!!!
886 */
887 /* ATTENTION2: It is possible to use ITMP3 as base reg. Remember that when
888  changing these macros!!!
889 */
890 
891 #define M_LDR(d, base, offset) \
892 do { \
893  CHECK_OFFSET(offset, 0x0fffff); \
894  if (IS_OFFSET(offset, 0x000fff)) { \
895  M_LDR_INTERN(d, base, offset); \
896  } else { \
897  /* we cannot handle REG_PC here */ \
898  assert((d) != REG_PC); \
899  if ((offset) > 0) { \
900  M_ADD_IMM(d, base, IMM_ROTL((offset) >> 12, 6)); \
901  M_LDR_INTERN(d, d, (offset) & 0x000fff); \
902  } else { \
903  M_SUB_IMM(d, base, IMM_ROTL((-(offset)) >> 12, 6)); \
904  M_LDR_INTERN(d, d, -(-(offset) & 0x000fff)); \
905  } \
906  } \
907 } while (0)
908 
909 #define M_LDR_NEGATIVE(d, base, offset) { \
910  /*assert((offset) <= 0);*/ \
911  if (IS_OFFSET(offset, 0x000fff)) { \
912  M_LDR_INTERN(d, base, offset); \
913  } else { \
914  /* we cannot handle REG_PC here */ \
915  assert((d) != REG_PC); \
916  M_SUB_IMM(d, base, IMM_ROTL((-(offset)) >> 12, 6)); \
917  M_LDR_INTERN(d, d, -(-(offset) & 0x000fff)); \
918  } \
919 }
920 
921 #define M_LDRD(d, base, offset) \
922 do { \
923  CHECK_OFFSET(offset, 0x0fffff - 4); \
924  if (IS_OFFSET(offset, 0x000fff - 4)) { \
925  if (GET_FIRST_REG(d) != (base)) { \
926  M_LDRD_INTERN(d, base, offset); \
927  } else { \
928  M_LDRD_ALTERN(d, base, offset); \
929  } \
930  } else if (IS_OFFSET(offset, 0x000fff)) { \
931  dolog("M_LDRD: this offset seems to be complicated (%d)", offset); \
932  assert(0); \
933  } else { \
934  if ((offset) > 0) { \
935  M_ADD_IMM(GET_SECOND_REG(d), base, IMM_ROTL((offset) >> 12, 6)); \
936  M_LDRD_INTERN(d, GET_SECOND_REG(d), (offset) & 0x000fff); \
937  } else { \
938  M_SUB_IMM(GET_SECOND_REG(d), base, IMM_ROTL((-(offset)) >> 12, 6)); \
939  M_LDRD_INTERN(d, GET_SECOND_REG(d), -(-(offset) & 0x000fff)); \
940  } \
941  } \
942 } while (0)
943 
944 #if !defined(ENABLE_SOFTFLOAT)
945 
946 #define M_LDFS(d, base, offset) \
947 do { \
948  CHECK_OFFSET(offset, 0x03ffff); \
949  if (IS_OFFSET(offset, 0x03ff)) { \
950  M_FLD_INTERN(d, base, offset); \
951  } else { \
952  if ((offset) > 0) { \
953  M_ADD_IMM(REG_ITMP3, base, IMM_ROTL((offset) >> 10, 5)); \
954  M_FLD_INTERN(d, REG_ITMP3, (offset) & 0x03ff); \
955  } else { \
956  M_SUB_IMM(REG_ITMP3, base, IMM_ROTL((-(offset)) >> 10, 5)); \
957  M_FLD_INTERN(d, REG_ITMP3, -(-(offset) & 0x03ff)); \
958  } \
959  } \
960 } while (0)
961 
962 #define M_LDFD(d, base, offset) \
963 do { \
964  CHECK_OFFSET(offset, 0x03ffff); \
965  if (IS_OFFSET(offset, 0x03ff)) { \
966  M_DLD_INTERN(d, base, offset); \
967  } else { \
968  if ((offset) > 0) { \
969  M_ADD_IMM(REG_ITMP3, base, IMM_ROTL((offset) >> 10, 5)); \
970  M_DLD_INTERN(d, REG_ITMP3, (offset) & 0x03ff); \
971  } else { \
972  M_SUB_IMM(REG_ITMP3, base, IMM_ROTL((-(offset)) >> 10, 5)); \
973  M_DLD_INTERN(d, REG_ITMP3, -(-(offset) & 0x03ff)); \
974  } \
975  } \
976 } while (0)
977 
978 #endif /* !defined(ENABLE_SOFTFLOAT) */
979 
980 #define M_STR(d, base, offset) \
981 do { \
982  CHECK_OFFSET(offset, 0x0fffff); \
983  if (IS_OFFSET(offset, 0x000fff)) { \
984  M_STR_INTERN(d, base, offset); \
985  } else { \
986  assert((d) != REG_ITMP3); \
987  if ((offset) > 0) { \
988  M_ADD_IMM(REG_ITMP3, base, IMM_ROTL((offset) >> 12, 6)); \
989  M_STR_INTERN(d, REG_ITMP3, (offset) & 0x000fff); \
990  } else { \
991  M_SUB_IMM(REG_ITMP3, base, IMM_ROTL((-(offset)) >> 12, 6)); \
992  M_STR_INTERN(d, REG_ITMP3, -(-(offset) & 0x000fff)); \
993  } \
994  } \
995 } while (0)
996 
997 #define M_STRD(d, base, offset) \
998 do { \
999  CHECK_OFFSET(offset, 0x0fffff - 4); \
1000  if (IS_OFFSET(offset, 0x000fff - 4)) { \
1001  M_STRD_INTERN(d,base,offset); \
1002  } else if (IS_OFFSET(offset, 0x000fff)) { \
1003  dolog("M_STRD: this offset seems to be complicated (%d)", offset); \
1004  assert(0); \
1005  } else { \
1006  assert(GET_LOW_REG(d) != REG_ITMP3); \
1007  assert(GET_HIGH_REG(d) != REG_ITMP3); \
1008  if ((offset) > 0) { \
1009  M_ADD_IMM(REG_ITMP3, base, IMM_ROTL((offset) >> 12, 6)); \
1010  M_STRD_INTERN(d, REG_ITMP3, (offset) & 0x000fff); \
1011  } else { \
1012  M_SUB_IMM(REG_ITMP3, base, IMM_ROTL((-(offset)) >> 12, 6)); \
1013  M_STRD_INTERN(d, REG_ITMP3, -(-(offset) & 0x000fff)); \
1014  } \
1015  } \
1016 } while (0)
1017 
1018 #if !defined(ENABLE_SOFTFLOAT)
1019 
1020 #define M_STFS(d, base, offset) \
1021 do { \
1022  CHECK_OFFSET(offset, 0x03ffff); \
1023  if (IS_OFFSET(offset, 0x03ff)) { \
1024  M_FST_INTERN(d, base, offset); \
1025  } else { \
1026  if ((offset) > 0) { \
1027  M_ADD_IMM(REG_ITMP3, base, IMM_ROTL((offset) >> 10, 5)); \
1028  M_FST_INTERN(d, REG_ITMP3, (offset) & 0x03ff); \
1029  } else { \
1030  M_SUB_IMM(REG_ITMP3, base, IMM_ROTL((-(offset)) >> 10, 5)); \
1031  M_FST_INTERN(d, REG_ITMP3, -(-(offset) & 0x03ff)); \
1032  } \
1033  } \
1034 } while (0)
1035 
1036 #define M_STFD(d, base, offset) \
1037 do { \
1038  CHECK_OFFSET(offset, 0x03ffff); \
1039  if (IS_OFFSET(offset, 0x03ff)) { \
1040  M_DST_INTERN(d, base, offset); \
1041  } else { \
1042  if ((offset) > 0) { \
1043  M_ADD_IMM(REG_ITMP3, base, IMM_ROTL((offset) >> 10, 5)); \
1044  M_DST_INTERN(d, REG_ITMP3, (offset) & 0x03ff); \
1045  } else { \
1046  M_SUB_IMM(REG_ITMP3, base, IMM_ROTL((-(offset)) >> 10, 5)); \
1047  M_DST_INTERN(d, REG_ITMP3, -(-(offset) & 0x03ff)); \
1048  } \
1049  } \
1050 } while (0)
1051 
1052 #endif /* !defined(ENABLE_SOFTFLOAT) */
1053 
1054 
1055 /******************************************************************************/
1056 /* additional helper macros ***************************************************/
1057 /******************************************************************************/
1058 
1059 /* M_???_IMM_EXT_MUL4:
1060  extended immediate operations, to handle immediates larger than 8bit.
1061  ATTENTION: the immediate is rotated left by 2 (multiplied by 4)!!!
1062 */
1063 
1064 #define M_ADD_IMM_EXT_MUL4(d,n,imm) \
1065  do { \
1066  assert(d != REG_PC); \
1067  assert((imm) >= 0 && (imm) <= 0x00ffffff); \
1068  M_ADD_IMM(d, n, IMM_ROTL(imm, 1)); \
1069  if ((imm) > 0x000000ff) M_ADD_IMM(d, d, IMM_ROTL((imm) >> 8, 5)); \
1070  if ((imm) > 0x0000ffff) M_ADD_IMM(d, d, IMM_ROTL((imm) >> 16, 9)); \
1071  } while (0)
1072 
1073 #define M_SUB_IMM_EXT_MUL4(d,n,imm) \
1074  do { \
1075  assert(d != REG_PC); \
1076  assert((imm) >= 0 && (imm) <= 0x00ffffff); \
1077  M_SUB_IMM(d, n, IMM_ROTL(imm, 1)); \
1078  if ((imm) > 0x000000ff) M_SUB_IMM(d, d, IMM_ROTL((imm) >> 8, 5)); \
1079  if ((imm) > 0x0000ffff) M_SUB_IMM(d, d, IMM_ROTL((imm) >> 16, 9)); \
1080  } while (0)
1081 
1082 
1083 /* ICONST/LCONST:
1084  loads the integer/long value const into register d.
1085 */
1086 
1087 #define ICONST(d,c) emit_iconst(cd, (d), (c))
1088 
1089 #define LCONST(d,c) \
1090  if (IS_IMM((c) >> 32)) { \
1091  M_MOV_IMM(GET_HIGH_REG(d), (s4) ((s8) (c) >> 32)); \
1092  ICONST(GET_LOW_REG(d), (s4) ((s8) (c) & 0xffffffff)); \
1093  } else if (IS_IMM((c) & 0xffffffff)) { \
1094  M_MOV_IMM(GET_LOW_REG(d), (s4) ((s8) (c) & 0xffffffff)); \
1095  ICONST(GET_HIGH_REG(d), (s4) ((s8) (c) >> 32)); \
1096  } else { \
1097  disp = dseg_add_s8(cd, (c)); \
1098  M_LDRD(d, REG_PV, disp); \
1099  }
1100 
1101 
1102 #if !defined(ENABLE_SOFTFLOAT)
1103 
1104 #define FCONST(d,c) \
1105  do { \
1106  disp = dseg_add_float(cd, (c)); \
1107  M_LDFS(d, REG_PV, disp); \
1108  } while (0)
1109 
1110 #define DCONST(d,c) \
1111  do { \
1112  disp = dseg_add_double(cd, (c)); \
1113  M_LDFD(d, REG_PV, disp); \
1114  } while (0)
1115 
1116 #endif /* !defined(ENABLE_SOFTFLOAT) */
1117 
1118 
1119 /* M_LONGBRANCH:
1120  performs a long branch to an absolute address with return address in LR
1121  takes up 3 bytes of code space; address is hard-coded into code
1122 */
1123 #define M_LONGBRANCH(adr) \
1124  M_ADD_IMM(REG_LR, REG_PC, 4); \
1125  M_LDR_INTERN(REG_PC, REG_PC, -4); \
1126  DCD((s4) adr);
1127 
1128 /* M_DSEG_LOAD/BRANCH:
1129  TODO: document me
1130  ATTENTION: if you change this, you have to look at the asm_call_jit_compiler!
1131  ATTENTION: we use M_LDR, so the same restrictions apply to us!
1132 */
1133 #define M_DSEG_LOAD(reg, offset) \
1134  M_LDR_NEGATIVE(reg, REG_PV, offset)
1135 
1136 #define M_DSEG_BRANCH(offset) \
1137  if (IS_OFFSET(offset, 0x0fff)) { \
1138  M_MOV(REG_LR, REG_PC); \
1139  M_LDR_INTERN(REG_PC, REG_PV, offset); \
1140  } else { \
1141  /*assert((offset) <= 0);*/ \
1142  CHECK_OFFSET(offset,0x0fffff); \
1143  M_SUB_IMM(REG_ITMP3, REG_PV, ((-(offset) >> 12) & 0xff) | (((10) & 0x0f) << 8)); /*TODO: more to go*/ \
1144  M_MOV(REG_LR, REG_PC); \
1145  M_LDR_INTERN(REG_PC, REG_ITMP3, -(-(offset) & 0x0fff)); /*TODO: this looks ugly*/ \
1146  }
1147 
1148 
1149 #define M_ILD(a,b,c) M_LDR(a,b,c)
1150 #define M_LLD(a,b,c) M_LDRD(a,b,c)
1151 
1152 #define M_ILD_INTERN(a,b,c) M_LDR_INTERN(a,b,c)
1153 #define M_LLD_INTERN(a,b,c) M_LDRD_INTERN(a,b,c)
1154 
1155 #define M_ALD(a,b,c) M_ILD(a,b,c)
1156 #define M_ALD_INTERN(a,b,c) M_ILD_INTERN(a,b,c)
1157 #define M_ALD_DSEG(a,c) M_DSEG_LOAD(a,c)
1158 
1159 
1160 #define M_IST(a,b,c) M_STR(a,b,c)
1161 #define M_LST(a,b,c) M_STRD(a,b,c)
1162 
1163 #define M_IST_INTERN(a,b,c) M_STR_INTERN(a,b,c)
1164 #define M_LST_INTERN(a,b,c) M_STRD_INTERN(a,b,c)
1165 
1166 #define M_AST(a,b,c) M_IST(a,b,c)
1167 #define M_AST_INTERN(a,b,c) M_IST_INTERN(a,b,c)
1168 
1169 
1170 #define M_ACMP(a,b) M_CMP(a,b)
1171 #define M_ICMP(a,b) M_CMP(a,b)
1172 
1173 
1174 #define M_TEST(a) M_TEQ_IMM(a, 0);
1175 
1176 
1177 #if !defined(ENABLE_SOFTFLOAT)
1178 
1179 #define M_FLD(a,b,c) M_LDFS(a,b,c)
1180 #define M_DLD(a,b,c) M_LDFD(a,b,c)
1181 
1182 #define M_FST(a,b,c) M_STFS(a,b,c)
1183 #define M_DST(a,b,c) M_STFD(a,b,c)
1184 
1185 #else /* !defined(ENABLE_SOFTFLOAT) */
1186 
1187 #define M_FMOV(s,d) M_MOV((d), (s))
1188 #define M_DMOV(s,d) \
1189  { \
1190  M_MOV(GET_LOW_REG(d), GET_LOW_REG(s)); \
1191  M_MOV(GET_HIGH_REG(d), GET_HIGH_REG(s)); \
1192  }
1193 
1194 #endif /* !defined(ENABLE_SOFTFLOAT) */
1195 
1196 
1197 #endif // CODEGEN_HPP_
1198 
1199 
1200 /*
1201  * These are local overrides for various environment variables in Emacs.
1202  * Please do not remove this and leave it at the end of the file, where
1203  * Emacs will automagically detect them.
1204  * ---------------------------------------------------------------------
1205  * Local variables:
1206  * mode: c++
1207  * indent-tabs-mode: t
1208  * c-basic-offset: 4
1209  * tab-width: 4
1210  * End:
1211  * vim:noexpandtab:sw=4:ts=4:
1212  */
#define a4
Definition: md-asm.hpp:36
void asm_debug(int a1, int a2, int a3, int a4)
Definition: codegen.cpp:2698
#define a1
Definition: md-asm.hpp:33
#define a3
Definition: md-asm.hpp:35
#define a2
Definition: md-asm.hpp:34
void asm_debug_intern(int a1, int a2, int a3, int a4)