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