Relicensing TinyCC
[tinycc.git] / arm-gen.c
blob250b1d91f6c26a2e4f94ba6c3fd9c98d6474a271
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 func_vc += nf * 4;
1221 avregs = AVAIL_REGS_INITIALIZER;
1222 #endif
1223 while ((sym = sym->next)) {
1224 CType *type;
1225 type = &sym->type;
1226 size = type_size(type, &align);
1227 size = (size + 3) >> 2;
1228 align = (align + 3) & ~3;
1229 #ifdef TCC_ARM_HARDFLOAT
1230 if (!variadic && (is_float(sym->type.t)
1231 || is_float_hgen_aggr(&sym->type))) {
1232 int fpn = assign_fpreg(&avregs, align, size << 2);
1233 if (fpn >= 0) {
1234 addr = fpn * 4;
1235 } else
1236 goto from_stack;
1237 } else
1238 #endif
1239 if (pn < 4) {
1240 #ifdef TCC_ARM_EABI
1241 pn = (pn + (align-1)/4) & -(align/4);
1242 #endif
1243 addr = (nf + pn) * 4;
1244 pn += size;
1245 if (!sn && pn > 4)
1246 sn = (pn - 4);
1247 } else {
1248 #ifdef TCC_ARM_HARDFLOAT
1249 from_stack:
1250 #endif
1251 #ifdef TCC_ARM_EABI
1252 sn = (sn + (align-1)/4) & -(align/4);
1253 #endif
1254 addr = (n + nf + sn) * 4;
1255 sn += size;
1257 sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | lvalue_type(type->t), addr+12);
1260 last_itod_magic=0;
1261 leaffunc = 1;
1262 loc = 0;
1265 /* generate function epilog */
1266 void gfunc_epilog(void)
1268 uint32_t x;
1269 int diff;
1270 #ifdef TCC_ARM_EABI
1271 /* Useless but harmless copy of the float result into main register(s) in case
1272 of variadic function in the hardfloat variant */
1273 if(is_float(func_vt.t)) {
1274 if((func_vt.t & VT_BTYPE) == VT_FLOAT)
1275 o(0xEE100A10); /* fmrs r0, s0 */
1276 else {
1277 o(0xEE100B10); /* fmrdl r0, d0 */
1278 o(0xEE301B10); /* fmrdh r1, d0 */
1281 #endif
1282 o(0xE89BA800); /* restore fp, sp, pc */
1283 diff = (-loc + 3) & -4;
1284 #ifdef TCC_ARM_EABI
1285 if(!leaffunc)
1286 diff = ((diff + 11) & -8) - 4;
1287 #endif
1288 if(diff > 0) {
1289 x=stuff_const(0xE24BD000, diff); /* sub sp,fp,# */
1290 if(x)
1291 *(uint32_t *)(cur_text_section->data + func_sub_sp_offset) = x;
1292 else {
1293 int addr;
1294 addr=ind;
1295 o(0xE59FC004); /* ldr ip,[pc+4] */
1296 o(0xE04BD00C); /* sub sp,fp,ip */
1297 o(0xE1A0F00E); /* mov pc,lr */
1298 o(diff);
1299 *(uint32_t *)(cur_text_section->data + func_sub_sp_offset) = 0xE1000000|encbranch(func_sub_sp_offset,addr,1);
1304 /* generate a jump to a label */
1305 int gjmp(int t)
1307 int r;
1308 r=ind;
1309 o(0xE0000000|encbranch(r,t,1));
1310 return r;
1313 /* generate a jump to a fixed address */
1314 void gjmp_addr(int a)
1316 gjmp(a);
1319 /* generate a test. set 'inv' to invert test. Stack entry is popped */
1320 int gtst(int inv, int t)
1322 int v, r;
1323 uint32_t op;
1324 v = vtop->r & VT_VALMASK;
1325 r=ind;
1326 if (v == VT_CMP) {
1327 op=mapcc(inv?negcc(vtop->c.i):vtop->c.i);
1328 op|=encbranch(r,t,1);
1329 o(op);
1330 t=r;
1331 } else if (v == VT_JMP || v == VT_JMPI) {
1332 if ((v & 1) == inv) {
1333 if(!vtop->c.i)
1334 vtop->c.i=t;
1335 else {
1336 uint32_t *x;
1337 int p,lp;
1338 if(t) {
1339 p = vtop->c.i;
1340 do {
1341 p = decbranch(lp=p);
1342 } while(p);
1343 x = (uint32_t *)(cur_text_section->data + lp);
1344 *x &= 0xff000000;
1345 *x |= encbranch(lp,t,1);
1347 t = vtop->c.i;
1349 } else {
1350 t = gjmp(t);
1351 gsym(vtop->c.i);
1353 } else {
1354 if (is_float(vtop->type.t)) {
1355 r=gv(RC_FLOAT);
1356 #ifdef TCC_ARM_VFP
1357 o(0xEEB50A40|(vfpr(r)<<12)|T2CPR(vtop->type.t)); /* fcmpzX */
1358 o(0xEEF1FA10); /* fmstat */
1359 #else
1360 o(0xEE90F118|(fpr(r)<<16));
1361 #endif
1362 vtop->r = VT_CMP;
1363 vtop->c.i = TOK_NE;
1364 return gtst(inv, t);
1365 } else if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
1366 /* constant jmp optimization */
1367 if ((vtop->c.i != 0) != inv)
1368 t = gjmp(t);
1369 } else {
1370 v = gv(RC_INT);
1371 o(0xE3300000|(intr(v)<<16));
1372 vtop->r = VT_CMP;
1373 vtop->c.i = TOK_NE;
1374 return gtst(inv, t);
1377 vtop--;
1378 return t;
1381 /* generate an integer binary operation */
1382 void gen_opi(int op)
1384 int c, func = 0;
1385 uint32_t opc = 0, r, fr;
1386 unsigned short retreg = REG_IRET;
1388 c=0;
1389 switch(op) {
1390 case '+':
1391 opc = 0x8;
1392 c=1;
1393 break;
1394 case TOK_ADDC1: /* add with carry generation */
1395 opc = 0x9;
1396 c=1;
1397 break;
1398 case '-':
1399 opc = 0x4;
1400 c=1;
1401 break;
1402 case TOK_SUBC1: /* sub with carry generation */
1403 opc = 0x5;
1404 c=1;
1405 break;
1406 case TOK_ADDC2: /* add with carry use */
1407 opc = 0xA;
1408 c=1;
1409 break;
1410 case TOK_SUBC2: /* sub with carry use */
1411 opc = 0xC;
1412 c=1;
1413 break;
1414 case '&':
1415 opc = 0x0;
1416 c=1;
1417 break;
1418 case '^':
1419 opc = 0x2;
1420 c=1;
1421 break;
1422 case '|':
1423 opc = 0x18;
1424 c=1;
1425 break;
1426 case '*':
1427 gv2(RC_INT, RC_INT);
1428 r = vtop[-1].r;
1429 fr = vtop[0].r;
1430 vtop--;
1431 o(0xE0000090|(intr(r)<<16)|(intr(r)<<8)|intr(fr));
1432 return;
1433 case TOK_SHL:
1434 opc = 0;
1435 c=2;
1436 break;
1437 case TOK_SHR:
1438 opc = 1;
1439 c=2;
1440 break;
1441 case TOK_SAR:
1442 opc = 2;
1443 c=2;
1444 break;
1445 case '/':
1446 case TOK_PDIV:
1447 func=TOK___divsi3;
1448 c=3;
1449 break;
1450 case TOK_UDIV:
1451 func=TOK___udivsi3;
1452 c=3;
1453 break;
1454 case '%':
1455 #ifdef TCC_ARM_EABI
1456 func=TOK___aeabi_idivmod;
1457 retreg=REG_LRET;
1458 #else
1459 func=TOK___modsi3;
1460 #endif
1461 c=3;
1462 break;
1463 case TOK_UMOD:
1464 #ifdef TCC_ARM_EABI
1465 func=TOK___aeabi_uidivmod;
1466 retreg=REG_LRET;
1467 #else
1468 func=TOK___umodsi3;
1469 #endif
1470 c=3;
1471 break;
1472 case TOK_UMULL:
1473 gv2(RC_INT, RC_INT);
1474 r=intr(vtop[-1].r2=get_reg(RC_INT));
1475 c=vtop[-1].r;
1476 vtop[-1].r=get_reg_ex(RC_INT,regmask(c));
1477 vtop--;
1478 o(0xE0800090|(r<<16)|(intr(vtop->r)<<12)|(intr(c)<<8)|intr(vtop[1].r));
1479 return;
1480 default:
1481 opc = 0x15;
1482 c=1;
1483 break;
1485 switch(c) {
1486 case 1:
1487 if((vtop[-1].r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
1488 if(opc == 4 || opc == 5 || opc == 0xc) {
1489 vswap();
1490 opc|=2; // sub -> rsb
1493 if ((vtop->r & VT_VALMASK) == VT_CMP ||
1494 (vtop->r & (VT_VALMASK & ~1)) == VT_JMP)
1495 gv(RC_INT);
1496 vswap();
1497 c=intr(gv(RC_INT));
1498 vswap();
1499 opc=0xE0000000|(opc<<20)|(c<<16);
1500 if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
1501 uint32_t x;
1502 x=stuff_const(opc|0x2000000,vtop->c.i);
1503 if(x) {
1504 r=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r)));
1505 o(x|(r<<12));
1506 goto done;
1509 fr=intr(gv(RC_INT));
1510 r=intr(vtop[-1].r=get_reg_ex(RC_INT,two2mask(vtop->r,vtop[-1].r)));
1511 o(opc|(r<<12)|fr);
1512 done:
1513 vtop--;
1514 if (op >= TOK_ULT && op <= TOK_GT) {
1515 vtop->r = VT_CMP;
1516 vtop->c.i = op;
1518 break;
1519 case 2:
1520 opc=0xE1A00000|(opc<<5);
1521 if ((vtop->r & VT_VALMASK) == VT_CMP ||
1522 (vtop->r & (VT_VALMASK & ~1)) == VT_JMP)
1523 gv(RC_INT);
1524 vswap();
1525 r=intr(gv(RC_INT));
1526 vswap();
1527 opc|=r;
1528 if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
1529 fr=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r)));
1530 c = vtop->c.i & 0x1f;
1531 o(opc|(c<<7)|(fr<<12));
1532 } else {
1533 fr=intr(gv(RC_INT));
1534 c=intr(vtop[-1].r=get_reg_ex(RC_INT,two2mask(vtop->r,vtop[-1].r)));
1535 o(opc|(c<<12)|(fr<<8)|0x10);
1537 vtop--;
1538 break;
1539 case 3:
1540 vpush_global_sym(&func_old_type, func);
1541 vrott(3);
1542 gfunc_call(2);
1543 vpushi(0);
1544 vtop->r = retreg;
1545 break;
1546 default:
1547 tcc_error("gen_opi %i unimplemented!",op);
1551 #ifdef TCC_ARM_VFP
1552 static int is_zero(int i)
1554 if((vtop[i].r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST)
1555 return 0;
1556 if (vtop[i].type.t == VT_FLOAT)
1557 return (vtop[i].c.f == 0.f);
1558 else if (vtop[i].type.t == VT_DOUBLE)
1559 return (vtop[i].c.d == 0.0);
1560 return (vtop[i].c.ld == 0.l);
1563 /* generate a floating point operation 'v = t1 op t2' instruction. The
1564 * two operands are guaranted to have the same floating point type */
1565 void gen_opf(int op)
1567 uint32_t x;
1568 int fneg=0,r;
1569 x=0xEE000A00|T2CPR(vtop->type.t);
1570 switch(op) {
1571 case '+':
1572 if(is_zero(-1))
1573 vswap();
1574 if(is_zero(0)) {
1575 vtop--;
1576 return;
1578 x|=0x300000;
1579 break;
1580 case '-':
1581 x|=0x300040;
1582 if(is_zero(0)) {
1583 vtop--;
1584 return;
1586 if(is_zero(-1)) {
1587 x|=0x810000; /* fsubX -> fnegX */
1588 vswap();
1589 vtop--;
1590 fneg=1;
1592 break;
1593 case '*':
1594 x|=0x200000;
1595 break;
1596 case '/':
1597 x|=0x800000;
1598 break;
1599 default:
1600 if(op < TOK_ULT || op > TOK_GT) {
1601 tcc_error("unknown fp op %x!",op);
1602 return;
1604 if(is_zero(-1)) {
1605 vswap();
1606 switch(op) {
1607 case TOK_LT: op=TOK_GT; break;
1608 case TOK_GE: op=TOK_ULE; break;
1609 case TOK_LE: op=TOK_GE; break;
1610 case TOK_GT: op=TOK_ULT; break;
1613 x|=0xB40040; /* fcmpX */
1614 if(op!=TOK_EQ && op!=TOK_NE)
1615 x|=0x80; /* fcmpX -> fcmpeX */
1616 if(is_zero(0)) {
1617 vtop--;
1618 o(x|0x10000|(vfpr(gv(RC_FLOAT))<<12)); /* fcmp(e)X -> fcmp(e)zX */
1619 } else {
1620 x|=vfpr(gv(RC_FLOAT));
1621 vswap();
1622 o(x|(vfpr(gv(RC_FLOAT))<<12));
1623 vtop--;
1625 o(0xEEF1FA10); /* fmstat */
1627 switch(op) {
1628 case TOK_LE: op=TOK_ULE; break;
1629 case TOK_LT: op=TOK_ULT; break;
1630 case TOK_UGE: op=TOK_GE; break;
1631 case TOK_UGT: op=TOK_GT; break;
1634 vtop->r = VT_CMP;
1635 vtop->c.i = op;
1636 return;
1638 r=gv(RC_FLOAT);
1639 x|=vfpr(r);
1640 r=regmask(r);
1641 if(!fneg) {
1642 int r2;
1643 vswap();
1644 r2=gv(RC_FLOAT);
1645 x|=vfpr(r2)<<16;
1646 r|=regmask(r2);
1648 vtop->r=get_reg_ex(RC_FLOAT,r);
1649 if(!fneg)
1650 vtop--;
1651 o(x|(vfpr(vtop->r)<<12));
1654 #else
1655 static uint32_t is_fconst()
1657 long double f;
1658 uint32_t r;
1659 if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST)
1660 return 0;
1661 if (vtop->type.t == VT_FLOAT)
1662 f = vtop->c.f;
1663 else if (vtop->type.t == VT_DOUBLE)
1664 f = vtop->c.d;
1665 else
1666 f = vtop->c.ld;
1667 if(!ieee_finite(f))
1668 return 0;
1669 r=0x8;
1670 if(f<0.0) {
1671 r=0x18;
1672 f=-f;
1674 if(f==0.0)
1675 return r;
1676 if(f==1.0)
1677 return r|1;
1678 if(f==2.0)
1679 return r|2;
1680 if(f==3.0)
1681 return r|3;
1682 if(f==4.0)
1683 return r|4;
1684 if(f==5.0)
1685 return r|5;
1686 if(f==0.5)
1687 return r|6;
1688 if(f==10.0)
1689 return r|7;
1690 return 0;
1693 /* generate a floating point operation 'v = t1 op t2' instruction. The
1694 two operands are guaranted to have the same floating point type */
1695 void gen_opf(int op)
1697 uint32_t x, r, r2, c1, c2;
1698 //fputs("gen_opf\n",stderr);
1699 vswap();
1700 c1 = is_fconst();
1701 vswap();
1702 c2 = is_fconst();
1703 x=0xEE000100;
1704 #if LDOUBLE_SIZE == 8
1705 if ((vtop->type.t & VT_BTYPE) != VT_FLOAT)
1706 x|=0x80;
1707 #else
1708 if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE)
1709 x|=0x80;
1710 else if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE)
1711 x|=0x80000;
1712 #endif
1713 switch(op)
1715 case '+':
1716 if(!c2) {
1717 vswap();
1718 c2=c1;
1720 vswap();
1721 r=fpr(gv(RC_FLOAT));
1722 vswap();
1723 if(c2) {
1724 if(c2>0xf)
1725 x|=0x200000; // suf
1726 r2=c2&0xf;
1727 } else {
1728 r2=fpr(gv(RC_FLOAT));
1730 break;
1731 case '-':
1732 if(c2) {
1733 if(c2<=0xf)
1734 x|=0x200000; // suf
1735 r2=c2&0xf;
1736 vswap();
1737 r=fpr(gv(RC_FLOAT));
1738 vswap();
1739 } else if(c1 && c1<=0xf) {
1740 x|=0x300000; // rsf
1741 r2=c1;
1742 r=fpr(gv(RC_FLOAT));
1743 vswap();
1744 } else {
1745 x|=0x200000; // suf
1746 vswap();
1747 r=fpr(gv(RC_FLOAT));
1748 vswap();
1749 r2=fpr(gv(RC_FLOAT));
1751 break;
1752 case '*':
1753 if(!c2 || c2>0xf) {
1754 vswap();
1755 c2=c1;
1757 vswap();
1758 r=fpr(gv(RC_FLOAT));
1759 vswap();
1760 if(c2 && c2<=0xf)
1761 r2=c2;
1762 else
1763 r2=fpr(gv(RC_FLOAT));
1764 x|=0x100000; // muf
1765 break;
1766 case '/':
1767 if(c2 && c2<=0xf) {
1768 x|=0x400000; // dvf
1769 r2=c2;
1770 vswap();
1771 r=fpr(gv(RC_FLOAT));
1772 vswap();
1773 } else if(c1 && c1<=0xf) {
1774 x|=0x500000; // rdf
1775 r2=c1;
1776 r=fpr(gv(RC_FLOAT));
1777 vswap();
1778 } else {
1779 x|=0x400000; // dvf
1780 vswap();
1781 r=fpr(gv(RC_FLOAT));
1782 vswap();
1783 r2=fpr(gv(RC_FLOAT));
1785 break;
1786 default:
1787 if(op >= TOK_ULT && op <= TOK_GT) {
1788 x|=0xd0f110; // cmfe
1789 /* bug (intention?) in Linux FPU emulator
1790 doesn't set carry if equal */
1791 switch(op) {
1792 case TOK_ULT:
1793 case TOK_UGE:
1794 case TOK_ULE:
1795 case TOK_UGT:
1796 tcc_error("unsigned comparision on floats?");
1797 break;
1798 case TOK_LT:
1799 op=TOK_Nset;
1800 break;
1801 case TOK_LE:
1802 op=TOK_ULE; /* correct in unordered case only if AC bit in FPSR set */
1803 break;
1804 case TOK_EQ:
1805 case TOK_NE:
1806 x&=~0x400000; // cmfe -> cmf
1807 break;
1809 if(c1 && !c2) {
1810 c2=c1;
1811 vswap();
1812 switch(op) {
1813 case TOK_Nset:
1814 op=TOK_GT;
1815 break;
1816 case TOK_GE:
1817 op=TOK_ULE;
1818 break;
1819 case TOK_ULE:
1820 op=TOK_GE;
1821 break;
1822 case TOK_GT:
1823 op=TOK_Nset;
1824 break;
1827 vswap();
1828 r=fpr(gv(RC_FLOAT));
1829 vswap();
1830 if(c2) {
1831 if(c2>0xf)
1832 x|=0x200000;
1833 r2=c2&0xf;
1834 } else {
1835 r2=fpr(gv(RC_FLOAT));
1837 vtop[-1].r = VT_CMP;
1838 vtop[-1].c.i = op;
1839 } else {
1840 tcc_error("unknown fp op %x!",op);
1841 return;
1844 if(vtop[-1].r == VT_CMP)
1845 c1=15;
1846 else {
1847 c1=vtop->r;
1848 if(r2&0x8)
1849 c1=vtop[-1].r;
1850 vtop[-1].r=get_reg_ex(RC_FLOAT,two2mask(vtop[-1].r,c1));
1851 c1=fpr(vtop[-1].r);
1853 vtop--;
1854 o(x|(r<<16)|(c1<<12)|r2);
1856 #endif
1858 /* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
1859 and 'long long' cases. */
1860 ST_FUNC void gen_cvt_itof1(int t)
1862 uint32_t r, r2;
1863 int bt;
1864 bt=vtop->type.t & VT_BTYPE;
1865 if(bt == VT_INT || bt == VT_SHORT || bt == VT_BYTE) {
1866 #ifndef TCC_ARM_VFP
1867 uint32_t dsize = 0;
1868 #endif
1869 r=intr(gv(RC_INT));
1870 #ifdef TCC_ARM_VFP
1871 r2=vfpr(vtop->r=get_reg(RC_FLOAT));
1872 o(0xEE000A10|(r<<12)|(r2<<16)); /* fmsr */
1873 r2|=r2<<12;
1874 if(!(vtop->type.t & VT_UNSIGNED))
1875 r2|=0x80; /* fuitoX -> fsituX */
1876 o(0xEEB80A40|r2|T2CPR(t)); /* fYitoX*/
1877 #else
1878 r2=fpr(vtop->r=get_reg(RC_FLOAT));
1879 if((t & VT_BTYPE) != VT_FLOAT)
1880 dsize=0x80; /* flts -> fltd */
1881 o(0xEE000110|dsize|(r2<<16)|(r<<12)); /* flts */
1882 if((vtop->type.t & (VT_UNSIGNED|VT_BTYPE)) == (VT_UNSIGNED|VT_INT)) {
1883 uint32_t off = 0;
1884 o(0xE3500000|(r<<12)); /* cmp */
1885 r=fpr(get_reg(RC_FLOAT));
1886 if(last_itod_magic) {
1887 off=ind+8-last_itod_magic;
1888 off/=4;
1889 if(off>255)
1890 off=0;
1892 o(0xBD1F0100|(r<<12)|off); /* ldflts */
1893 if(!off) {
1894 o(0xEA000000); /* b */
1895 last_itod_magic=ind;
1896 o(0x4F800000); /* 4294967296.0f */
1898 o(0xBE000100|dsize|(r2<<16)|(r2<<12)|r); /* adflt */
1900 #endif
1901 return;
1902 } else if(bt == VT_LLONG) {
1903 int func;
1904 CType *func_type = 0;
1905 if((t & VT_BTYPE) == VT_FLOAT) {
1906 func_type = &func_float_type;
1907 if(vtop->type.t & VT_UNSIGNED)
1908 func=TOK___floatundisf;
1909 else
1910 func=TOK___floatdisf;
1911 #if LDOUBLE_SIZE != 8
1912 } else if((t & VT_BTYPE) == VT_LDOUBLE) {
1913 func_type = &func_ldouble_type;
1914 if(vtop->type.t & VT_UNSIGNED)
1915 func=TOK___floatundixf;
1916 else
1917 func=TOK___floatdixf;
1918 } else if((t & VT_BTYPE) == VT_DOUBLE) {
1919 #else
1920 } else if((t & VT_BTYPE) == VT_DOUBLE || (t & VT_BTYPE) == VT_LDOUBLE) {
1921 #endif
1922 func_type = &func_double_type;
1923 if(vtop->type.t & VT_UNSIGNED)
1924 func=TOK___floatundidf;
1925 else
1926 func=TOK___floatdidf;
1928 if(func_type) {
1929 vpush_global_sym(func_type, func);
1930 vswap();
1931 gfunc_call(1);
1932 vpushi(0);
1933 vtop->r=TREG_F0;
1934 return;
1937 tcc_error("unimplemented gen_cvt_itof %x!",vtop->type.t);
1940 /* convert fp to int 't' type */
1941 void gen_cvt_ftoi(int t)
1943 uint32_t r, r2;
1944 int u, func = 0;
1945 u=t&VT_UNSIGNED;
1946 t&=VT_BTYPE;
1947 r2=vtop->type.t & VT_BTYPE;
1948 if(t==VT_INT) {
1949 #ifdef TCC_ARM_VFP
1950 r=vfpr(gv(RC_FLOAT));
1951 u=u?0:0x10000;
1952 o(0xEEBC0AC0|(r<<12)|r|T2CPR(r2)|u); /* ftoXizY */
1953 r2=intr(vtop->r=get_reg(RC_INT));
1954 o(0xEE100A10|(r<<16)|(r2<<12));
1955 return;
1956 #else
1957 if(u) {
1958 if(r2 == VT_FLOAT)
1959 func=TOK___fixunssfsi;
1960 #if LDOUBLE_SIZE != 8
1961 else if(r2 == VT_LDOUBLE)
1962 func=TOK___fixunsxfsi;
1963 else if(r2 == VT_DOUBLE)
1964 #else
1965 else if(r2 == VT_LDOUBLE || r2 == VT_DOUBLE)
1966 #endif
1967 func=TOK___fixunsdfsi;
1968 } else {
1969 r=fpr(gv(RC_FLOAT));
1970 r2=intr(vtop->r=get_reg(RC_INT));
1971 o(0xEE100170|(r2<<12)|r);
1972 return;
1974 #endif
1975 } else if(t == VT_LLONG) { // unsigned handled in gen_cvt_ftoi1
1976 if(r2 == VT_FLOAT)
1977 func=TOK___fixsfdi;
1978 #if LDOUBLE_SIZE != 8
1979 else if(r2 == VT_LDOUBLE)
1980 func=TOK___fixxfdi;
1981 else if(r2 == VT_DOUBLE)
1982 #else
1983 else if(r2 == VT_LDOUBLE || r2 == VT_DOUBLE)
1984 #endif
1985 func=TOK___fixdfdi;
1987 if(func) {
1988 vpush_global_sym(&func_old_type, func);
1989 vswap();
1990 gfunc_call(1);
1991 vpushi(0);
1992 if(t == VT_LLONG)
1993 vtop->r2 = REG_LRET;
1994 vtop->r = REG_IRET;
1995 return;
1997 tcc_error("unimplemented gen_cvt_ftoi!");
2000 /* convert from one floating point type to another */
2001 void gen_cvt_ftof(int t)
2003 #ifdef TCC_ARM_VFP
2004 if(((vtop->type.t & VT_BTYPE) == VT_FLOAT) != ((t & VT_BTYPE) == VT_FLOAT)) {
2005 uint32_t r = vfpr(gv(RC_FLOAT));
2006 o(0xEEB70AC0|(r<<12)|r|T2CPR(vtop->type.t));
2008 #else
2009 /* all we have to do on i386 and FPA ARM is to put the float in a register */
2010 gv(RC_FLOAT);
2011 #endif
2014 /* computed goto support */
2015 void ggoto(void)
2017 gcall_or_jmp(1);
2018 vtop--;
2021 /* Save the stack pointer onto the stack and return the location of its address */
2022 ST_FUNC void gen_vla_sp_save(int addr) {
2023 tcc_error("variable length arrays unsupported for this target");
2026 /* Restore the SP from a location on the stack */
2027 ST_FUNC void gen_vla_sp_restore(int addr) {
2028 tcc_error("variable length arrays unsupported for this target");
2031 /* Subtract from the stack pointer, and push the resulting value onto the stack */
2032 ST_FUNC void gen_vla_alloc(CType *type, int align) {
2033 tcc_error("variable length arrays unsupported for this target");
2036 /* end of ARM code generator */
2037 /*************************************************************/
2038 #endif
2039 /*************************************************************/