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