Mercurial > hg > tinycc
annotate arm/gen.c @ 546:3f683703c8db
Rename ggoto() to gen_goto().
author | Rob Landley <rob@landley.net> |
---|---|
date | Fri, 28 Dec 2007 17:33:06 -0600 |
parents | 95fd7f30f7e3 |
children | d1fe34c5b92e |
rev | line source |
---|---|
295 | 1 /* |
2 * ARMv4 code generator for TCC | |
3 * | |
4 * Copyright (c) 2003 Daniel Glöckner | |
5 * | |
6 * Based on i386-gen.c by Fabrice Bellard | |
7 * | |
499
2b451d2e68ea
Exercise LGPL clause 3 and convert more notices from LGPL to GPLv2. (If you
Rob Landley <rob@landley.net>
parents:
410
diff
changeset
|
8 * Licensed under GPLv2, see file LICENSE in this tarball. |
295 | 9 */ |
10 | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
11 #ifdef TCC_ARM_EABI |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
12 #define TCC_ARM_VFP |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
13 #endif |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
14 |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
15 |
295 | 16 /* number of available registers */ |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
17 #ifdef TCC_ARM_VFP |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
18 #define NB_REGS 13 |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
19 #else |
295 | 20 #define NB_REGS 9 |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
21 #endif |
295 | 22 |
23 /* a register can belong to several classes. The classes must be | |
24 sorted from more general to more precise (see gv2() code which does | |
25 assumptions on it). */ | |
26 #define RC_INT 0x0001 /* generic integer register */ | |
27 #define RC_FLOAT 0x0002 /* generic float register */ | |
28 #define RC_R0 0x0004 | |
29 #define RC_R1 0x0008 | |
30 #define RC_R2 0x0010 | |
31 #define RC_R3 0x0020 | |
32 #define RC_R12 0x0040 | |
33 #define RC_F0 0x0080 | |
34 #define RC_F1 0x0100 | |
35 #define RC_F2 0x0200 | |
36 #define RC_F3 0x0400 | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
37 #ifdef TCC_ARM_VFP |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
38 #define RC_F4 0x0800 |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
39 #define RC_F5 0x1000 |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
40 #define RC_F6 0x2000 |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
41 #define RC_F7 0x4000 |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
42 #endif |
295 | 43 #define RC_IRET RC_R0 /* function return: integer register */ |
44 #define RC_LRET RC_R1 /* function return: second integer register */ | |
45 #define RC_FRET RC_F0 /* function return: float register */ | |
46 | |
47 /* pretty names for the registers */ | |
48 enum { | |
49 TREG_R0 = 0, | |
50 TREG_R1, | |
51 TREG_R2, | |
52 TREG_R3, | |
53 TREG_R12, | |
54 TREG_F0, | |
55 TREG_F1, | |
56 TREG_F2, | |
57 TREG_F3, | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
58 #ifdef TCC_ARM_VFP |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
59 TREG_F4, |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
60 TREG_F5, |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
61 TREG_F6, |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
62 TREG_F7, |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
63 #endif |
295 | 64 }; |
65 | |
66 int reg_classes[NB_REGS] = { | |
67 /* r0 */ RC_INT | RC_R0, | |
68 /* r1 */ RC_INT | RC_R1, | |
69 /* r2 */ RC_INT | RC_R2, | |
70 /* r3 */ RC_INT | RC_R3, | |
71 /* r12 */ RC_INT | RC_R12, | |
72 /* f0 */ RC_FLOAT | RC_F0, | |
73 /* f1 */ RC_FLOAT | RC_F1, | |
74 /* f2 */ RC_FLOAT | RC_F2, | |
75 /* f3 */ RC_FLOAT | RC_F3, | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
76 #ifdef TCC_ARM_VFP |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
77 /* d4/s8 */ RC_FLOAT | RC_F4, |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
78 /* d5/s10 */ RC_FLOAT | RC_F5, |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
79 /* d6/s12 */ RC_FLOAT | RC_F6, |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
80 /* d7/s14 */ RC_FLOAT | RC_F7, |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
81 #endif |
295 | 82 }; |
83 | |
84 static int two2mask(int a,int b) { | |
85 return (reg_classes[a]|reg_classes[b])&~(RC_INT|RC_FLOAT); | |
86 } | |
87 | |
88 static int regmask(int r) { | |
89 return reg_classes[r]&~(RC_INT|RC_FLOAT); | |
90 } | |
91 | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
92 #ifdef TCC_ARM_VFP |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
93 #define T2CPR(t) (((t) & VT_BTYPE) != VT_FLOAT ? 0x100 : 0) |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
94 #endif |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
95 |
295 | 96 /* return registers for function */ |
97 #define REG_IRET TREG_R0 /* single word int return register */ | |
98 #define REG_LRET TREG_R1 /* second word return register (for long long) */ | |
99 #define REG_FRET TREG_F0 /* float return register */ | |
100 | |
101 /* defined if function parameters must be evaluated in reverse order */ | |
102 #define INVERT_FUNC_PARAMS | |
103 | |
104 /* defined if structures are passed as pointers. Otherwise structures | |
105 are directly pushed on stack. */ | |
106 //#define FUNC_STRUCT_PARAM_AS_PTR | |
107 | |
410 | 108 #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP) |
109 static CType float_type, double_type, func_float_type, func_double_type; | |
110 #endif | |
111 | |
295 | 112 /* pointer size, in bytes */ |
113 #define PTR_SIZE 4 | |
114 | |
115 /* long double size and alignment, in bytes */ | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
116 #ifdef TCC_ARM_VFP |
295 | 117 #define LDOUBLE_SIZE 8 |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
118 #endif |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
119 |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
120 #ifndef LDOUBLE_SIZE |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
121 #define LDOUBLE_SIZE 8 |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
122 #endif |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
123 |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
124 #ifdef TCC_ARM_EABI |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
125 #define LDOUBLE_ALIGN 8 |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
126 #else |
295 | 127 #define LDOUBLE_ALIGN 4 |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
128 #endif |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
129 |
295 | 130 /* maximum alignment (for aligned attribute support) */ |
131 #define MAX_ALIGN 8 | |
132 | |
133 #define CHAR_IS_UNSIGNED | |
134 | |
135 /******************************************************/ | |
136 /* ELF defines */ | |
137 | |
138 #define EM_TCC_TARGET EM_ARM | |
139 | |
140 /* relocation type for 32 bit data relocation */ | |
141 #define R_DATA_32 R_ARM_ABS32 | |
142 #define R_JMP_SLOT R_ARM_JUMP_SLOT | |
143 #define R_COPY R_ARM_COPY | |
144 | |
145 #define ELF_START_ADDR 0x00008000 | |
146 #define ELF_PAGE_SIZE 0x1000 | |
147 | |
148 /******************************************************/ | |
149 static unsigned long func_sub_sp_offset,last_itod_magic; | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
150 static int leaffunc; |
295 | 151 |
152 void o(unsigned long i) | |
153 { | |
154 /* this is a good place to start adding big-endian support*/ | |
155 int ind1; | |
156 | |
157 ind1 = ind + 4; | |
307 | 158 if (!cur_text_section) |
159 error("compiler error! This happens f.ex. if the compiler\n" | |
160 "can't evaluate constant expressions outside of a function."); | |
295 | 161 if (ind1 > cur_text_section->data_allocated) |
162 section_realloc(cur_text_section, ind1); | |
163 cur_text_section->data[ind++] = i&255; | |
164 i>>=8; | |
165 cur_text_section->data[ind++] = i&255; | |
166 i>>=8; | |
167 cur_text_section->data[ind++] = i&255; | |
168 i>>=8; | |
169 cur_text_section->data[ind++] = i; | |
170 } | |
171 | |
172 static unsigned long stuff_const(unsigned long op,unsigned long c) | |
173 { | |
174 int try_neg=0; | |
337 | 175 unsigned long nc = 0,negop = 0; |
176 | |
295 | 177 switch(op&0x1F00000) |
178 { | |
179 case 0x800000: //add | |
180 case 0x400000: //sub | |
181 try_neg=1; | |
182 negop=op^0xC00000; | |
183 nc=-c; | |
184 break; | |
185 case 0x1A00000: //mov | |
186 case 0x1E00000: //mvn | |
187 try_neg=1; | |
188 negop=op^0x400000; | |
189 nc=~c; | |
190 break; | |
191 case 0x200000: //xor | |
192 if(c==~0) | |
193 return (op&0xF010F000)|((op>>16)&0xF)|0x1E00000; | |
194 break; | |
195 case 0x0: //and | |
196 if(c==~0) | |
197 return (op&0xF010F000)|((op>>16)&0xF)|0x1A00000; | |
198 case 0x1C00000: //bic | |
199 try_neg=1; | |
200 negop=op^0x1C00000; | |
201 nc=~c; | |
202 break; | |
203 case 0x1800000: //orr | |
204 if(c==~0) | |
205 return (op&0xFFF0FFFF)|0x1E00000; | |
206 break; | |
207 } | |
208 do { | |
209 unsigned long m; | |
210 int i; | |
211 if(c<256) /* catch undefined <<32 */ | |
212 return op|c; | |
213 for(i=2;i<32;i+=2) { | |
214 m=(0xff>>i)|(0xff<<(32-i)); | |
215 if(!(c&~m)) | |
216 return op|(i<<7)|(c<<i)|(c>>(32-i)); | |
217 } | |
218 op=negop; | |
219 c=nc; | |
220 } while(try_neg--); | |
221 return 0; | |
222 } | |
223 | |
224 | |
225 //only add,sub | |
226 void stuff_const_harder(unsigned long op,unsigned long v) { | |
227 unsigned long x; | |
228 x=stuff_const(op,v); | |
229 if(x) | |
230 o(x); | |
231 else { | |
232 unsigned long a[16],nv,no,o2,n2; | |
233 int i,j,k; | |
234 a[0]=0xff; | |
235 o2=(op&0xfff0ffff)|((op&0xf000)<<4);; | |
236 for(i=1;i<16;i++) | |
237 a[i]=(a[i-1]>>2)|(a[i-1]<<30); | |
238 for(i=0;i<12;i++) | |
239 for(j=i+4;i<13+i;i++) | |
240 if((v&(a[i]|a[j]))==v) { | |
241 o(stuff_const(op,v&a[i])); | |
242 o(stuff_const(o2,v&a[j])); | |
243 return; | |
244 } | |
245 no=op^0xC00000; | |
246 n2=o2^0xC00000; | |
247 nv=-v; | |
248 for(i=0;i<12;i++) | |
249 for(j=i+4;i<13+i;i++) | |
250 if((nv&(a[i]|a[j]))==nv) { | |
251 o(stuff_const(no,nv&a[i])); | |
252 o(stuff_const(n2,nv&a[j])); | |
253 return; | |
254 } | |
255 for(i=0;i<8;i++) | |
256 for(j=i+4;i<12;i++) | |
257 for(k=j+4;k<13+i;i++) | |
258 if((v&(a[i]|a[j]|a[k]))==v) { | |
259 o(stuff_const(op,v&a[i])); | |
260 o(stuff_const(o2,v&a[j])); | |
261 o(stuff_const(o2,v&a[k])); | |
262 return; | |
263 } | |
264 no=op^0xC00000; | |
265 nv=-v; | |
266 for(i=0;i<8;i++) | |
267 for(j=i+4;i<12;i++) | |
268 for(k=j+4;k<13+i;i++) | |
269 if((nv&(a[i]|a[j]|a[k]))==nv) { | |
270 o(stuff_const(no,nv&a[i])); | |
271 o(stuff_const(n2,nv&a[j])); | |
272 o(stuff_const(n2,nv&a[k])); | |
273 return; | |
274 } | |
275 o(stuff_const(op,v&a[0])); | |
276 o(stuff_const(o2,v&a[4])); | |
277 o(stuff_const(o2,v&a[8])); | |
278 o(stuff_const(o2,v&a[12])); | |
279 } | |
280 } | |
281 | |
282 unsigned long encbranch(int pos,int addr,int fail) | |
283 { | |
284 addr-=pos+8; | |
285 addr/=4; | |
286 if(addr>=0x1000000 || addr<-0x1000000) { | |
287 if(fail) | |
288 error("FIXME: function bigger than 32MB"); | |
289 return 0; | |
290 } | |
291 return 0x0A000000|(addr&0xffffff); | |
292 } | |
293 | |
294 int decbranch(int pos) | |
295 { | |
296 int x; | |
297 x=*(int *)(cur_text_section->data + pos); | |
298 x&=0x00ffffff; | |
299 if(x&0x800000) | |
300 x-=0x1000000; | |
301 return x*4+pos+8; | |
302 } | |
303 | |
304 /* output a symbol and patch all calls to it */ | |
305 void gsym_addr(int t, int a) | |
306 { | |
307 unsigned long *x; | |
308 int lt; | |
309 while(t) { | |
310 x=(unsigned long *)(cur_text_section->data + t); | |
311 t=decbranch(lt=t); | |
312 if(a==lt+4) | |
313 *x=0xE1A00000; // nop | |
314 else { | |
315 *x &= 0xff000000; | |
316 *x |= encbranch(lt,a,1); | |
317 } | |
318 } | |
319 } | |
320 | |
321 void gsym(int t) | |
322 { | |
323 gsym_addr(t, ind); | |
324 } | |
325 | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
326 #ifdef TCC_ARM_VFP |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
327 static unsigned long vfpr(int r) |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
328 { |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
329 if(r<TREG_F0 || r>TREG_F7) |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
330 error("compiler error! register %i is no vfp register",r); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
331 return r-5; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
332 } |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
333 #else |
295 | 334 static unsigned long fpr(int r) |
335 { | |
307 | 336 if(r<TREG_F0 || r>TREG_F3) |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
337 error("compiler error! register %i is no fpa register",r); |
295 | 338 return r-5; |
339 } | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
340 #endif |
295 | 341 |
342 static unsigned long intr(int r) | |
343 { | |
307 | 344 if(r==4) |
345 return 12; | |
346 if((r<0 || r>4) && r!=14) | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
347 error("compiler error! register %i is no int register",r); |
307 | 348 return r; |
295 | 349 } |
350 | |
351 static void calcaddr(unsigned long *base,int *off,int *sgn,int maxoff,unsigned shift) | |
352 { | |
353 if(*off>maxoff || *off&((1<<shift)-1)) { | |
354 unsigned long x,y; | |
355 x=0xE280E000; | |
356 if(*sgn) | |
357 x=0xE240E000; | |
358 x|=(*base)<<16; | |
359 *base=14; // lr | |
360 y=stuff_const(x,*off&~maxoff); | |
361 if(y) { | |
362 o(y); | |
363 *off&=maxoff; | |
364 return; | |
365 } | |
366 y=stuff_const(x,(*off+maxoff)&~maxoff); | |
367 if(y) { | |
368 o(y); | |
369 *sgn=!*sgn; | |
370 *off=((*off+maxoff)&~maxoff)-*off; | |
371 return; | |
372 } | |
373 stuff_const_harder(x,*off&~maxoff); | |
374 *off&=maxoff; | |
375 } | |
376 } | |
377 | |
378 static unsigned long mapcc(int cc) | |
379 { | |
380 switch(cc) | |
381 { | |
382 case TOK_ULT: | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
383 return 0x30000000; /* CC/LO */ |
295 | 384 case TOK_UGE: |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
385 return 0x20000000; /* CS/HS */ |
295 | 386 case TOK_EQ: |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
387 return 0x00000000; /* EQ */ |
295 | 388 case TOK_NE: |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
389 return 0x10000000; /* NE */ |
295 | 390 case TOK_ULE: |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
391 return 0x90000000; /* LS */ |
295 | 392 case TOK_UGT: |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
393 return 0x80000000; /* HI */ |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
394 case TOK_Nset: |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
395 return 0x40000000; /* MI */ |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
396 case TOK_Nclear: |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
397 return 0x50000000; /* PL */ |
295 | 398 case TOK_LT: |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
399 return 0xB0000000; /* LT */ |
295 | 400 case TOK_GE: |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
401 return 0xA0000000; /* GE */ |
295 | 402 case TOK_LE: |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
403 return 0xD0000000; /* LE */ |
295 | 404 case TOK_GT: |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
405 return 0xC0000000; /* GT */ |
295 | 406 } |
407 error("unexpected condition code"); | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
408 return 0xE0000000; /* AL */ |
295 | 409 } |
410 | |
411 static int negcc(int cc) | |
412 { | |
413 switch(cc) | |
414 { | |
415 case TOK_ULT: | |
416 return TOK_UGE; | |
417 case TOK_UGE: | |
418 return TOK_ULT; | |
419 case TOK_EQ: | |
420 return TOK_NE; | |
421 case TOK_NE: | |
422 return TOK_EQ; | |
423 case TOK_ULE: | |
424 return TOK_UGT; | |
425 case TOK_UGT: | |
426 return TOK_ULE; | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
427 case TOK_Nset: |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
428 return TOK_Nclear; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
429 case TOK_Nclear: |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
430 return TOK_Nset; |
295 | 431 case TOK_LT: |
432 return TOK_GE; | |
433 case TOK_GE: | |
434 return TOK_LT; | |
435 case TOK_LE: | |
436 return TOK_GT; | |
437 case TOK_GT: | |
438 return TOK_LE; | |
439 } | |
440 error("unexpected condition code"); | |
441 return TOK_NE; | |
442 } | |
443 | |
444 /* load 'r' from value 'sv' */ | |
445 void load(int r, SValue *sv) | |
446 { | |
447 int v, ft, fc, fr, sign; | |
448 unsigned long op; | |
449 SValue v1; | |
450 | |
451 fr = sv->r; | |
452 ft = sv->type.t; | |
453 fc = sv->c.ul; | |
454 | |
455 if(fc>=0) | |
456 sign=0; | |
457 else { | |
458 sign=1; | |
459 fc=-fc; | |
460 } | |
461 | |
462 v = fr & VT_VALMASK; | |
463 if (fr & VT_LVAL) { | |
464 unsigned long base=0xB; // fp | |
465 if(v == VT_LLOCAL) { | |
466 v1.type.t = VT_PTR; | |
467 v1.r = VT_LOCAL | VT_LVAL; | |
468 v1.c.ul = sv->c.ul; | |
469 load(base=14 /* lr */, &v1); | |
470 fc=sign=0; | |
471 v=VT_LOCAL; | |
472 } else if(v == VT_CONST) { | |
473 v1.type.t = VT_PTR; | |
474 v1.r = fr&~VT_LVAL; | |
475 v1.c.ul = sv->c.ul; | |
476 v1.sym=sv->sym; | |
477 load(base=14, &v1); | |
478 fc=sign=0; | |
479 v=VT_LOCAL; | |
480 } else if(v < VT_CONST) { | |
481 base=intr(v); | |
482 fc=sign=0; | |
483 v=VT_LOCAL; | |
484 } | |
485 if(v == VT_LOCAL) { | |
486 if(is_float(ft)) { | |
487 calcaddr(&base,&fc,&sign,1020,2); | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
488 #ifdef TCC_ARM_VFP |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
489 op=0xED100A00; /* flds */ |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
490 if(!sign) |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
491 op|=0x800000; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
492 if ((ft & VT_BTYPE) != VT_FLOAT) |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
493 op|=0x100; /* flds -> fldd */ |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
494 o(op|(vfpr(r)<<12)|(fc>>2)|(base<<16)); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
495 #else |
295 | 496 op=0xED100100; |
497 if(!sign) | |
498 op|=0x800000; | |
307 | 499 #if LDOUBLE_SIZE == 8 |
295 | 500 if ((ft & VT_BTYPE) != VT_FLOAT) |
501 op|=0x8000; | |
307 | 502 #else |
503 if ((ft & VT_BTYPE) == VT_DOUBLE) | |
504 op|=0x8000; | |
505 else if ((ft & VT_BTYPE) == VT_LDOUBLE) | |
506 op|=0x400000; | |
507 #endif | |
295 | 508 o(op|(fpr(r)<<12)|(fc>>2)|(base<<16)); |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
509 #endif |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
510 } else if((ft & (VT_BTYPE|VT_UNSIGNED)) == VT_BYTE |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
511 || (ft & VT_BTYPE) == VT_SHORT) { |
295 | 512 calcaddr(&base,&fc,&sign,255,0); |
513 op=0xE1500090; | |
514 if ((ft & VT_BTYPE) == VT_SHORT) | |
515 op|=0x20; | |
516 if ((ft & VT_UNSIGNED) == 0) | |
517 op|=0x40; | |
518 if(!sign) | |
519 op|=0x800000; | |
520 o(op|(intr(r)<<12)|(base<<16)|((fc&0xf0)<<4)|(fc&0xf)); | |
521 } else { | |
522 calcaddr(&base,&fc,&sign,4095,0); | |
523 op=0xE5100000; | |
524 if(!sign) | |
525 op|=0x800000; | |
526 if ((ft & VT_BTYPE) == VT_BYTE) | |
527 op|=0x400000; | |
528 o(op|(intr(r)<<12)|fc|(base<<16)); | |
529 } | |
530 return; | |
531 } | |
532 } else { | |
533 if (v == VT_CONST) { | |
534 op=stuff_const(0xE3A00000|(intr(r)<<12),sv->c.ul); | |
535 if (fr & VT_SYM || !op) { | |
536 o(0xE59F0000|(intr(r)<<12)); | |
537 o(0xEA000000); | |
538 if(fr & VT_SYM) | |
539 greloc(cur_text_section, sv->sym, ind, R_ARM_ABS32); | |
540 o(sv->c.ul); | |
541 } else | |
542 o(op); | |
543 return; | |
544 } else if (v == VT_LOCAL) { | |
545 op=stuff_const(0xE28B0000|(intr(r)<<12),sv->c.ul); | |
546 if (fr & VT_SYM || !op) { | |
547 o(0xE59F0000|(intr(r)<<12)); | |
548 o(0xEA000000); | |
549 if(fr & VT_SYM) // needed ? | |
550 greloc(cur_text_section, sv->sym, ind, R_ARM_ABS32); | |
551 o(sv->c.ul); | |
552 o(0xE08B0000|(intr(r)<<12)|intr(r)); | |
553 } else | |
554 o(op); | |
555 return; | |
556 } else if(v == VT_CMP) { | |
557 o(mapcc(sv->c.ul)|0x3A00001|(intr(r)<<12)); | |
558 o(mapcc(negcc(sv->c.ul))|0x3A00000|(intr(r)<<12)); | |
559 return; | |
560 } else if (v == VT_JMP || v == VT_JMPI) { | |
561 int t; | |
562 t = v & 1; | |
563 o(0xE3A00000|(intr(r)<<12)|t); | |
564 o(0xEA000000); | |
565 gsym(sv->c.ul); | |
566 o(0xE3A00000|(intr(r)<<12)|(t^1)); | |
567 return; | |
568 } else if (v < VT_CONST) { | |
569 if(is_float(ft)) | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
570 #ifdef TCC_ARM_VFP |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
571 o(0xEEB00A40|(vfpr(r)<<12)|vfpr(v)|T2CPR(ft)); /* fcpyX */ |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
572 #else |
295 | 573 o(0xEE008180|(fpr(r)<<12)|fpr(v)); |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
574 #endif |
295 | 575 else |
576 o(0xE1A00000|(intr(r)<<12)|intr(v)); | |
577 return; | |
578 } | |
579 } | |
580 error("load unimplemented!"); | |
581 } | |
582 | |
583 /* store register 'r' in lvalue 'v' */ | |
584 void store(int r, SValue *sv) | |
585 { | |
586 SValue v1; | |
587 int v, ft, fc, fr, sign; | |
588 unsigned long op; | |
589 | |
590 fr = sv->r; | |
591 ft = sv->type.t; | |
592 fc = sv->c.ul; | |
593 | |
594 if(fc>=0) | |
595 sign=0; | |
596 else { | |
597 sign=1; | |
598 fc=-fc; | |
599 } | |
600 | |
601 v = fr & VT_VALMASK; | |
602 if (fr & VT_LVAL || fr == VT_LOCAL) { | |
603 unsigned long base=0xb; | |
604 if(v < VT_CONST) { | |
605 base=intr(v); | |
606 v=VT_LOCAL; | |
607 fc=sign=0; | |
608 } else if(v == VT_CONST) { | |
609 v1.type.t = ft; | |
610 v1.r = fr&~VT_LVAL; | |
611 v1.c.ul = sv->c.ul; | |
612 v1.sym=sv->sym; | |
613 load(base=14, &v1); | |
614 fc=sign=0; | |
615 v=VT_LOCAL; | |
616 } | |
617 if(v == VT_LOCAL) { | |
618 if(is_float(ft)) { | |
619 calcaddr(&base,&fc,&sign,1020,2); | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
620 #ifdef TCC_ARM_VFP |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
621 op=0xED000A00; /* fsts */ |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
622 if(!sign) |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
623 op|=0x800000; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
624 if ((ft & VT_BTYPE) != VT_FLOAT) |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
625 op|=0x100; /* fsts -> fstd */ |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
626 o(op|(vfpr(r)<<12)|(fc>>2)|(base<<16)); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
627 #else |
295 | 628 op=0xED000100; |
629 if(!sign) | |
630 op|=0x800000; | |
307 | 631 #if LDOUBLE_SIZE == 8 |
295 | 632 if ((ft & VT_BTYPE) != VT_FLOAT) |
633 op|=0x8000; | |
307 | 634 #else |
635 if ((ft & VT_BTYPE) == VT_DOUBLE) | |
636 op|=0x8000; | |
637 if ((ft & VT_BTYPE) == VT_LDOUBLE) | |
638 op|=0x400000; | |
639 #endif | |
295 | 640 o(op|(fpr(r)<<12)|(fc>>2)|(base<<16)); |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
641 #endif |
295 | 642 return; |
643 } else if((ft & VT_BTYPE) == VT_SHORT) { | |
644 calcaddr(&base,&fc,&sign,255,0); | |
645 op=0xE14000B0; | |
646 if(!sign) | |
647 op|=0x800000; | |
648 o(op|(intr(r)<<12)|(base<<16)|((fc&0xf0)<<4)|(fc&0xf)); | |
649 } else { | |
650 calcaddr(&base,&fc,&sign,4095,0); | |
651 op=0xE5000000; | |
652 if(!sign) | |
653 op|=0x800000; | |
654 if ((ft & VT_BTYPE) == VT_BYTE) | |
655 op|=0x400000; | |
656 o(op|(intr(r)<<12)|fc|(base<<16)); | |
657 } | |
658 return; | |
659 } | |
660 } | |
661 error("store unimplemented"); | |
662 } | |
663 | |
664 static void gadd_sp(int val) | |
665 { | |
666 stuff_const_harder(0xE28DD000,val); | |
667 } | |
668 | |
669 /* 'is_jmp' is '1' if it is a jump */ | |
670 static void gcall_or_jmp(int is_jmp) | |
671 { | |
672 int r; | |
673 if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { | |
674 unsigned long x; | |
675 /* constant case */ | |
676 x=encbranch(ind,ind+vtop->c.ul,0); | |
677 if(x) { | |
678 if (vtop->r & VT_SYM) { | |
679 /* relocation case */ | |
680 greloc(cur_text_section, vtop->sym, ind, R_ARM_PC24); | |
681 } else | |
682 put_elf_reloc(symtab_section, cur_text_section, ind, R_ARM_PC24, 0); | |
683 o(x|(is_jmp?0xE0000000:0xE1000000)); | |
684 } else { | |
685 if(!is_jmp) | |
686 o(0xE28FE004); // add lr,pc,#4 | |
687 o(0xE51FF004); // ldr pc,[pc,#-4] | |
688 if (vtop->r & VT_SYM) | |
689 greloc(cur_text_section, vtop->sym, ind, R_ARM_ABS32); | |
690 o(vtop->c.ul); | |
691 } | |
692 } else { | |
693 /* otherwise, indirect call */ | |
694 r = gv(RC_INT); | |
695 if(!is_jmp) | |
696 o(0xE1A0E00F); // mov lr,pc | |
697 o(0xE1A0F000|intr(r)); // mov pc,r | |
698 } | |
699 } | |
700 | |
701 /* Generate function call. The function address is pushed first, then | |
702 all the parameters in call order. This functions pops all the | |
703 parameters and the function address. */ | |
704 void gfunc_call(int nb_args) | |
705 { | |
706 int size, align, r, args_size, i; | |
707 Sym *func_sym; | |
307 | 708 signed char plan[4][2]={{-1,-1},{-1,-1},{-1,-1},{-1,-1}}; |
709 int todo=0xf, keep, plan2[4]={0,0,0,0}; | |
295 | 710 |
307 | 711 r = vtop->r & VT_VALMASK; |
712 if (r == VT_CMP || (r & ~1) == VT_JMP) | |
713 gv(RC_INT); | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
714 #ifdef TCC_ARM_EABI |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
715 if((vtop[-nb_args].type.ref->type.t & VT_BTYPE) == VT_STRUCT |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
716 && type_size(&vtop[-nb_args].type, &align) <= 4) { |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
717 SValue tmp; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
718 tmp=vtop[-nb_args]; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
719 vtop[-nb_args]=vtop[-nb_args+1]; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
720 vtop[-nb_args+1]=tmp; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
721 --nb_args; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
722 } |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
723 |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
724 vpushi(0); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
725 vtop->type.t = VT_LLONG; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
726 args_size = 0; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
727 for(i = nb_args + 1 ; i-- ;) { |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
728 size = type_size(&vtop[-i].type, &align); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
729 if(args_size & (align-1)) { |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
730 vpushi(0); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
731 vtop->type.t = VT_VOID; /* padding */ |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
732 vrott(i+2); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
733 args_size += 4; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
734 ++nb_args; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
735 } |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
736 args_size += (size + 3) & -4; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
737 } |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
738 vtop--; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
739 #endif |
295 | 740 args_size = 0; |
307 | 741 for(i = nb_args ; i-- && args_size < 16 ;) { |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
742 switch(vtop[-i].type.t & VT_BTYPE) { |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
743 case VT_STRUCT: |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
744 case VT_FLOAT: |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
745 case VT_DOUBLE: |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
746 case VT_LDOUBLE: |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
747 size = type_size(&vtop[-i].type, &align); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
748 size = (size + 3) & -4; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
749 args_size += size; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
750 break; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
751 default: |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
752 plan[nb_args-1-i][0]=args_size/4; |
307 | 753 args_size += 4; |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
754 if ((vtop[-i].type.t & VT_BTYPE) == VT_LLONG && args_size < 16) { |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
755 plan[nb_args-1-i][1]=args_size/4; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
756 args_size += 4; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
757 } |
307 | 758 } |
759 } | |
760 args_size = keep = 0; | |
295 | 761 for(i = 0;i < nb_args; i++) { |
307 | 762 vnrott(keep+1); |
295 | 763 if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) { |
764 size = type_size(&vtop->type, &align); | |
765 /* align to stack align size */ | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
766 size = (size + 3) & -4; |
295 | 767 /* allocate the necessary size on stack */ |
768 gadd_sp(-size); | |
769 /* generate structure store */ | |
770 r = get_reg(RC_INT); | |
771 o(0xE1A0000D|(intr(r)<<12)); | |
772 vset(&vtop->type, r | VT_LVAL, 0); | |
773 vswap(); | |
774 vstore(); | |
307 | 775 vtop--; |
295 | 776 args_size += size; |
777 } else if (is_float(vtop->type.t)) { | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
778 #ifdef TCC_ARM_VFP |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
779 r=vfpr(gv(RC_FLOAT))<<12; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
780 size=4; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
781 if ((vtop->type.t & VT_BTYPE) != VT_FLOAT) |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
782 { |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
783 size=8; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
784 r|=0x101; /* fstms -> fstmd */ |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
785 } |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
786 o(0xED2D0A01+r); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
787 #else |
295 | 788 r=fpr(gv(RC_FLOAT))<<12; |
789 if ((vtop->type.t & VT_BTYPE) == VT_FLOAT) | |
790 size = 4; | |
791 else if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) | |
792 size = 8; | |
793 else | |
794 size = LDOUBLE_SIZE; | |
795 | |
796 if (size == 12) | |
797 r|=0x400000; | |
798 else if(size == 8) | |
799 r|=0x8000; | |
800 | |
307 | 801 o(0xED2D0100|r|(size>>2)); |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
802 #endif |
307 | 803 vtop--; |
295 | 804 args_size += size; |
805 } else { | |
307 | 806 int s; |
295 | 807 /* simple type (currently always same size) */ |
808 /* XXX: implicit cast ? */ | |
307 | 809 size=4; |
295 | 810 if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { |
307 | 811 lexpand_nr(); |
812 s=RC_INT; | |
813 if(nb_args-i<5 && plan[nb_args-i-1][1]!=-1) { | |
814 s=regmask(plan[nb_args-i-1][1]); | |
815 todo&=~(1<<plan[nb_args-i-1][1]); | |
816 } | |
817 if(s==RC_INT) { | |
818 r = gv(s); | |
819 o(0xE52D0004|(intr(r)<<12)); /* str r,[sp,#-4]! */ | |
820 vtop--; | |
821 } else { | |
822 plan2[keep]=s; | |
823 keep++; | |
824 vswap(); | |
825 } | |
295 | 826 size = 8; |
307 | 827 } |
828 s=RC_INT; | |
829 if(nb_args-i<5 && plan[nb_args-i-1][0]!=-1) { | |
830 s=regmask(plan[nb_args-i-1][0]); | |
831 todo&=~(1<<plan[nb_args-i-1][0]); | |
832 } | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
833 #ifdef TCC_ARM_EABI |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
834 if(vtop->type.t == VT_VOID) { |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
835 if(s == RC_INT) |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
836 o(0xE24DD004); /* sub sp,sp,#4 */ |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
837 vtop--; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
838 } else |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
839 #endif |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
840 if(s == RC_INT) { |
307 | 841 r = gv(s); |
842 o(0xE52D0004|(intr(r)<<12)); /* str r,[sp,#-4]! */ | |
843 vtop--; | |
295 | 844 } else { |
307 | 845 plan2[keep]=s; |
846 keep++; | |
295 | 847 } |
848 args_size += size; | |
849 } | |
850 } | |
307 | 851 for(i=keep;i--;) { |
852 gv(plan2[i]); | |
853 vrott(keep); | |
854 } | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
855 save_regs(keep); /* save used temporary registers */ |
307 | 856 keep++; |
295 | 857 if(args_size) { |
858 int n; | |
859 n=args_size/4; | |
860 if(n>4) | |
861 n=4; | |
307 | 862 todo&=((1<<n)-1); |
863 if(todo) { | |
864 int i; | |
865 o(0xE8BD0000|todo); | |
866 for(i=0;i<4;i++) | |
867 if(todo&(1<<i)) { | |
868 vpushi(0); | |
869 vtop->r=i; | |
870 keep++; | |
871 } | |
872 } | |
295 | 873 args_size-=n*4; |
874 } | |
307 | 875 vnrott(keep); |
295 | 876 func_sym = vtop->type.ref; |
877 gcall_or_jmp(0); | |
878 if (args_size) | |
879 gadd_sp(args_size); | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
880 #ifdef TCC_ARM_EABI |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
881 if((vtop->type.ref->type.t & VT_BTYPE) == VT_STRUCT |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
882 && type_size(&vtop->type.ref->type, &align) <= 4) |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
883 { |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
884 store(REG_IRET,vtop-keep); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
885 ++keep; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
886 } |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
887 #ifdef TCC_ARM_VFP |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
888 else if(is_float(vtop->type.ref->type.t)) { |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
889 if((vtop->type.ref->type.t & VT_BTYPE) == VT_FLOAT) { |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
890 o(0xEE000A10); /* fmsr s0,r0 */ |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
891 } else { |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
892 o(0xEE000B10); /* fmdlr d0,r0 */ |
410 | 893 o(0xEE201B10); /* fmdhr d0,r1 */ |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
894 } |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
895 } |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
896 #endif |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
897 #endif |
307 | 898 vtop-=keep; |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
899 leaffunc = 0; |
295 | 900 } |
901 | |
902 /* generate function prolog of type 't' */ | |
903 void gfunc_prolog(CType *func_type) | |
904 { | |
905 Sym *sym,*sym2; | |
906 int n,addr,size,align; | |
907 | |
908 sym = func_type->ref; | |
909 func_vt = sym->type; | |
910 | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
911 n = 0; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
912 addr = 0; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
913 if((func_vt.t & VT_BTYPE) == VT_STRUCT |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
914 && type_size(&func_vt,&align) > 4) |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
915 { |
295 | 916 func_vc = addr; |
917 addr += 4; | |
918 n++; | |
919 } | |
920 for(sym2=sym->next;sym2 && n<4;sym2=sym2->next) { | |
921 size = type_size(&sym2->type, &align); | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
922 n += (size + 3) / 4; |
295 | 923 } |
924 o(0xE1A0C00D); /* mov ip,sp */ | |
925 if(func_type->ref->c == FUNC_ELLIPSIS) | |
926 n=4; | |
927 if(n) { | |
928 if(n>4) | |
929 n=4; | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
930 #ifdef TCC_ARM_EABI |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
931 n=(n+1)&-2; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
932 #endif |
295 | 933 o(0xE92D0000|((1<<n)-1)); /* save r0-r4 on stack if needed */ |
934 } | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
935 o(0xE92D5800); /* save fp, ip, lr */ |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
936 o(0xE28DB00C); /* add fp, sp, #12 */ |
295 | 937 func_sub_sp_offset = ind; |
938 o(0xE1A00000); /* nop, leave space for stack adjustment */ | |
939 while ((sym = sym->next)) { | |
940 CType *type; | |
941 type = &sym->type; | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
942 size = type_size(type, &align); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
943 size = (size + 3) & -4; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
944 #ifdef TCC_ARM_EABI |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
945 addr = (addr + align - 1) & -align; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
946 #endif |
295 | 947 sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr); |
948 addr += size; | |
949 } | |
950 last_itod_magic=0; | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
951 leaffunc = 1; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
952 loc = -12; |
295 | 953 } |
954 | |
955 /* generate function epilog */ | |
956 void gfunc_epilog(void) | |
957 { | |
958 unsigned long x; | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
959 int diff; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
960 #ifdef TCC_ARM_EABI |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
961 if(is_float(func_vt.t)) { |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
962 if((func_vt.t & VT_BTYPE) == VT_FLOAT) |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
963 o(0xEE100A10); /* fmrs r0, s0 */ |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
964 else { |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
965 o(0xEE100B10); /* fmrdl r0, d0 */ |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
966 o(0xEE301B10); /* fmrdh r1, d0 */ |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
967 } |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
968 } |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
969 #endif |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
970 o(0xE91BA800); /* restore fp, sp, pc */ |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
971 diff = (-loc + 3) & -4; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
972 #ifdef TCC_ARM_EABI |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
973 if(!leaffunc) |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
974 diff = (diff + 7) & -8; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
975 #endif |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
976 if(diff > 12) { |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
977 x=stuff_const(0xE24BD000, diff); /* sub sp,fp,# */ |
295 | 978 if(x) |
979 *(unsigned long *)(cur_text_section->data + func_sub_sp_offset) = x; | |
980 else { | |
981 unsigned long addr; | |
982 addr=ind; | |
983 o(0xE59FC004); /* ldr ip,[pc+4] */ | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
984 o(0xE04BD00C); /* sub sp,fp,ip */ |
295 | 985 o(0xE1A0F00E); /* mov pc,lr */ |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
986 o(diff); |
295 | 987 *(unsigned long *)(cur_text_section->data + func_sub_sp_offset) = 0xE1000000|encbranch(func_sub_sp_offset,addr,1); |
988 } | |
989 } | |
990 } | |
991 | |
992 /* generate a jump to a label */ | |
993 int gjmp(int t) | |
994 { | |
995 int r; | |
996 r=ind; | |
997 o(0xE0000000|encbranch(r,t,1)); | |
998 return r; | |
999 } | |
1000 | |
1001 /* generate a jump to a fixed address */ | |
1002 void gjmp_addr(int a) | |
1003 { | |
1004 gjmp(a); | |
1005 } | |
1006 | |
1007 /* generate a test. set 'inv' to invert test. Stack entry is popped */ | |
1008 int gtst(int inv, int t) | |
1009 { | |
1010 int v, r; | |
1011 unsigned long op; | |
1012 v = vtop->r & VT_VALMASK; | |
1013 r=ind; | |
1014 if (v == VT_CMP) { | |
1015 op=mapcc(inv?negcc(vtop->c.i):vtop->c.i); | |
1016 op|=encbranch(r,t,1); | |
1017 o(op); | |
1018 t=r; | |
1019 } else if (v == VT_JMP || v == VT_JMPI) { | |
1020 if ((v & 1) == inv) { | |
1021 if(!vtop->c.i) | |
1022 vtop->c.i=t; | |
1023 else { | |
1024 unsigned long *x; | |
1025 int p,lp; | |
1026 if(t) { | |
1027 p = vtop->c.i; | |
1028 do { | |
1029 p = decbranch(lp=p); | |
1030 } while(p); | |
1031 x = (unsigned long *)(cur_text_section->data + lp); | |
1032 *x &= 0xff000000; | |
1033 *x |= encbranch(lp,t,1); | |
1034 } | |
1035 t = vtop->c.i; | |
1036 } | |
1037 } else { | |
1038 t = gjmp(t); | |
1039 gsym(vtop->c.i); | |
1040 } | |
1041 } else { | |
1042 if (is_float(vtop->type.t)) { | |
1043 r=gv(RC_FLOAT); | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1044 #ifdef TCC_ARM_VFP |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1045 o(0xEEB50A40|(vfpr(r)<<12)|T2CPR(vtop->type.t)); /* fcmpzX */ |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1046 o(0xEEF1FA10); /* fmstat */ |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1047 #else |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1048 o(0xEE90F118|(fpr(r)<<16)); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1049 #endif |
295 | 1050 vtop->r = VT_CMP; |
1051 vtop->c.i = TOK_NE; | |
1052 return gtst(inv, t); | |
1053 } else if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { | |
1054 /* constant jmp optimization */ | |
1055 if ((vtop->c.i != 0) != inv) | |
1056 t = gjmp(t); | |
1057 } else { | |
1058 v = gv(RC_INT); | |
1059 o(0xE3300000|(intr(v)<<16)); | |
1060 vtop->r = VT_CMP; | |
1061 vtop->c.i = TOK_NE; | |
1062 return gtst(inv, t); | |
1063 } | |
1064 } | |
1065 vtop--; | |
1066 return t; | |
1067 } | |
1068 | |
1069 /* generate an integer binary operation */ | |
1070 void gen_opi(int op) | |
1071 { | |
337 | 1072 int c, func = 0; |
1073 unsigned long opc = 0,r,fr; | |
295 | 1074 |
1075 c=0; | |
1076 switch(op) { | |
1077 case '+': | |
1078 opc = 0x8; | |
1079 c=1; | |
1080 break; | |
1081 case TOK_ADDC1: /* add with carry generation */ | |
1082 opc = 0x9; | |
1083 c=1; | |
1084 break; | |
1085 case '-': | |
1086 opc = 0x4; | |
1087 c=1; | |
1088 break; | |
1089 case TOK_SUBC1: /* sub with carry generation */ | |
1090 opc = 0x5; | |
1091 c=1; | |
1092 break; | |
1093 case TOK_ADDC2: /* add with carry use */ | |
1094 opc = 0xA; | |
1095 c=1; | |
1096 break; | |
1097 case TOK_SUBC2: /* sub with carry use */ | |
1098 opc = 0xC; | |
1099 c=1; | |
1100 break; | |
1101 case '&': | |
1102 opc = 0x0; | |
1103 c=1; | |
1104 break; | |
1105 case '^': | |
1106 opc = 0x2; | |
1107 c=1; | |
1108 break; | |
1109 case '|': | |
1110 opc = 0x18; | |
1111 c=1; | |
1112 break; | |
1113 case '*': | |
1114 gv2(RC_INT, RC_INT); | |
1115 r = vtop[-1].r; | |
1116 fr = vtop[0].r; | |
1117 vtop--; | |
1118 o(0xE0000090|(intr(r)<<16)|(intr(r)<<8)|intr(fr)); | |
1119 return; | |
1120 case TOK_SHL: | |
1121 opc = 0; | |
1122 c=2; | |
1123 break; | |
1124 case TOK_SHR: | |
1125 opc = 1; | |
1126 c=2; | |
1127 break; | |
1128 case TOK_SAR: | |
1129 opc = 2; | |
1130 c=2; | |
1131 break; | |
1132 case '/': | |
1133 case TOK_PDIV: | |
1134 func=TOK___divsi3; | |
1135 c=3; | |
1136 break; | |
1137 case TOK_UDIV: | |
1138 func=TOK___udivsi3; | |
1139 c=3; | |
1140 break; | |
1141 case '%': | |
1142 func=TOK___modsi3; | |
1143 c=3; | |
1144 break; | |
1145 case TOK_UMOD: | |
1146 func=TOK___umodsi3; | |
1147 c=3; | |
1148 break; | |
1149 case TOK_UMULL: | |
1150 gv2(RC_INT, RC_INT); | |
1151 r=intr(vtop[-1].r2=get_reg(RC_INT)); | |
1152 c=vtop[-1].r; | |
1153 vtop[-1].r=get_reg_ex(RC_INT,regmask(c)); | |
1154 vtop--; | |
1155 o(0xE0800090|(r<<16)|(intr(vtop->r)<<12)|(intr(c)<<8)|intr(vtop[1].r)); | |
1156 return; | |
1157 default: | |
1158 opc = 0x15; | |
1159 c=1; | |
337 | 1160 break; |
295 | 1161 } |
1162 switch(c) { | |
1163 case 1: | |
1164 if((vtop[-1].r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { | |
1165 if(opc == 4 || opc == 5 || opc == 0xc) { | |
1166 vswap(); | |
1167 opc|=2; // sub -> rsb | |
1168 } | |
1169 } | |
307 | 1170 if ((vtop->r & VT_VALMASK) == VT_CMP || |
1171 (vtop->r & (VT_VALMASK & ~1)) == VT_JMP) | |
1172 gv(RC_INT); | |
295 | 1173 vswap(); |
1174 c=intr(gv(RC_INT)); | |
1175 vswap(); | |
1176 opc=0xE0000000|(opc<<20)|(c<<16); | |
1177 if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { | |
1178 unsigned long x; | |
1179 x=stuff_const(opc|0x2000000,vtop->c.i); | |
1180 if(x) { | |
1181 r=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r))); | |
1182 o(x|(r<<12)); | |
1183 goto done; | |
1184 } | |
1185 } | |
1186 fr=intr(gv(RC_INT)); | |
1187 r=intr(vtop[-1].r=get_reg_ex(RC_INT,two2mask(vtop->r,vtop[-1].r))); | |
1188 o(opc|(r<<12)|fr); | |
1189 done: | |
1190 vtop--; | |
1191 if (op >= TOK_ULT && op <= TOK_GT) { | |
1192 vtop->r = VT_CMP; | |
1193 vtop->c.i = op; | |
1194 } | |
1195 break; | |
1196 case 2: | |
1197 opc=0xE1A00000|(opc<<5); | |
307 | 1198 if ((vtop->r & VT_VALMASK) == VT_CMP || |
1199 (vtop->r & (VT_VALMASK & ~1)) == VT_JMP) | |
1200 gv(RC_INT); | |
295 | 1201 vswap(); |
1202 r=intr(gv(RC_INT)); | |
1203 vswap(); | |
1204 opc|=r; | |
1205 if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { | |
1206 fr=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r))); | |
1207 c = vtop->c.i & 0x1f; | |
1208 o(opc|(c<<7)|(fr<<12)); | |
1209 } else { | |
1210 fr=intr(gv(RC_INT)); | |
1211 c=intr(vtop[-1].r=get_reg_ex(RC_INT,two2mask(vtop->r,vtop[-1].r))); | |
1212 o(opc|(c<<12)|(fr<<8)|0x10); | |
1213 } | |
1214 vtop--; | |
1215 break; | |
1216 case 3: | |
1217 vpush_global_sym(&func_old_type, func); | |
1218 vrott(3); | |
1219 gfunc_call(2); | |
1220 vpushi(0); | |
1221 vtop->r = REG_IRET; | |
1222 break; | |
1223 default: | |
1224 error("gen_opi %i unimplemented!",op); | |
1225 } | |
1226 } | |
1227 | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1228 #ifdef TCC_ARM_VFP |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1229 static int is_zero(int i) |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1230 { |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1231 if((vtop[i].r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1232 return 0; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1233 if (vtop[i].type.t == VT_FLOAT) |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1234 return (vtop[i].c.f == 0.f); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1235 else if (vtop[i].type.t == VT_DOUBLE) |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1236 return (vtop[i].c.d == 0.0); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1237 return (vtop[i].c.ld == 0.l); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1238 } |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1239 |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1240 /* generate a floating point operation 'v = t1 op t2' instruction. The |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1241 * two operands are guaranted to have the same floating point type */ |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1242 void gen_opf(int op) |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1243 { |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1244 unsigned long x; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1245 int fneg=0,r; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1246 x=0xEE000A00|T2CPR(vtop->type.t); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1247 switch(op) { |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1248 case '+': |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1249 if(is_zero(-1)) |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1250 vswap(); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1251 if(is_zero(0)) { |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1252 vtop--; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1253 return; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1254 } |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1255 x|=0x300000; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1256 break; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1257 case '-': |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1258 x|=0x300040; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1259 if(is_zero(0)) { |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1260 vtop--; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1261 return; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1262 } |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1263 if(is_zero(-1)) { |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1264 x|=0x810000; /* fsubX -> fnegX */ |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1265 vswap(); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1266 vtop--; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1267 fneg=1; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1268 } |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1269 break; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1270 case '*': |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1271 x|=0x200000; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1272 break; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1273 case '/': |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1274 x|=0x800000; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1275 break; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1276 default: |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1277 if(op < TOK_ULT && op > TOK_GT) { |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1278 error("unknown fp op %x!",op); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1279 return; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1280 } |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1281 if(is_zero(-1)) { |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1282 vswap(); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1283 switch(op) { |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1284 case TOK_LT: op=TOK_GT; break; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1285 case TOK_GE: op=TOK_ULE; break; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1286 case TOK_LE: op=TOK_GE; break; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1287 case TOK_GT: op=TOK_ULT; break; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1288 } |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1289 } |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1290 x|=0xB40040; /* fcmpX */ |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1291 if(op!=TOK_EQ && op!=TOK_NE) |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1292 x|=0x80; /* fcmpX -> fcmpeX */ |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1293 if(is_zero(0)) { |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1294 vtop--; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1295 o(x|0x10000|(vfpr(gv(RC_FLOAT))<<12)); /* fcmp(e)X -> fcmp(e)zX */ |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1296 } else { |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1297 x|=vfpr(gv(RC_FLOAT)); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1298 vswap(); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1299 o(x|(vfpr(gv(RC_FLOAT))<<12)); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1300 vtop--; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1301 } |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1302 o(0xEEF1FA10); /* fmstat */ |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1303 |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1304 switch(op) { |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1305 case TOK_LE: op=TOK_ULE; break; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1306 case TOK_LT: op=TOK_ULT; break; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1307 case TOK_UGE: op=TOK_GE; break; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1308 case TOK_UGT: op=TOK_GT; break; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1309 } |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1310 |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1311 vtop->r = VT_CMP; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1312 vtop->c.i = op; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1313 return; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1314 } |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1315 r=gv(RC_FLOAT); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1316 x|=vfpr(r); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1317 r=regmask(r); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1318 if(!fneg) { |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1319 int r2; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1320 vswap(); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1321 r2=gv(RC_FLOAT); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1322 x|=vfpr(r2)<<16; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1323 r|=regmask(r2); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1324 } |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1325 vtop->r=get_reg_ex(RC_FLOAT,r); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1326 if(!fneg) |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1327 vtop--; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1328 o(x|(vfpr(vtop->r)<<12)); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1329 } |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1330 |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1331 #else |
295 | 1332 static int is_fconst() |
1333 { | |
1334 long double f; | |
1335 int r; | |
1336 if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) | |
1337 return 0; | |
1338 if (vtop->type.t == VT_FLOAT) | |
1339 f = vtop->c.f; | |
1340 else if (vtop->type.t == VT_DOUBLE) | |
1341 f = vtop->c.d; | |
1342 else | |
1343 f = vtop->c.ld; | |
1344 if(!ieee_finite(f)) | |
1345 return 0; | |
1346 r=0x8; | |
1347 if(f<0.0) { | |
1348 r=0x18; | |
1349 f=-f; | |
1350 } | |
1351 if(f==0.0) | |
1352 return r; | |
1353 if(f==1.0) | |
1354 return r|1; | |
1355 if(f==2.0) | |
1356 return r|2; | |
1357 if(f==3.0) | |
1358 return r|3; | |
1359 if(f==4.0) | |
1360 return r|4; | |
1361 if(f==5.0) | |
1362 return r|5; | |
1363 if(f==0.5) | |
1364 return r|6; | |
1365 if(f==10.0) | |
1366 return r|7; | |
1367 return 0; | |
1368 } | |
1369 | |
1370 /* generate a floating point operation 'v = t1 op t2' instruction. The | |
1371 two operands are guaranted to have the same floating point type */ | |
1372 void gen_opf(int op) | |
1373 { | |
1374 unsigned long x; | |
1375 int r,r2,c1,c2; | |
1376 //fputs("gen_opf\n",stderr); | |
1377 vswap(); | |
1378 c1 = is_fconst(); | |
1379 vswap(); | |
1380 c2 = is_fconst(); | |
307 | 1381 x=0xEE000100; |
1382 #if LDOUBLE_SIZE == 8 | |
1383 if ((vtop->type.t & VT_BTYPE) != VT_FLOAT) | |
1384 x|=0x80; | |
1385 #else | |
1386 if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) | |
1387 x|=0x80; | |
1388 else if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) | |
1389 x|=0x80000; | |
1390 #endif | |
295 | 1391 switch(op) |
1392 { | |
1393 case '+': | |
1394 if(!c2) { | |
1395 vswap(); | |
1396 c2=c1; | |
1397 } | |
1398 vswap(); | |
1399 r=fpr(gv(RC_FLOAT)); | |
1400 vswap(); | |
1401 if(c2) { | |
1402 if(c2>0xf) | |
1403 x|=0x200000; // suf | |
1404 r2=c2&0xf; | |
1405 } else { | |
1406 r2=fpr(gv(RC_FLOAT)); | |
1407 } | |
1408 break; | |
1409 case '-': | |
1410 if(c2) { | |
1411 if(c2<=0xf) | |
1412 x|=0x200000; // suf | |
1413 r2=c2&0xf; | |
1414 vswap(); | |
1415 r=fpr(gv(RC_FLOAT)); | |
1416 vswap(); | |
1417 } else if(c1 && c1<=0xf) { | |
1418 x|=0x300000; // rsf | |
1419 r2=c1; | |
1420 r=fpr(gv(RC_FLOAT)); | |
1421 vswap(); | |
1422 } else { | |
1423 x|=0x200000; // suf | |
1424 vswap(); | |
1425 r=fpr(gv(RC_FLOAT)); | |
1426 vswap(); | |
1427 r2=fpr(gv(RC_FLOAT)); | |
1428 } | |
1429 break; | |
1430 case '*': | |
1431 if(!c2 || c2>0xf) { | |
1432 vswap(); | |
1433 c2=c1; | |
1434 } | |
1435 vswap(); | |
1436 r=fpr(gv(RC_FLOAT)); | |
1437 vswap(); | |
1438 if(c2 && c2<=0xf) | |
1439 r2=c2; | |
1440 else | |
1441 r2=fpr(gv(RC_FLOAT)); | |
1442 x|=0x100000; // muf | |
1443 break; | |
1444 case '/': | |
1445 if(c2 && c2<=0xf) { | |
1446 x|=0x400000; // dvf | |
1447 r2=c2; | |
1448 vswap(); | |
1449 r=fpr(gv(RC_FLOAT)); | |
1450 vswap(); | |
1451 } else if(c1 && c1<=0xf) { | |
1452 x|=0x500000; // rdf | |
1453 r2=c1; | |
1454 r=fpr(gv(RC_FLOAT)); | |
1455 vswap(); | |
1456 } else { | |
1457 x|=0x400000; // dvf | |
1458 vswap(); | |
1459 r=fpr(gv(RC_FLOAT)); | |
1460 vswap(); | |
1461 r2=fpr(gv(RC_FLOAT)); | |
1462 } | |
1463 break; | |
1464 default: | |
1465 if(op >= TOK_ULT && op <= TOK_GT) { | |
307 | 1466 x|=0xd0f110; // cmfe |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1467 /* bug (intention?) in Linux FPU emulator |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1468 doesn't set carry if equal */ |
295 | 1469 switch(op) { |
1470 case TOK_ULT: | |
1471 case TOK_UGE: | |
1472 case TOK_ULE: | |
1473 case TOK_UGT: | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1474 error("unsigned comparision on floats?"); |
295 | 1475 break; |
1476 case TOK_LT: | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1477 op=TOK_Nset; |
295 | 1478 break; |
1479 case TOK_LE: | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1480 op=TOK_ULE; /* correct in unordered case only if AC bit in FPSR set */ |
295 | 1481 break; |
307 | 1482 case TOK_EQ: |
1483 case TOK_NE: | |
1484 x&=~0x400000; // cmfe -> cmf | |
1485 break; | |
295 | 1486 } |
1487 if(c1 && !c2) { | |
1488 c2=c1; | |
1489 vswap(); | |
1490 switch(op) { | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1491 case TOK_Nset: |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1492 op=TOK_GT; |
295 | 1493 break; |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1494 case TOK_GE: |
295 | 1495 op=TOK_ULE; |
1496 break; | |
1497 case TOK_ULE: | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1498 op=TOK_GE; |
295 | 1499 break; |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1500 case TOK_GT: |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1501 op=TOK_Nset; |
295 | 1502 break; |
1503 } | |
1504 } | |
1505 vswap(); | |
1506 r=fpr(gv(RC_FLOAT)); | |
1507 vswap(); | |
1508 if(c2) { | |
1509 if(c2>0xf) | |
1510 x|=0x200000; | |
1511 r2=c2&0xf; | |
1512 } else { | |
1513 r2=fpr(gv(RC_FLOAT)); | |
1514 } | |
1515 vtop[-1].r = VT_CMP; | |
1516 vtop[-1].c.i = op; | |
1517 } else { | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1518 error("unknown fp op %x!",op); |
295 | 1519 return; |
1520 } | |
1521 } | |
1522 if(vtop[-1].r == VT_CMP) | |
1523 c1=15; | |
1524 else { | |
1525 c1=vtop->r; | |
1526 if(r2&0x8) | |
1527 c1=vtop[-1].r; | |
1528 vtop[-1].r=get_reg_ex(RC_FLOAT,two2mask(vtop[-1].r,c1)); | |
1529 c1=fpr(vtop[-1].r); | |
1530 } | |
1531 vtop--; | |
1532 o(x|(r<<16)|(c1<<12)|r2); | |
1533 } | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1534 #endif |
295 | 1535 |
1536 /* convert integers to fp 't' type. Must handle 'int', 'unsigned int' | |
1537 and 'long long' cases. */ | |
1538 void gen_cvt_itof(int t) | |
1539 { | |
1540 int r,r2,bt; | |
1541 bt=vtop->type.t & VT_BTYPE; | |
1542 if(bt == VT_INT || bt == VT_SHORT || bt == VT_BYTE) { | |
307 | 1543 r=intr(gv(RC_INT)); |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1544 #ifdef TCC_ARM_VFP |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1545 r2=vfpr(vtop->r=get_reg(RC_FLOAT)); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1546 o(0xEE000A10|(r<<12)|(r2<<16)); /* fmsr */ |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1547 r2<<=12; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1548 if(!(vtop->type.t & VT_UNSIGNED)) |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1549 r2|=0x80; /* fuitoX -> fsituX */ |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1550 o(0xEEB80A40|r2|T2CPR(t)); /* fYitoX*/ |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1551 #else |
307 | 1552 r2=fpr(vtop->r=get_reg(RC_FLOAT)); |
295 | 1553 o(0xEE000190|(r2<<16)|(r<<12)); |
1554 if((vtop->type.t & (VT_UNSIGNED|VT_BTYPE)) == (VT_UNSIGNED|VT_INT)) { | |
1555 unsigned int off=0; | |
1556 o(0xE3500000|(r<<12)); | |
1557 r=fpr(get_reg(RC_FLOAT)); | |
1558 if(last_itod_magic) { | |
1559 off=ind+8-last_itod_magic; | |
1560 off/=4; | |
1561 if(off>255) | |
1562 off=0; | |
1563 } | |
1564 o(0xBD1F8100|(r<<12)|off); | |
1565 if(!off) { | |
1566 o(0xEA000001); | |
1567 last_itod_magic=ind; | |
1568 o(0x41F00000); | |
1569 o(0); | |
1570 } | |
1571 o(0xBE000180|(r2<<16)|(r2<<12)|r); | |
1572 } | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1573 #endif |
295 | 1574 return; |
1575 } else if(bt == VT_LLONG) { | |
307 | 1576 int func; |
410 | 1577 CType *func_type = &func_old_type; |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1578 #ifdef TCC_ARM_VFP |
410 | 1579 #ifdef TCC_ARM_EABI |
1580 func_type = &func_double_type; | |
1581 #endif | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1582 if((t & VT_BTYPE) == VT_FLOAT) { |
410 | 1583 #ifdef TCC_ARM_EABI |
1584 func_type = &func_float_type; | |
1585 #endif | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1586 if(vtop->type.t & VT_UNSIGNED) |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1587 func=TOK___ulltof; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1588 else |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1589 func=TOK___slltof; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1590 } else |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1591 #endif |
307 | 1592 if(vtop->type.t & VT_UNSIGNED) |
1593 func=TOK___ulltold; | |
1594 else | |
1595 func=TOK___slltold; | |
410 | 1596 vpush_global_sym(func_type, func); |
307 | 1597 vswap(); |
1598 gfunc_call(1); | |
1599 vpushi(0); | |
1600 vtop->r=TREG_F0; | |
295 | 1601 return; |
1602 } | |
1603 error("unimplemented gen_cvt_itof %x!",vtop->type.t); | |
1604 } | |
1605 | |
1606 /* convert fp to int 't' type */ | |
1607 void gen_cvt_ftoi(int t) | |
1608 { | |
307 | 1609 int r,r2,u,func=0; |
295 | 1610 u=t&VT_UNSIGNED; |
1611 t&=VT_BTYPE; | |
307 | 1612 r2=vtop->type.t & VT_BTYPE; |
295 | 1613 if(t==VT_INT) { |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1614 #ifdef TCC_ARM_VFP |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1615 r=vfpr(gv(RC_FLOAT)); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1616 u=u?0:0x10000; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1617 o(0xEEBC0A40|(r<<12)|r|T2CPR(r2)); /* ftoXiY */ |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1618 r2=intr(vtop->r=get_reg(RC_INT)); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1619 o(0xEE100A10|(r<<16)|(r2<<12)); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1620 return; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1621 #else |
295 | 1622 if(u) { |
307 | 1623 if(r2 == VT_FLOAT) |
1624 func=TOK___fixunssfsi; | |
1625 else if(r2 == VT_DOUBLE) | |
1626 func=TOK___fixunsdfsi; | |
1627 else if(r2 == VT_LDOUBLE) | |
1628 #if LDOUBLE_SIZE == 8 | |
1629 func=TOK___fixunsdfsi; | |
1630 #else | |
1631 func=TOK___fixunsxfsi; | |
1632 #endif | |
1633 } else { | |
1634 r=fpr(gv(RC_FLOAT)); | |
1635 r2=intr(vtop->r=get_reg(RC_INT)); | |
1636 o(0xEE100170|(r2<<12)|r); | |
295 | 1637 return; |
1638 } | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1639 #endif |
307 | 1640 } else if(t == VT_LLONG) { // unsigned handled in gen_cvt_ftoi1 |
1641 if(r2 == VT_FLOAT) | |
1642 func=TOK___fixsfdi; | |
1643 else if(r2 == VT_DOUBLE) | |
1644 func=TOK___fixdfdi; | |
1645 else if(r2 == VT_LDOUBLE) | |
1646 #if LDOUBLE_SIZE == 8 | |
1647 func=TOK___fixdfdi; | |
1648 #else | |
1649 func=TOK___fixxfdi; | |
1650 #endif | |
295 | 1651 } |
307 | 1652 if(func) { |
1653 vpush_global_sym(&func_old_type, func); | |
1654 vswap(); | |
1655 gfunc_call(1); | |
1656 vpushi(0); | |
1657 if(t == VT_LLONG) | |
1658 vtop->r2 = REG_LRET; | |
1659 vtop->r = REG_IRET; | |
295 | 1660 return; |
1661 } | |
1662 error("unimplemented gen_cvt_ftoi!"); | |
1663 } | |
1664 | |
1665 /* convert from one floating point type to another */ | |
1666 void gen_cvt_ftof(int t) | |
1667 { | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1668 #ifdef TCC_ARM_VFP |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1669 if(((vtop->type.t & VT_BTYPE) == VT_FLOAT) != ((t & VT_BTYPE) == VT_FLOAT)) { |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1670 int r=vfpr(gv(RC_FLOAT)); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1671 o(0xEEB70AC0|(r<<12)|r|T2CPR(vtop->type.t)); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1672 } |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1673 #else |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1674 /* all we have to do on i386 and FPA ARM is to put the float in a register */ |
295 | 1675 gv(RC_FLOAT); |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
337
diff
changeset
|
1676 #endif |
295 | 1677 } |
1678 | |
1679 /* computed goto support */ | |
546
3f683703c8db
Rename ggoto() to gen_goto().
Rob Landley <rob@landley.net>
parents:
509
diff
changeset
|
1680 void gen_goto(void) |
295 | 1681 { |
1682 gcall_or_jmp(1); | |
1683 vtop--; | |
1684 } | |
1685 | |
1686 /* end of ARM code generator */ | |
1687 /*************************************************************/ | |
1688 |