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