Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
145 | halyavin | 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 | * |
||
8 | * This library is free software; you can redistribute it and/or |
||
9 | * modify it under the terms of the GNU Lesser General Public |
||
10 | * License as published by the Free Software Foundation; either |
||
11 | * version 2 of the License, or (at your option) any later version. |
||
12 | * |
||
13 | * This library is distributed in the hope that it will be useful, |
||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||
16 | * Lesser General Public License for more details. |
||
17 | * |
||
18 | * You should have received a copy of the GNU Lesser General Public |
||
19 | * License along with this library; if not, write to the Free Software |
||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||
21 | */ |
||
22 | |||
23 | /* number of available registers */ |
||
24 | #define NB_REGS 9 |
||
25 | |||
26 | /* a register can belong to several classes. The classes must be |
||
27 | sorted from more general to more precise (see gv2() code which does |
||
28 | assumptions on it). */ |
||
29 | #define RC_INT 0x0001 /* generic integer register */ |
||
30 | #define RC_FLOAT 0x0002 /* generic float register */ |
||
31 | #define RC_R0 0x0004 |
||
32 | #define RC_R1 0x0008 |
||
33 | #define RC_R2 0x0010 |
||
34 | #define RC_R3 0x0020 |
||
35 | #define RC_R12 0x0040 |
||
36 | #define RC_F0 0x0080 |
||
37 | #define RC_F1 0x0100 |
||
38 | #define RC_F2 0x0200 |
||
39 | #define RC_F3 0x0400 |
||
40 | #define RC_IRET RC_R0 /* function return: integer register */ |
||
41 | #define RC_LRET RC_R1 /* function return: second integer register */ |
||
42 | #define RC_FRET RC_F0 /* function return: float register */ |
||
43 | |||
44 | /* pretty names for the registers */ |
||
45 | enum { |
||
46 | TREG_R0 = 0, |
||
47 | TREG_R1, |
||
48 | TREG_R2, |
||
49 | TREG_R3, |
||
50 | TREG_R12, |
||
51 | TREG_F0, |
||
52 | TREG_F1, |
||
53 | TREG_F2, |
||
54 | TREG_F3, |
||
55 | }; |
||
56 | |||
57 | int reg_classes[NB_REGS] = { |
||
58 | /* r0 */ RC_INT | RC_R0, |
||
59 | /* r1 */ RC_INT | RC_R1, |
||
60 | /* r2 */ RC_INT | RC_R2, |
||
61 | /* r3 */ RC_INT | RC_R3, |
||
62 | /* r12 */ RC_INT | RC_R12, |
||
63 | /* f0 */ RC_FLOAT | RC_F0, |
||
64 | /* f1 */ RC_FLOAT | RC_F1, |
||
65 | /* f2 */ RC_FLOAT | RC_F2, |
||
66 | /* f3 */ RC_FLOAT | RC_F3, |
||
67 | }; |
||
68 | |||
69 | static int two2mask(int a,int b) { |
||
70 | return (reg_classes[a]|reg_classes[b])&~(RC_INT|RC_FLOAT); |
||
71 | } |
||
72 | |||
73 | static int regmask(int r) { |
||
74 | return reg_classes[r]&~(RC_INT|RC_FLOAT); |
||
75 | } |
||
76 | |||
77 | /* return registers for function */ |
||
78 | #define REG_IRET TREG_R0 /* single word int return register */ |
||
79 | #define REG_LRET TREG_R1 /* second word return register (for long long) */ |
||
80 | #define REG_FRET TREG_F0 /* float return register */ |
||
81 | |||
82 | /* defined if function parameters must be evaluated in reverse order */ |
||
83 | #define INVERT_FUNC_PARAMS |
||
84 | |||
85 | /* defined if structures are passed as pointers. Otherwise structures |
||
86 | are directly pushed on stack. */ |
||
87 | //#define FUNC_STRUCT_PARAM_AS_PTR |
||
88 | |||
89 | /* pointer size, in bytes */ |
||
90 | #define PTR_SIZE 4 |
||
91 | |||
92 | /* long double size and alignment, in bytes */ |
||
93 | #define LDOUBLE_SIZE 8 |
||
94 | #define LDOUBLE_ALIGN 4 |
||
95 | /* maximum alignment (for aligned attribute support) */ |
||
96 | #define MAX_ALIGN 8 |
||
97 | |||
98 | #define CHAR_IS_UNSIGNED |
||
99 | |||
100 | /******************************************************/ |
||
101 | /* ELF defines */ |
||
102 | |||
103 | #define EM_TCC_TARGET EM_ARM |
||
104 | |||
105 | /* relocation type for 32 bit data relocation */ |
||
106 | #define R_DATA_32 R_ARM_ABS32 |
||
107 | #define R_JMP_SLOT R_ARM_JUMP_SLOT |
||
108 | #define R_COPY R_ARM_COPY |
||
109 | |||
110 | #define ELF_START_ADDR 0x00008000 |
||
111 | #define ELF_PAGE_SIZE 0x1000 |
||
112 | |||
113 | /******************************************************/ |
||
114 | static unsigned long func_sub_sp_offset,last_itod_magic; |
||
115 | |||
116 | void o(unsigned long i) |
||
117 | { |
||
118 | /* this is a good place to start adding big-endian support*/ |
||
119 | int ind1; |
||
120 | |||
121 | ind1 = ind + 4; |
||
122 | if (!cur_text_section) |
||
123 | error("compiler error! This happens f.ex. if the compiler\n" |
||
124 | "can't evaluate constant expressions outside of a function."); |
||
125 | if (ind1 > cur_text_section->data_allocated) |
||
126 | section_realloc(cur_text_section, ind1); |
||
127 | cur_text_section->data[ind++] = i&255; |
||
128 | i>>=8; |
||
129 | cur_text_section->data[ind++] = i&255; |
||
130 | i>>=8; |
||
131 | cur_text_section->data[ind++] = i&255; |
||
132 | i>>=8; |
||
133 | cur_text_section->data[ind++] = i; |
||
134 | } |
||
135 | |||
136 | static unsigned long stuff_const(unsigned long op,unsigned long c) |
||
137 | { |
||
138 | int try_neg=0; |
||
139 | unsigned long nc = 0,negop = 0; |
||
140 | |||
141 | switch(op&0x1F00000) |
||
142 | { |
||
143 | case 0x800000: //add |
||
144 | case 0x400000: //sub |
||
145 | try_neg=1; |
||
146 | negop=op^0xC00000; |
||
147 | nc=-c; |
||
148 | break; |
||
149 | case 0x1A00000: //mov |
||
150 | case 0x1E00000: //mvn |
||
151 | try_neg=1; |
||
152 | negop=op^0x400000; |
||
153 | nc=~c; |
||
154 | break; |
||
155 | case 0x200000: //xor |
||
156 | if(c==~0) |
||
157 | return (op&0xF010F000)|((op>>16)&0xF)|0x1E00000; |
||
158 | break; |
||
159 | case 0x0: //and |
||
160 | if(c==~0) |
||
161 | return (op&0xF010F000)|((op>>16)&0xF)|0x1A00000; |
||
162 | case 0x1C00000: //bic |
||
163 | try_neg=1; |
||
164 | negop=op^0x1C00000; |
||
165 | nc=~c; |
||
166 | break; |
||
167 | case 0x1800000: //orr |
||
168 | if(c==~0) |
||
169 | return (op&0xFFF0FFFF)|0x1E00000; |
||
170 | break; |
||
171 | } |
||
172 | do { |
||
173 | unsigned long m; |
||
174 | int i; |
||
175 | if(c<256) /* catch undefined <<32 */ |
||
176 | return op|c; |
||
177 | for(i=2;i<32;i+=2) { |
||
178 | m=(0xff>>i)|(0xff<<(32-i)); |
||
179 | if(!(c&~m)) |
||
180 | return op|(i<<7)|(c<>(32-i)); |
||
181 | } |
||
182 | op=negop; |
||
183 | c=nc; |
||
184 | } while(try_neg--); |
||
185 | return 0; |
||
186 | } |
||
187 | |||
188 | |||
189 | //only add,sub |
||
190 | void stuff_const_harder(unsigned long op,unsigned long v) { |
||
191 | unsigned long x; |
||
192 | x=stuff_const(op,v); |
||
193 | if(x) |
||
194 | o(x); |
||
195 | else { |
||
196 | unsigned long a[16],nv,no,o2,n2; |
||
197 | int i,j,k; |
||
198 | a[0]=0xff; |
||
199 | o2=(op&0xfff0ffff)|((op&0xf000)<<4);; |
||
200 | for(i=1;i<16;i++) |
||
201 | a[i]=(a[i-1]>>2)|(a[i-1]<<30); |
||
202 | for(i=0;i<12;i++) |
||
203 | for(j=i+4;i<13+i;i++) |
||
204 | if((v&(a[i]|a[j]))==v) { |
||
205 | o(stuff_const(op,v&a[i])); |
||
206 | o(stuff_const(o2,v&a[j])); |
||
207 | return; |
||
208 | } |
||
209 | no=op^0xC00000; |
||
210 | n2=o2^0xC00000; |
||
211 | nv=-v; |
||
212 | for(i=0;i<12;i++) |
||
213 | for(j=i+4;i<13+i;i++) |
||
214 | if((nv&(a[i]|a[j]))==nv) { |
||
215 | o(stuff_const(no,nv&a[i])); |
||
216 | o(stuff_const(n2,nv&a[j])); |
||
217 | return; |
||
218 | } |
||
219 | for(i=0;i<8;i++) |
||
220 | for(j=i+4;i<12;i++) |
||
221 | for(k=j+4;k<13+i;i++) |
||
222 | if((v&(a[i]|a[j]|a[k]))==v) { |
||
223 | o(stuff_const(op,v&a[i])); |
||
224 | o(stuff_const(o2,v&a[j])); |
||
225 | o(stuff_const(o2,v&a[k])); |
||
226 | return; |
||
227 | } |
||
228 | no=op^0xC00000; |
||
229 | nv=-v; |
||
230 | for(i=0;i<8;i++) |
||
231 | for(j=i+4;i<12;i++) |
||
232 | for(k=j+4;k<13+i;i++) |
||
233 | if((nv&(a[i]|a[j]|a[k]))==nv) { |
||
234 | o(stuff_const(no,nv&a[i])); |
||
235 | o(stuff_const(n2,nv&a[j])); |
||
236 | o(stuff_const(n2,nv&a[k])); |
||
237 | return; |
||
238 | } |
||
239 | o(stuff_const(op,v&a[0])); |
||
240 | o(stuff_const(o2,v&a[4])); |
||
241 | o(stuff_const(o2,v&a[8])); |
||
242 | o(stuff_const(o2,v&a[12])); |
||
243 | } |
||
244 | } |
||
245 | |||
246 | unsigned long encbranch(int pos,int addr,int fail) |
||
247 | { |
||
248 | addr-=pos+8; |
||
249 | addr/=4; |
||
250 | if(addr>=0x1000000 || addr<-0x1000000) { |
||
251 | if(fail) |
||
252 | error("FIXME: function bigger than 32MB"); |
||
253 | return 0; |
||
254 | } |
||
255 | return 0x0A000000|(addr&0xffffff); |
||
256 | } |
||
257 | |||
258 | int decbranch(int pos) |
||
259 | { |
||
260 | int x; |
||
261 | x=*(int *)(cur_text_section->data + pos); |
||
262 | x&=0x00ffffff; |
||
263 | if(x&0x800000) |
||
264 | x-=0x1000000; |
||
265 | return x*4+pos+8; |
||
266 | } |
||
267 | |||
268 | /* output a symbol and patch all calls to it */ |
||
269 | void gsym_addr(int t, int a) |
||
270 | { |
||
271 | unsigned long *x; |
||
272 | int lt; |
||
273 | while(t) { |
||
274 | x=(unsigned long *)(cur_text_section->data + t); |
||
275 | t=decbranch(lt=t); |
||
276 | if(a==lt+4) |
||
277 | *x=0xE1A00000; // nop |
||
278 | else { |
||
279 | *x &= 0xff000000; |
||
280 | *x |= encbranch(lt,a,1); |
||
281 | } |
||
282 | } |
||
283 | } |
||
284 | |||
285 | void gsym(int t) |
||
286 | { |
||
287 | gsym_addr(t, ind); |
||
288 | } |
||
289 | |||
290 | static unsigned long fpr(int r) |
||
291 | { |
||
292 | if(r |
||
293 | error("compiler error! register %i is no fp register\n",r); |
||
294 | return r-5; |
||
295 | } |
||
296 | |||
297 | static unsigned long intr(int r) |
||
298 | { |
||
299 | if(r==4) |
||
300 | return 12; |
||
301 | if((r<0 || r>4) && r!=14) |
||
302 | error("compiler error! register %i is no int register\n",r); |
||
303 | return r; |
||
304 | } |
||
305 | |||
306 | static void calcaddr(unsigned long *base,int *off,int *sgn,int maxoff,unsigned shift) |
||
307 | { |
||
308 | if(*off>maxoff || *off&((1< |
||
309 | unsigned long x,y; |
||
310 | x=0xE280E000; |
||
311 | if(*sgn) |
||
312 | x=0xE240E000; |
||
313 | x|=(*base)<<16; |
||
314 | *base=14; // lr |
||
315 | y=stuff_const(x,*off&~maxoff); |
||
316 | if(y) { |
||
317 | o(y); |
||
318 | *off&=maxoff; |
||
319 | return; |
||
320 | } |
||
321 | y=stuff_const(x,(*off+maxoff)&~maxoff); |
||
322 | if(y) { |
||
323 | o(y); |
||
324 | *sgn=!*sgn; |
||
325 | *off=((*off+maxoff)&~maxoff)-*off; |
||
326 | return; |
||
327 | } |
||
328 | stuff_const_harder(x,*off&~maxoff); |
||
329 | *off&=maxoff; |
||
330 | } |
||
331 | } |
||
332 | |||
333 | static unsigned long mapcc(int cc) |
||
334 | { |
||
335 | switch(cc) |
||
336 | { |
||
337 | case TOK_ULT: |
||
338 | return 0x30000000; |
||
339 | case TOK_UGE: |
||
340 | return 0x20000000; |
||
341 | case TOK_EQ: |
||
342 | return 0x00000000; |
||
343 | case TOK_NE: |
||
344 | return 0x10000000; |
||
345 | case TOK_ULE: |
||
346 | return 0x90000000; |
||
347 | case TOK_UGT: |
||
348 | return 0x80000000; |
||
349 | case TOK_LT: |
||
350 | return 0xB0000000; |
||
351 | case TOK_GE: |
||
352 | return 0xA0000000; |
||
353 | case TOK_LE: |
||
354 | return 0xD0000000; |
||
355 | case TOK_GT: |
||
356 | return 0xC0000000; |
||
357 | } |
||
358 | error("unexpected condition code"); |
||
359 | return 0xE0000000; |
||
360 | } |
||
361 | |||
362 | static int negcc(int cc) |
||
363 | { |
||
364 | switch(cc) |
||
365 | { |
||
366 | case TOK_ULT: |
||
367 | return TOK_UGE; |
||
368 | case TOK_UGE: |
||
369 | return TOK_ULT; |
||
370 | case TOK_EQ: |
||
371 | return TOK_NE; |
||
372 | case TOK_NE: |
||
373 | return TOK_EQ; |
||
374 | case TOK_ULE: |
||
375 | return TOK_UGT; |
||
376 | case TOK_UGT: |
||
377 | return TOK_ULE; |
||
378 | case TOK_LT: |
||
379 | return TOK_GE; |
||
380 | case TOK_GE: |
||
381 | return TOK_LT; |
||
382 | case TOK_LE: |
||
383 | return TOK_GT; |
||
384 | case TOK_GT: |
||
385 | return TOK_LE; |
||
386 | } |
||
387 | error("unexpected condition code"); |
||
388 | return TOK_NE; |
||
389 | } |
||
390 | |||
391 | /* load 'r' from value 'sv' */ |
||
392 | void load(int r, SValue *sv) |
||
393 | { |
||
394 | int v, ft, fc, fr, sign; |
||
395 | unsigned long op; |
||
396 | SValue v1; |
||
397 | |||
398 | fr = sv->r; |
||
399 | ft = sv->type.t; |
||
400 | fc = sv->c.ul; |
||
401 | |||
402 | if(fc>=0) |
||
403 | sign=0; |
||
404 | else { |
||
405 | sign=1; |
||
406 | fc=-fc; |
||
407 | } |
||
408 | |||
409 | v = fr & VT_VALMASK; |
||
410 | if (fr & VT_LVAL) { |
||
411 | unsigned long base=0xB; // fp |
||
412 | if(v == VT_LLOCAL) { |
||
413 | v1.type.t = VT_PTR; |
||
414 | v1.r = VT_LOCAL | VT_LVAL; |
||
415 | v1.c.ul = sv->c.ul; |
||
416 | load(base=14 /* lr */, &v1); |
||
417 | fc=sign=0; |
||
418 | v=VT_LOCAL; |
||
419 | } else if(v == VT_CONST) { |
||
420 | v1.type.t = VT_PTR; |
||
421 | v1.r = fr&~VT_LVAL; |
||
422 | v1.c.ul = sv->c.ul; |
||
423 | v1.sym=sv->sym; |
||
424 | load(base=14, &v1); |
||
425 | fc=sign=0; |
||
426 | v=VT_LOCAL; |
||
427 | } else if(v < VT_CONST) { |
||
428 | base=intr(v); |
||
429 | fc=sign=0; |
||
430 | v=VT_LOCAL; |
||
431 | } |
||
432 | if(v == VT_LOCAL) { |
||
433 | if(is_float(ft)) { |
||
434 | calcaddr(&base,&fc,&sign,1020,2); |
||
435 | op=0xED100100; |
||
436 | if(!sign) |
||
437 | op|=0x800000; |
||
438 | #if LDOUBLE_SIZE == 8 |
||
439 | if ((ft & VT_BTYPE) != VT_FLOAT) |
||
440 | op|=0x8000; |
||
441 | #else |
||
442 | if ((ft & VT_BTYPE) == VT_DOUBLE) |
||
443 | op|=0x8000; |
||
444 | else if ((ft & VT_BTYPE) == VT_LDOUBLE) |
||
445 | op|=0x400000; |
||
446 | #endif |
||
447 | o(op|(fpr(r)<<12)|(fc>>2)|(base<<16)); |
||
448 | } else if((ft & VT_TYPE) == VT_BYTE || (ft & VT_BTYPE) == VT_SHORT) { |
||
449 | calcaddr(&base,&fc,&sign,255,0); |
||
450 | op=0xE1500090; |
||
451 | if ((ft & VT_BTYPE) == VT_SHORT) |
||
452 | op|=0x20; |
||
453 | if ((ft & VT_UNSIGNED) == 0) |
||
454 | op|=0x40; |
||
455 | if(!sign) |
||
456 | op|=0x800000; |
||
457 | o(op|(intr(r)<<12)|(base<<16)|((fc&0xf0)<<4)|(fc&0xf)); |
||
458 | } else { |
||
459 | calcaddr(&base,&fc,&sign,4095,0); |
||
460 | op=0xE5100000; |
||
461 | if(!sign) |
||
462 | op|=0x800000; |
||
463 | if ((ft & VT_BTYPE) == VT_BYTE) |
||
464 | op|=0x400000; |
||
465 | o(op|(intr(r)<<12)|fc|(base<<16)); |
||
466 | } |
||
467 | return; |
||
468 | } |
||
469 | } else { |
||
470 | if (v == VT_CONST) { |
||
471 | op=stuff_const(0xE3A00000|(intr(r)<<12),sv->c.ul); |
||
472 | if (fr & VT_SYM || !op) { |
||
473 | o(0xE59F0000|(intr(r)<<12)); |
||
474 | o(0xEA000000); |
||
475 | if(fr & VT_SYM) |
||
476 | greloc(cur_text_section, sv->sym, ind, R_ARM_ABS32); |
||
477 | o(sv->c.ul); |
||
478 | } else |
||
479 | o(op); |
||
480 | return; |
||
481 | } else if (v == VT_LOCAL) { |
||
482 | op=stuff_const(0xE28B0000|(intr(r)<<12),sv->c.ul); |
||
483 | if (fr & VT_SYM || !op) { |
||
484 | o(0xE59F0000|(intr(r)<<12)); |
||
485 | o(0xEA000000); |
||
486 | if(fr & VT_SYM) // needed ? |
||
487 | greloc(cur_text_section, sv->sym, ind, R_ARM_ABS32); |
||
488 | o(sv->c.ul); |
||
489 | o(0xE08B0000|(intr(r)<<12)|intr(r)); |
||
490 | } else |
||
491 | o(op); |
||
492 | return; |
||
493 | } else if(v == VT_CMP) { |
||
494 | o(mapcc(sv->c.ul)|0x3A00001|(intr(r)<<12)); |
||
495 | o(mapcc(negcc(sv->c.ul))|0x3A00000|(intr(r)<<12)); |
||
496 | return; |
||
497 | } else if (v == VT_JMP || v == VT_JMPI) { |
||
498 | int t; |
||
499 | t = v & 1; |
||
500 | o(0xE3A00000|(intr(r)<<12)|t); |
||
501 | o(0xEA000000); |
||
502 | gsym(sv->c.ul); |
||
503 | o(0xE3A00000|(intr(r)<<12)|(t^1)); |
||
504 | return; |
||
505 | } else if (v < VT_CONST) { |
||
506 | if(is_float(ft)) |
||
507 | o(0xEE008180|(fpr(r)<<12)|fpr(v)); |
||
508 | else |
||
509 | o(0xE1A00000|(intr(r)<<12)|intr(v)); |
||
510 | return; |
||
511 | } |
||
512 | } |
||
513 | error("load unimplemented!"); |
||
514 | } |
||
515 | |||
516 | /* store register 'r' in lvalue 'v' */ |
||
517 | void store(int r, SValue *sv) |
||
518 | { |
||
519 | SValue v1; |
||
520 | int v, ft, fc, fr, sign; |
||
521 | unsigned long op; |
||
522 | |||
523 | fr = sv->r; |
||
524 | ft = sv->type.t; |
||
525 | fc = sv->c.ul; |
||
526 | |||
527 | if(fc>=0) |
||
528 | sign=0; |
||
529 | else { |
||
530 | sign=1; |
||
531 | fc=-fc; |
||
532 | } |
||
533 | |||
534 | v = fr & VT_VALMASK; |
||
535 | if (fr & VT_LVAL || fr == VT_LOCAL) { |
||
536 | unsigned long base=0xb; |
||
537 | if(v < VT_CONST) { |
||
538 | base=intr(v); |
||
539 | v=VT_LOCAL; |
||
540 | fc=sign=0; |
||
541 | } else if(v == VT_CONST) { |
||
542 | v1.type.t = ft; |
||
543 | v1.r = fr&~VT_LVAL; |
||
544 | v1.c.ul = sv->c.ul; |
||
545 | v1.sym=sv->sym; |
||
546 | load(base=14, &v1); |
||
547 | fc=sign=0; |
||
548 | v=VT_LOCAL; |
||
549 | } |
||
550 | if(v == VT_LOCAL) { |
||
551 | if(is_float(ft)) { |
||
552 | calcaddr(&base,&fc,&sign,1020,2); |
||
553 | op=0xED000100; |
||
554 | if(!sign) |
||
555 | op|=0x800000; |
||
556 | #if LDOUBLE_SIZE == 8 |
||
557 | if ((ft & VT_BTYPE) != VT_FLOAT) |
||
558 | op|=0x8000; |
||
559 | #else |
||
560 | if ((ft & VT_BTYPE) == VT_DOUBLE) |
||
561 | op|=0x8000; |
||
562 | if ((ft & VT_BTYPE) == VT_LDOUBLE) |
||
563 | op|=0x400000; |
||
564 | #endif |
||
565 | o(op|(fpr(r)<<12)|(fc>>2)|(base<<16)); |
||
566 | return; |
||
567 | } else if((ft & VT_BTYPE) == VT_SHORT) { |
||
568 | calcaddr(&base,&fc,&sign,255,0); |
||
569 | op=0xE14000B0; |
||
570 | if(!sign) |
||
571 | op|=0x800000; |
||
572 | o(op|(intr(r)<<12)|(base<<16)|((fc&0xf0)<<4)|(fc&0xf)); |
||
573 | } else { |
||
574 | calcaddr(&base,&fc,&sign,4095,0); |
||
575 | op=0xE5000000; |
||
576 | if(!sign) |
||
577 | op|=0x800000; |
||
578 | if ((ft & VT_BTYPE) == VT_BYTE) |
||
579 | op|=0x400000; |
||
580 | o(op|(intr(r)<<12)|fc|(base<<16)); |
||
581 | } |
||
582 | return; |
||
583 | } |
||
584 | } |
||
585 | error("store unimplemented"); |
||
586 | } |
||
587 | |||
588 | static void gadd_sp(int val) |
||
589 | { |
||
590 | stuff_const_harder(0xE28DD000,val); |
||
591 | } |
||
592 | |||
593 | /* 'is_jmp' is '1' if it is a jump */ |
||
594 | static void gcall_or_jmp(int is_jmp) |
||
595 | { |
||
596 | int r; |
||
597 | if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { |
||
598 | unsigned long x; |
||
599 | /* constant case */ |
||
600 | x=encbranch(ind,ind+vtop->c.ul,0); |
||
601 | if(x) { |
||
602 | if (vtop->r & VT_SYM) { |
||
603 | /* relocation case */ |
||
604 | greloc(cur_text_section, vtop->sym, ind, R_ARM_PC24); |
||
605 | } else |
||
606 | put_elf_reloc(symtab_section, cur_text_section, ind, R_ARM_PC24, 0); |
||
607 | o(x|(is_jmp?0xE0000000:0xE1000000)); |
||
608 | } else { |
||
609 | if(!is_jmp) |
||
610 | o(0xE28FE004); // add lr,pc,#4 |
||
611 | o(0xE51FF004); // ldr pc,[pc,#-4] |
||
612 | if (vtop->r & VT_SYM) |
||
613 | greloc(cur_text_section, vtop->sym, ind, R_ARM_ABS32); |
||
614 | o(vtop->c.ul); |
||
615 | } |
||
616 | } else { |
||
617 | /* otherwise, indirect call */ |
||
618 | r = gv(RC_INT); |
||
619 | if(!is_jmp) |
||
620 | o(0xE1A0E00F); // mov lr,pc |
||
621 | o(0xE1A0F000|intr(r)); // mov pc,r |
||
622 | } |
||
623 | } |
||
624 | |||
625 | /* Generate function call. The function address is pushed first, then |
||
626 | all the parameters in call order. This functions pops all the |
||
627 | parameters and the function address. */ |
||
628 | void gfunc_call(int nb_args) |
||
629 | { |
||
630 | int size, align, r, args_size, i; |
||
631 | Sym *func_sym; |
||
632 | signed char plan[4][2]={{-1,-1},{-1,-1},{-1,-1},{-1,-1}}; |
||
633 | int todo=0xf, keep, plan2[4]={0,0,0,0}; |
||
634 | |||
635 | r = vtop->r & VT_VALMASK; |
||
636 | if (r == VT_CMP || (r & ~1) == VT_JMP) |
||
637 | gv(RC_INT); |
||
638 | args_size = 0; |
||
639 | for(i = nb_args ; i-- && args_size < 16 ;) { |
||
640 | if ((vtop[-i].type.t & VT_BTYPE) == VT_STRUCT) { |
||
641 | size = type_size(&vtop[-i].type, &align); |
||
642 | size = (size + 3) & ~3; |
||
643 | args_size += size; |
||
644 | } else if ((vtop[-i].type.t & VT_BTYPE) == VT_FLOAT) |
||
645 | args_size += 4; |
||
646 | else if ((vtop[-i].type.t & VT_BTYPE) == VT_DOUBLE) |
||
647 | args_size += 8; |
||
648 | else if ((vtop[-i].type.t & VT_BTYPE) == VT_LDOUBLE) |
||
649 | args_size += LDOUBLE_SIZE; |
||
650 | else { |
||
651 | plan[nb_args-1-i][0]=args_size/4; |
||
652 | args_size += 4; |
||
653 | if ((vtop[-i].type.t & VT_BTYPE) == VT_LLONG && args_size < 16) { |
||
654 | plan[nb_args-1-i][1]=args_size/4; |
||
655 | args_size += 4; |
||
656 | } |
||
657 | } |
||
658 | } |
||
659 | args_size = keep = 0; |
||
660 | for(i = 0;i < nb_args; i++) { |
||
661 | vnrott(keep+1); |
||
662 | if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) { |
||
663 | size = type_size(&vtop->type, &align); |
||
664 | /* align to stack align size */ |
||
665 | size = (size + 3) & ~3; |
||
666 | /* allocate the necessary size on stack */ |
||
667 | gadd_sp(-size); |
||
668 | /* generate structure store */ |
||
669 | r = get_reg(RC_INT); |
||
670 | o(0xE1A0000D|(intr(r)<<12)); |
||
671 | vset(&vtop->type, r | VT_LVAL, 0); |
||
672 | vswap(); |
||
673 | vstore(); |
||
674 | vtop--; |
||
675 | args_size += size; |
||
676 | } else if (is_float(vtop->type.t)) { |
||
677 | r=fpr(gv(RC_FLOAT))<<12; |
||
678 | if ((vtop->type.t & VT_BTYPE) == VT_FLOAT) |
||
679 | size = 4; |
||
680 | else if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) |
||
681 | size = 8; |
||
682 | else |
||
683 | size = LDOUBLE_SIZE; |
||
684 | |||
685 | if (size == 12) |
||
686 | r|=0x400000; |
||
687 | else if(size == 8) |
||
688 | r|=0x8000; |
||
689 | |||
690 | o(0xED2D0100|r|(size>>2)); |
||
691 | vtop--; |
||
692 | args_size += size; |
||
693 | } else { |
||
694 | int s; |
||
695 | /* simple type (currently always same size) */ |
||
696 | /* XXX: implicit cast ? */ |
||
697 | size=4; |
||
698 | if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { |
||
699 | lexpand_nr(); |
||
700 | s=RC_INT; |
||
701 | if(nb_args-i<5 && plan[nb_args-i-1][1]!=-1) { |
||
702 | s=regmask(plan[nb_args-i-1][1]); |
||
703 | todo&=~(1< |
||
704 | } |
||
705 | if(s==RC_INT) { |
||
706 | r = gv(s); |
||
707 | o(0xE52D0004|(intr(r)<<12)); /* str r,[sp,#-4]! */ |
||
708 | vtop--; |
||
709 | } else { |
||
710 | plan2[keep]=s; |
||
711 | keep++; |
||
712 | vswap(); |
||
713 | } |
||
714 | size = 8; |
||
715 | } |
||
716 | s=RC_INT; |
||
717 | if(nb_args-i<5 && plan[nb_args-i-1][0]!=-1) { |
||
718 | s=regmask(plan[nb_args-i-1][0]); |
||
719 | todo&=~(1< |
||
720 | } |
||
721 | if(s==RC_INT) { |
||
722 | r = gv(s); |
||
723 | o(0xE52D0004|(intr(r)<<12)); /* str r,[sp,#-4]! */ |
||
724 | vtop--; |
||
725 | } else { |
||
726 | plan2[keep]=s; |
||
727 | keep++; |
||
728 | } |
||
729 | args_size += size; |
||
730 | } |
||
731 | } |
||
732 | for(i=keep;i--;) { |
||
733 | gv(plan2[i]); |
||
734 | vrott(keep); |
||
735 | } |
||
736 | save_regs(keep); /* save used temporary registers */ |
||
737 | keep++; |
||
738 | if(args_size) { |
||
739 | int n; |
||
740 | n=args_size/4; |
||
741 | if(n>4) |
||
742 | n=4; |
||
743 | todo&=((1< |
||
744 | if(todo) { |
||
745 | int i; |
||
746 | o(0xE8BD0000|todo); |
||
747 | for(i=0;i<4;i++) |
||
748 | if(todo&(1< |
||
749 | vpushi(0); |
||
750 | vtop->r=i; |
||
751 | keep++; |
||
752 | } |
||
753 | } |
||
754 | args_size-=n*4; |
||
755 | } |
||
756 | vnrott(keep); |
||
757 | func_sym = vtop->type.ref; |
||
758 | gcall_or_jmp(0); |
||
759 | if (args_size) |
||
760 | gadd_sp(args_size); |
||
761 | vtop-=keep; |
||
762 | } |
||
763 | |||
764 | /* generate function prolog of type 't' */ |
||
765 | void gfunc_prolog(CType *func_type) |
||
766 | { |
||
767 | Sym *sym,*sym2; |
||
768 | int n,addr,size,align; |
||
769 | |||
770 | sym = func_type->ref; |
||
771 | func_vt = sym->type; |
||
772 | |||
773 | n=0; |
||
774 | addr=12; |
||
775 | if((func_vt.t & VT_BTYPE) == VT_STRUCT) { |
||
776 | func_vc = addr; |
||
777 | addr += 4; |
||
778 | n++; |
||
779 | } |
||
780 | for(sym2=sym->next;sym2 && n<4;sym2=sym2->next) { |
||
781 | size = type_size(&sym2->type, &align); |
||
782 | size = (size + 3) & ~3; |
||
783 | n+=size/4; |
||
784 | } |
||
785 | o(0xE1A0C00D); /* mov ip,sp */ |
||
786 | if(func_type->ref->c == FUNC_ELLIPSIS) |
||
787 | n=4; |
||
788 | if(n) { |
||
789 | if(n>4) |
||
790 | n=4; |
||
791 | o(0xE92D0000|((1< |
||
792 | } |
||
793 | o(0xE92D5800); /* save fp, ip, lr*/ |
||
794 | o(0xE1A0B00D); /* mov fp,sp */ |
||
795 | func_sub_sp_offset = ind; |
||
796 | o(0xE1A00000); /* nop, leave space for stack adjustment */ |
||
797 | while ((sym = sym->next)) { |
||
798 | CType *type; |
||
799 | type = &sym->type; |
||
800 | sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr); |
||
801 | size = type_size(type, &align); |
||
802 | size = (size + 3) & ~3; |
||
803 | addr += size; |
||
804 | } |
||
805 | last_itod_magic=0; |
||
806 | loc = 0; |
||
807 | } |
||
808 | |||
809 | /* generate function epilog */ |
||
810 | void gfunc_epilog(void) |
||
811 | { |
||
812 | unsigned long x; |
||
813 | o(0xE89BA800); /* restore fp, sp, pc */ |
||
814 | if(loc) { |
||
815 | x=stuff_const(0xE24DD000, (-loc + 3) & -4); /* sub sp,sp,# */ |
||
816 | if(x) |
||
817 | *(unsigned long *)(cur_text_section->data + func_sub_sp_offset) = x; |
||
818 | else { |
||
819 | unsigned long addr; |
||
820 | addr=ind; |
||
821 | o(0xE59FC004); /* ldr ip,[pc+4] */ |
||
822 | o(0xE04DD00C); /* sub sp,sp,ip */ |
||
823 | o(0xE1A0F00E); /* mov pc,lr */ |
||
824 | o((-loc + 3) & -4); |
||
825 | *(unsigned long *)(cur_text_section->data + func_sub_sp_offset) = 0xE1000000|encbranch(func_sub_sp_offset,addr,1); |
||
826 | } |
||
827 | } |
||
828 | } |
||
829 | |||
830 | /* generate a jump to a label */ |
||
831 | int gjmp(int t) |
||
832 | { |
||
833 | int r; |
||
834 | r=ind; |
||
835 | o(0xE0000000|encbranch(r,t,1)); |
||
836 | return r; |
||
837 | } |
||
838 | |||
839 | /* generate a jump to a fixed address */ |
||
840 | void gjmp_addr(int a) |
||
841 | { |
||
842 | gjmp(a); |
||
843 | } |
||
844 | |||
845 | /* generate a test. set 'inv' to invert test. Stack entry is popped */ |
||
846 | int gtst(int inv, int t) |
||
847 | { |
||
848 | int v, r; |
||
849 | unsigned long op; |
||
850 | v = vtop->r & VT_VALMASK; |
||
851 | r=ind; |
||
852 | if (v == VT_CMP) { |
||
853 | op=mapcc(inv?negcc(vtop->c.i):vtop->c.i); |
||
854 | op|=encbranch(r,t,1); |
||
855 | o(op); |
||
856 | t=r; |
||
857 | } else if (v == VT_JMP || v == VT_JMPI) { |
||
858 | if ((v & 1) == inv) { |
||
859 | if(!vtop->c.i) |
||
860 | vtop->c.i=t; |
||
861 | else { |
||
862 | unsigned long *x; |
||
863 | int p,lp; |
||
864 | if(t) { |
||
865 | p = vtop->c.i; |
||
866 | do { |
||
867 | p = decbranch(lp=p); |
||
868 | } while(p); |
||
869 | x = (unsigned long *)(cur_text_section->data + lp); |
||
870 | *x &= 0xff000000; |
||
871 | *x |= encbranch(lp,t,1); |
||
872 | } |
||
873 | t = vtop->c.i; |
||
874 | } |
||
875 | } else { |
||
876 | t = gjmp(t); |
||
877 | gsym(vtop->c.i); |
||
878 | } |
||
879 | } else { |
||
880 | if (is_float(vtop->type.t)) { |
||
881 | r=gv(RC_FLOAT); |
||
882 | o(0xEE90F118|fpr(r)<<16); |
||
883 | vtop->r = VT_CMP; |
||
884 | vtop->c.i = TOK_NE; |
||
885 | return gtst(inv, t); |
||
886 | } else if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { |
||
887 | /* constant jmp optimization */ |
||
888 | if ((vtop->c.i != 0) != inv) |
||
889 | t = gjmp(t); |
||
890 | } else { |
||
891 | v = gv(RC_INT); |
||
892 | o(0xE3300000|(intr(v)<<16)); |
||
893 | vtop->r = VT_CMP; |
||
894 | vtop->c.i = TOK_NE; |
||
895 | return gtst(inv, t); |
||
896 | } |
||
897 | } |
||
898 | vtop--; |
||
899 | return t; |
||
900 | } |
||
901 | |||
902 | /* generate an integer binary operation */ |
||
903 | void gen_opi(int op) |
||
904 | { |
||
905 | int c, func = 0; |
||
906 | unsigned long opc = 0,r,fr; |
||
907 | |||
908 | c=0; |
||
909 | switch(op) { |
||
910 | case '+': |
||
911 | opc = 0x8; |
||
912 | c=1; |
||
913 | break; |
||
914 | case TOK_ADDC1: /* add with carry generation */ |
||
915 | opc = 0x9; |
||
916 | c=1; |
||
917 | break; |
||
918 | case '-': |
||
919 | opc = 0x4; |
||
920 | c=1; |
||
921 | break; |
||
922 | case TOK_SUBC1: /* sub with carry generation */ |
||
923 | opc = 0x5; |
||
924 | c=1; |
||
925 | break; |
||
926 | case TOK_ADDC2: /* add with carry use */ |
||
927 | opc = 0xA; |
||
928 | c=1; |
||
929 | break; |
||
930 | case TOK_SUBC2: /* sub with carry use */ |
||
931 | opc = 0xC; |
||
932 | c=1; |
||
933 | break; |
||
934 | case '&': |
||
935 | opc = 0x0; |
||
936 | c=1; |
||
937 | break; |
||
938 | case '^': |
||
939 | opc = 0x2; |
||
940 | c=1; |
||
941 | break; |
||
942 | case '|': |
||
943 | opc = 0x18; |
||
944 | c=1; |
||
945 | break; |
||
946 | case '*': |
||
947 | gv2(RC_INT, RC_INT); |
||
948 | r = vtop[-1].r; |
||
949 | fr = vtop[0].r; |
||
950 | vtop--; |
||
951 | o(0xE0000090|(intr(r)<<16)|(intr(r)<<8)|intr(fr)); |
||
952 | return; |
||
953 | case TOK_SHL: |
||
954 | opc = 0; |
||
955 | c=2; |
||
956 | break; |
||
957 | case TOK_SHR: |
||
958 | opc = 1; |
||
959 | c=2; |
||
960 | break; |
||
961 | case TOK_SAR: |
||
962 | opc = 2; |
||
963 | c=2; |
||
964 | break; |
||
965 | case '/': |
||
966 | case TOK_PDIV: |
||
967 | func=TOK___divsi3; |
||
968 | c=3; |
||
969 | break; |
||
970 | case TOK_UDIV: |
||
971 | func=TOK___udivsi3; |
||
972 | c=3; |
||
973 | break; |
||
974 | case '%': |
||
975 | func=TOK___modsi3; |
||
976 | c=3; |
||
977 | break; |
||
978 | case TOK_UMOD: |
||
979 | func=TOK___umodsi3; |
||
980 | c=3; |
||
981 | break; |
||
982 | case TOK_UMULL: |
||
983 | gv2(RC_INT, RC_INT); |
||
984 | r=intr(vtop[-1].r2=get_reg(RC_INT)); |
||
985 | c=vtop[-1].r; |
||
986 | vtop[-1].r=get_reg_ex(RC_INT,regmask(c)); |
||
987 | vtop--; |
||
988 | o(0xE0800090|(r<<16)|(intr(vtop->r)<<12)|(intr(c)<<8)|intr(vtop[1].r)); |
||
989 | return; |
||
990 | default: |
||
991 | opc = 0x15; |
||
992 | c=1; |
||
993 | break; |
||
994 | } |
||
995 | switch(c) { |
||
996 | case 1: |
||
997 | if((vtop[-1].r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { |
||
998 | if(opc == 4 || opc == 5 || opc == 0xc) { |
||
999 | vswap(); |
||
1000 | opc|=2; // sub -> rsb |
||
1001 | } |
||
1002 | } |
||
1003 | if ((vtop->r & VT_VALMASK) == VT_CMP || |
||
1004 | (vtop->r & (VT_VALMASK & ~1)) == VT_JMP) |
||
1005 | gv(RC_INT); |
||
1006 | vswap(); |
||
1007 | c=intr(gv(RC_INT)); |
||
1008 | vswap(); |
||
1009 | opc=0xE0000000|(opc<<20)|(c<<16); |
||
1010 | if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { |
||
1011 | unsigned long x; |
||
1012 | x=stuff_const(opc|0x2000000,vtop->c.i); |
||
1013 | if(x) { |
||
1014 | r=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r))); |
||
1015 | o(x|(r<<12)); |
||
1016 | goto done; |
||
1017 | } |
||
1018 | } |
||
1019 | fr=intr(gv(RC_INT)); |
||
1020 | r=intr(vtop[-1].r=get_reg_ex(RC_INT,two2mask(vtop->r,vtop[-1].r))); |
||
1021 | o(opc|(r<<12)|fr); |
||
1022 | done: |
||
1023 | vtop--; |
||
1024 | if (op >= TOK_ULT && op <= TOK_GT) { |
||
1025 | vtop->r = VT_CMP; |
||
1026 | vtop->c.i = op; |
||
1027 | } |
||
1028 | break; |
||
1029 | case 2: |
||
1030 | opc=0xE1A00000|(opc<<5); |
||
1031 | if ((vtop->r & VT_VALMASK) == VT_CMP || |
||
1032 | (vtop->r & (VT_VALMASK & ~1)) == VT_JMP) |
||
1033 | gv(RC_INT); |
||
1034 | vswap(); |
||
1035 | r=intr(gv(RC_INT)); |
||
1036 | vswap(); |
||
1037 | opc|=r; |
||
1038 | if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { |
||
1039 | fr=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r))); |
||
1040 | c = vtop->c.i & 0x1f; |
||
1041 | o(opc|(c<<7)|(fr<<12)); |
||
1042 | } else { |
||
1043 | fr=intr(gv(RC_INT)); |
||
1044 | c=intr(vtop[-1].r=get_reg_ex(RC_INT,two2mask(vtop->r,vtop[-1].r))); |
||
1045 | o(opc|(c<<12)|(fr<<8)|0x10); |
||
1046 | } |
||
1047 | vtop--; |
||
1048 | break; |
||
1049 | case 3: |
||
1050 | vpush_global_sym(&func_old_type, func); |
||
1051 | vrott(3); |
||
1052 | gfunc_call(2); |
||
1053 | vpushi(0); |
||
1054 | vtop->r = REG_IRET; |
||
1055 | break; |
||
1056 | default: |
||
1057 | error("gen_opi %i unimplemented!",op); |
||
1058 | } |
||
1059 | } |
||
1060 | |||
1061 | static int is_fconst() |
||
1062 | { |
||
1063 | long double f; |
||
1064 | int r; |
||
1065 | if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) |
||
1066 | return 0; |
||
1067 | if (vtop->type.t == VT_FLOAT) |
||
1068 | f = vtop->c.f; |
||
1069 | else if (vtop->type.t == VT_DOUBLE) |
||
1070 | f = vtop->c.d; |
||
1071 | else |
||
1072 | f = vtop->c.ld; |
||
1073 | if(!ieee_finite(f)) |
||
1074 | return 0; |
||
1075 | r=0x8; |
||
1076 | if(f<0.0) { |
||
1077 | r=0x18; |
||
1078 | f=-f; |
||
1079 | } |
||
1080 | if(f==0.0) |
||
1081 | return r; |
||
1082 | if(f==1.0) |
||
1083 | return r|1; |
||
1084 | if(f==2.0) |
||
1085 | return r|2; |
||
1086 | if(f==3.0) |
||
1087 | return r|3; |
||
1088 | if(f==4.0) |
||
1089 | return r|4; |
||
1090 | if(f==5.0) |
||
1091 | return r|5; |
||
1092 | if(f==0.5) |
||
1093 | return r|6; |
||
1094 | if(f==10.0) |
||
1095 | return r|7; |
||
1096 | return 0; |
||
1097 | } |
||
1098 | |||
1099 | /* generate a floating point operation 'v = t1 op t2' instruction. The |
||
1100 | two operands are guaranted to have the same floating point type */ |
||
1101 | void gen_opf(int op) |
||
1102 | { |
||
1103 | unsigned long x; |
||
1104 | int r,r2,c1,c2; |
||
1105 | //fputs("gen_opf\n",stderr); |
||
1106 | vswap(); |
||
1107 | c1 = is_fconst(); |
||
1108 | vswap(); |
||
1109 | c2 = is_fconst(); |
||
1110 | x=0xEE000100; |
||
1111 | #if LDOUBLE_SIZE == 8 |
||
1112 | if ((vtop->type.t & VT_BTYPE) != VT_FLOAT) |
||
1113 | x|=0x80; |
||
1114 | #else |
||
1115 | if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) |
||
1116 | x|=0x80; |
||
1117 | else if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) |
||
1118 | x|=0x80000; |
||
1119 | #endif |
||
1120 | switch(op) |
||
1121 | { |
||
1122 | case '+': |
||
1123 | if(!c2) { |
||
1124 | vswap(); |
||
1125 | c2=c1; |
||
1126 | } |
||
1127 | vswap(); |
||
1128 | r=fpr(gv(RC_FLOAT)); |
||
1129 | vswap(); |
||
1130 | if(c2) { |
||
1131 | if(c2>0xf) |
||
1132 | x|=0x200000; // suf |
||
1133 | r2=c2&0xf; |
||
1134 | } else { |
||
1135 | r2=fpr(gv(RC_FLOAT)); |
||
1136 | } |
||
1137 | break; |
||
1138 | case '-': |
||
1139 | if(c2) { |
||
1140 | if(c2<=0xf) |
||
1141 | x|=0x200000; // suf |
||
1142 | r2=c2&0xf; |
||
1143 | vswap(); |
||
1144 | r=fpr(gv(RC_FLOAT)); |
||
1145 | vswap(); |
||
1146 | } else if(c1 && c1<=0xf) { |
||
1147 | x|=0x300000; // rsf |
||
1148 | r2=c1; |
||
1149 | r=fpr(gv(RC_FLOAT)); |
||
1150 | vswap(); |
||
1151 | } else { |
||
1152 | x|=0x200000; // suf |
||
1153 | vswap(); |
||
1154 | r=fpr(gv(RC_FLOAT)); |
||
1155 | vswap(); |
||
1156 | r2=fpr(gv(RC_FLOAT)); |
||
1157 | } |
||
1158 | break; |
||
1159 | case '*': |
||
1160 | if(!c2 || c2>0xf) { |
||
1161 | vswap(); |
||
1162 | c2=c1; |
||
1163 | } |
||
1164 | vswap(); |
||
1165 | r=fpr(gv(RC_FLOAT)); |
||
1166 | vswap(); |
||
1167 | if(c2 && c2<=0xf) |
||
1168 | r2=c2; |
||
1169 | else |
||
1170 | r2=fpr(gv(RC_FLOAT)); |
||
1171 | x|=0x100000; // muf |
||
1172 | break; |
||
1173 | case '/': |
||
1174 | if(c2 && c2<=0xf) { |
||
1175 | x|=0x400000; // dvf |
||
1176 | r2=c2; |
||
1177 | vswap(); |
||
1178 | r=fpr(gv(RC_FLOAT)); |
||
1179 | vswap(); |
||
1180 | } else if(c1 && c1<=0xf) { |
||
1181 | x|=0x500000; // rdf |
||
1182 | r2=c1; |
||
1183 | r=fpr(gv(RC_FLOAT)); |
||
1184 | vswap(); |
||
1185 | } else { |
||
1186 | x|=0x400000; // dvf |
||
1187 | vswap(); |
||
1188 | r=fpr(gv(RC_FLOAT)); |
||
1189 | vswap(); |
||
1190 | r2=fpr(gv(RC_FLOAT)); |
||
1191 | } |
||
1192 | break; |
||
1193 | default: |
||
1194 | if(op >= TOK_ULT && op <= TOK_GT) { |
||
1195 | x|=0xd0f110; // cmfe |
||
1196 | switch(op) { |
||
1197 | case TOK_ULT: |
||
1198 | case TOK_UGE: |
||
1199 | case TOK_ULE: |
||
1200 | case TOK_UGT: |
||
1201 | fputs("unsigned comparision on floats?\n",stderr); |
||
1202 | break; |
||
1203 | case TOK_LT: |
||
1204 | op=TOK_ULT; |
||
1205 | break; |
||
1206 | case TOK_GE: |
||
1207 | op=TOK_UGE; |
||
1208 | break; |
||
1209 | case TOK_LE: |
||
1210 | op=TOK_ULE; |
||
1211 | break; |
||
1212 | case TOK_GT: |
||
1213 | op=TOK_UGT; |
||
1214 | break; |
||
1215 | case TOK_EQ: |
||
1216 | case TOK_NE: |
||
1217 | x&=~0x400000; // cmfe -> cmf |
||
1218 | break; |
||
1219 | } |
||
1220 | if(c1 && !c2) { |
||
1221 | c2=c1; |
||
1222 | vswap(); |
||
1223 | switch(op) { |
||
1224 | case TOK_ULT: |
||
1225 | op=TOK_UGT; |
||
1226 | break; |
||
1227 | case TOK_UGE: |
||
1228 | op=TOK_ULE; |
||
1229 | break; |
||
1230 | case TOK_ULE: |
||
1231 | op=TOK_UGE; |
||
1232 | break; |
||
1233 | case TOK_UGT: |
||
1234 | op=TOK_ULT; |
||
1235 | break; |
||
1236 | } |
||
1237 | } |
||
1238 | // bug (intention?) in Linux FPU emulator |
||
1239 | // doesn't set carry if equal |
||
1240 | if(op==TOK_ULT) |
||
1241 | op=TOK_LT; |
||
1242 | else if(op==TOK_UGE) |
||
1243 | op=TOK_GE; |
||
1244 | vswap(); |
||
1245 | r=fpr(gv(RC_FLOAT)); |
||
1246 | vswap(); |
||
1247 | if(c2) { |
||
1248 | if(c2>0xf) |
||
1249 | x|=0x200000; |
||
1250 | r2=c2&0xf; |
||
1251 | } else { |
||
1252 | r2=fpr(gv(RC_FLOAT)); |
||
1253 | } |
||
1254 | vtop[-1].r = VT_CMP; |
||
1255 | vtop[-1].c.i = op; |
||
1256 | } else { |
||
1257 | error("unknown fp op %x!\n",op); |
||
1258 | return; |
||
1259 | } |
||
1260 | } |
||
1261 | if(vtop[-1].r == VT_CMP) |
||
1262 | c1=15; |
||
1263 | else { |
||
1264 | c1=vtop->r; |
||
1265 | if(r2&0x8) |
||
1266 | c1=vtop[-1].r; |
||
1267 | vtop[-1].r=get_reg_ex(RC_FLOAT,two2mask(vtop[-1].r,c1)); |
||
1268 | c1=fpr(vtop[-1].r); |
||
1269 | } |
||
1270 | vtop--; |
||
1271 | o(x|(r<<16)|(c1<<12)|r2); |
||
1272 | } |
||
1273 | |||
1274 | /* convert integers to fp 't' type. Must handle 'int', 'unsigned int' |
||
1275 | and 'long long' cases. */ |
||
1276 | void gen_cvt_itof(int t) |
||
1277 | { |
||
1278 | int r,r2,bt; |
||
1279 | bt=vtop->type.t & VT_BTYPE; |
||
1280 | if(bt == VT_INT || bt == VT_SHORT || bt == VT_BYTE) { |
||
1281 | r=intr(gv(RC_INT)); |
||
1282 | r2=fpr(vtop->r=get_reg(RC_FLOAT)); |
||
1283 | o(0xEE000190|(r2<<16)|(r<<12)); |
||
1284 | if((vtop->type.t & (VT_UNSIGNED|VT_BTYPE)) == (VT_UNSIGNED|VT_INT)) { |
||
1285 | unsigned int off=0; |
||
1286 | o(0xE3500000|(r<<12)); |
||
1287 | r=fpr(get_reg(RC_FLOAT)); |
||
1288 | if(last_itod_magic) { |
||
1289 | off=ind+8-last_itod_magic; |
||
1290 | off/=4; |
||
1291 | if(off>255) |
||
1292 | off=0; |
||
1293 | } |
||
1294 | o(0xBD1F8100|(r<<12)|off); |
||
1295 | if(!off) { |
||
1296 | o(0xEA000001); |
||
1297 | last_itod_magic=ind; |
||
1298 | o(0x41F00000); |
||
1299 | o(0); |
||
1300 | } |
||
1301 | o(0xBE000180|(r2<<16)|(r2<<12)|r); |
||
1302 | } |
||
1303 | return; |
||
1304 | } else if(bt == VT_LLONG) { |
||
1305 | int func; |
||
1306 | if(vtop->type.t & VT_UNSIGNED) |
||
1307 | func=TOK___ulltold; |
||
1308 | else |
||
1309 | func=TOK___slltold; |
||
1310 | vpush_global_sym(&func_old_type, func); |
||
1311 | vswap(); |
||
1312 | gfunc_call(1); |
||
1313 | vpushi(0); |
||
1314 | vtop->r=TREG_F0; |
||
1315 | return; |
||
1316 | } |
||
1317 | error("unimplemented gen_cvt_itof %x!",vtop->type.t); |
||
1318 | } |
||
1319 | |||
1320 | /* convert fp to int 't' type */ |
||
1321 | void gen_cvt_ftoi(int t) |
||
1322 | { |
||
1323 | int r,r2,u,func=0; |
||
1324 | u=t&VT_UNSIGNED; |
||
1325 | t&=VT_BTYPE; |
||
1326 | r2=vtop->type.t & VT_BTYPE; |
||
1327 | if(t==VT_INT) { |
||
1328 | if(u) { |
||
1329 | if(r2 == VT_FLOAT) |
||
1330 | func=TOK___fixunssfsi; |
||
1331 | else if(r2 == VT_DOUBLE) |
||
1332 | func=TOK___fixunsdfsi; |
||
1333 | else if(r2 == VT_LDOUBLE) |
||
1334 | #if LDOUBLE_SIZE == 8 |
||
1335 | func=TOK___fixunsdfsi; |
||
1336 | #else |
||
1337 | func=TOK___fixunsxfsi; |
||
1338 | #endif |
||
1339 | } else { |
||
1340 | r=fpr(gv(RC_FLOAT)); |
||
1341 | r2=intr(vtop->r=get_reg(RC_INT)); |
||
1342 | o(0xEE100170|(r2<<12)|r); |
||
1343 | return; |
||
1344 | } |
||
1345 | } else if(t == VT_LLONG) { // unsigned handled in gen_cvt_ftoi1 |
||
1346 | if(r2 == VT_FLOAT) |
||
1347 | func=TOK___fixsfdi; |
||
1348 | else if(r2 == VT_DOUBLE) |
||
1349 | func=TOK___fixdfdi; |
||
1350 | else if(r2 == VT_LDOUBLE) |
||
1351 | #if LDOUBLE_SIZE == 8 |
||
1352 | func=TOK___fixdfdi; |
||
1353 | #else |
||
1354 | func=TOK___fixxfdi; |
||
1355 | #endif |
||
1356 | } |
||
1357 | if(func) { |
||
1358 | vpush_global_sym(&func_old_type, func); |
||
1359 | vswap(); |
||
1360 | gfunc_call(1); |
||
1361 | vpushi(0); |
||
1362 | if(t == VT_LLONG) |
||
1363 | vtop->r2 = REG_LRET; |
||
1364 | vtop->r = REG_IRET; |
||
1365 | return; |
||
1366 | } |
||
1367 | error("unimplemented gen_cvt_ftoi!"); |
||
1368 | } |
||
1369 | |||
1370 | /* convert from one floating point type to another */ |
||
1371 | void gen_cvt_ftof(int t) |
||
1372 | { |
||
1373 | /* all we have to do on i386 and ARM is to put the float in a register */ |
||
1374 | gv(RC_FLOAT); |
||
1375 | } |
||
1376 | |||
1377 | /* computed goto support */ |
||
1378 | void ggoto(void) |
||
1379 | { |
||
1380 | gcall_or_jmp(1); |
||
1381 | vtop--; |
||
1382 | } |
||
1383 | |||
1384 | /* end of ARM code generator */ |
||
1385 | /*************************************************************/12)|r); |
||
1386 |