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