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