* src/vm/jit/codegen.c (codegen): Change the operand direction of some
[cacao.git] / src / vm / jit / arm / codegen.h
1 /* src/vm/jit/arm/codegen.h - code generation macros and definitions for ARM
2
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
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301, USA.
24
25    Contact: cacao@cacaojvm.org
26
27    Authors: Michael Starzinger
28             Christian Thalinger
29
30    $Id: codegen.h 7505 2007-03-12 13:34:37Z twisti $
31
32 */
33
34
35 #ifndef _CODEGEN_H
36 #define _CODEGEN_H
37
38 #include "config.h"
39
40
41 /* helper macros for generating code ******************************************/
42
43 /* load_var_to_reg_xxx:
44    this function generates code to fetch data from a pseudo-register
45    into a real 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)
54 */
55
56 #if defined(__ARMEL__)
57 #define load_var_to_reg_lng(regnr,v,tempnr) { \
58         if ((v)->flags & INMEMORY) { \
59                 COUNT_SPILLS; \
60                 M_STACK_LOAD_LNG(tempnr, (v)->regoff); \
61                 regnr = tempnr; \
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; \
66 }
67 #else /* defined(__ARMEB__) */
68 #define load_var_to_reg_lng(regnr,v,tempnr) { \
69         if ((v)->flags & INMEMORY) { \
70                 COUNT_SPILLS; \
71                 M_STACK_LOAD_LNG(tempnr, (v)->regoff); \
72                 regnr = tempnr; \
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; \
77 }
78 #endif
79
80
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.
86    v:      Pseudovariable
87    tempnr: Number of the temporary registers as returned by
88            reg_of_var.
89 */
90
91 #if defined(__ARMEL__)
92 #define store_reg_to_var_lng(v,tempnr) { \
93         if ((v)->flags & INMEMORY) { \
94                 COUNT_SPILLS; \
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? */ \
98         } \
99 }
100 #else /* defined(__ARMEB__) */
101 #define store_reg_to_var_lng(v,tempnr) { \
102         if ((v)->flags & INMEMORY) { \
103                 COUNT_SPILLS; \
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? */ \
107         } \
108 }
109 #endif
110
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); \
117         }
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)); \
122         }
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); \
128         }
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)); \
135         }
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)); \
140         }
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)); \
146         }
147 #endif
148
149
150 #define MCODECHECK(icnt) \
151     do { \
152         if ((cd->mcodeptr + (icnt) * 4) > cd->mcodeend) \
153             codegen_increase(cd); \
154     } while (0)
155
156
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))
160
161 #if !defined(NDEBUG)
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))
167 #else
168 # define CHECK_INT_REG(r)
169 # define CHECK_FLT_REG(r)
170 # define CHECK_OFFSET(off,max)
171 #endif
172
173
174 /* branch defines *************************************************************/
175
176 #define BRANCH_NOPS \
177     do { \
178         M_NOP; \
179     } while (0)
180
181
182 /* patcher defines ************************************************************/
183
184 #define PATCHER_CALL_SIZE    1 * 4      /* an instruction is 4-bytes long     */
185
186 #define PATCHER_NOPS \
187     do { \
188         M_NOP; \
189     } while (0)
190
191
192 /* lazy debugger **************************************************************/
193
194 #if !defined(NDEBUG)
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);
197
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)
206 #endif
207
208
209 /* macros to create code ******************************************************/
210
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
229
230 /* data processing operation: M_DAT
231    cond ... conditional execution
232    op ..... opcode
233    d ...... destination reg
234    n ...... source reg
235    S ...... update condition codes
236    I ...... switch to immediate mode
237    shift .. shifter operand
238 */
239
240 #define M_DAT(cond,op,d,n,S,I,shift) \
241     do { \
242         *((u4 *) cd->mcodeptr) = (((cond) << 28) | ((op) << 21) | ((d) << 12) | ((n) << 16) | ((I) << 25) | ((S) << 20) | ((shift) & 0x00000fff)); \
243         cd->mcodeptr += 4; \
244     } while (0)
245
246
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
254 */
255
256 #define M_MEM(cond,L,B,d,n,adr,I,P,U,W) \
257     do { \
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)); \
259         cd->mcodeptr += 4; \
260     } while (0)
261
262
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
271 */
272
273 #define M_MEM2(cond,L,H,S,d,n,adr,I,P,U,W) \
274     do { \
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)); \
276         cd->mcodeptr += 4; \
277     } while (0)
278
279
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
286 */
287
288 #define M_MEM_MULTI(cond,L,S,regs,n,P,U,W) \
289     do { \
290         *((u4 *) cd->mcodeptr) = (((cond) << 28) | (1 << 27) | ((L) << 20) | ((S) << 22) | ((n) << 16) | ((regs) & 0xffff) | ((P) << 24) | ((U) << 23) | ((W) << 21)); \
291         cd->mcodeptr += 4; \
292     } while (0)
293
294
295 /* branch and branch with link: M_BRA
296    cond ... conditional execution
297    L ...... branch with link (L=1)
298    offset . 24bit offset
299 */
300
301 #define M_BRA(cond,L,offset) \
302     do { \
303         *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x5 << 25) | ((L) << 24) | ((offset) & 0x00ffffff)); \
304         cd->mcodeptr += 4; \
305     } while (0)
306
307
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
315 */
316
317 #define M_MULT(cond,d,n,m,S,A,s) \
318     do { \
319         *((u4 *) cd->mcodeptr) = (((cond) << 28) | ((d) << 16) | ((n) << 8) | (m) | (0x09 << 4) | ((S) << 20) | ((A) << 21) | ((s) << 12)); \
320         cd->mcodeptr += 4; \
321     } while (0)
322
323
324 /* no operation (mov r0,r0): M_NOP */
325
326 #define M_NOP \
327     do { \
328         *((u4 *) cd->mcodeptr) = (0xe1a00000); \
329         cd->mcodeptr += 4; \
330     } while (0)
331
332
333 /* software breakpoint (only v5 and above): M_BREAKPOINT */
334
335 #define M_BREAKPOINT(imm) \
336     do { \
337         *((u4 *) cd->mcodeptr) = (0x0e12 << 20) | (0x07 << 4) | (((imm) & 0xfff0) << (8-4)) | ((imm) & 0x0f); \
338         cd->mcodeptr += 4; \
339     } while (0)
340
341
342 #if !defined(ENABLE_SOFTFLOAT)
343
344 /* M_CPDO **********************************************************************
345
346    Floating-Point Coprocessor Data Operations
347
348    cond ... conditional execution
349    op ..... opcode
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
354
355 *******************************************************************************/
356
357 #define M_CPDOS(cond,op,D,Fd,Fn,Fm) \
358     do { \
359         *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0e << 24) | (1 << 8) | ((op) << 20) | ((D) << 15) | ((Fd) << 12) | ((Fn) << 16) | ((Fm) & 0x0f)); \
360         cd->mcodeptr += 4; \
361     } while (0)
362
363
364 #define M_CPDOD(cond,op,D,Fd,Fn,Fm) \
365     do { \
366         *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0e << 24) | (1 << 8) | ((op) << 20) | ((D) << 15) | ((Fd) << 12) | ((Fn) << 16) | ((Fm) & 0x0f) | (1 << 7)); \
367         cd->mcodeptr += 4; \
368     } while (0)
369
370
371 /* M_CPDT **********************************************************************
372
373    Floating-Point Coprocessor Data Transfer
374
375    cond ... conditional execution
376    L ...... load (L=1) or store (L=0)
377    Fd ..... destination float-register
378    n ...... base reg for addressing
379
380 *******************************************************************************/
381
382 #define M_CPDT(cond,L,T1,T0,Fd,n,off,P,U,W) \
383     do { \
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)); \
385         cd->mcodeptr += 4; \
386     } while (0)
387
388
389 /* M_CPRT **********************************************************************
390
391    Floating-Point Coprocessor Register Transfer
392
393    XXX
394
395 *******************************************************************************/
396
397 #define M_CPRTS(cond,L,d,Fn,Fm) \
398     do { \
399         *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0e << 24) | (1 << 8) | (1 << 4) | ((L) << 20) | ((d) << 12) | ((Fn) << 16) | (Fm)); \
400         cd->mcodeptr += 4; \
401     } while (0)
402
403
404 #define M_CPRTD(cond,L,d,Fn,Fm) \
405     do { \
406         *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0e << 24) | (1 << 8) | (1 << 4) | ((L) << 20) | ((d) << 12) | ((Fn) << 16) | (Fm) | (1 << 7)); \
407         cd->mcodeptr += 4; \
408     } while (0)
409
410
411 #define M_CPRTI(cond,L,d,Fn,Fm) \
412     do { \
413         *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0e << 24) | (1 << 8) | (1 << 4) | ((L) << 20) | ((d) << 12) | ((Fn) << 16) | (Fm) | (3 << 5)); \
414         cd->mcodeptr += 4; \
415     } while (0)
416
417
418 /* XXX TWISTI: replace X by something useful */
419
420 #define M_CPRTX(cond,L,d,Fn,Fm) \
421     do { \
422         *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0e << 24) | (1 << 8) | (1 << 4) | ((L) << 20) | ((d) << 12) | ((Fn) << 16) | (Fm) | (1 << 23)); \
423         cd->mcodeptr += 4; \
424     } while (0)
425
426 #endif /* !defined(ENABLE_SOFTFLOAT) */
427
428
429 /* used to store values! */
430 #define DCD(val) \
431     do { \
432         *((u4 *) cd->mcodeptr) = val; \
433         cd->mcodeptr += 4; \
434     } while (0)
435
436
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) )
444
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))
449
450 /* macros for all arm instructions ********************************************/
451
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) */
467
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) */
483
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)
486
487 #define M_MOVVS_IMM(i,d)   M_DAT(COND_VS,0x0d,d,0,0,1,i)
488 #define M_MOVNE_IMM(i,d)   M_DAT(COND_NE,0x0d,d,0,0,1,i)
489 #define M_MOVLT_IMM(i,d)   M_DAT(COND_LT,0x0d,d,0,0,1,i)
490 #define M_MOVLS_IMM(i,d)   M_DAT(COND_LS,0x0d,d,0,0,1,i)
491
492 #define M_ADDLT_IMM(d,a,i) M_DAT(COND_LT,0x04,d,a,0,1,i)
493 #define M_ADDGT_IMM(d,a,i) M_DAT(COND_GT,0x04,d,a,0,1,i)
494 #define M_SUBLT_IMM(d,a,i) M_DAT(COND_LT,0x02,d,a,0,1,i)
495 #define M_SUBGT_IMM(d,a,i) M_DAT(COND_GT,0x02,d,a,0,1,i)
496 #define M_RSBMI_IMM(d,a,i) M_DAT(COND_MI,0x03,d,a,0,1,i)
497 #define M_ADCMI_IMM(d,a,i) M_DAT(COND_MI,0x05,d,a,0,1,i)
498
499 #define M_CMPEQ(a,b)       M_DAT(COND_EQ,0x0a,0,a,1,0,b)        /* TST a -  b */
500 #define M_CMPLE(a,b)       M_DAT(COND_LE,0x0a,0,a,1,0,b)        /* TST a -  b */
501
502 #define M_MUL(d,a,b)       M_MULT(UNCOND,d,a,b,0,0,0x0)         /* d = a *  b */
503
504
505 #define M_LDMFD(regs,base) M_MEM_MULTI(UNCOND,1,0,regs,base,0,1,1)
506 #define M_STMFD(regs,base) M_MEM_MULTI(UNCOND,0,0,regs,base,1,0,1)
507
508 #define M_LDR_INTERN(d,base,off) \
509     do { \
510         CHECK_OFFSET(off, 0x0fff); \
511         M_MEM(UNCOND,1,0,d,base,(((off) < 0) ? -(off) : off),0,1,(((off) < 0) ? 0 : 1),0); \
512     } while (0)
513
514 #define M_STR_INTERN(d,base,off) \
515     do { \
516         CHECK_OFFSET(off, 0x0fff); \
517         M_MEM(UNCOND,0,0,d,base,(((off) < 0) ? -(off) : off),0,1,(((off) < 0) ? 0 : 1),0); \
518     } while (0)
519
520 #define M_LDR_UPDATE(d,base,off) \
521     do { \
522         CHECK_OFFSET(off, 0x0fff); \
523         M_MEM(UNCOND,1,0,d,base,(((off) < 0) ? -(off) : off),0,0,(((off) < 0) ? 0 : 1),0); \
524     } while (0)
525
526 #define M_STR_UPDATE(d,base,off) \
527     do { \
528         CHECK_OFFSET(off,0x0fff); \
529         M_MEM(UNCOND,0,0,d,base,(((off) < 0) ? -(off) : off),0,1,(((off) < 0) ? 0 : 1),1); \
530     } while (0)
531
532
533 #define M_LDRH(d,base,off) \
534     do { \
535         CHECK_OFFSET(off, 0x00ff); \
536         assert(off >= 0); \
537         M_MEM2(UNCOND,1,1,0,d,base,off,1,1,1,0); \
538     } while (0)
539
540 #define M_LDRSH(d,base,off) \
541     do { \
542         CHECK_OFFSET(off, 0x00ff); \
543         assert(off >= 0); \
544         M_MEM2(UNCOND,1,1,1,d,base,off,1,1,1,0); \
545     } while (0)
546
547 #define M_LDRSB(d,base,off) \
548     do { \
549         CHECK_OFFSET(off, 0x00ff); \
550         assert(off >= 0); \
551         M_MEM2(UNCOND,1,0,1,d,base,off,1,1,1,0); \
552     } while (0)
553
554 #define M_STRH(d,base,off) \
555     do { \
556         CHECK_OFFSET(off, 0x00ff); \
557         assert(off >= 0); \
558         M_MEM2(UNCOND,0,1,0,d,base,off,1,1,1,0); \
559     } while (0)
560
561 #define M_STRB(d,base,off) \
562     do { \
563         CHECK_OFFSET(off, 0x0fff); \
564         assert(off >= 0); \
565         M_MEM(UNCOND,0,1,d,base,off,0,1,1,0); \
566     } while (0)
567
568                                                                                                       
569 #if !defined(ENABLE_SOFTFLOAT)
570
571 #define M_LDFS_INTERN(d,base,off) \
572     do { \
573         CHECK_OFFSET(off, 0x03ff); \
574         M_CPDT(UNCOND,1,0,0,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),1,(((off) < 0) ? 0 : 1),0); \
575     } while (0)
576
577 #define M_LDFD_INTERN(d,base,off) \
578     do { \
579         CHECK_OFFSET(off, 0x03ff); \
580         M_CPDT(UNCOND,1,0,1,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),1,(((off) < 0) ? 0 : 1),0); \
581     } while (0)
582
583 #define M_STFS_INTERN(d,base,off) \
584     do { \
585         CHECK_OFFSET(off, 0x03ff); \
586         M_CPDT(UNCOND,0,0,0,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),1,(((off) < 0) ? 0 : 1),0); \
587     } while (0)
588
589 #define M_STFD_INTERN(d,base,off) \
590     do { \
591         CHECK_OFFSET(off, 0x03ff); \
592         M_CPDT(UNCOND,0,0,1,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),1,(((off) < 0) ? 0 : 1),0); \
593     } while (0)
594
595 #define M_LDFS_UPDATE(d,base,off) \
596     do { \
597         CHECK_OFFSET(off, 0x03ff); \
598         M_CPDT(UNCOND,1,0,0,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),0,(((off) < 0) ? 0 : 1),1); \
599     } while (0)
600
601 #define M_LDFD_UPDATE(d,base,off) \
602     do { \
603         CHECK_OFFSET(off, 0x03ff); \
604         M_CPDT(UNCOND,1,0,1,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),0,(((off) < 0) ? 0 : 1),1); \
605     } while (0)
606
607 #define M_STFS_UPDATE(d,base,off) \
608     do { \
609         CHECK_OFFSET(off, 0x03ff); \
610         M_CPDT(UNCOND,0,0,0,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),1,(((off) < 0) ? 0 : 1),1); \
611     } while (0)
612
613 #define M_STFD_UPDATE(d,base,off) \
614     do { \
615         CHECK_OFFSET(off, 0x03ff); \
616         M_CPDT(UNCOND,0,0,1,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),1,(((off) < 0) ? 0 : 1),1); \
617     } while (0)
618
619 #define M_ADFS(d,a,b)      M_CPDOS(UNCOND,0x00,0,d,a,b)         /* d = a +  b */
620 #define M_SUFS(d,a,b)      M_CPDOS(UNCOND,0x02,0,d,a,b)         /* d = a -  b */
621 #define M_RSFS(d,a,b)      M_CPDOS(UNCOND,0x03,0,d,a,b)         /* d = b -  a */
622 #define M_MUFS(d,a,b)      M_CPDOS(UNCOND,0x01,0,d,a,b)         /* d = a *  b */
623 #define M_DVFS(d,a,b)      M_CPDOS(UNCOND,0x04,0,d,a,b)         /* d = a /  b */
624 #define M_RMFS(d,a,b)      M_CPDOS(UNCOND,0x08,0,d,a,b)         /* d = a %  b */
625 #define M_ADFD(d,a,b)      M_CPDOD(UNCOND,0x00,0,d,a,b)         /* d = a +  b */
626 #define M_SUFD(d,a,b)      M_CPDOD(UNCOND,0x02,0,d,a,b)         /* d = a -  b */
627 #define M_RSFD(d,a,b)      M_CPDOD(UNCOND,0x03,0,d,a,b)         /* d = b -  a */
628 #define M_MUFD(d,a,b)      M_CPDOD(UNCOND,0x01,0,d,a,b)         /* d = a *  b */
629 #define M_DVFD(d,a,b)      M_CPDOD(UNCOND,0x04,0,d,a,b)         /* d = a /  b */
630 #define M_RMFD(d,a,b)      M_CPDOD(UNCOND,0x08,0,d,a,b)         /* d = a %  b */
631 #define M_MVFS(d,a)        M_CPDOS(UNCOND,0x00,1,d,0,a)         /* d =      a */
632 #define M_MVFD(d,a)        M_CPDOD(UNCOND,0x00,1,d,0,a)         /* d =      a */
633 #define M_MNFS(d,a)        M_CPDOS(UNCOND,0x01,1,d,0,a)         /* d =    - a */
634 #define M_MNFD(d,a)        M_CPDOD(UNCOND,0x01,1,d,0,a)         /* d =    - a */
635 #define M_CMF(a,b)         M_CPRTX(UNCOND,1,0x0f,a,b)           /* COMPARE a;  b */
636 #define M_FLTS(d,a)        M_CPRTS(UNCOND,0,a,d,0)              /* d = (float) a */
637 #define M_FLTD(d,a)        M_CPRTD(UNCOND,0,a,d,0)              /* d = (float) a */
638 #define M_FIX(d,a)         M_CPRTI(UNCOND,1,d,0,a)              /* d = (int)   a */
639
640 #endif /* !defined(ENABLE_SOFTFLOAT) */
641
642
643 #define M_B(off)           M_BRA(UNCOND,0,off)    /* unconditional branch */
644 #define M_BL(off)          M_BRA(UNCOND,1,off)    /* branch and link      */
645 #define M_BEQ(off)         M_BRA(COND_EQ,0,off)   /* conditional branches */
646 #define M_BNE(off)         M_BRA(COND_NE,0,off)
647 #define M_BGE(off)         M_BRA(COND_GE,0,off)
648 #define M_BGT(off)         M_BRA(COND_GT,0,off)
649 #define M_BLT(off)         M_BRA(COND_LT,0,off)
650 #define M_BLE(off)         M_BRA(COND_LE,0,off)
651 #define M_BHI(off)         M_BRA(COND_HI,0,off)   /* unsigned conditional */
652 #define M_BHS(off)         M_BRA(COND_CS,0,off)
653 #define M_BLO(off)         M_BRA(COND_CC,0,off)
654 #define M_BLS(off)         M_BRA(COND_LS,0,off)
655
656
657 #define M_FMOV(a,b)        M_MVFS(b,a)
658 #define M_DMOV(a,b)        M_MVFD(b,a)
659
660
661 /* if we do not have double-word load/store command, we can fake them */
662 /* ATTENTION: the original LDRD/STRD of ARMv5e would always use (Rd/Rd+1),
663    so these faked versions are more "powerful" */
664
665 #if defined(__ARMEL__)
666
667 #define M_LDRD_INTERN(d,base,off) \
668     do { \
669         M_LDR_INTERN(GET_LOW_REG(d), base, off); \
670         M_LDR_INTERN(GET_HIGH_REG(d), base, (off) + 4); \
671     } while (0)
672
673 #define M_STRD_INTERN(d,base,off) \
674     do { \
675         M_STR_INTERN(GET_LOW_REG(d), base, off); \
676         M_STR_INTERN(GET_HIGH_REG(d), base, (off) + 4); \
677     } while (0)
678
679 #define M_LDRD_ALTERN(d,base,off) \
680     do { \
681         M_LDR_INTERN(GET_HIGH_REG(d), base, (off) + 4); \
682         M_LDR_INTERN(GET_LOW_REG(d), base, off); \
683     } while (0)
684
685 #define M_LDRD_UPDATE(d,base,off) \
686     do { \
687         assert((off) == +8); \
688         M_LDR_UPDATE(GET_LOW_REG(d), base, 4); \
689         M_LDR_UPDATE(GET_HIGH_REG(d), base, 4); \
690     } while (0)
691
692 #define M_STRD_UPDATE(d,base,off) \
693     do { \
694         assert((off) == -8); \
695         M_STR_UPDATE(GET_HIGH_REG(d), base, -4); \
696         M_STR_UPDATE(GET_LOW_REG(d), base, -4); \
697     } while (0)
698
699 #define GET_FIRST_REG(d)  GET_LOW_REG(d)
700 #define GET_SECOND_REG(d) GET_HIGH_REG(d)
701
702 #else /* defined(__ARMEB__) */
703
704 #define M_LDRD_INTERN(d,base,off) \
705     do { \
706         M_LDR_INTERN(GET_HIGH_REG(d), base, off); \
707         M_LDR_INTERN(GET_LOW_REG(d), base, (off) + 4); \
708     } while (0)
709
710 #define M_STRD_INTERN(d,base,off) \
711     do { \
712         M_STR_INTERN(GET_HIGH_REG(d), base, off); \
713         M_STR_INTERN(GET_LOW_REG(d), base, (off) + 4); \
714     } while (0)
715
716 #define M_LDRD_ALTERN(d,base,off) \
717     do { \
718         M_LDR_INTERN(GET_LOW_REG(d), base, (off) + 4); \
719         M_LDR_INTERN(GET_HIGH_REG(d), base, off); \
720     } while (0)
721
722 #define M_LDRD_UPDATE(d,base,off) \
723     do { \
724         assert((off) == +8); \
725         M_LDR_UPDATE(GET_HIGH_REG(d), base, 4); \
726         M_LDR_UPDATE(GET_LOW_REG(d), base, 4); \
727     } while (0)
728
729 #define M_STRD_UPDATE(d,base,off) \
730     do { \
731         assert((off) == -8); \
732         M_STR_UPDATE(GET_LOW_REG(d), base, -4); \
733         M_STR_UPDATE(GET_HIGH_REG(d) ,base, -4); \
734     } while (0)
735
736 #define GET_FIRST_REG(d)  GET_HIGH_REG(d)
737 #define GET_SECOND_REG(d) GET_LOW_REG(d)
738
739 #endif /* defined(__ARMEB__) */
740
741
742 /* M_LDR/M_STR:
743    these are replacements for the original LDR/STR instructions, which can
744    handle longer offsets (up to 20bits). the original functions are now
745    called M_xxx_INTERN.
746 */
747 /* ATTENTION: We use ITMP3 here, take into account that it gets destroyed.
748    This means that only ITMP1 and ITMP2 can be used in reg_of_var()!!!
749 */
750 /* ATTENTION2: It is possible to use ITMP3 as base reg. Remember that when
751    changing these macros!!!
752 */
753
754 #define M_LDR(d, base, offset) \
755 do { \
756         CHECK_OFFSET(offset, 0x0fffff); \
757         if (IS_OFFSET(offset, 0x000fff)) { \
758                 M_LDR_INTERN(d, base, offset); \
759         } else { \
760                 /* we cannot handle REG_PC here */ \
761                 assert((d) != REG_PC); \
762                 if ((offset) > 0) { \
763                         M_ADD_IMM(d, base, IMM_ROTL((offset) >> 12, 6)); \
764                         M_LDR_INTERN(d, d, (offset) & 0x000fff); \
765                 } else { \
766                         M_SUB_IMM(d, base, IMM_ROTL((-(offset)) >> 12, 6)); \
767                         M_LDR_INTERN(d, d, -(-(offset) & 0x000fff)); \
768                 } \
769         } \
770 } while (0)
771
772 #define M_LDR_NEGATIVE(d, base, offset) { \
773         /*assert((offset) <= 0);*/ \
774         if (IS_OFFSET(offset, 0x000fff)) { \
775                 M_LDR_INTERN(d, base, offset); \
776         } else { \
777                 /* we cannot handle REG_PC here */ \
778                 assert((d) != REG_PC); \
779                 M_SUB_IMM(d, base, IMM_ROTL((-(offset)) >> 12, 6)); \
780                 M_LDR_INTERN(d, d, -(-(offset) & 0x000fff)); \
781         } \
782 }
783
784 #define M_LDRD(d, base, offset) \
785 do { \
786         CHECK_OFFSET(offset, 0x0fffff - 4); \
787         if (IS_OFFSET(offset, 0x000fff - 4)) { \
788                 if (GET_FIRST_REG(d) != (base)) { \
789                         M_LDRD_INTERN(d, base, offset); \
790                 } else { \
791                         M_LDRD_ALTERN(d, base, offset); \
792                 } \
793         } else if (IS_OFFSET(offset, 0x000fff)) { \
794                 dolog("M_LDRD: this offset seems to be complicated (%d)", offset); \
795                 assert(0); \
796         } else { \
797                 if ((offset) > 0) { \
798                         M_ADD_IMM(GET_SECOND_REG(d), base, IMM_ROTL((offset) >> 12, 6)); \
799                         M_LDRD_INTERN(d, GET_SECOND_REG(d), (offset) & 0x000fff); \
800                 } else { \
801                         M_SUB_IMM(GET_SECOND_REG(d), base, IMM_ROTL((-(offset)) >> 12, 6)); \
802                         M_LDRD_INTERN(d, GET_SECOND_REG(d), -(-(offset) & 0x000fff)); \
803                 } \
804         } \
805 } while (0)
806
807 #if !defined(ENABLE_SOFTFLOAT)
808 #define M_LDFS(d, base, offset) \
809 do { \
810         CHECK_OFFSET(offset, 0x03ffff); \
811         if (IS_OFFSET(offset, 0x03ff)) { \
812                 M_LDFS_INTERN(d, base, offset); \
813         } else { \
814                 if ((offset) > 0) { \
815                         M_ADD_IMM(REG_ITMP3, base, IMM_ROTL((offset) >> 10, 5)); \
816                         M_LDFS_INTERN(d, REG_ITMP3, (offset) & 0x03ff); \
817                 } else { \
818                         M_SUB_IMM(REG_ITMP3, base, IMM_ROTL((-(offset)) >> 10, 5)); \
819                         M_LDFS_INTERN(d, REG_ITMP3, -(-(offset) & 0x03ff)); \
820                 } \
821         } \
822 } while (0)
823
824 #define M_LDFD(d, base, offset) \
825 do { \
826         CHECK_OFFSET(offset, 0x03ffff); \
827         if (IS_OFFSET(offset, 0x03ff)) { \
828                 M_LDFD_INTERN(d, base, offset); \
829         } else { \
830                 if ((offset) > 0) { \
831                         M_ADD_IMM(REG_ITMP3, base, IMM_ROTL((offset) >> 10, 5)); \
832                         M_LDFD_INTERN(d, REG_ITMP3, (offset) & 0x03ff); \
833                 } else { \
834                         M_SUB_IMM(REG_ITMP3, base, IMM_ROTL((-(offset)) >> 10, 5)); \
835                         M_LDFD_INTERN(d, REG_ITMP3, -(-(offset) & 0x03ff)); \
836                 } \
837         } \
838 } while (0)
839
840 #endif /* !defined(ENABLE_SOFTFLOAT) */
841
842 #define M_STR(d, base, offset) \
843 do { \
844         assert((d) != REG_ITMP3); \
845         CHECK_OFFSET(offset, 0x0fffff); \
846         if (IS_OFFSET(offset, 0x000fff)) { \
847                 M_STR_INTERN(d, base, offset); \
848         } else { \
849                 if ((offset) > 0) { \
850                         M_ADD_IMM(REG_ITMP3, base, IMM_ROTL((offset) >> 12, 6)); \
851                         M_STR_INTERN(d, REG_ITMP3, (offset) & 0x000fff); \
852                 } else { \
853                         M_SUB_IMM(REG_ITMP3, base, IMM_ROTL((-(offset)) >> 12, 6)); \
854                         M_STR_INTERN(d, REG_ITMP3, -(-(offset) & 0x000fff)); \
855                 } \
856         } \
857 } while (0)
858
859 #define M_STRD(d, base, offset) \
860 do { \
861         assert(GET_LOW_REG(d) != REG_ITMP3); \
862         assert(GET_HIGH_REG(d) != REG_ITMP3); \
863         CHECK_OFFSET(offset, 0x0fffff - 4); \
864         if (IS_OFFSET(offset, 0x000fff - 4)) { \
865                 M_STRD_INTERN(d,base,offset); \
866         } else if (IS_OFFSET(offset, 0x000fff)) { \
867                 dolog("M_STRD: this offset seems to be complicated (%d)", offset); \
868                 assert(0); \
869         } else { \
870                 if ((offset) > 0) { \
871                         M_ADD_IMM(REG_ITMP3, base, IMM_ROTL((offset) >> 12, 6)); \
872                         M_STRD_INTERN(d, REG_ITMP3, (offset) & 0x000fff); \
873                 } else { \
874                         M_SUB_IMM(REG_ITMP3, base, IMM_ROTL((-(offset)) >> 12, 6)); \
875                         M_STRD_INTERN(d, REG_ITMP3, -(-(offset) & 0x000fff)); \
876                 } \
877         } \
878 } while (0)
879
880 #if !defined(ENABLE_SOFTFLOAT)
881
882 #define M_STFS(d, base, offset) \
883 do { \
884         CHECK_OFFSET(offset, 0x03ffff); \
885         if (IS_OFFSET(offset, 0x03ff)) { \
886                 M_STFS_INTERN(d, base, offset); \
887         } else { \
888                 if ((offset) > 0) { \
889                         M_ADD_IMM(REG_ITMP3, base, IMM_ROTL((offset) >> 10, 5)); \
890                         M_STFS_INTERN(d, REG_ITMP3, (offset) & 0x03ff); \
891                 } else { \
892                         M_SUB_IMM(REG_ITMP3, base, IMM_ROTL((-(offset)) >> 10, 5)); \
893                         M_STFS_INTERN(d, REG_ITMP3, -(-(offset) & 0x03ff)); \
894                 } \
895         } \
896 } while (0)
897
898 #define M_STFD(d, base, offset) \
899 do { \
900         CHECK_OFFSET(offset, 0x03ffff); \
901         if (IS_OFFSET(offset, 0x03ff)) { \
902                 M_STFD_INTERN(d, base, offset); \
903         } else { \
904                 if ((offset) > 0) { \
905                         M_ADD_IMM(REG_ITMP3, base, IMM_ROTL((offset) >> 10, 5)); \
906                         M_STFD_INTERN(d, REG_ITMP3, (offset) & 0x03ff); \
907                 } else { \
908                         M_SUB_IMM(REG_ITMP3, base, IMM_ROTL((-(offset)) >> 10, 5)); \
909                         M_STFD_INTERN(d, REG_ITMP3, -(-(offset) & 0x03ff)); \
910                 } \
911         } \
912 } while (0)
913
914 #endif /* !defined(ENABLE_SOFTFLOAT) */
915
916 /* M_???_IMM_EXT_MUL4:
917    extended immediate operations, to handle immediates lager than 8bit.
918    ATTENTION: the immediate is rotatet left by 2 (multiplied by 4)!!!
919 */
920
921 #define M_ADD_IMM_EXT_MUL4(d,n,imm) \
922     do { \
923         assert(d != REG_PC); \
924         assert((imm) >= 0 && (imm) <= 0x00ffffff); \
925         M_ADD_IMM(d, n, IMM_ROTL(imm, 1)); \
926         if ((imm) > 0x000000ff) M_ADD_IMM(d, d, IMM_ROTL((imm) >>  8, 5)); \
927         if ((imm) > 0x0000ffff) M_ADD_IMM(d, d, IMM_ROTL((imm) >> 16, 9)); \
928     } while (0)
929
930 #define M_SUB_IMM_EXT_MUL4(d,n,imm) \
931     do { \
932         assert(d != REG_PC); \
933         assert((imm) >= 0 && (imm) <= 0x00ffffff); \
934         M_SUB_IMM(d, n, IMM_ROTL(imm, 1)); \
935         if ((imm) > 0x000000ff) M_SUB_IMM(d, d, IMM_ROTL((imm) >>  8, 5)); \
936         if ((imm) > 0x0000ffff) M_SUB_IMM(d, d, IMM_ROTL((imm) >> 16, 9)); \
937     } while (0)
938
939
940 /* ICONST/LCONST:
941    loads the integer/long value const into register d.
942 */
943
944 #define ICONST(d,c)                     emit_iconst(cd, (d), (c))
945
946 #define ICONST_CONDITIONAL(cond,d,const) \
947         if (IS_IMM(const)) { \
948                 /* M_MOV_IMM */ M_DAT(cond,0x0d,d,0,0,1,const); \
949         } else { \
950                 disp = dseg_adds4(cd, const); \
951                 /* TODO: implement this using M_DSEG_LOAD!!! */ \
952                 /* 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); \
953         }
954
955 #define LCONST(d,c) \
956         if (IS_IMM((c) >> 32)) { \
957                 M_MOV_IMM(GET_HIGH_REG(d), (s4) ((s8) (c) >> 32)); \
958                 ICONST(GET_LOW_REG(d), (s4) ((s8) (c) & 0xffffffff)); \
959         } else if (IS_IMM((c) & 0xffffffff)) { \
960                 M_MOV_IMM(GET_LOW_REG(d), (s4) ((s8) (c) & 0xffffffff)); \
961                 ICONST(GET_HIGH_REG(d), (s4) ((s8) (c) >> 32)); \
962         } else { \
963                 disp = dseg_add_s8(cd, (c)); \
964                 M_LDRD(d, REG_PV, disp); \
965         }
966
967
968 #if !defined(ENABLE_SOFTFLOAT)
969
970 #define FCONST(d,c) \
971     do { \
972         disp = dseg_add_float(cd, (c)); \
973         M_LDFS(d, REG_PV, disp); \
974     } while (0)
975
976 #define DCONST(d,c) \
977     do { \
978         disp = dseg_add_double(cd, (c)); \
979         M_LDFD(d, REG_PV, disp); \
980     } while (0)
981
982 #endif /* !defined(ENABLE_SOFTFLOAT) */
983
984
985 /* M_RECOMPUTE_PV:
986    used to recompute our PV (we use the IP for this) out of the current PC
987    ATTENTION: if you change this, you have to look at other functions as well!
988    Following things depend on it: asm_call_jit_compiler(); codegen_findmethod();
989 */
990 #define M_RECOMPUTE_PV(disp) \
991         disp += 8; /* we use PC relative addr.  */ \
992         assert((disp & 0x03) == 0); \
993         assert(disp >= 0 && disp <= 0x03ffffff); \
994         M_SUB_IMM(REG_PV, REG_PC, IMM_ROTL(disp >> 2, 1)); \
995         if (disp > 0x000003ff) M_SUB_IMM(REG_PV, REG_PV, IMM_ROTL(disp >> 10, 5)); \
996         if (disp > 0x0003ffff) M_SUB_IMM(REG_PV, REG_PV, IMM_ROTL(disp >> 18, 9)); \
997
998 /* M_INTMOVE:
999    generates an integer-move from register a to b.
1000    if a and b are the same int-register, no code will be generated.
1001 */
1002
1003 #define M_INTMOVE(a,b) \
1004     do { \
1005         if ((a) != (b)) \
1006             M_MOV(b, a); \
1007     } while (0)
1008
1009 #define M_LNGMOVE(a,b) \
1010     do { \
1011         if (GET_HIGH_REG(a) == GET_LOW_REG(b)) { \
1012             assert((GET_LOW_REG(a) != GET_HIGH_REG(b))); \
1013             M_INTMOVE(GET_HIGH_REG(a), GET_HIGH_REG(b)); \
1014             M_INTMOVE(GET_LOW_REG(a), GET_LOW_REG(b)); \
1015         } else { \
1016             M_INTMOVE(GET_LOW_REG(a), GET_LOW_REG(b)); \
1017             M_INTMOVE(GET_HIGH_REG(a), GET_HIGH_REG(b)); \
1018         } \
1019     } while (0)
1020
1021
1022 #if !defined(ENABLE_SOFTFLOAT)
1023
1024 /* M_FLTMOVE:
1025    generates a floating-point-move from register a to b.
1026    if a and b are the same float-register, no code will be generated.
1027 */
1028
1029 #define M_FLTMOVE(a,b) \
1030     do { \
1031         if ((a) != (b)) \
1032             M_FMOV(a, b); \
1033     } while (0)
1034
1035 #define M_DBLMOVE(a,b) \
1036     do { \
1037         if ((a) != (b)) \
1038             M_DMOV(a, b); \
1039     } while (0)
1040
1041 #endif
1042
1043 #if !defined(ENABLE_SOFTFLOAT)
1044 /* M_CAST_INT_TO_FLT_TYPED:
1045    loads the value of the integer-register a (argument or result) into
1046    float-register Fb. (and vice versa)
1047 */
1048 #define M_CAST_INT_TO_FLT_TYPED(t,a,Fb) \
1049         CHECK_FLT_REG(Fb); \
1050         if ((t) == TYPE_FLT) { \
1051                 CHECK_INT_REG(a); \
1052                 M_STR_UPDATE(a, REG_SP, -4); \
1053                 M_LDFS_UPDATE(Fb, REG_SP, 4); \
1054         } else { \
1055                 CHECK_INT_REG(GET_LOW_REG(a)); \
1056                 CHECK_INT_REG(GET_HIGH_REG(a)); \
1057                 M_STRD_UPDATE(a, REG_SP, -8); \
1058                 M_LDFD_UPDATE(Fb, REG_SP, 8); \
1059         }
1060 #define M_CAST_FLT_TO_INT_TYPED(t,Fa,b) \
1061         CHECK_FLT_REG(Fa); \
1062         if ((t) == TYPE_FLT) { \
1063                 CHECK_INT_REG(b); \
1064                 M_STFS_UPDATE(Fa, REG_SP, -4); \
1065                 M_LDR_UPDATE(b, REG_SP, 4); \
1066         } else { \
1067                 CHECK_INT_REG(GET_LOW_REG(b)); \
1068                 CHECK_INT_REG(GET_HIGH_REG(b)); \
1069                 M_STFD_UPDATE(Fa, REG_SP, -8); \
1070                 M_LDRD_UPDATE(b, REG_SP, 8); \
1071         }
1072 #endif /* !defined(ENABLE_SOFTFLOAT) */
1073
1074
1075 /* M_COMPARE:
1076    generates the compare part of an if-sequece
1077    uses M_CMP or M_CMP_IMM to do the compare
1078    ATTENTION: uses REG_ITMP3 as intermediate register
1079 */
1080 /* TODO: improve this and add some comments! */
1081 #define M_COMPARE(reg, val, cond, overjump) \
1082         if (IS_IMM(val)) { \
1083                 if (overjump) M_BNE(1); \
1084                 /* M_CMP_IMM */ M_DAT(cond,0x0a,0,(reg),1,1,(val)); \
1085         } else if(IS_IMM(-(val))) { \
1086                 if (overjump) M_BNE(1); \
1087                 /* M_CMN_IMM */ M_DAT(cond,0x0b,0,(reg),1,1,-(val)); \
1088         } else { \
1089                 ICONST(REG_ITMP3, (val)); \
1090                 if (overjump) M_BNE(1); \
1091                 /* M_CMP */ M_DAT(cond,0x0a,0,(reg),1,0,REG_ITMP3); \
1092         }
1093
1094 /* M_LONGBRANCH:
1095    performs a long branch to an absolute address with return address in LR
1096    takes up 3 bytes of code space; address is hard-coded into code
1097 */
1098 #define M_LONGBRANCH(adr) \
1099         M_ADD_IMM(REG_LR, REG_PC, 4); \
1100         M_LDR_INTERN(REG_PC, REG_PC, -4); \
1101         DCD((s4) adr);
1102
1103 /* M_DSEG_LOAD/BRANCH:
1104    TODO: document me
1105    ATTENTION: if you change this, you have to look at the asm_call_jit_compiler!
1106    ATTENTION: we use M_LDR, so the same restrictions apply to us!
1107 */
1108 #define M_DSEG_LOAD(reg, offset) \
1109         M_LDR_NEGATIVE(reg, REG_PV, offset)
1110
1111 #define M_DSEG_BRANCH(offset) \
1112         if (IS_OFFSET(offset, 0x0fff)) { \
1113                 M_MOV(REG_LR, REG_PC); \
1114                 M_LDR_INTERN(REG_PC, REG_PV, offset); \
1115         } else { \
1116                 /*assert((offset) <= 0);*/ \
1117                 CHECK_OFFSET(offset,0x0fffff); \
1118                 M_SUB_IMM(REG_ITMP3, REG_PV, ((-(offset) >>  12) & 0xff) | (((10) & 0x0f) << 8)); /*TODO: more to go*/ \
1119                 M_MOV(REG_LR, REG_PC); \
1120                 M_LDR_INTERN(REG_PC, REG_ITMP3, -(-(offset) & 0x0fff)); /*TODO: this looks ugly*/ \
1121         }
1122
1123 /* M_STACK_LOAD/STORE:
1124    loads or stores integer values from register to stack or from stack to register
1125    ATTENTION: we use M_LDR and M_STR, so the same restrictions apply to us!
1126 */
1127
1128 #define M_STACK_LOAD_LNG(reg, offset) { \
1129         CHECK_INT_REG(GET_LOW_REG(reg)); \
1130         CHECK_INT_REG(GET_HIGH_REG(reg)); \
1131         M_LDRD(reg, REG_SP, (offset) * 4); \
1132 }
1133
1134
1135 #define M_ILD(a,b,c)                    M_LDR(a,b,c)
1136 #define M_LLD(a,b,c)                    M_LDRD(a,b,c)
1137
1138 #define M_ILD_INTERN(a,b,c)             M_LDR_INTERN(a,b,c)
1139 #define M_LLD_INTERN(a,b,c)             M_LDRD_INTERN(a,b,c)
1140
1141 #define M_ALD(a,b,c)                    M_ILD(a,b,c)
1142 #define M_ALD_INTERN(a,b,c)             M_ILD_INTERN(a,b,c)
1143
1144
1145 #define M_IST(a,b,c)                    M_STR(a,b,c)
1146 #define M_LST(a,b,c)                    M_STRD(a,b,c)
1147
1148 #define M_IST_INTERN(a,b,c)             M_STR_INTERN(a,b,c)
1149 #define M_LST_INTERN(a,b,c)             M_STRD_INTERN(a,b,c)
1150
1151 #define M_AST(a,b,c)                    M_IST(a,b,c)
1152 #define M_AST_INTERN(a,b,c)             M_IST_INTERN(a,b,c)
1153
1154
1155 #if !defined(ENABLE_SOFTFLOAT)
1156
1157 #define M_FLD(a,b,c)                    M_LDFS(a,b,c)
1158 #define M_DLD(a,b,c)                    M_LDFD(a,b,c)
1159
1160 #define M_FLD_INTERN(a,b,c)             M_LDFS_INTERN(a,b,c)
1161 #define M_DLD_INTERN(a,b,c)             M_LDFD_INTERN(a,b,c)
1162
1163
1164 #define M_FST(a,b,c)                    M_STFS(a,b,c)
1165 #define M_DST(a,b,c)                    M_STFD(a,b,c)
1166
1167 #define M_FST_INTERN(a,b,c)             M_STFS_INTERN(a,b,c)
1168 #define M_DST_INTERN(a,b,c)             M_STFD_INTERN(a,b,c)
1169
1170 #endif /* !defined(ENABLE_SOFTFLOAT) */
1171
1172
1173 /* function gen_resolvebranch **************************************************
1174    ip ... pointer to instruction after branch (void*)
1175    so ... offset of instruction after branch  (s4)
1176    to ... offset of branch target             (s4) */
1177
1178 #define gen_resolvebranch(ip,so,to) \
1179         assert((((s4*) (ip))[-1] & 0x0e000000) == 0x0a000000); \
1180         ((s4*) (ip))[-1] |= ((s4) (to) - (so) - 1) >> 2 & 0x0ffffff
1181
1182
1183 /* function gen_nullptr_check *************************************************/
1184
1185 #define gen_nullptr_check_intern(objreg) { \
1186         M_TST((objreg), (objreg)); \
1187         M_BEQ(0); \
1188         codegen_add_nullpointerexception_ref(cd); \
1189 }
1190
1191 #define gen_nullptr_check(objreg) \
1192         if (checknull) \
1193                 gen_nullptr_check_intern(objreg)
1194
1195
1196 /* function gen_div_check *****************************************************/
1197
1198 #define gen_div_check(type,reg) \
1199     do { \
1200         if (IS_2_WORD_TYPE(type)) { \
1201                 M_TEQ_IMM(GET_LOW_REG(reg), 0); \
1202                 /* M_TEQ_EQ_IMM(GET_HIGH_REG(reg), 0) */ M_DAT(COND_EQ,0x09,0,GET_HIGH_REG(reg),1,1,0); \
1203                 M_BEQ(0); \
1204         } else { \
1205                 M_TEQ_IMM((reg), 0); \
1206                 M_BEQ(0); \
1207         } \
1208         codegen_add_arithmeticexception_ref(cd); \
1209     } while (0)
1210
1211 /* function gen_bound_check ***************************************************
1212    ATTENTION: uses REG_ITMP3 as intermediate register */
1213 /* TODO: maybe use another reg instead of REG_ITMP3! */
1214
1215 #define gen_bound_check(arrayref,index) \
1216         if (checkbounds) { \
1217                 M_LDR_INTERN(REG_ITMP3, (arrayref), OFFSET(java_arrayheader, size)); \
1218                 M_CMP((index), REG_ITMP3); \
1219                 M_BHS(0); \
1220                 codegen_add_arrayindexoutofboundsexception_ref(cd, index); \
1221         }
1222
1223
1224 #endif /* _CODEGEN_H */
1225
1226
1227 /*
1228  * These are local overrides for various environment variables in Emacs.
1229  * Please do not remove this and leave it at the end of the file, where
1230  * Emacs will automagically detect them.
1231  * ---------------------------------------------------------------------
1232  * Local variables:
1233  * mode: c
1234  * indent-tabs-mode: t
1235  * c-basic-offset: 4
1236  * tab-width: 4
1237  * End:
1238  * vim:noexpandtab:sw=4:ts=4:
1239  */