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