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