removed warnings
[tinycc/miki.git] / arm-gen.c
blobf6573311e4163a8cfd5169bac1efb1bf812f2573
1 /*
2 * ARMv4 code generator for TCC
3 *
4 * Copyright (c) 2003 Daniel Glöckner
6 * Based on i386-gen.c by Fabrice Bellard
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 /* number of available registers */
24 #define NB_REGS 9
26 /* a register can belong to several classes. The classes must be
27 sorted from more general to more precise (see gv2() code which does
28 assumptions on it). */
29 #define RC_INT 0x0001 /* generic integer register */
30 #define RC_FLOAT 0x0002 /* generic float register */
31 #define RC_R0 0x0004
32 #define RC_R1 0x0008
33 #define RC_R2 0x0010
34 #define RC_R3 0x0020
35 #define RC_R12 0x0040
36 #define RC_F0 0x0080
37 #define RC_F1 0x0100
38 #define RC_F2 0x0200
39 #define RC_F3 0x0400
40 #define RC_IRET RC_R0 /* function return: integer register */
41 #define RC_LRET RC_R1 /* function return: second integer register */
42 #define RC_FRET RC_F0 /* function return: float register */
44 /* pretty names for the registers */
45 enum {
46 TREG_R0 = 0,
47 TREG_R1,
48 TREG_R2,
49 TREG_R3,
50 TREG_R12,
51 TREG_F0,
52 TREG_F1,
53 TREG_F2,
54 TREG_F3,
57 int reg_classes[NB_REGS] = {
58 /* r0 */ RC_INT | RC_R0,
59 /* r1 */ RC_INT | RC_R1,
60 /* r2 */ RC_INT | RC_R2,
61 /* r3 */ RC_INT | RC_R3,
62 /* r12 */ RC_INT | RC_R12,
63 /* f0 */ RC_FLOAT | RC_F0,
64 /* f1 */ RC_FLOAT | RC_F1,
65 /* f2 */ RC_FLOAT | RC_F2,
66 /* f3 */ RC_FLOAT | RC_F3,
69 static int two2mask(int a,int b) {
70 return (reg_classes[a]|reg_classes[b])&~(RC_INT|RC_FLOAT);
73 static int regmask(int r) {
74 return reg_classes[r]&~(RC_INT|RC_FLOAT);
77 /* return registers for function */
78 #define REG_IRET TREG_R0 /* single word int return register */
79 #define REG_LRET TREG_R1 /* second word return register (for long long) */
80 #define REG_FRET TREG_F0 /* float return register */
82 /* defined if function parameters must be evaluated in reverse order */
83 #define INVERT_FUNC_PARAMS
85 /* defined if structures are passed as pointers. Otherwise structures
86 are directly pushed on stack. */
87 //#define FUNC_STRUCT_PARAM_AS_PTR
89 /* pointer size, in bytes */
90 #define PTR_SIZE 4
92 /* long double size and alignment, in bytes */
93 #define LDOUBLE_SIZE 8
94 #define LDOUBLE_ALIGN 4
95 /* maximum alignment (for aligned attribute support) */
96 #define MAX_ALIGN 8
98 #define CHAR_IS_UNSIGNED
100 /******************************************************/
101 /* ELF defines */
103 #define EM_TCC_TARGET EM_ARM
105 /* relocation type for 32 bit data relocation */
106 #define R_DATA_32 R_ARM_ABS32
107 #define R_JMP_SLOT R_ARM_JUMP_SLOT
108 #define R_COPY R_ARM_COPY
110 #define ELF_START_ADDR 0x00008000
111 #define ELF_PAGE_SIZE 0x1000
113 /******************************************************/
114 static unsigned long func_sub_sp_offset,last_itod_magic;
116 void o(unsigned long i)
118 /* this is a good place to start adding big-endian support*/
119 int ind1;
121 ind1 = ind + 4;
122 if (!cur_text_section)
123 error("compiler error! This happens f.ex. if the compiler\n"
124 "can't evaluate constant expressions outside of a function.");
125 if (ind1 > cur_text_section->data_allocated)
126 section_realloc(cur_text_section, ind1);
127 cur_text_section->data[ind++] = i&255;
128 i>>=8;
129 cur_text_section->data[ind++] = i&255;
130 i>>=8;
131 cur_text_section->data[ind++] = i&255;
132 i>>=8;
133 cur_text_section->data[ind++] = i;
136 static unsigned long stuff_const(unsigned long op,unsigned long c)
138 int try_neg=0;
139 unsigned long nc = 0,negop = 0;
141 switch(op&0x1F00000)
143 case 0x800000: //add
144 case 0x400000: //sub
145 try_neg=1;
146 negop=op^0xC00000;
147 nc=-c;
148 break;
149 case 0x1A00000: //mov
150 case 0x1E00000: //mvn
151 try_neg=1;
152 negop=op^0x400000;
153 nc=~c;
154 break;
155 case 0x200000: //xor
156 if(c==~0)
157 return (op&0xF010F000)|((op>>16)&0xF)|0x1E00000;
158 break;
159 case 0x0: //and
160 if(c==~0)
161 return (op&0xF010F000)|((op>>16)&0xF)|0x1A00000;
162 case 0x1C00000: //bic
163 try_neg=1;
164 negop=op^0x1C00000;
165 nc=~c;
166 break;
167 case 0x1800000: //orr
168 if(c==~0)
169 return (op&0xFFF0FFFF)|0x1E00000;
170 break;
172 do {
173 unsigned long m;
174 int i;
175 if(c<256) /* catch undefined <<32 */
176 return op|c;
177 for(i=2;i<32;i+=2) {
178 m=(0xff>>i)|(0xff<<(32-i));
179 if(!(c&~m))
180 return op|(i<<7)|(c<<i)|(c>>(32-i));
182 op=negop;
183 c=nc;
184 } while(try_neg--);
185 return 0;
189 //only add,sub
190 void stuff_const_harder(unsigned long op,unsigned long v) {
191 unsigned long x;
192 x=stuff_const(op,v);
193 if(x)
194 o(x);
195 else {
196 unsigned long a[16],nv,no,o2,n2;
197 int i,j,k;
198 a[0]=0xff;
199 o2=(op&0xfff0ffff)|((op&0xf000)<<4);;
200 for(i=1;i<16;i++)
201 a[i]=(a[i-1]>>2)|(a[i-1]<<30);
202 for(i=0;i<12;i++)
203 for(j=i+4;i<13+i;i++)
204 if((v&(a[i]|a[j]))==v) {
205 o(stuff_const(op,v&a[i]));
206 o(stuff_const(o2,v&a[j]));
207 return;
209 no=op^0xC00000;
210 n2=o2^0xC00000;
211 nv=-v;
212 for(i=0;i<12;i++)
213 for(j=i+4;i<13+i;i++)
214 if((nv&(a[i]|a[j]))==nv) {
215 o(stuff_const(no,nv&a[i]));
216 o(stuff_const(n2,nv&a[j]));
217 return;
219 for(i=0;i<8;i++)
220 for(j=i+4;i<12;i++)
221 for(k=j+4;k<13+i;i++)
222 if((v&(a[i]|a[j]|a[k]))==v) {
223 o(stuff_const(op,v&a[i]));
224 o(stuff_const(o2,v&a[j]));
225 o(stuff_const(o2,v&a[k]));
226 return;
228 no=op^0xC00000;
229 nv=-v;
230 for(i=0;i<8;i++)
231 for(j=i+4;i<12;i++)
232 for(k=j+4;k<13+i;i++)
233 if((nv&(a[i]|a[j]|a[k]))==nv) {
234 o(stuff_const(no,nv&a[i]));
235 o(stuff_const(n2,nv&a[j]));
236 o(stuff_const(n2,nv&a[k]));
237 return;
239 o(stuff_const(op,v&a[0]));
240 o(stuff_const(o2,v&a[4]));
241 o(stuff_const(o2,v&a[8]));
242 o(stuff_const(o2,v&a[12]));
246 unsigned long encbranch(int pos,int addr,int fail)
248 addr-=pos+8;
249 addr/=4;
250 if(addr>=0x1000000 || addr<-0x1000000) {
251 if(fail)
252 error("FIXME: function bigger than 32MB");
253 return 0;
255 return 0x0A000000|(addr&0xffffff);
258 int decbranch(int pos)
260 int x;
261 x=*(int *)(cur_text_section->data + pos);
262 x&=0x00ffffff;
263 if(x&0x800000)
264 x-=0x1000000;
265 return x*4+pos+8;
268 /* output a symbol and patch all calls to it */
269 void gsym_addr(int t, int a)
271 unsigned long *x;
272 int lt;
273 while(t) {
274 x=(unsigned long *)(cur_text_section->data + t);
275 t=decbranch(lt=t);
276 if(a==lt+4)
277 *x=0xE1A00000; // nop
278 else {
279 *x &= 0xff000000;
280 *x |= encbranch(lt,a,1);
285 void gsym(int t)
287 gsym_addr(t, ind);
290 static unsigned long fpr(int r)
292 if(r<TREG_F0 || r>TREG_F3)
293 error("compiler error! register %i is no fp register\n",r);
294 return r-5;
297 static unsigned long intr(int r)
299 if(r==4)
300 return 12;
301 if((r<0 || r>4) && r!=14)
302 error("compiler error! register %i is no int register\n",r);
303 return r;
306 static void calcaddr(unsigned long *base,int *off,int *sgn,int maxoff,unsigned shift)
308 if(*off>maxoff || *off&((1<<shift)-1)) {
309 unsigned long x,y;
310 x=0xE280E000;
311 if(*sgn)
312 x=0xE240E000;
313 x|=(*base)<<16;
314 *base=14; // lr
315 y=stuff_const(x,*off&~maxoff);
316 if(y) {
317 o(y);
318 *off&=maxoff;
319 return;
321 y=stuff_const(x,(*off+maxoff)&~maxoff);
322 if(y) {
323 o(y);
324 *sgn=!*sgn;
325 *off=((*off+maxoff)&~maxoff)-*off;
326 return;
328 stuff_const_harder(x,*off&~maxoff);
329 *off&=maxoff;
333 static unsigned long mapcc(int cc)
335 switch(cc)
337 case TOK_ULT:
338 return 0x30000000;
339 case TOK_UGE:
340 return 0x20000000;
341 case TOK_EQ:
342 return 0x00000000;
343 case TOK_NE:
344 return 0x10000000;
345 case TOK_ULE:
346 return 0x90000000;
347 case TOK_UGT:
348 return 0x80000000;
349 case TOK_LT:
350 return 0xB0000000;
351 case TOK_GE:
352 return 0xA0000000;
353 case TOK_LE:
354 return 0xD0000000;
355 case TOK_GT:
356 return 0xC0000000;
358 error("unexpected condition code");
359 return 0xE0000000;
362 static int negcc(int cc)
364 switch(cc)
366 case TOK_ULT:
367 return TOK_UGE;
368 case TOK_UGE:
369 return TOK_ULT;
370 case TOK_EQ:
371 return TOK_NE;
372 case TOK_NE:
373 return TOK_EQ;
374 case TOK_ULE:
375 return TOK_UGT;
376 case TOK_UGT:
377 return TOK_ULE;
378 case TOK_LT:
379 return TOK_GE;
380 case TOK_GE:
381 return TOK_LT;
382 case TOK_LE:
383 return TOK_GT;
384 case TOK_GT:
385 return TOK_LE;
387 error("unexpected condition code");
388 return TOK_NE;
391 /* load 'r' from value 'sv' */
392 void load(int r, SValue *sv)
394 int v, ft, fc, fr, sign;
395 unsigned long op;
396 SValue v1;
398 fr = sv->r;
399 ft = sv->type.t;
400 fc = sv->c.ul;
402 if(fc>=0)
403 sign=0;
404 else {
405 sign=1;
406 fc=-fc;
409 v = fr & VT_VALMASK;
410 if (fr & VT_LVAL) {
411 unsigned long base=0xB; // fp
412 if(v == VT_LLOCAL) {
413 v1.type.t = VT_PTR;
414 v1.r = VT_LOCAL | VT_LVAL;
415 v1.c.ul = sv->c.ul;
416 load(base=14 /* lr */, &v1);
417 fc=sign=0;
418 v=VT_LOCAL;
419 } else if(v == VT_CONST) {
420 v1.type.t = VT_PTR;
421 v1.r = fr&~VT_LVAL;
422 v1.c.ul = sv->c.ul;
423 v1.sym=sv->sym;
424 load(base=14, &v1);
425 fc=sign=0;
426 v=VT_LOCAL;
427 } else if(v < VT_CONST) {
428 base=intr(v);
429 fc=sign=0;
430 v=VT_LOCAL;
432 if(v == VT_LOCAL) {
433 if(is_float(ft)) {
434 calcaddr(&base,&fc,&sign,1020,2);
435 op=0xED100100;
436 if(!sign)
437 op|=0x800000;
438 #if LDOUBLE_SIZE == 8
439 if ((ft & VT_BTYPE) != VT_FLOAT)
440 op|=0x8000;
441 #else
442 if ((ft & VT_BTYPE) == VT_DOUBLE)
443 op|=0x8000;
444 else if ((ft & VT_BTYPE) == VT_LDOUBLE)
445 op|=0x400000;
446 #endif
447 o(op|(fpr(r)<<12)|(fc>>2)|(base<<16));
448 } else if((ft & VT_TYPE) == VT_BYTE || (ft & VT_BTYPE) == VT_SHORT) {
449 calcaddr(&base,&fc,&sign,255,0);
450 op=0xE1500090;
451 if ((ft & VT_BTYPE) == VT_SHORT)
452 op|=0x20;
453 if ((ft & VT_UNSIGNED) == 0)
454 op|=0x40;
455 if(!sign)
456 op|=0x800000;
457 o(op|(intr(r)<<12)|(base<<16)|((fc&0xf0)<<4)|(fc&0xf));
458 } else {
459 calcaddr(&base,&fc,&sign,4095,0);
460 op=0xE5100000;
461 if(!sign)
462 op|=0x800000;
463 if ((ft & VT_BTYPE) == VT_BYTE)
464 op|=0x400000;
465 o(op|(intr(r)<<12)|fc|(base<<16));
467 return;
469 } else {
470 if (v == VT_CONST) {
471 op=stuff_const(0xE3A00000|(intr(r)<<12),sv->c.ul);
472 if (fr & VT_SYM || !op) {
473 o(0xE59F0000|(intr(r)<<12));
474 o(0xEA000000);
475 if(fr & VT_SYM)
476 greloc(cur_text_section, sv->sym, ind, R_ARM_ABS32);
477 o(sv->c.ul);
478 } else
479 o(op);
480 return;
481 } else if (v == VT_LOCAL) {
482 op=stuff_const(0xE28B0000|(intr(r)<<12),sv->c.ul);
483 if (fr & VT_SYM || !op) {
484 o(0xE59F0000|(intr(r)<<12));
485 o(0xEA000000);
486 if(fr & VT_SYM) // needed ?
487 greloc(cur_text_section, sv->sym, ind, R_ARM_ABS32);
488 o(sv->c.ul);
489 o(0xE08B0000|(intr(r)<<12)|intr(r));
490 } else
491 o(op);
492 return;
493 } else if(v == VT_CMP) {
494 o(mapcc(sv->c.ul)|0x3A00001|(intr(r)<<12));
495 o(mapcc(negcc(sv->c.ul))|0x3A00000|(intr(r)<<12));
496 return;
497 } else if (v == VT_JMP || v == VT_JMPI) {
498 int t;
499 t = v & 1;
500 o(0xE3A00000|(intr(r)<<12)|t);
501 o(0xEA000000);
502 gsym(sv->c.ul);
503 o(0xE3A00000|(intr(r)<<12)|(t^1));
504 return;
505 } else if (v < VT_CONST) {
506 if(is_float(ft))
507 o(0xEE008180|(fpr(r)<<12)|fpr(v));
508 else
509 o(0xE1A00000|(intr(r)<<12)|intr(v));
510 return;
513 error("load unimplemented!");
516 /* store register 'r' in lvalue 'v' */
517 void store(int r, SValue *sv)
519 SValue v1;
520 int v, ft, fc, fr, sign;
521 unsigned long op;
523 fr = sv->r;
524 ft = sv->type.t;
525 fc = sv->c.ul;
527 if(fc>=0)
528 sign=0;
529 else {
530 sign=1;
531 fc=-fc;
534 v = fr & VT_VALMASK;
535 if (fr & VT_LVAL || fr == VT_LOCAL) {
536 unsigned long base=0xb;
537 if(v < VT_CONST) {
538 base=intr(v);
539 v=VT_LOCAL;
540 fc=sign=0;
541 } else if(v == VT_CONST) {
542 v1.type.t = ft;
543 v1.r = fr&~VT_LVAL;
544 v1.c.ul = sv->c.ul;
545 v1.sym=sv->sym;
546 load(base=14, &v1);
547 fc=sign=0;
548 v=VT_LOCAL;
550 if(v == VT_LOCAL) {
551 if(is_float(ft)) {
552 calcaddr(&base,&fc,&sign,1020,2);
553 op=0xED000100;
554 if(!sign)
555 op|=0x800000;
556 #if LDOUBLE_SIZE == 8
557 if ((ft & VT_BTYPE) != VT_FLOAT)
558 op|=0x8000;
559 #else
560 if ((ft & VT_BTYPE) == VT_DOUBLE)
561 op|=0x8000;
562 if ((ft & VT_BTYPE) == VT_LDOUBLE)
563 op|=0x400000;
564 #endif
565 o(op|(fpr(r)<<12)|(fc>>2)|(base<<16));
566 return;
567 } else if((ft & VT_BTYPE) == VT_SHORT) {
568 calcaddr(&base,&fc,&sign,255,0);
569 op=0xE14000B0;
570 if(!sign)
571 op|=0x800000;
572 o(op|(intr(r)<<12)|(base<<16)|((fc&0xf0)<<4)|(fc&0xf));
573 } else {
574 calcaddr(&base,&fc,&sign,4095,0);
575 op=0xE5000000;
576 if(!sign)
577 op|=0x800000;
578 if ((ft & VT_BTYPE) == VT_BYTE)
579 op|=0x400000;
580 o(op|(intr(r)<<12)|fc|(base<<16));
582 return;
585 error("store unimplemented");
588 static void gadd_sp(int val)
590 stuff_const_harder(0xE28DD000,val);
593 /* 'is_jmp' is '1' if it is a jump */
594 static void gcall_or_jmp(int is_jmp)
596 int r;
597 if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
598 unsigned long x;
599 /* constant case */
600 x=encbranch(ind,ind+vtop->c.ul,0);
601 if(x) {
602 if (vtop->r & VT_SYM) {
603 /* relocation case */
604 greloc(cur_text_section, vtop->sym, ind, R_ARM_PC24);
605 } else
606 put_elf_reloc(symtab_section, cur_text_section, ind, R_ARM_PC24, 0);
607 o(x|(is_jmp?0xE0000000:0xE1000000));
608 } else {
609 if(!is_jmp)
610 o(0xE28FE004); // add lr,pc,#4
611 o(0xE51FF004); // ldr pc,[pc,#-4]
612 if (vtop->r & VT_SYM)
613 greloc(cur_text_section, vtop->sym, ind, R_ARM_ABS32);
614 o(vtop->c.ul);
616 } else {
617 /* otherwise, indirect call */
618 r = gv(RC_INT);
619 if(!is_jmp)
620 o(0xE1A0E00F); // mov lr,pc
621 o(0xE1A0F000|intr(r)); // mov pc,r
625 /* Generate function call. The function address is pushed first, then
626 all the parameters in call order. This functions pops all the
627 parameters and the function address. */
628 void gfunc_call(int nb_args)
630 int size, align, r, args_size, i;
631 Sym *func_sym;
632 signed char plan[4][2]={{-1,-1},{-1,-1},{-1,-1},{-1,-1}};
633 int todo=0xf, keep, plan2[4]={0,0,0,0};
635 r = vtop->r & VT_VALMASK;
636 if (r == VT_CMP || (r & ~1) == VT_JMP)
637 gv(RC_INT);
638 args_size = 0;
639 for(i = nb_args ; i-- && args_size < 16 ;) {
640 if ((vtop[-i].type.t & VT_BTYPE) == VT_STRUCT) {
641 size = type_size(&vtop[-i].type, &align);
642 size = (size + 3) & ~3;
643 args_size += size;
644 } else if ((vtop[-i].type.t & VT_BTYPE) == VT_FLOAT)
645 args_size += 4;
646 else if ((vtop[-i].type.t & VT_BTYPE) == VT_DOUBLE)
647 args_size += 8;
648 else if ((vtop[-i].type.t & VT_BTYPE) == VT_LDOUBLE)
649 args_size += LDOUBLE_SIZE;
650 else {
651 plan[nb_args-1-i][0]=args_size/4;
652 args_size += 4;
653 if ((vtop[-i].type.t & VT_BTYPE) == VT_LLONG && args_size < 16) {
654 plan[nb_args-1-i][1]=args_size/4;
655 args_size += 4;
659 args_size = keep = 0;
660 for(i = 0;i < nb_args; i++) {
661 vnrott(keep+1);
662 if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
663 size = type_size(&vtop->type, &align);
664 /* align to stack align size */
665 size = (size + 3) & ~3;
666 /* allocate the necessary size on stack */
667 gadd_sp(-size);
668 /* generate structure store */
669 r = get_reg(RC_INT);
670 o(0xE1A0000D|(intr(r)<<12));
671 vset(&vtop->type, r | VT_LVAL, 0);
672 vswap();
673 vstore();
674 vtop--;
675 args_size += size;
676 } else if (is_float(vtop->type.t)) {
677 r=fpr(gv(RC_FLOAT))<<12;
678 if ((vtop->type.t & VT_BTYPE) == VT_FLOAT)
679 size = 4;
680 else if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE)
681 size = 8;
682 else
683 size = LDOUBLE_SIZE;
685 if (size == 12)
686 r|=0x400000;
687 else if(size == 8)
688 r|=0x8000;
690 o(0xED2D0100|r|(size>>2));
691 vtop--;
692 args_size += size;
693 } else {
694 int s;
695 /* simple type (currently always same size) */
696 /* XXX: implicit cast ? */
697 size=4;
698 if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
699 lexpand_nr();
700 s=RC_INT;
701 if(nb_args-i<5 && plan[nb_args-i-1][1]!=-1) {
702 s=regmask(plan[nb_args-i-1][1]);
703 todo&=~(1<<plan[nb_args-i-1][1]);
705 if(s==RC_INT) {
706 r = gv(s);
707 o(0xE52D0004|(intr(r)<<12)); /* str r,[sp,#-4]! */
708 vtop--;
709 } else {
710 plan2[keep]=s;
711 keep++;
712 vswap();
714 size = 8;
716 s=RC_INT;
717 if(nb_args-i<5 && plan[nb_args-i-1][0]!=-1) {
718 s=regmask(plan[nb_args-i-1][0]);
719 todo&=~(1<<plan[nb_args-i-1][0]);
721 if(s==RC_INT) {
722 r = gv(s);
723 o(0xE52D0004|(intr(r)<<12)); /* str r,[sp,#-4]! */
724 vtop--;
725 } else {
726 plan2[keep]=s;
727 keep++;
729 args_size += size;
732 for(i=keep;i--;) {
733 gv(plan2[i]);
734 vrott(keep);
736 save_regs(keep); /* save used temporary registers */
737 keep++;
738 if(args_size) {
739 int n;
740 n=args_size/4;
741 if(n>4)
742 n=4;
743 todo&=((1<<n)-1);
744 if(todo) {
745 int i;
746 o(0xE8BD0000|todo);
747 for(i=0;i<4;i++)
748 if(todo&(1<<i)) {
749 vpushi(0);
750 vtop->r=i;
751 keep++;
754 args_size-=n*4;
756 vnrott(keep);
757 func_sym = vtop->type.ref;
758 gcall_or_jmp(0);
759 if (args_size)
760 gadd_sp(args_size);
761 vtop-=keep;
764 /* generate function prolog of type 't' */
765 void gfunc_prolog(CType *func_type)
767 Sym *sym,*sym2;
768 int n,addr,size,align;
770 sym = func_type->ref;
771 func_vt = sym->type;
773 n=0;
774 addr=12;
775 if((func_vt.t & VT_BTYPE) == VT_STRUCT) {
776 func_vc = addr;
777 addr += 4;
778 n++;
780 for(sym2=sym->next;sym2 && n<4;sym2=sym2->next) {
781 size = type_size(&sym2->type, &align);
782 size = (size + 3) & ~3;
783 n+=size/4;
785 o(0xE1A0C00D); /* mov ip,sp */
786 if(func_type->ref->c == FUNC_ELLIPSIS)
787 n=4;
788 if(n) {
789 if(n>4)
790 n=4;
791 o(0xE92D0000|((1<<n)-1)); /* save r0-r4 on stack if needed */
793 o(0xE92D5800); /* save fp, ip, lr*/
794 o(0xE1A0B00D); /* mov fp,sp */
795 func_sub_sp_offset = ind;
796 o(0xE1A00000); /* nop, leave space for stack adjustment */
797 while ((sym = sym->next)) {
798 CType *type;
799 type = &sym->type;
800 sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr);
801 size = type_size(type, &align);
802 size = (size + 3) & ~3;
803 addr += size;
805 last_itod_magic=0;
806 loc = 0;
809 /* generate function epilog */
810 void gfunc_epilog(void)
812 unsigned long x;
813 o(0xE89BA800); /* restore fp, sp, pc */
814 if(loc) {
815 x=stuff_const(0xE24DD000, (-loc + 3) & -4); /* sub sp,sp,# */
816 if(x)
817 *(unsigned long *)(cur_text_section->data + func_sub_sp_offset) = x;
818 else {
819 unsigned long addr;
820 addr=ind;
821 o(0xE59FC004); /* ldr ip,[pc+4] */
822 o(0xE04DD00C); /* sub sp,sp,ip */
823 o(0xE1A0F00E); /* mov pc,lr */
824 o((-loc + 3) & -4);
825 *(unsigned long *)(cur_text_section->data + func_sub_sp_offset) = 0xE1000000|encbranch(func_sub_sp_offset,addr,1);
830 /* generate a jump to a label */
831 int gjmp(int t)
833 int r;
834 r=ind;
835 o(0xE0000000|encbranch(r,t,1));
836 return r;
839 /* generate a jump to a fixed address */
840 void gjmp_addr(int a)
842 gjmp(a);
845 /* generate a test. set 'inv' to invert test. Stack entry is popped */
846 int gtst(int inv, int t)
848 int v, r;
849 unsigned long op;
850 v = vtop->r & VT_VALMASK;
851 r=ind;
852 if (v == VT_CMP) {
853 op=mapcc(inv?negcc(vtop->c.i):vtop->c.i);
854 op|=encbranch(r,t,1);
855 o(op);
856 t=r;
857 } else if (v == VT_JMP || v == VT_JMPI) {
858 if ((v & 1) == inv) {
859 if(!vtop->c.i)
860 vtop->c.i=t;
861 else {
862 unsigned long *x;
863 int p,lp;
864 if(t) {
865 p = vtop->c.i;
866 do {
867 p = decbranch(lp=p);
868 } while(p);
869 x = (unsigned long *)(cur_text_section->data + lp);
870 *x &= 0xff000000;
871 *x |= encbranch(lp,t,1);
873 t = vtop->c.i;
875 } else {
876 t = gjmp(t);
877 gsym(vtop->c.i);
879 } else {
880 if (is_float(vtop->type.t)) {
881 r=gv(RC_FLOAT);
882 o(0xEE90F118|fpr(r)<<16);
883 vtop->r = VT_CMP;
884 vtop->c.i = TOK_NE;
885 return gtst(inv, t);
886 } else if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
887 /* constant jmp optimization */
888 if ((vtop->c.i != 0) != inv)
889 t = gjmp(t);
890 } else {
891 v = gv(RC_INT);
892 o(0xE3300000|(intr(v)<<16));
893 vtop->r = VT_CMP;
894 vtop->c.i = TOK_NE;
895 return gtst(inv, t);
898 vtop--;
899 return t;
902 /* generate an integer binary operation */
903 void gen_opi(int op)
905 int c, func = 0;
906 unsigned long opc = 0,r,fr;
908 c=0;
909 switch(op) {
910 case '+':
911 opc = 0x8;
912 c=1;
913 break;
914 case TOK_ADDC1: /* add with carry generation */
915 opc = 0x9;
916 c=1;
917 break;
918 case '-':
919 opc = 0x4;
920 c=1;
921 break;
922 case TOK_SUBC1: /* sub with carry generation */
923 opc = 0x5;
924 c=1;
925 break;
926 case TOK_ADDC2: /* add with carry use */
927 opc = 0xA;
928 c=1;
929 break;
930 case TOK_SUBC2: /* sub with carry use */
931 opc = 0xC;
932 c=1;
933 break;
934 case '&':
935 opc = 0x0;
936 c=1;
937 break;
938 case '^':
939 opc = 0x2;
940 c=1;
941 break;
942 case '|':
943 opc = 0x18;
944 c=1;
945 break;
946 case '*':
947 gv2(RC_INT, RC_INT);
948 r = vtop[-1].r;
949 fr = vtop[0].r;
950 vtop--;
951 o(0xE0000090|(intr(r)<<16)|(intr(r)<<8)|intr(fr));
952 return;
953 case TOK_SHL:
954 opc = 0;
955 c=2;
956 break;
957 case TOK_SHR:
958 opc = 1;
959 c=2;
960 break;
961 case TOK_SAR:
962 opc = 2;
963 c=2;
964 break;
965 case '/':
966 case TOK_PDIV:
967 func=TOK___divsi3;
968 c=3;
969 break;
970 case TOK_UDIV:
971 func=TOK___udivsi3;
972 c=3;
973 break;
974 case '%':
975 func=TOK___modsi3;
976 c=3;
977 break;
978 case TOK_UMOD:
979 func=TOK___umodsi3;
980 c=3;
981 break;
982 case TOK_UMULL:
983 gv2(RC_INT, RC_INT);
984 r=intr(vtop[-1].r2=get_reg(RC_INT));
985 c=vtop[-1].r;
986 vtop[-1].r=get_reg_ex(RC_INT,regmask(c));
987 vtop--;
988 o(0xE0800090|(r<<16)|(intr(vtop->r)<<12)|(intr(c)<<8)|intr(vtop[1].r));
989 return;
990 default:
991 opc = 0x15;
992 c=1;
993 break;
995 switch(c) {
996 case 1:
997 if((vtop[-1].r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
998 if(opc == 4 || opc == 5 || opc == 0xc) {
999 vswap();
1000 opc|=2; // sub -> rsb
1003 if ((vtop->r & VT_VALMASK) == VT_CMP ||
1004 (vtop->r & (VT_VALMASK & ~1)) == VT_JMP)
1005 gv(RC_INT);
1006 vswap();
1007 c=intr(gv(RC_INT));
1008 vswap();
1009 opc=0xE0000000|(opc<<20)|(c<<16);
1010 if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
1011 unsigned long x;
1012 x=stuff_const(opc|0x2000000,vtop->c.i);
1013 if(x) {
1014 r=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r)));
1015 o(x|(r<<12));
1016 goto done;
1019 fr=intr(gv(RC_INT));
1020 r=intr(vtop[-1].r=get_reg_ex(RC_INT,two2mask(vtop->r,vtop[-1].r)));
1021 o(opc|(r<<12)|fr);
1022 done:
1023 vtop--;
1024 if (op >= TOK_ULT && op <= TOK_GT) {
1025 vtop->r = VT_CMP;
1026 vtop->c.i = op;
1028 break;
1029 case 2:
1030 opc=0xE1A00000|(opc<<5);
1031 if ((vtop->r & VT_VALMASK) == VT_CMP ||
1032 (vtop->r & (VT_VALMASK & ~1)) == VT_JMP)
1033 gv(RC_INT);
1034 vswap();
1035 r=intr(gv(RC_INT));
1036 vswap();
1037 opc|=r;
1038 if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
1039 fr=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r)));
1040 c = vtop->c.i & 0x1f;
1041 o(opc|(c<<7)|(fr<<12));
1042 } else {
1043 fr=intr(gv(RC_INT));
1044 c=intr(vtop[-1].r=get_reg_ex(RC_INT,two2mask(vtop->r,vtop[-1].r)));
1045 o(opc|(c<<12)|(fr<<8)|0x10);
1047 vtop--;
1048 break;
1049 case 3:
1050 vpush_global_sym(&func_old_type, func);
1051 vrott(3);
1052 gfunc_call(2);
1053 vpushi(0);
1054 vtop->r = REG_IRET;
1055 break;
1056 default:
1057 error("gen_opi %i unimplemented!",op);
1061 static int is_fconst()
1063 long double f;
1064 int r;
1065 if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST)
1066 return 0;
1067 if (vtop->type.t == VT_FLOAT)
1068 f = vtop->c.f;
1069 else if (vtop->type.t == VT_DOUBLE)
1070 f = vtop->c.d;
1071 else
1072 f = vtop->c.ld;
1073 if(!ieee_finite(f))
1074 return 0;
1075 r=0x8;
1076 if(f<0.0) {
1077 r=0x18;
1078 f=-f;
1080 if(f==0.0)
1081 return r;
1082 if(f==1.0)
1083 return r|1;
1084 if(f==2.0)
1085 return r|2;
1086 if(f==3.0)
1087 return r|3;
1088 if(f==4.0)
1089 return r|4;
1090 if(f==5.0)
1091 return r|5;
1092 if(f==0.5)
1093 return r|6;
1094 if(f==10.0)
1095 return r|7;
1096 return 0;
1099 /* generate a floating point operation 'v = t1 op t2' instruction. The
1100 two operands are guaranted to have the same floating point type */
1101 void gen_opf(int op)
1103 unsigned long x;
1104 int r,r2,c1,c2;
1105 //fputs("gen_opf\n",stderr);
1106 vswap();
1107 c1 = is_fconst();
1108 vswap();
1109 c2 = is_fconst();
1110 x=0xEE000100;
1111 #if LDOUBLE_SIZE == 8
1112 if ((vtop->type.t & VT_BTYPE) != VT_FLOAT)
1113 x|=0x80;
1114 #else
1115 if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE)
1116 x|=0x80;
1117 else if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE)
1118 x|=0x80000;
1119 #endif
1120 switch(op)
1122 case '+':
1123 if(!c2) {
1124 vswap();
1125 c2=c1;
1127 vswap();
1128 r=fpr(gv(RC_FLOAT));
1129 vswap();
1130 if(c2) {
1131 if(c2>0xf)
1132 x|=0x200000; // suf
1133 r2=c2&0xf;
1134 } else {
1135 r2=fpr(gv(RC_FLOAT));
1137 break;
1138 case '-':
1139 if(c2) {
1140 if(c2<=0xf)
1141 x|=0x200000; // suf
1142 r2=c2&0xf;
1143 vswap();
1144 r=fpr(gv(RC_FLOAT));
1145 vswap();
1146 } else if(c1 && c1<=0xf) {
1147 x|=0x300000; // rsf
1148 r2=c1;
1149 r=fpr(gv(RC_FLOAT));
1150 vswap();
1151 } else {
1152 x|=0x200000; // suf
1153 vswap();
1154 r=fpr(gv(RC_FLOAT));
1155 vswap();
1156 r2=fpr(gv(RC_FLOAT));
1158 break;
1159 case '*':
1160 if(!c2 || c2>0xf) {
1161 vswap();
1162 c2=c1;
1164 vswap();
1165 r=fpr(gv(RC_FLOAT));
1166 vswap();
1167 if(c2 && c2<=0xf)
1168 r2=c2;
1169 else
1170 r2=fpr(gv(RC_FLOAT));
1171 x|=0x100000; // muf
1172 break;
1173 case '/':
1174 if(c2 && c2<=0xf) {
1175 x|=0x400000; // dvf
1176 r2=c2;
1177 vswap();
1178 r=fpr(gv(RC_FLOAT));
1179 vswap();
1180 } else if(c1 && c1<=0xf) {
1181 x|=0x500000; // rdf
1182 r2=c1;
1183 r=fpr(gv(RC_FLOAT));
1184 vswap();
1185 } else {
1186 x|=0x400000; // dvf
1187 vswap();
1188 r=fpr(gv(RC_FLOAT));
1189 vswap();
1190 r2=fpr(gv(RC_FLOAT));
1192 break;
1193 default:
1194 if(op >= TOK_ULT && op <= TOK_GT) {
1195 x|=0xd0f110; // cmfe
1196 switch(op) {
1197 case TOK_ULT:
1198 case TOK_UGE:
1199 case TOK_ULE:
1200 case TOK_UGT:
1201 fputs("unsigned comparision on floats?\n",stderr);
1202 break;
1203 case TOK_LT:
1204 op=TOK_ULT;
1205 break;
1206 case TOK_GE:
1207 op=TOK_UGE;
1208 break;
1209 case TOK_LE:
1210 op=TOK_ULE;
1211 break;
1212 case TOK_GT:
1213 op=TOK_UGT;
1214 break;
1215 case TOK_EQ:
1216 case TOK_NE:
1217 x&=~0x400000; // cmfe -> cmf
1218 break;
1220 if(c1 && !c2) {
1221 c2=c1;
1222 vswap();
1223 switch(op) {
1224 case TOK_ULT:
1225 op=TOK_UGT;
1226 break;
1227 case TOK_UGE:
1228 op=TOK_ULE;
1229 break;
1230 case TOK_ULE:
1231 op=TOK_UGE;
1232 break;
1233 case TOK_UGT:
1234 op=TOK_ULT;
1235 break;
1238 // bug (intention?) in Linux FPU emulator
1239 // doesn't set carry if equal
1240 if(op==TOK_ULT)
1241 op=TOK_LT;
1242 else if(op==TOK_UGE)
1243 op=TOK_GE;
1244 vswap();
1245 r=fpr(gv(RC_FLOAT));
1246 vswap();
1247 if(c2) {
1248 if(c2>0xf)
1249 x|=0x200000;
1250 r2=c2&0xf;
1251 } else {
1252 r2=fpr(gv(RC_FLOAT));
1254 vtop[-1].r = VT_CMP;
1255 vtop[-1].c.i = op;
1256 } else {
1257 error("unknown fp op %x!\n",op);
1258 return;
1261 if(vtop[-1].r == VT_CMP)
1262 c1=15;
1263 else {
1264 c1=vtop->r;
1265 if(r2&0x8)
1266 c1=vtop[-1].r;
1267 vtop[-1].r=get_reg_ex(RC_FLOAT,two2mask(vtop[-1].r,c1));
1268 c1=fpr(vtop[-1].r);
1270 vtop--;
1271 o(x|(r<<16)|(c1<<12)|r2);
1274 /* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
1275 and 'long long' cases. */
1276 void gen_cvt_itof(int t)
1278 int r,r2,bt;
1279 bt=vtop->type.t & VT_BTYPE;
1280 if(bt == VT_INT || bt == VT_SHORT || bt == VT_BYTE) {
1281 r=intr(gv(RC_INT));
1282 r2=fpr(vtop->r=get_reg(RC_FLOAT));
1283 o(0xEE000190|(r2<<16)|(r<<12));
1284 if((vtop->type.t & (VT_UNSIGNED|VT_BTYPE)) == (VT_UNSIGNED|VT_INT)) {
1285 unsigned int off=0;
1286 o(0xE3500000|(r<<12));
1287 r=fpr(get_reg(RC_FLOAT));
1288 if(last_itod_magic) {
1289 off=ind+8-last_itod_magic;
1290 off/=4;
1291 if(off>255)
1292 off=0;
1294 o(0xBD1F8100|(r<<12)|off);
1295 if(!off) {
1296 o(0xEA000001);
1297 last_itod_magic=ind;
1298 o(0x41F00000);
1299 o(0);
1301 o(0xBE000180|(r2<<16)|(r2<<12)|r);
1303 return;
1304 } else if(bt == VT_LLONG) {
1305 int func;
1306 if(vtop->type.t & VT_UNSIGNED)
1307 func=TOK___ulltold;
1308 else
1309 func=TOK___slltold;
1310 vpush_global_sym(&func_old_type, func);
1311 vswap();
1312 gfunc_call(1);
1313 vpushi(0);
1314 vtop->r=TREG_F0;
1315 return;
1317 error("unimplemented gen_cvt_itof %x!",vtop->type.t);
1320 /* convert fp to int 't' type */
1321 void gen_cvt_ftoi(int t)
1323 int r,r2,u,func=0;
1324 u=t&VT_UNSIGNED;
1325 t&=VT_BTYPE;
1326 r2=vtop->type.t & VT_BTYPE;
1327 if(t==VT_INT) {
1328 if(u) {
1329 if(r2 == VT_FLOAT)
1330 func=TOK___fixunssfsi;
1331 else if(r2 == VT_DOUBLE)
1332 func=TOK___fixunsdfsi;
1333 else if(r2 == VT_LDOUBLE)
1334 #if LDOUBLE_SIZE == 8
1335 func=TOK___fixunsdfsi;
1336 #else
1337 func=TOK___fixunsxfsi;
1338 #endif
1339 } else {
1340 r=fpr(gv(RC_FLOAT));
1341 r2=intr(vtop->r=get_reg(RC_INT));
1342 o(0xEE100170|(r2<<12)|r);
1343 return;
1345 } else if(t == VT_LLONG) { // unsigned handled in gen_cvt_ftoi1
1346 if(r2 == VT_FLOAT)
1347 func=TOK___fixsfdi;
1348 else if(r2 == VT_DOUBLE)
1349 func=TOK___fixdfdi;
1350 else if(r2 == VT_LDOUBLE)
1351 #if LDOUBLE_SIZE == 8
1352 func=TOK___fixdfdi;
1353 #else
1354 func=TOK___fixxfdi;
1355 #endif
1357 if(func) {
1358 vpush_global_sym(&func_old_type, func);
1359 vswap();
1360 gfunc_call(1);
1361 vpushi(0);
1362 if(t == VT_LLONG)
1363 vtop->r2 = REG_LRET;
1364 vtop->r = REG_IRET;
1365 return;
1367 error("unimplemented gen_cvt_ftoi!");
1370 /* convert from one floating point type to another */
1371 void gen_cvt_ftof(int t)
1373 /* all we have to do on i386 and ARM is to put the float in a register */
1374 gv(RC_FLOAT);
1377 /* computed goto support */
1378 void ggoto(void)
1380 gcall_or_jmp(1);
1381 vtop--;
1384 /* end of ARM code generator */
1385 /*************************************************************/