64-bit tests now pass (well, nearly).
[tinycc.git] / arm-gen.c
blob0f70062ad427863eedbf61b13417b66bafd46912
1 /*
2 * ARMv4 code generator for TCC
3 *
4 * Copyright (c) 2003 Daniel Glöckner
5 * Copyright (c) 2012 Thomas Preud'homme
7 * Based on i386-gen.c by Fabrice Bellard
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #ifdef TARGET_DEFS_ONLY
26 #ifdef TCC_ARM_EABI
27 #ifndef TCC_ARM_VFP /* Avoid useless warning */
28 #define TCC_ARM_VFP
29 #endif
30 #endif
32 /* number of available registers */
33 #ifdef TCC_ARM_VFP
34 #define NB_REGS 13
35 #else
36 #define NB_REGS 9
37 #endif
39 #ifndef TCC_ARM_VERSION
40 # define TCC_ARM_VERSION 5
41 #endif
43 /* a register can belong to several classes. The classes must be
44 sorted from more general to more precise (see gv2() code which does
45 assumptions on it). */
46 #define RC_INT 0x0001 /* generic integer register */
47 #define RC_FLOAT 0x0002 /* generic float register */
48 #define RC_R0 0x0004
49 #define RC_R1 0x0008
50 #define RC_R2 0x0010
51 #define RC_R3 0x0020
52 #define RC_R12 0x0040
53 #define RC_F0 0x0080
54 #define RC_F1 0x0100
55 #define RC_F2 0x0200
56 #define RC_F3 0x0400
57 #ifdef TCC_ARM_VFP
58 #define RC_F4 0x0800
59 #define RC_F5 0x1000
60 #define RC_F6 0x2000
61 #define RC_F7 0x4000
62 #endif
63 #define RC_IRET RC_R0 /* function return: integer register */
64 #define RC_LRET RC_R1 /* function return: second integer register */
65 #define RC_FRET RC_F0 /* function return: float register */
67 /* pretty names for the registers */
68 enum {
69 TREG_R0 = 0,
70 TREG_R1,
71 TREG_R2,
72 TREG_R3,
73 TREG_R12,
74 TREG_F0,
75 TREG_F1,
76 TREG_F2,
77 TREG_F3,
78 #ifdef TCC_ARM_VFP
79 TREG_F4,
80 TREG_F5,
81 TREG_F6,
82 TREG_F7,
83 #endif
86 #ifdef TCC_ARM_VFP
87 #define T2CPR(t) (((t) & VT_BTYPE) != VT_FLOAT ? 0x100 : 0)
88 #endif
90 /* return registers for function */
91 #define REG_IRET TREG_R0 /* single word int return register */
92 #define REG_LRET TREG_R1 /* second word return register (for long long) */
93 #define REG_FRET TREG_F0 /* float return register */
95 #ifdef TCC_ARM_EABI
96 #define TOK___divdi3 TOK___aeabi_ldivmod
97 #define TOK___moddi3 TOK___aeabi_ldivmod
98 #define TOK___udivdi3 TOK___aeabi_uldivmod
99 #define TOK___umoddi3 TOK___aeabi_uldivmod
100 #endif
102 /* defined if function parameters must be evaluated in reverse order */
103 #define INVERT_FUNC_PARAMS
105 /* defined if structures are passed as pointers. Otherwise structures
106 are directly pushed on stack. */
107 /* #define FUNC_STRUCT_PARAM_AS_PTR */
109 /* pointer size, in bytes */
110 #define PTR_SIZE 4
112 /* long double size and alignment, in bytes */
113 #ifdef TCC_ARM_VFP
114 #define LDOUBLE_SIZE 8
115 #endif
117 #ifndef LDOUBLE_SIZE
118 #define LDOUBLE_SIZE 8
119 #endif
121 #ifdef TCC_ARM_EABI
122 #define LDOUBLE_ALIGN 8
123 #else
124 #define LDOUBLE_ALIGN 4
125 #endif
127 /* maximum alignment (for aligned attribute support) */
128 #define MAX_ALIGN 8
130 #define CHAR_IS_UNSIGNED
132 /******************************************************/
133 /* ELF defines */
135 #define EM_TCC_TARGET EM_ARM
137 /* relocation type for 32 bit data relocation */
138 #define R_DATA_32 R_ARM_ABS32
139 #define R_DATA_PTR R_ARM_ABS32
140 #define R_JMP_SLOT R_ARM_JUMP_SLOT
141 #define R_COPY R_ARM_COPY
143 #define ELF_START_ADDR 0x00008000
144 #define ELF_PAGE_SIZE 0x1000
146 /******************************************************/
147 #else /* ! TARGET_DEFS_ONLY */
148 /******************************************************/
149 #include "tcc.h"
151 ST_DATA const int reg_classes[NB_REGS] = {
152 /* r0 */ RC_INT | RC_R0,
153 /* r1 */ RC_INT | RC_R1,
154 /* r2 */ RC_INT | RC_R2,
155 /* r3 */ RC_INT | RC_R3,
156 /* r12 */ RC_INT | RC_R12,
157 /* f0 */ RC_FLOAT | RC_F0,
158 /* f1 */ RC_FLOAT | RC_F1,
159 /* f2 */ RC_FLOAT | RC_F2,
160 /* f3 */ RC_FLOAT | RC_F3,
161 #ifdef TCC_ARM_VFP
162 /* d4/s8 */ RC_FLOAT | RC_F4,
163 /* d5/s10 */ RC_FLOAT | RC_F5,
164 /* d6/s12 */ RC_FLOAT | RC_F6,
165 /* d7/s14 */ RC_FLOAT | RC_F7,
166 #endif
169 static int func_sub_sp_offset, last_itod_magic;
170 static int leaffunc;
172 #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
173 static CType float_type, double_type, func_float_type, func_double_type;
174 ST_FUNC void arm_init_types(void)
176 float_type.t = VT_FLOAT;
177 double_type.t = VT_DOUBLE;
178 func_float_type.t = VT_FUNC;
179 func_float_type.ref = sym_push(SYM_FIELD, &float_type, FUNC_CDECL, FUNC_OLD);
180 func_double_type.t = VT_FUNC;
181 func_double_type.ref = sym_push(SYM_FIELD, &double_type, FUNC_CDECL, FUNC_OLD);
183 #else
184 #define func_float_type func_old_type
185 #define func_double_type func_old_type
186 #define func_ldouble_type func_old_type
187 ST_FUNC void arm_init_types(void) {}
188 #endif
190 static int two2mask(int a,int b) {
191 return (reg_classes[a]|reg_classes[b])&~(RC_INT|RC_FLOAT);
194 static int regmask(int r) {
195 return reg_classes[r]&~(RC_INT|RC_FLOAT);
198 /******************************************************/
200 void o(uint32_t i)
202 /* this is a good place to start adding big-endian support*/
203 int ind1;
205 ind1 = ind + 4;
206 if (!cur_text_section)
207 tcc_error("compiler error! This happens f.ex. if the compiler\n"
208 "can't evaluate constant expressions outside of a function.");
209 if (ind1 > cur_text_section->data_allocated)
210 section_realloc(cur_text_section, ind1);
211 cur_text_section->data[ind++] = i&255;
212 i>>=8;
213 cur_text_section->data[ind++] = i&255;
214 i>>=8;
215 cur_text_section->data[ind++] = i&255;
216 i>>=8;
217 cur_text_section->data[ind++] = i;
220 static uint32_t stuff_const(uint32_t op, uint32_t c)
222 int try_neg=0;
223 uint32_t nc = 0, negop = 0;
225 switch(op&0x1F00000)
227 case 0x800000: //add
228 case 0x400000: //sub
229 try_neg=1;
230 negop=op^0xC00000;
231 nc=-c;
232 break;
233 case 0x1A00000: //mov
234 case 0x1E00000: //mvn
235 try_neg=1;
236 negop=op^0x400000;
237 nc=~c;
238 break;
239 case 0x200000: //xor
240 if(c==~0)
241 return (op&0xF010F000)|((op>>16)&0xF)|0x1E00000;
242 break;
243 case 0x0: //and
244 if(c==~0)
245 return (op&0xF010F000)|((op>>16)&0xF)|0x1A00000;
246 case 0x1C00000: //bic
247 try_neg=1;
248 negop=op^0x1C00000;
249 nc=~c;
250 break;
251 case 0x1800000: //orr
252 if(c==~0)
253 return (op&0xFFF0FFFF)|0x1E00000;
254 break;
256 do {
257 uint32_t m;
258 int i;
259 if(c<256) /* catch undefined <<32 */
260 return op|c;
261 for(i=2;i<32;i+=2) {
262 m=(0xff>>i)|(0xff<<(32-i));
263 if(!(c&~m))
264 return op|(i<<7)|(c<<i)|(c>>(32-i));
266 op=negop;
267 c=nc;
268 } while(try_neg--);
269 return 0;
273 //only add,sub
274 void stuff_const_harder(uint32_t op, uint32_t v) {
275 uint32_t x;
276 x=stuff_const(op,v);
277 if(x)
278 o(x);
279 else {
280 uint32_t a[16], nv, no, o2, n2;
281 int i,j,k;
282 a[0]=0xff;
283 o2=(op&0xfff0ffff)|((op&0xf000)<<4);;
284 for(i=1;i<16;i++)
285 a[i]=(a[i-1]>>2)|(a[i-1]<<30);
286 for(i=0;i<12;i++)
287 for(j=i<4?i+12:15;j>=i+4;j--)
288 if((v&(a[i]|a[j]))==v) {
289 o(stuff_const(op,v&a[i]));
290 o(stuff_const(o2,v&a[j]));
291 return;
293 no=op^0xC00000;
294 n2=o2^0xC00000;
295 nv=-v;
296 for(i=0;i<12;i++)
297 for(j=i<4?i+12:15;j>=i+4;j--)
298 if((nv&(a[i]|a[j]))==nv) {
299 o(stuff_const(no,nv&a[i]));
300 o(stuff_const(n2,nv&a[j]));
301 return;
303 for(i=0;i<8;i++)
304 for(j=i+4;j<12;j++)
305 for(k=i<4?i+12:15;k>=j+4;k--)
306 if((v&(a[i]|a[j]|a[k]))==v) {
307 o(stuff_const(op,v&a[i]));
308 o(stuff_const(o2,v&a[j]));
309 o(stuff_const(o2,v&a[k]));
310 return;
312 no=op^0xC00000;
313 nv=-v;
314 for(i=0;i<8;i++)
315 for(j=i+4;j<12;j++)
316 for(k=i<4?i+12:15;k>=j+4;k--)
317 if((nv&(a[i]|a[j]|a[k]))==nv) {
318 o(stuff_const(no,nv&a[i]));
319 o(stuff_const(n2,nv&a[j]));
320 o(stuff_const(n2,nv&a[k]));
321 return;
323 o(stuff_const(op,v&a[0]));
324 o(stuff_const(o2,v&a[4]));
325 o(stuff_const(o2,v&a[8]));
326 o(stuff_const(o2,v&a[12]));
330 ST_FUNC uint32_t encbranch(int pos, int addr, int fail)
332 addr-=pos+8;
333 addr/=4;
334 if(addr>=0x1000000 || addr<-0x1000000) {
335 if(fail)
336 tcc_error("FIXME: function bigger than 32MB");
337 return 0;
339 return 0x0A000000|(addr&0xffffff);
342 int decbranch(int pos)
344 int x;
345 x=*(uint32_t *)(cur_text_section->data + pos);
346 x&=0x00ffffff;
347 if(x&0x800000)
348 x-=0x1000000;
349 return x*4+pos+8;
352 /* output a symbol and patch all calls to it */
353 void gsym_addr(int t, int a)
355 uint32_t *x;
356 int lt;
357 while(t) {
358 x=(uint32_t *)(cur_text_section->data + t);
359 t=decbranch(lt=t);
360 if(a==lt+4)
361 *x=0xE1A00000; // nop
362 else {
363 *x &= 0xff000000;
364 *x |= encbranch(lt,a,1);
369 void gsym(int t)
371 gsym_addr(t, ind);
374 #ifdef TCC_ARM_VFP
375 static uint32_t vfpr(int r)
377 if(r<TREG_F0 || r>TREG_F7)
378 tcc_error("compiler error! register %i is no vfp register",r);
379 return r-5;
381 #else
382 static uint32_t fpr(int r)
384 if(r<TREG_F0 || r>TREG_F3)
385 tcc_error("compiler error! register %i is no fpa register",r);
386 return r-5;
388 #endif
390 static uint32_t intr(int r)
392 if(r==4)
393 return 12;
394 if((r<0 || r>4) && r!=14)
395 tcc_error("compiler error! register %i is no int register",r);
396 return r;
399 static void calcaddr(uint32_t *base, int *off, int *sgn, int maxoff, unsigned shift)
401 if(*off>maxoff || *off&((1<<shift)-1)) {
402 uint32_t x, y;
403 x=0xE280E000;
404 if(*sgn)
405 x=0xE240E000;
406 x|=(*base)<<16;
407 *base=14; // lr
408 y=stuff_const(x,*off&~maxoff);
409 if(y) {
410 o(y);
411 *off&=maxoff;
412 return;
414 y=stuff_const(x,(*off+maxoff)&~maxoff);
415 if(y) {
416 o(y);
417 *sgn=!*sgn;
418 *off=((*off+maxoff)&~maxoff)-*off;
419 return;
421 stuff_const_harder(x,*off&~maxoff);
422 *off&=maxoff;
426 static uint32_t mapcc(int cc)
428 switch(cc)
430 case TOK_ULT:
431 return 0x30000000; /* CC/LO */
432 case TOK_UGE:
433 return 0x20000000; /* CS/HS */
434 case TOK_EQ:
435 return 0x00000000; /* EQ */
436 case TOK_NE:
437 return 0x10000000; /* NE */
438 case TOK_ULE:
439 return 0x90000000; /* LS */
440 case TOK_UGT:
441 return 0x80000000; /* HI */
442 case TOK_Nset:
443 return 0x40000000; /* MI */
444 case TOK_Nclear:
445 return 0x50000000; /* PL */
446 case TOK_LT:
447 return 0xB0000000; /* LT */
448 case TOK_GE:
449 return 0xA0000000; /* GE */
450 case TOK_LE:
451 return 0xD0000000; /* LE */
452 case TOK_GT:
453 return 0xC0000000; /* GT */
455 tcc_error("unexpected condition code");
456 return 0xE0000000; /* AL */
459 static int negcc(int cc)
461 switch(cc)
463 case TOK_ULT:
464 return TOK_UGE;
465 case TOK_UGE:
466 return TOK_ULT;
467 case TOK_EQ:
468 return TOK_NE;
469 case TOK_NE:
470 return TOK_EQ;
471 case TOK_ULE:
472 return TOK_UGT;
473 case TOK_UGT:
474 return TOK_ULE;
475 case TOK_Nset:
476 return TOK_Nclear;
477 case TOK_Nclear:
478 return TOK_Nset;
479 case TOK_LT:
480 return TOK_GE;
481 case TOK_GE:
482 return TOK_LT;
483 case TOK_LE:
484 return TOK_GT;
485 case TOK_GT:
486 return TOK_LE;
488 tcc_error("unexpected condition code");
489 return TOK_NE;
492 /* load 'r' from value 'sv' */
493 void load(int r, SValue *sv)
495 int v, ft, fc, fr, sign;
496 uint32_t op;
497 SValue v1;
499 fr = sv->r;
500 ft = sv->type.t;
501 fc = sv->c.ul;
503 if(fc>=0)
504 sign=0;
505 else {
506 sign=1;
507 fc=-fc;
510 v = fr & VT_VALMASK;
511 if (fr & VT_LVAL) {
512 uint32_t base = 0xB; // fp
513 if(v == VT_LLOCAL) {
514 v1.type.t = VT_PTR;
515 v1.r = VT_LOCAL | VT_LVAL;
516 v1.c.ul = sv->c.ul;
517 load(base=14 /* lr */, &v1);
518 fc=sign=0;
519 v=VT_LOCAL;
520 } else if(v == VT_CONST) {
521 v1.type.t = VT_PTR;
522 v1.r = fr&~VT_LVAL;
523 v1.c.ul = sv->c.ul;
524 v1.sym=sv->sym;
525 load(base=14, &v1);
526 fc=sign=0;
527 v=VT_LOCAL;
528 } else if(v < VT_CONST) {
529 base=intr(v);
530 fc=sign=0;
531 v=VT_LOCAL;
533 if(v == VT_LOCAL) {
534 if(is_float(ft)) {
535 calcaddr(&base,&fc,&sign,1020,2);
536 #ifdef TCC_ARM_VFP
537 op=0xED100A00; /* flds */
538 if(!sign)
539 op|=0x800000;
540 if ((ft & VT_BTYPE) != VT_FLOAT)
541 op|=0x100; /* flds -> fldd */
542 o(op|(vfpr(r)<<12)|(fc>>2)|(base<<16));
543 #else
544 op=0xED100100;
545 if(!sign)
546 op|=0x800000;
547 #if LDOUBLE_SIZE == 8
548 if ((ft & VT_BTYPE) != VT_FLOAT)
549 op|=0x8000;
550 #else
551 if ((ft & VT_BTYPE) == VT_DOUBLE)
552 op|=0x8000;
553 else if ((ft & VT_BTYPE) == VT_LDOUBLE)
554 op|=0x400000;
555 #endif
556 o(op|(fpr(r)<<12)|(fc>>2)|(base<<16));
557 #endif
558 } else if((ft & (VT_BTYPE|VT_UNSIGNED)) == VT_BYTE
559 || (ft & VT_BTYPE) == VT_SHORT) {
560 calcaddr(&base,&fc,&sign,255,0);
561 op=0xE1500090;
562 if ((ft & VT_BTYPE) == VT_SHORT)
563 op|=0x20;
564 if ((ft & VT_UNSIGNED) == 0)
565 op|=0x40;
566 if(!sign)
567 op|=0x800000;
568 o(op|(intr(r)<<12)|(base<<16)|((fc&0xf0)<<4)|(fc&0xf));
569 } else {
570 calcaddr(&base,&fc,&sign,4095,0);
571 op=0xE5100000;
572 if(!sign)
573 op|=0x800000;
574 if ((ft & VT_BTYPE) == VT_BYTE)
575 op|=0x400000;
576 o(op|(intr(r)<<12)|fc|(base<<16));
578 return;
580 } else {
581 if (v == VT_CONST) {
582 op=stuff_const(0xE3A00000|(intr(r)<<12),sv->c.ul);
583 if (fr & VT_SYM || !op) {
584 o(0xE59F0000|(intr(r)<<12));
585 o(0xEA000000);
586 if(fr & VT_SYM)
587 greloc(cur_text_section, sv->sym, ind, R_ARM_ABS32);
588 o(sv->c.ul);
589 } else
590 o(op);
591 return;
592 } else if (v == VT_LOCAL) {
593 op=stuff_const(0xE28B0000|(intr(r)<<12),sv->c.ul);
594 if (fr & VT_SYM || !op) {
595 o(0xE59F0000|(intr(r)<<12));
596 o(0xEA000000);
597 if(fr & VT_SYM) // needed ?
598 greloc(cur_text_section, sv->sym, ind, R_ARM_ABS32);
599 o(sv->c.ul);
600 o(0xE08B0000|(intr(r)<<12)|intr(r));
601 } else
602 o(op);
603 return;
604 } else if(v == VT_CMP) {
605 o(mapcc(sv->c.ul)|0x3A00001|(intr(r)<<12));
606 o(mapcc(negcc(sv->c.ul))|0x3A00000|(intr(r)<<12));
607 return;
608 } else if (v == VT_JMP || v == VT_JMPI) {
609 int t;
610 t = v & 1;
611 o(0xE3A00000|(intr(r)<<12)|t);
612 o(0xEA000000);
613 gsym(sv->c.ul);
614 o(0xE3A00000|(intr(r)<<12)|(t^1));
615 return;
616 } else if (v < VT_CONST) {
617 if(is_float(ft))
618 #ifdef TCC_ARM_VFP
619 o(0xEEB00A40|(vfpr(r)<<12)|vfpr(v)|T2CPR(ft)); /* fcpyX */
620 #else
621 o(0xEE008180|(fpr(r)<<12)|fpr(v));
622 #endif
623 else
624 o(0xE1A00000|(intr(r)<<12)|intr(v));
625 return;
628 tcc_error("load unimplemented!");
631 /* store register 'r' in lvalue 'v' */
632 void store(int r, SValue *sv)
634 SValue v1;
635 int v, ft, fc, fr, sign;
636 uint32_t op;
638 fr = sv->r;
639 ft = sv->type.t;
640 fc = sv->c.ul;
642 if(fc>=0)
643 sign=0;
644 else {
645 sign=1;
646 fc=-fc;
649 v = fr & VT_VALMASK;
650 if (fr & VT_LVAL || fr == VT_LOCAL) {
651 uint32_t base = 0xb;
652 if(v < VT_CONST) {
653 base=intr(v);
654 v=VT_LOCAL;
655 fc=sign=0;
656 } else if(v == VT_CONST) {
657 v1.type.t = ft;
658 v1.r = fr&~VT_LVAL;
659 v1.c.ul = sv->c.ul;
660 v1.sym=sv->sym;
661 load(base=14, &v1);
662 fc=sign=0;
663 v=VT_LOCAL;
665 if(v == VT_LOCAL) {
666 if(is_float(ft)) {
667 calcaddr(&base,&fc,&sign,1020,2);
668 #ifdef TCC_ARM_VFP
669 op=0xED000A00; /* fsts */
670 if(!sign)
671 op|=0x800000;
672 if ((ft & VT_BTYPE) != VT_FLOAT)
673 op|=0x100; /* fsts -> fstd */
674 o(op|(vfpr(r)<<12)|(fc>>2)|(base<<16));
675 #else
676 op=0xED000100;
677 if(!sign)
678 op|=0x800000;
679 #if LDOUBLE_SIZE == 8
680 if ((ft & VT_BTYPE) != VT_FLOAT)
681 op|=0x8000;
682 #else
683 if ((ft & VT_BTYPE) == VT_DOUBLE)
684 op|=0x8000;
685 if ((ft & VT_BTYPE) == VT_LDOUBLE)
686 op|=0x400000;
687 #endif
688 o(op|(fpr(r)<<12)|(fc>>2)|(base<<16));
689 #endif
690 return;
691 } else if((ft & VT_BTYPE) == VT_SHORT) {
692 calcaddr(&base,&fc,&sign,255,0);
693 op=0xE14000B0;
694 if(!sign)
695 op|=0x800000;
696 o(op|(intr(r)<<12)|(base<<16)|((fc&0xf0)<<4)|(fc&0xf));
697 } else {
698 calcaddr(&base,&fc,&sign,4095,0);
699 op=0xE5000000;
700 if(!sign)
701 op|=0x800000;
702 if ((ft & VT_BTYPE) == VT_BYTE)
703 op|=0x400000;
704 o(op|(intr(r)<<12)|fc|(base<<16));
706 return;
709 tcc_error("store unimplemented");
712 static void gadd_sp(int val)
714 stuff_const_harder(0xE28DD000,val);
717 /* 'is_jmp' is '1' if it is a jump */
718 static void gcall_or_jmp(int is_jmp)
720 int r;
721 if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
722 uint32_t x;
723 /* constant case */
724 x=encbranch(ind,ind+vtop->c.ul,0);
725 if(x) {
726 if (vtop->r & VT_SYM) {
727 /* relocation case */
728 greloc(cur_text_section, vtop->sym, ind, R_ARM_PC24);
729 } else
730 put_elf_reloc(symtab_section, cur_text_section, ind, R_ARM_PC24, 0);
731 o(x|(is_jmp?0xE0000000:0xE1000000));
732 } else {
733 if(!is_jmp)
734 o(0xE28FE004); // add lr,pc,#4
735 o(0xE51FF004); // ldr pc,[pc,#-4]
736 if (vtop->r & VT_SYM)
737 greloc(cur_text_section, vtop->sym, ind, R_ARM_ABS32);
738 o(vtop->c.ul);
740 } else {
741 /* otherwise, indirect call */
742 r = gv(RC_INT);
743 if(!is_jmp)
744 o(0xE1A0E00F); // mov lr,pc
745 o(0xE1A0F000|intr(r)); // mov pc,r
749 #ifdef TCC_ARM_HARDFLOAT
750 static int is_float_hgen_aggr(CType *type)
752 if ((type->t & VT_BTYPE) == VT_STRUCT) {
753 struct Sym *ref;
754 int btype, nb_fields = 0;
756 ref = type->ref;
757 btype = ref->type.t & VT_BTYPE;
758 if (btype == VT_FLOAT || btype == VT_DOUBLE) {
759 for(; ref && btype == (ref->type.t & VT_BTYPE); ref = ref->next, nb_fields++);
760 return !ref && nb_fields <= 4;
763 return 0;
766 struct avail_regs {
767 /* worst case: f(float, double, 3 float struct, double, 3 float struct, double) */
768 signed char avail[3];
769 int first_hole;
770 int last_hole;
771 int first_free_reg;
774 #define AVAIL_REGS_INITIALIZER (struct avail_regs) { { 0, 0, 0}, 0, 0, 0 }
776 /* Assign a register for a CPRC param with correct size and alignment
777 * size and align are in bytes, as returned by type_size */
778 int assign_fpreg(struct avail_regs *avregs, int align, int size)
780 int first_reg = 0;
782 if (avregs->first_free_reg == -1)
783 return -1;
784 if (align >> 3) { // alignment needed (base type: double)
785 first_reg = avregs->first_free_reg;
786 if (first_reg & 1)
787 avregs->avail[avregs->last_hole++] = first_reg++;
788 } else {
789 if (size == 4 && avregs->first_hole != avregs->last_hole)
790 return avregs->avail[avregs->first_hole++];
791 else
792 first_reg = avregs->first_free_reg;
794 if (first_reg + size / 4 <= 16) {
795 avregs->first_free_reg = first_reg + size / 4;
796 return first_reg;
798 avregs->first_free_reg = -1;
799 return -1;
801 #endif
803 /* Return 1 if this function returns via an sret pointer, 0 otherwise */
804 ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align) {
805 #if TCC_ARM_EABI
806 int size, align;
807 size = type_size(vt, &align);
808 if (size > 4) {
809 return 1;
810 } else {
811 *ret_align = 4;
812 ret->ref = NULL;
813 ret->t = VT_INT;
814 return 0;
816 #else
817 return 1;
818 #endif
821 /* Generate function call. The function address is pushed first, then
822 all the parameters in call order. This functions pops all the
823 parameters and the function address. */
824 void gfunc_call(int nb_args)
826 int size, align, r, args_size, i, ncrn, ncprn, argno, vfp_argno;
827 signed char plan[4][2]={{-1,-1},{-1,-1},{-1,-1},{-1,-1}};
828 SValue *before_stack = NULL; /* SValue before first on stack argument */
829 SValue *before_vfpreg_hfa = NULL; /* SValue before first in VFP reg hfa argument */
830 #ifdef TCC_ARM_HARDFLOAT
831 struct avail_regs avregs = AVAIL_REGS_INITIALIZER;
832 signed char vfp_plan[16];
833 int plan2[4+16];
834 int variadic;
835 #else
836 int plan2[4]={0,0,0,0};
837 #endif
838 int vfp_todo=0;
839 int todo=0, keep;
841 #ifdef TCC_ARM_HARDFLOAT
842 memset(vfp_plan, -1, sizeof(vfp_plan));
843 memset(plan2, 0, sizeof(plan2));
844 variadic = (vtop[-nb_args].type.ref->c == FUNC_ELLIPSIS);
845 #endif
846 r = vtop->r & VT_VALMASK;
847 if (r == VT_CMP || (r & ~1) == VT_JMP)
848 gv(RC_INT);
849 #ifdef TCC_ARM_EABI
850 if((vtop[-nb_args].type.ref->type.t & VT_BTYPE) == VT_STRUCT
851 && type_size(&vtop[-nb_args].type.ref->type, &align) <= 4) {
852 SValue tmp;
853 tmp=vtop[-nb_args];
854 vtop[-nb_args]=vtop[-nb_args+1];
855 vtop[-nb_args+1]=tmp;
856 --nb_args;
859 vpushi(0), nb_args++;
860 vtop->type.t = VT_LLONG;
861 #endif
862 ncrn = ncprn = argno = vfp_argno = args_size = 0;
863 /* Assign argument to registers and stack with alignment.
864 If, considering alignment constraints, enough registers of the correct type
865 (core or VFP) are free for the current argument, assign them to it, else
866 allocate on stack with correct alignment. Whenever a structure is allocated
867 in registers or on stack, it is always put on the stack at this stage. The
868 stack is divided in 3 zones. The zone are, from low addresses to high
869 addresses: structures to be loaded in core registers, structures to be
870 loaded in VFP registers, argument allocated to stack. SValue's representing
871 structures in the first zone are moved just after the SValue pointed by
872 before_vfpreg_hfa. SValue's representing structures in the second zone are
873 moved just after the SValue pointer by before_stack. */
874 for(i = nb_args; i-- ;) {
875 int j, assigned_vfpreg = 0;
876 size = type_size(&vtop[-i].type, &align);
877 switch(vtop[-i].type.t & VT_BTYPE) {
878 case VT_STRUCT:
879 case VT_FLOAT:
880 case VT_DOUBLE:
881 case VT_LDOUBLE:
882 #ifdef TCC_ARM_HARDFLOAT
883 if (!variadic) {
884 int hfa = 0; /* Homogeneous float aggregate */
886 if (is_float(vtop[-i].type.t)
887 || (hfa = is_float_hgen_aggr(&vtop[-i].type))) {
888 int end_reg;
890 assigned_vfpreg = assign_fpreg(&avregs, align, size);
891 end_reg = assigned_vfpreg + (size - 1) / 4;
892 if (assigned_vfpreg >= 0) {
893 vfp_plan[vfp_argno++]=TREG_F0 + assigned_vfpreg/2;
894 if (hfa) {
895 /* before_stack can only have been set because all core registers
896 are assigned, so no need to care about before_vfpreg_hfa if
897 before_stack is set */
898 if (before_stack) {
899 vrote(&vtop[-i], &vtop[-i] - before_stack);
900 before_stack++;
901 } else if (!before_vfpreg_hfa)
902 before_vfpreg_hfa = &vtop[-i-1];
903 for (j = assigned_vfpreg; j <= end_reg; j++)
904 vfp_todo|=(1<<j);
906 continue;
907 } else {
908 if (!hfa)
909 vfp_argno++;
910 /* No need to update before_stack as no more hfa can be allocated in
911 VFP regs */
912 if (!before_vfpreg_hfa)
913 before_vfpreg_hfa = &vtop[-i-1];
914 break;
918 #endif
919 ncrn = (ncrn + (align-1)/4) & -(align/4);
920 size = (size + 3) & -4;
921 if (ncrn + size/4 <= 4 || (ncrn < 4 && assigned_vfpreg != -1)) {
922 /* Either there is HFA in VFP registers, or there is arguments on stack,
923 it cannot be both. Hence either before_stack already points after
924 the slot where the vtop[-i] SValue is moved, or before_stack will not
925 be used */
926 if (before_vfpreg_hfa) {
927 vrote(&vtop[-i], &vtop[-i] - before_vfpreg_hfa);
928 before_vfpreg_hfa++;
930 for (j = ncrn; j < 4 && j < ncrn + size / 4; j++)
931 todo|=(1<<j);
932 ncrn+=size/4;
933 if (ncrn > 4) {
934 args_size = (ncrn - 4) * 4;
935 if (!before_stack)
936 before_stack = &vtop[-i-1];
939 else {
940 ncrn = 4;
941 /* No need to set before_vfpreg_hfa if not set since there will no
942 longer be any structure assigned to core registers */
943 if (!before_stack)
944 before_stack = &vtop[-i-1];
945 break;
947 continue;
948 default:
949 #ifdef TCC_ARM_EABI
950 if (!i) {
951 break;
953 #endif
954 if (ncrn < 4) {
955 int is_long = (vtop[-i].type.t & VT_BTYPE) == VT_LLONG;
957 if (is_long) {
958 ncrn = (ncrn + 1) & -2;
959 if (ncrn == 4) {
960 argno++;
961 break;
964 plan[argno++][0]=ncrn++;
965 if (is_long) {
966 plan[argno-1][1]=ncrn++;
968 continue;
970 argno++;
972 #ifdef TCC_ARM_EABI
973 if(args_size & (align-1)) {
974 vpushi(0);
975 vtop->type.t = VT_VOID; /* padding */
976 vrott(i+2);
977 args_size += 4;
978 nb_args++;
979 argno++;
981 #endif
982 args_size += (size + 3) & -4;
984 #ifdef TCC_ARM_EABI
985 vtop--, nb_args--;
986 #endif
987 args_size = keep = 0;
988 for(i = 0;i < nb_args; i++) {
989 vrotb(keep+1);
990 if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
991 size = type_size(&vtop->type, &align);
992 /* align to stack align size */
993 size = (size + 3) & -4;
994 /* allocate the necessary size on stack */
995 gadd_sp(-size);
996 /* generate structure store */
997 r = get_reg(RC_INT);
998 o(0xE1A0000D|(intr(r)<<12));
999 vset(&vtop->type, r | VT_LVAL, 0);
1000 vswap();
1001 vstore();
1002 vtop--;
1003 args_size += size;
1004 } else if (is_float(vtop->type.t)) {
1005 #ifdef TCC_ARM_HARDFLOAT
1006 if (!variadic && --vfp_argno<16 && vfp_plan[vfp_argno]!=-1) {
1007 plan2[keep++]=vfp_plan[vfp_argno];
1008 continue;
1010 #endif
1011 #ifdef TCC_ARM_VFP
1012 r=vfpr(gv(RC_FLOAT))<<12;
1013 size=4;
1014 if ((vtop->type.t & VT_BTYPE) != VT_FLOAT)
1016 size=8;
1017 r|=0x101; /* fstms -> fstmd */
1019 o(0xED2D0A01+r);
1020 #else
1021 r=fpr(gv(RC_FLOAT))<<12;
1022 if ((vtop->type.t & VT_BTYPE) == VT_FLOAT)
1023 size = 4;
1024 else if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE)
1025 size = 8;
1026 else
1027 size = LDOUBLE_SIZE;
1029 if (size == 12)
1030 r|=0x400000;
1031 else if(size == 8)
1032 r|=0x8000;
1034 o(0xED2D0100|r|(size>>2));
1035 #endif
1036 vtop--;
1037 args_size += size;
1038 } else {
1039 int s;
1040 /* simple type (currently always same size) */
1041 /* XXX: implicit cast ? */
1042 size=4;
1043 if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
1044 lexpand_nr();
1045 s=-1;
1046 if(--argno<4 && plan[argno][1]!=-1)
1047 s=plan[argno][1];
1048 argno++;
1049 size = 8;
1050 if(s==-1) {
1051 r = gv(RC_INT);
1052 o(0xE52D0004|(intr(r)<<12)); /* str r,[sp,#-4]! */
1053 vtop--;
1054 } else {
1055 size=0;
1056 plan2[keep]=s;
1057 keep++;
1058 vswap();
1061 s=-1;
1062 if(--argno<4 && plan[argno][0]!=-1)
1063 s=plan[argno][0];
1064 #ifdef TCC_ARM_EABI
1065 if(vtop->type.t == VT_VOID) {
1066 if(s == -1)
1067 o(0xE24DD004); /* sub sp,sp,#4 */
1068 vtop--;
1069 } else
1070 #endif
1071 if(s == -1) {
1072 r = gv(RC_INT);
1073 o(0xE52D0004|(intr(r)<<12)); /* str r,[sp,#-4]! */
1074 vtop--;
1075 } else {
1076 size=0;
1077 plan2[keep]=s;
1078 keep++;
1080 args_size += size;
1083 for(i = 0; i < keep; i++) {
1084 vrotb(keep);
1085 gv(regmask(plan2[i]));
1086 #ifdef TCC_ARM_HARDFLOAT
1087 /* arg is in s(2d+1): plan2[i]<plan2[i+1] => alignment occured (ex f,d,f) */
1088 if (i < keep - 1 && is_float(vtop->type.t) && (plan2[i] <= plan2[i + 1])) {
1089 o(0xEEF00A40|(vfpr(plan2[i])<<12)|vfpr(plan2[i]));
1091 #endif
1093 save_regs(keep); /* save used temporary registers */
1094 keep++;
1095 if(ncrn) {
1096 int nb_regs=0;
1097 if (ncrn>4)
1098 ncrn=4;
1099 todo&=((1<<ncrn)-1);
1100 if(todo) {
1101 int i;
1102 o(0xE8BD0000|todo);
1103 for(i=0;i<4;i++)
1104 if(todo&(1<<i)) {
1105 vpushi(0);
1106 vtop->r=i;
1107 keep++;
1108 nb_regs++;
1111 args_size-=nb_regs*4;
1113 if(vfp_todo) {
1114 int nb_fregs=0;
1116 for(i=0;i<16;i++)
1117 if(vfp_todo&(1<<i)) {
1118 o(0xED9D0A00|(i&1)<<22|(i>>1)<<12|nb_fregs);
1119 vpushi(0);
1120 /* There might be 2 floats in a double VFP reg but that doesn't seem
1121 to matter */
1122 if (!(i%2))
1123 vtop->r=TREG_F0+i/2;
1124 keep++;
1125 nb_fregs++;
1127 if (nb_fregs) {
1128 gadd_sp(nb_fregs*4);
1129 args_size-=nb_fregs*4;
1132 vrotb(keep);
1133 gcall_or_jmp(0);
1134 if (args_size)
1135 gadd_sp(args_size);
1136 #ifdef TCC_ARM_EABI
1137 if((vtop->type.ref->type.t & VT_BTYPE) == VT_STRUCT
1138 && type_size(&vtop->type.ref->type, &align) <= 4)
1140 store(REG_IRET,vtop-keep);
1141 ++keep;
1143 #ifdef TCC_ARM_VFP
1144 #ifdef TCC_ARM_HARDFLOAT
1145 else if(variadic && is_float(vtop->type.ref->type.t)) {
1146 #else
1147 else if(is_float(vtop->type.ref->type.t)) {
1148 #endif
1149 if((vtop->type.ref->type.t & VT_BTYPE) == VT_FLOAT) {
1150 o(0xEE000A10); /* fmsr s0,r0 */
1151 } else {
1152 o(0xEE000B10); /* fmdlr d0,r0 */
1153 o(0xEE201B10); /* fmdhr d0,r1 */
1156 #endif
1157 #endif
1158 vtop-=keep;
1159 leaffunc = 0;
1162 /* generate function prolog of type 't' */
1163 void gfunc_prolog(CType *func_type)
1165 Sym *sym,*sym2;
1166 int n,nf,size,align, variadic, struct_ret = 0;
1167 #ifdef TCC_ARM_HARDFLOAT
1168 struct avail_regs avregs = AVAIL_REGS_INITIALIZER;
1169 #endif
1171 sym = func_type->ref;
1172 func_vt = sym->type;
1174 n = nf = 0;
1175 variadic = (func_type->ref->c == FUNC_ELLIPSIS);
1176 if((func_vt.t & VT_BTYPE) == VT_STRUCT
1177 && type_size(&func_vt,&align) > 4)
1179 n++;
1180 struct_ret = 1;
1181 func_vc = 12; /* Offset from fp of the place to store the result */
1183 for(sym2=sym->next;sym2 && (n<4 || nf<16);sym2=sym2->next) {
1184 size = type_size(&sym2->type, &align);
1185 #ifdef TCC_ARM_HARDFLOAT
1186 if (!variadic && (is_float(sym2->type.t)
1187 || is_float_hgen_aggr(&sym2->type))) {
1188 int tmpnf = assign_fpreg(&avregs, align, size) + 1;
1189 nf = (tmpnf > nf) ? tmpnf : nf;
1190 } else
1191 #endif
1192 if (n < 4)
1193 n += (size + 3) / 4;
1195 o(0xE1A0C00D); /* mov ip,sp */
1196 if(variadic)
1197 n=4;
1198 if(n) {
1199 if(n>4)
1200 n=4;
1201 #ifdef TCC_ARM_EABI
1202 n=(n+1)&-2;
1203 #endif
1204 o(0xE92D0000|((1<<n)-1)); /* save r0-r4 on stack if needed */
1206 if (nf) {
1207 if (nf>16)
1208 nf=16;
1209 nf=(nf+1)&-2; /* nf => HARDFLOAT => EABI */
1210 o(0xED2D0A00|nf); /* save s0-s15 on stack if needed */
1212 o(0xE92D5800); /* save fp, ip, lr */
1213 o(0xE1A0B00D); /* mov fp, sp */
1214 func_sub_sp_offset = ind;
1215 o(0xE1A00000); /* nop, leave space for stack adjustment in epilogue */
1217 int addr, pn = struct_ret, sn = 0; /* pn=core, sn=stack */
1219 #ifdef TCC_ARM_HARDFLOAT
1220 avregs = AVAIL_REGS_INITIALIZER;
1221 #endif
1222 while ((sym = sym->next)) {
1223 CType *type;
1224 type = &sym->type;
1225 size = type_size(type, &align);
1226 size = (size + 3) >> 2;
1227 align = (align + 3) & ~3;
1228 #ifdef TCC_ARM_HARDFLOAT
1229 if (!variadic && (is_float(sym->type.t)
1230 || is_float_hgen_aggr(&sym->type))) {
1231 int fpn = assign_fpreg(&avregs, align, size << 2);
1232 if (fpn >= 0) {
1233 addr = fpn * 4;
1234 } else
1235 goto from_stack;
1236 } else
1237 #endif
1238 if (pn < 4) {
1239 #ifdef TCC_ARM_EABI
1240 pn = (pn + (align-1)/4) & -(align/4);
1241 #endif
1242 addr = (nf + pn) * 4;
1243 pn += size;
1244 if (!sn && pn > 4)
1245 sn = (pn - 4);
1246 } else {
1247 #ifdef TCC_ARM_HARDFLOAT
1248 from_stack:
1249 #endif
1250 #ifdef TCC_ARM_EABI
1251 sn = (sn + (align-1)/4) & -(align/4);
1252 #endif
1253 addr = (n + nf + sn) * 4;
1254 sn += size;
1256 sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | lvalue_type(type->t), addr+12);
1259 last_itod_magic=0;
1260 leaffunc = 1;
1261 loc = 0;
1264 /* generate function epilog */
1265 void gfunc_epilog(void)
1267 uint32_t x;
1268 int diff;
1269 #ifdef TCC_ARM_EABI
1270 /* Useless but harmless copy of the float result into main register(s) in case
1271 of variadic function in the hardfloat variant */
1272 if(is_float(func_vt.t)) {
1273 if((func_vt.t & VT_BTYPE) == VT_FLOAT)
1274 o(0xEE100A10); /* fmrs r0, s0 */
1275 else {
1276 o(0xEE100B10); /* fmrdl r0, d0 */
1277 o(0xEE301B10); /* fmrdh r1, d0 */
1280 #endif
1281 o(0xE89BA800); /* restore fp, sp, pc */
1282 diff = (-loc + 3) & -4;
1283 #ifdef TCC_ARM_EABI
1284 if(!leaffunc)
1285 diff = ((diff + 11) & -8) - 4;
1286 #endif
1287 if(diff > 0) {
1288 x=stuff_const(0xE24BD000, diff); /* sub sp,fp,# */
1289 if(x)
1290 *(uint32_t *)(cur_text_section->data + func_sub_sp_offset) = x;
1291 else {
1292 int addr;
1293 addr=ind;
1294 o(0xE59FC004); /* ldr ip,[pc+4] */
1295 o(0xE04BD00C); /* sub sp,fp,ip */
1296 o(0xE1A0F00E); /* mov pc,lr */
1297 o(diff);
1298 *(uint32_t *)(cur_text_section->data + func_sub_sp_offset) = 0xE1000000|encbranch(func_sub_sp_offset,addr,1);
1303 /* generate a jump to a label */
1304 int gjmp(int t)
1306 int r;
1307 r=ind;
1308 o(0xE0000000|encbranch(r,t,1));
1309 return r;
1312 /* generate a jump to a fixed address */
1313 void gjmp_addr(int a)
1315 gjmp(a);
1318 /* generate a test. set 'inv' to invert test. Stack entry is popped */
1319 int gtst(int inv, int t)
1321 int v, r;
1322 uint32_t op;
1323 v = vtop->r & VT_VALMASK;
1324 r=ind;
1325 if (v == VT_CMP) {
1326 op=mapcc(inv?negcc(vtop->c.i):vtop->c.i);
1327 op|=encbranch(r,t,1);
1328 o(op);
1329 t=r;
1330 } else if (v == VT_JMP || v == VT_JMPI) {
1331 if ((v & 1) == inv) {
1332 if(!vtop->c.i)
1333 vtop->c.i=t;
1334 else {
1335 uint32_t *x;
1336 int p,lp;
1337 if(t) {
1338 p = vtop->c.i;
1339 do {
1340 p = decbranch(lp=p);
1341 } while(p);
1342 x = (uint32_t *)(cur_text_section->data + lp);
1343 *x &= 0xff000000;
1344 *x |= encbranch(lp,t,1);
1346 t = vtop->c.i;
1348 } else {
1349 t = gjmp(t);
1350 gsym(vtop->c.i);
1352 } else {
1353 if (is_float(vtop->type.t)) {
1354 r=gv(RC_FLOAT);
1355 #ifdef TCC_ARM_VFP
1356 o(0xEEB50A40|(vfpr(r)<<12)|T2CPR(vtop->type.t)); /* fcmpzX */
1357 o(0xEEF1FA10); /* fmstat */
1358 #else
1359 o(0xEE90F118|(fpr(r)<<16));
1360 #endif
1361 vtop->r = VT_CMP;
1362 vtop->c.i = TOK_NE;
1363 return gtst(inv, t);
1364 } else if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
1365 /* constant jmp optimization */
1366 if ((vtop->c.i != 0) != inv)
1367 t = gjmp(t);
1368 } else {
1369 v = gv(RC_INT);
1370 o(0xE3300000|(intr(v)<<16));
1371 vtop->r = VT_CMP;
1372 vtop->c.i = TOK_NE;
1373 return gtst(inv, t);
1376 vtop--;
1377 return t;
1380 /* generate an integer binary operation */
1381 void gen_opi(int op)
1383 int c, func = 0;
1384 uint32_t opc = 0, r, fr;
1385 unsigned short retreg = REG_IRET;
1387 c=0;
1388 switch(op) {
1389 case '+':
1390 opc = 0x8;
1391 c=1;
1392 break;
1393 case TOK_ADDC1: /* add with carry generation */
1394 opc = 0x9;
1395 c=1;
1396 break;
1397 case '-':
1398 opc = 0x4;
1399 c=1;
1400 break;
1401 case TOK_SUBC1: /* sub with carry generation */
1402 opc = 0x5;
1403 c=1;
1404 break;
1405 case TOK_ADDC2: /* add with carry use */
1406 opc = 0xA;
1407 c=1;
1408 break;
1409 case TOK_SUBC2: /* sub with carry use */
1410 opc = 0xC;
1411 c=1;
1412 break;
1413 case '&':
1414 opc = 0x0;
1415 c=1;
1416 break;
1417 case '^':
1418 opc = 0x2;
1419 c=1;
1420 break;
1421 case '|':
1422 opc = 0x18;
1423 c=1;
1424 break;
1425 case '*':
1426 gv2(RC_INT, RC_INT);
1427 r = vtop[-1].r;
1428 fr = vtop[0].r;
1429 vtop--;
1430 o(0xE0000090|(intr(r)<<16)|(intr(r)<<8)|intr(fr));
1431 return;
1432 case TOK_SHL:
1433 opc = 0;
1434 c=2;
1435 break;
1436 case TOK_SHR:
1437 opc = 1;
1438 c=2;
1439 break;
1440 case TOK_SAR:
1441 opc = 2;
1442 c=2;
1443 break;
1444 case '/':
1445 case TOK_PDIV:
1446 func=TOK___divsi3;
1447 c=3;
1448 break;
1449 case TOK_UDIV:
1450 func=TOK___udivsi3;
1451 c=3;
1452 break;
1453 case '%':
1454 #ifdef TCC_ARM_EABI
1455 func=TOK___aeabi_idivmod;
1456 retreg=REG_LRET;
1457 #else
1458 func=TOK___modsi3;
1459 #endif
1460 c=3;
1461 break;
1462 case TOK_UMOD:
1463 #ifdef TCC_ARM_EABI
1464 func=TOK___aeabi_uidivmod;
1465 retreg=REG_LRET;
1466 #else
1467 func=TOK___umodsi3;
1468 #endif
1469 c=3;
1470 break;
1471 case TOK_UMULL:
1472 gv2(RC_INT, RC_INT);
1473 r=intr(vtop[-1].r2=get_reg(RC_INT));
1474 c=vtop[-1].r;
1475 vtop[-1].r=get_reg_ex(RC_INT,regmask(c));
1476 vtop--;
1477 o(0xE0800090|(r<<16)|(intr(vtop->r)<<12)|(intr(c)<<8)|intr(vtop[1].r));
1478 return;
1479 default:
1480 opc = 0x15;
1481 c=1;
1482 break;
1484 switch(c) {
1485 case 1:
1486 if((vtop[-1].r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
1487 if(opc == 4 || opc == 5 || opc == 0xc) {
1488 vswap();
1489 opc|=2; // sub -> rsb
1492 if ((vtop->r & VT_VALMASK) == VT_CMP ||
1493 (vtop->r & (VT_VALMASK & ~1)) == VT_JMP)
1494 gv(RC_INT);
1495 vswap();
1496 c=intr(gv(RC_INT));
1497 vswap();
1498 opc=0xE0000000|(opc<<20)|(c<<16);
1499 if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
1500 uint32_t x;
1501 x=stuff_const(opc|0x2000000,vtop->c.i);
1502 if(x) {
1503 r=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r)));
1504 o(x|(r<<12));
1505 goto done;
1508 fr=intr(gv(RC_INT));
1509 r=intr(vtop[-1].r=get_reg_ex(RC_INT,two2mask(vtop->r,vtop[-1].r)));
1510 o(opc|(r<<12)|fr);
1511 done:
1512 vtop--;
1513 if (op >= TOK_ULT && op <= TOK_GT) {
1514 vtop->r = VT_CMP;
1515 vtop->c.i = op;
1517 break;
1518 case 2:
1519 opc=0xE1A00000|(opc<<5);
1520 if ((vtop->r & VT_VALMASK) == VT_CMP ||
1521 (vtop->r & (VT_VALMASK & ~1)) == VT_JMP)
1522 gv(RC_INT);
1523 vswap();
1524 r=intr(gv(RC_INT));
1525 vswap();
1526 opc|=r;
1527 if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
1528 fr=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r)));
1529 c = vtop->c.i & 0x1f;
1530 o(opc|(c<<7)|(fr<<12));
1531 } else {
1532 fr=intr(gv(RC_INT));
1533 c=intr(vtop[-1].r=get_reg_ex(RC_INT,two2mask(vtop->r,vtop[-1].r)));
1534 o(opc|(c<<12)|(fr<<8)|0x10);
1536 vtop--;
1537 break;
1538 case 3:
1539 vpush_global_sym(&func_old_type, func);
1540 vrott(3);
1541 gfunc_call(2);
1542 vpushi(0);
1543 vtop->r = retreg;
1544 break;
1545 default:
1546 tcc_error("gen_opi %i unimplemented!",op);
1550 #ifdef TCC_ARM_VFP
1551 static int is_zero(int i)
1553 if((vtop[i].r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST)
1554 return 0;
1555 if (vtop[i].type.t == VT_FLOAT)
1556 return (vtop[i].c.f == 0.f);
1557 else if (vtop[i].type.t == VT_DOUBLE)
1558 return (vtop[i].c.d == 0.0);
1559 return (vtop[i].c.ld == 0.l);
1562 /* generate a floating point operation 'v = t1 op t2' instruction. The
1563 * two operands are guaranted to have the same floating point type */
1564 void gen_opf(int op)
1566 uint32_t x;
1567 int fneg=0,r;
1568 x=0xEE000A00|T2CPR(vtop->type.t);
1569 switch(op) {
1570 case '+':
1571 if(is_zero(-1))
1572 vswap();
1573 if(is_zero(0)) {
1574 vtop--;
1575 return;
1577 x|=0x300000;
1578 break;
1579 case '-':
1580 x|=0x300040;
1581 if(is_zero(0)) {
1582 vtop--;
1583 return;
1585 if(is_zero(-1)) {
1586 x|=0x810000; /* fsubX -> fnegX */
1587 vswap();
1588 vtop--;
1589 fneg=1;
1591 break;
1592 case '*':
1593 x|=0x200000;
1594 break;
1595 case '/':
1596 x|=0x800000;
1597 break;
1598 default:
1599 if(op < TOK_ULT || op > TOK_GT) {
1600 tcc_error("unknown fp op %x!",op);
1601 return;
1603 if(is_zero(-1)) {
1604 vswap();
1605 switch(op) {
1606 case TOK_LT: op=TOK_GT; break;
1607 case TOK_GE: op=TOK_ULE; break;
1608 case TOK_LE: op=TOK_GE; break;
1609 case TOK_GT: op=TOK_ULT; break;
1612 x|=0xB40040; /* fcmpX */
1613 if(op!=TOK_EQ && op!=TOK_NE)
1614 x|=0x80; /* fcmpX -> fcmpeX */
1615 if(is_zero(0)) {
1616 vtop--;
1617 o(x|0x10000|(vfpr(gv(RC_FLOAT))<<12)); /* fcmp(e)X -> fcmp(e)zX */
1618 } else {
1619 x|=vfpr(gv(RC_FLOAT));
1620 vswap();
1621 o(x|(vfpr(gv(RC_FLOAT))<<12));
1622 vtop--;
1624 o(0xEEF1FA10); /* fmstat */
1626 switch(op) {
1627 case TOK_LE: op=TOK_ULE; break;
1628 case TOK_LT: op=TOK_ULT; break;
1629 case TOK_UGE: op=TOK_GE; break;
1630 case TOK_UGT: op=TOK_GT; break;
1633 vtop->r = VT_CMP;
1634 vtop->c.i = op;
1635 return;
1637 r=gv(RC_FLOAT);
1638 x|=vfpr(r);
1639 r=regmask(r);
1640 if(!fneg) {
1641 int r2;
1642 vswap();
1643 r2=gv(RC_FLOAT);
1644 x|=vfpr(r2)<<16;
1645 r|=regmask(r2);
1647 vtop->r=get_reg_ex(RC_FLOAT,r);
1648 if(!fneg)
1649 vtop--;
1650 o(x|(vfpr(vtop->r)<<12));
1653 #else
1654 static uint32_t is_fconst()
1656 long double f;
1657 uint32_t r;
1658 if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST)
1659 return 0;
1660 if (vtop->type.t == VT_FLOAT)
1661 f = vtop->c.f;
1662 else if (vtop->type.t == VT_DOUBLE)
1663 f = vtop->c.d;
1664 else
1665 f = vtop->c.ld;
1666 if(!ieee_finite(f))
1667 return 0;
1668 r=0x8;
1669 if(f<0.0) {
1670 r=0x18;
1671 f=-f;
1673 if(f==0.0)
1674 return r;
1675 if(f==1.0)
1676 return r|1;
1677 if(f==2.0)
1678 return r|2;
1679 if(f==3.0)
1680 return r|3;
1681 if(f==4.0)
1682 return r|4;
1683 if(f==5.0)
1684 return r|5;
1685 if(f==0.5)
1686 return r|6;
1687 if(f==10.0)
1688 return r|7;
1689 return 0;
1692 /* generate a floating point operation 'v = t1 op t2' instruction. The
1693 two operands are guaranted to have the same floating point type */
1694 void gen_opf(int op)
1696 uint32_t x, r, r2, c1, c2;
1697 //fputs("gen_opf\n",stderr);
1698 vswap();
1699 c1 = is_fconst();
1700 vswap();
1701 c2 = is_fconst();
1702 x=0xEE000100;
1703 #if LDOUBLE_SIZE == 8
1704 if ((vtop->type.t & VT_BTYPE) != VT_FLOAT)
1705 x|=0x80;
1706 #else
1707 if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE)
1708 x|=0x80;
1709 else if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE)
1710 x|=0x80000;
1711 #endif
1712 switch(op)
1714 case '+':
1715 if(!c2) {
1716 vswap();
1717 c2=c1;
1719 vswap();
1720 r=fpr(gv(RC_FLOAT));
1721 vswap();
1722 if(c2) {
1723 if(c2>0xf)
1724 x|=0x200000; // suf
1725 r2=c2&0xf;
1726 } else {
1727 r2=fpr(gv(RC_FLOAT));
1729 break;
1730 case '-':
1731 if(c2) {
1732 if(c2<=0xf)
1733 x|=0x200000; // suf
1734 r2=c2&0xf;
1735 vswap();
1736 r=fpr(gv(RC_FLOAT));
1737 vswap();
1738 } else if(c1 && c1<=0xf) {
1739 x|=0x300000; // rsf
1740 r2=c1;
1741 r=fpr(gv(RC_FLOAT));
1742 vswap();
1743 } else {
1744 x|=0x200000; // suf
1745 vswap();
1746 r=fpr(gv(RC_FLOAT));
1747 vswap();
1748 r2=fpr(gv(RC_FLOAT));
1750 break;
1751 case '*':
1752 if(!c2 || c2>0xf) {
1753 vswap();
1754 c2=c1;
1756 vswap();
1757 r=fpr(gv(RC_FLOAT));
1758 vswap();
1759 if(c2 && c2<=0xf)
1760 r2=c2;
1761 else
1762 r2=fpr(gv(RC_FLOAT));
1763 x|=0x100000; // muf
1764 break;
1765 case '/':
1766 if(c2 && c2<=0xf) {
1767 x|=0x400000; // dvf
1768 r2=c2;
1769 vswap();
1770 r=fpr(gv(RC_FLOAT));
1771 vswap();
1772 } else if(c1 && c1<=0xf) {
1773 x|=0x500000; // rdf
1774 r2=c1;
1775 r=fpr(gv(RC_FLOAT));
1776 vswap();
1777 } else {
1778 x|=0x400000; // dvf
1779 vswap();
1780 r=fpr(gv(RC_FLOAT));
1781 vswap();
1782 r2=fpr(gv(RC_FLOAT));
1784 break;
1785 default:
1786 if(op >= TOK_ULT && op <= TOK_GT) {
1787 x|=0xd0f110; // cmfe
1788 /* bug (intention?) in Linux FPU emulator
1789 doesn't set carry if equal */
1790 switch(op) {
1791 case TOK_ULT:
1792 case TOK_UGE:
1793 case TOK_ULE:
1794 case TOK_UGT:
1795 tcc_error("unsigned comparision on floats?");
1796 break;
1797 case TOK_LT:
1798 op=TOK_Nset;
1799 break;
1800 case TOK_LE:
1801 op=TOK_ULE; /* correct in unordered case only if AC bit in FPSR set */
1802 break;
1803 case TOK_EQ:
1804 case TOK_NE:
1805 x&=~0x400000; // cmfe -> cmf
1806 break;
1808 if(c1 && !c2) {
1809 c2=c1;
1810 vswap();
1811 switch(op) {
1812 case TOK_Nset:
1813 op=TOK_GT;
1814 break;
1815 case TOK_GE:
1816 op=TOK_ULE;
1817 break;
1818 case TOK_ULE:
1819 op=TOK_GE;
1820 break;
1821 case TOK_GT:
1822 op=TOK_Nset;
1823 break;
1826 vswap();
1827 r=fpr(gv(RC_FLOAT));
1828 vswap();
1829 if(c2) {
1830 if(c2>0xf)
1831 x|=0x200000;
1832 r2=c2&0xf;
1833 } else {
1834 r2=fpr(gv(RC_FLOAT));
1836 vtop[-1].r = VT_CMP;
1837 vtop[-1].c.i = op;
1838 } else {
1839 tcc_error("unknown fp op %x!",op);
1840 return;
1843 if(vtop[-1].r == VT_CMP)
1844 c1=15;
1845 else {
1846 c1=vtop->r;
1847 if(r2&0x8)
1848 c1=vtop[-1].r;
1849 vtop[-1].r=get_reg_ex(RC_FLOAT,two2mask(vtop[-1].r,c1));
1850 c1=fpr(vtop[-1].r);
1852 vtop--;
1853 o(x|(r<<16)|(c1<<12)|r2);
1855 #endif
1857 /* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
1858 and 'long long' cases. */
1859 ST_FUNC void gen_cvt_itof1(int t)
1861 uint32_t r, r2;
1862 int bt;
1863 bt=vtop->type.t & VT_BTYPE;
1864 if(bt == VT_INT || bt == VT_SHORT || bt == VT_BYTE) {
1865 #ifndef TCC_ARM_VFP
1866 uint32_t dsize = 0;
1867 #endif
1868 r=intr(gv(RC_INT));
1869 #ifdef TCC_ARM_VFP
1870 r2=vfpr(vtop->r=get_reg(RC_FLOAT));
1871 o(0xEE000A10|(r<<12)|(r2<<16)); /* fmsr */
1872 r2|=r2<<12;
1873 if(!(vtop->type.t & VT_UNSIGNED))
1874 r2|=0x80; /* fuitoX -> fsituX */
1875 o(0xEEB80A40|r2|T2CPR(t)); /* fYitoX*/
1876 #else
1877 r2=fpr(vtop->r=get_reg(RC_FLOAT));
1878 if((t & VT_BTYPE) != VT_FLOAT)
1879 dsize=0x80; /* flts -> fltd */
1880 o(0xEE000110|dsize|(r2<<16)|(r<<12)); /* flts */
1881 if((vtop->type.t & (VT_UNSIGNED|VT_BTYPE)) == (VT_UNSIGNED|VT_INT)) {
1882 uint32_t off = 0;
1883 o(0xE3500000|(r<<12)); /* cmp */
1884 r=fpr(get_reg(RC_FLOAT));
1885 if(last_itod_magic) {
1886 off=ind+8-last_itod_magic;
1887 off/=4;
1888 if(off>255)
1889 off=0;
1891 o(0xBD1F0100|(r<<12)|off); /* ldflts */
1892 if(!off) {
1893 o(0xEA000000); /* b */
1894 last_itod_magic=ind;
1895 o(0x4F800000); /* 4294967296.0f */
1897 o(0xBE000100|dsize|(r2<<16)|(r2<<12)|r); /* adflt */
1899 #endif
1900 return;
1901 } else if(bt == VT_LLONG) {
1902 int func;
1903 CType *func_type = 0;
1904 if((t & VT_BTYPE) == VT_FLOAT) {
1905 func_type = &func_float_type;
1906 if(vtop->type.t & VT_UNSIGNED)
1907 func=TOK___floatundisf;
1908 else
1909 func=TOK___floatdisf;
1910 #if LDOUBLE_SIZE != 8
1911 } else if((t & VT_BTYPE) == VT_LDOUBLE) {
1912 func_type = &func_ldouble_type;
1913 if(vtop->type.t & VT_UNSIGNED)
1914 func=TOK___floatundixf;
1915 else
1916 func=TOK___floatdixf;
1917 } else if((t & VT_BTYPE) == VT_DOUBLE) {
1918 #else
1919 } else if((t & VT_BTYPE) == VT_DOUBLE || (t & VT_BTYPE) == VT_LDOUBLE) {
1920 #endif
1921 func_type = &func_double_type;
1922 if(vtop->type.t & VT_UNSIGNED)
1923 func=TOK___floatundidf;
1924 else
1925 func=TOK___floatdidf;
1927 if(func_type) {
1928 vpush_global_sym(func_type, func);
1929 vswap();
1930 gfunc_call(1);
1931 vpushi(0);
1932 vtop->r=TREG_F0;
1933 return;
1936 tcc_error("unimplemented gen_cvt_itof %x!",vtop->type.t);
1939 /* convert fp to int 't' type */
1940 void gen_cvt_ftoi(int t)
1942 uint32_t r, r2;
1943 int u, func = 0;
1944 u=t&VT_UNSIGNED;
1945 t&=VT_BTYPE;
1946 r2=vtop->type.t & VT_BTYPE;
1947 if(t==VT_INT) {
1948 #ifdef TCC_ARM_VFP
1949 r=vfpr(gv(RC_FLOAT));
1950 u=u?0:0x10000;
1951 o(0xEEBC0AC0|(r<<12)|r|T2CPR(r2)|u); /* ftoXizY */
1952 r2=intr(vtop->r=get_reg(RC_INT));
1953 o(0xEE100A10|(r<<16)|(r2<<12));
1954 return;
1955 #else
1956 if(u) {
1957 if(r2 == VT_FLOAT)
1958 func=TOK___fixunssfsi;
1959 #if LDOUBLE_SIZE != 8
1960 else if(r2 == VT_LDOUBLE)
1961 func=TOK___fixunsxfsi;
1962 else if(r2 == VT_DOUBLE)
1963 #else
1964 else if(r2 == VT_LDOUBLE || r2 == VT_DOUBLE)
1965 #endif
1966 func=TOK___fixunsdfsi;
1967 } else {
1968 r=fpr(gv(RC_FLOAT));
1969 r2=intr(vtop->r=get_reg(RC_INT));
1970 o(0xEE100170|(r2<<12)|r);
1971 return;
1973 #endif
1974 } else if(t == VT_LLONG) { // unsigned handled in gen_cvt_ftoi1
1975 if(r2 == VT_FLOAT)
1976 func=TOK___fixsfdi;
1977 #if LDOUBLE_SIZE != 8
1978 else if(r2 == VT_LDOUBLE)
1979 func=TOK___fixxfdi;
1980 else if(r2 == VT_DOUBLE)
1981 #else
1982 else if(r2 == VT_LDOUBLE || r2 == VT_DOUBLE)
1983 #endif
1984 func=TOK___fixdfdi;
1986 if(func) {
1987 vpush_global_sym(&func_old_type, func);
1988 vswap();
1989 gfunc_call(1);
1990 vpushi(0);
1991 if(t == VT_LLONG)
1992 vtop->r2 = REG_LRET;
1993 vtop->r = REG_IRET;
1994 return;
1996 tcc_error("unimplemented gen_cvt_ftoi!");
1999 /* convert from one floating point type to another */
2000 void gen_cvt_ftof(int t)
2002 #ifdef TCC_ARM_VFP
2003 if(((vtop->type.t & VT_BTYPE) == VT_FLOAT) != ((t & VT_BTYPE) == VT_FLOAT)) {
2004 uint32_t r = vfpr(gv(RC_FLOAT));
2005 o(0xEEB70AC0|(r<<12)|r|T2CPR(vtop->type.t));
2007 #else
2008 /* all we have to do on i386 and FPA ARM is to put the float in a register */
2009 gv(RC_FLOAT);
2010 #endif
2013 /* computed goto support */
2014 void ggoto(void)
2016 gcall_or_jmp(1);
2017 vtop--;
2020 /* end of ARM code generator */
2021 /*************************************************************/
2022 #endif
2023 /*************************************************************/