fix-mixed-struct (patch by Pip Cet)
[tinycc.git] / arm-gen.c
blob39185d2852b4f02428349af11d70c4d2f82150cd
1 /*
2 * ARMv4 code generator for TCC
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 #if defined(TCC_ARM_EABI) && !defined(TCC_ARM_VFP)
27 #error "Currently TinyCC only supports float computation with VFP instructions"
28 #endif
30 /* number of available registers */
31 #ifdef TCC_ARM_VFP
32 #define NB_REGS 13
33 #else
34 #define NB_REGS 9
35 #endif
37 typedef int RegArgs;
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 enum float_abi {
147 ARM_SOFTFP_FLOAT,
148 ARM_HARD_FLOAT,
151 /******************************************************/
152 #else /* ! TARGET_DEFS_ONLY */
153 /******************************************************/
154 #include "tcc.h"
156 enum float_abi float_abi;
158 ST_DATA const int reg_classes[NB_REGS] = {
159 /* r0 */ RC_INT | RC_R0,
160 /* r1 */ RC_INT | RC_R1,
161 /* r2 */ RC_INT | RC_R2,
162 /* r3 */ RC_INT | RC_R3,
163 /* r12 */ RC_INT | RC_R12,
164 /* f0 */ RC_FLOAT | RC_F0,
165 /* f1 */ RC_FLOAT | RC_F1,
166 /* f2 */ RC_FLOAT | RC_F2,
167 /* f3 */ RC_FLOAT | RC_F3,
168 #ifdef TCC_ARM_VFP
169 /* d4/s8 */ RC_FLOAT | RC_F4,
170 /* d5/s10 */ RC_FLOAT | RC_F5,
171 /* d6/s12 */ RC_FLOAT | RC_F6,
172 /* d7/s14 */ RC_FLOAT | RC_F7,
173 #endif
176 static int func_sub_sp_offset, last_itod_magic;
177 static int leaffunc;
179 #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
180 static CType float_type, double_type, func_float_type, func_double_type;
181 ST_FUNC void arm_init(struct TCCState *s)
183 float_type.t = VT_FLOAT;
184 double_type.t = VT_DOUBLE;
185 func_float_type.t = VT_FUNC;
186 func_float_type.ref = sym_push(SYM_FIELD, &float_type, FUNC_CDECL, FUNC_OLD);
187 func_double_type.t = VT_FUNC;
188 func_double_type.ref = sym_push(SYM_FIELD, &double_type, FUNC_CDECL, FUNC_OLD);
190 float_abi = s->float_abi;
191 #ifndef TCC_ARM_HARDFLOAT
192 tcc_warning("soft float ABI currently not supported: default to softfp");
193 #endif
195 #else
196 #define func_float_type func_old_type
197 #define func_double_type func_old_type
198 #define func_ldouble_type func_old_type
199 ST_FUNC void arm_init(struct TCCState *s)
201 #if !defined (TCC_ARM_VFP)
202 tcc_warning("Support for FPA is deprecated and will be removed in next"
203 " release");
204 #endif
205 #if !defined (TCC_ARM_EABI)
206 tcc_warning("Support for OABI is deprecated and will be removed in next"
207 " release");
208 #endif
210 #endif
212 static int two2mask(int a,int b) {
213 return (reg_classes[a]|reg_classes[b])&~(RC_INT|RC_FLOAT);
216 static int regmask(int r) {
217 return reg_classes[r]&~(RC_INT|RC_FLOAT);
220 /******************************************************/
222 #if defined(TCC_ARM_EABI) && !defined(CONFIG_TCC_ELFINTERP)
223 char *default_elfinterp(struct TCCState *s)
225 if (s->float_abi == ARM_HARD_FLOAT)
226 return "/lib/ld-linux-armhf.so.3";
227 else
228 return "/lib/ld-linux.so.3";
230 #endif
232 void o(uint32_t i)
234 /* this is a good place to start adding big-endian support*/
235 int ind1;
237 ind1 = ind + 4;
238 if (!cur_text_section)
239 tcc_error("compiler error! This happens f.ex. if the compiler\n"
240 "can't evaluate constant expressions outside of a function.");
241 if (ind1 > cur_text_section->data_allocated)
242 section_realloc(cur_text_section, ind1);
243 cur_text_section->data[ind++] = i&255;
244 i>>=8;
245 cur_text_section->data[ind++] = i&255;
246 i>>=8;
247 cur_text_section->data[ind++] = i&255;
248 i>>=8;
249 cur_text_section->data[ind++] = i;
252 static uint32_t stuff_const(uint32_t op, uint32_t c)
254 int try_neg=0;
255 uint32_t nc = 0, negop = 0;
257 switch(op&0x1F00000)
259 case 0x800000: //add
260 case 0x400000: //sub
261 try_neg=1;
262 negop=op^0xC00000;
263 nc=-c;
264 break;
265 case 0x1A00000: //mov
266 case 0x1E00000: //mvn
267 try_neg=1;
268 negop=op^0x400000;
269 nc=~c;
270 break;
271 case 0x200000: //xor
272 if(c==~0)
273 return (op&0xF010F000)|((op>>16)&0xF)|0x1E00000;
274 break;
275 case 0x0: //and
276 if(c==~0)
277 return (op&0xF010F000)|((op>>16)&0xF)|0x1A00000;
278 case 0x1C00000: //bic
279 try_neg=1;
280 negop=op^0x1C00000;
281 nc=~c;
282 break;
283 case 0x1800000: //orr
284 if(c==~0)
285 return (op&0xFFF0FFFF)|0x1E00000;
286 break;
288 do {
289 uint32_t m;
290 int i;
291 if(c<256) /* catch undefined <<32 */
292 return op|c;
293 for(i=2;i<32;i+=2) {
294 m=(0xff>>i)|(0xff<<(32-i));
295 if(!(c&~m))
296 return op|(i<<7)|(c<<i)|(c>>(32-i));
298 op=negop;
299 c=nc;
300 } while(try_neg--);
301 return 0;
305 //only add,sub
306 void stuff_const_harder(uint32_t op, uint32_t v) {
307 uint32_t x;
308 x=stuff_const(op,v);
309 if(x)
310 o(x);
311 else {
312 uint32_t a[16], nv, no, o2, n2;
313 int i,j,k;
314 a[0]=0xff;
315 o2=(op&0xfff0ffff)|((op&0xf000)<<4);;
316 for(i=1;i<16;i++)
317 a[i]=(a[i-1]>>2)|(a[i-1]<<30);
318 for(i=0;i<12;i++)
319 for(j=i<4?i+12:15;j>=i+4;j--)
320 if((v&(a[i]|a[j]))==v) {
321 o(stuff_const(op,v&a[i]));
322 o(stuff_const(o2,v&a[j]));
323 return;
325 no=op^0xC00000;
326 n2=o2^0xC00000;
327 nv=-v;
328 for(i=0;i<12;i++)
329 for(j=i<4?i+12:15;j>=i+4;j--)
330 if((nv&(a[i]|a[j]))==nv) {
331 o(stuff_const(no,nv&a[i]));
332 o(stuff_const(n2,nv&a[j]));
333 return;
335 for(i=0;i<8;i++)
336 for(j=i+4;j<12;j++)
337 for(k=i<4?i+12:15;k>=j+4;k--)
338 if((v&(a[i]|a[j]|a[k]))==v) {
339 o(stuff_const(op,v&a[i]));
340 o(stuff_const(o2,v&a[j]));
341 o(stuff_const(o2,v&a[k]));
342 return;
344 no=op^0xC00000;
345 nv=-v;
346 for(i=0;i<8;i++)
347 for(j=i+4;j<12;j++)
348 for(k=i<4?i+12:15;k>=j+4;k--)
349 if((nv&(a[i]|a[j]|a[k]))==nv) {
350 o(stuff_const(no,nv&a[i]));
351 o(stuff_const(n2,nv&a[j]));
352 o(stuff_const(n2,nv&a[k]));
353 return;
355 o(stuff_const(op,v&a[0]));
356 o(stuff_const(o2,v&a[4]));
357 o(stuff_const(o2,v&a[8]));
358 o(stuff_const(o2,v&a[12]));
362 ST_FUNC uint32_t encbranch(int pos, int addr, int fail)
364 addr-=pos+8;
365 addr/=4;
366 if(addr>=0x1000000 || addr<-0x1000000) {
367 if(fail)
368 tcc_error("FIXME: function bigger than 32MB");
369 return 0;
371 return 0x0A000000|(addr&0xffffff);
374 int decbranch(int pos)
376 int x;
377 x=*(uint32_t *)(cur_text_section->data + pos);
378 x&=0x00ffffff;
379 if(x&0x800000)
380 x-=0x1000000;
381 return x*4+pos+8;
384 /* output a symbol and patch all calls to it */
385 void gsym_addr(int t, int a)
387 uint32_t *x;
388 int lt;
389 while(t) {
390 x=(uint32_t *)(cur_text_section->data + t);
391 t=decbranch(lt=t);
392 if(a==lt+4)
393 *x=0xE1A00000; // nop
394 else {
395 *x &= 0xff000000;
396 *x |= encbranch(lt,a,1);
401 void gsym(int t)
403 gsym_addr(t, ind);
406 #ifdef TCC_ARM_VFP
407 static uint32_t vfpr(int r)
409 if(r<TREG_F0 || r>TREG_F7)
410 tcc_error("compiler error! register %i is no vfp register",r);
411 return r-5;
413 #else
414 static uint32_t fpr(int r)
416 if(r<TREG_F0 || r>TREG_F3)
417 tcc_error("compiler error! register %i is no fpa register",r);
418 return r-5;
420 #endif
422 static uint32_t intr(int r)
424 if(r==4)
425 return 12;
426 if((r<0 || r>4) && r!=14)
427 tcc_error("compiler error! register %i is no int register",r);
428 return r;
431 static void calcaddr(uint32_t *base, int *off, int *sgn, int maxoff, unsigned shift)
433 if(*off>maxoff || *off&((1<<shift)-1)) {
434 uint32_t x, y;
435 x=0xE280E000;
436 if(*sgn)
437 x=0xE240E000;
438 x|=(*base)<<16;
439 *base=14; // lr
440 y=stuff_const(x,*off&~maxoff);
441 if(y) {
442 o(y);
443 *off&=maxoff;
444 return;
446 y=stuff_const(x,(*off+maxoff)&~maxoff);
447 if(y) {
448 o(y);
449 *sgn=!*sgn;
450 *off=((*off+maxoff)&~maxoff)-*off;
451 return;
453 stuff_const_harder(x,*off&~maxoff);
454 *off&=maxoff;
458 static uint32_t mapcc(int cc)
460 switch(cc)
462 case TOK_ULT:
463 return 0x30000000; /* CC/LO */
464 case TOK_UGE:
465 return 0x20000000; /* CS/HS */
466 case TOK_EQ:
467 return 0x00000000; /* EQ */
468 case TOK_NE:
469 return 0x10000000; /* NE */
470 case TOK_ULE:
471 return 0x90000000; /* LS */
472 case TOK_UGT:
473 return 0x80000000; /* HI */
474 case TOK_Nset:
475 return 0x40000000; /* MI */
476 case TOK_Nclear:
477 return 0x50000000; /* PL */
478 case TOK_LT:
479 return 0xB0000000; /* LT */
480 case TOK_GE:
481 return 0xA0000000; /* GE */
482 case TOK_LE:
483 return 0xD0000000; /* LE */
484 case TOK_GT:
485 return 0xC0000000; /* GT */
487 tcc_error("unexpected condition code");
488 return 0xE0000000; /* AL */
491 static int negcc(int cc)
493 switch(cc)
495 case TOK_ULT:
496 return TOK_UGE;
497 case TOK_UGE:
498 return TOK_ULT;
499 case TOK_EQ:
500 return TOK_NE;
501 case TOK_NE:
502 return TOK_EQ;
503 case TOK_ULE:
504 return TOK_UGT;
505 case TOK_UGT:
506 return TOK_ULE;
507 case TOK_Nset:
508 return TOK_Nclear;
509 case TOK_Nclear:
510 return TOK_Nset;
511 case TOK_LT:
512 return TOK_GE;
513 case TOK_GE:
514 return TOK_LT;
515 case TOK_LE:
516 return TOK_GT;
517 case TOK_GT:
518 return TOK_LE;
520 tcc_error("unexpected condition code");
521 return TOK_NE;
524 /* load 'r' from value 'sv' */
525 void load(int r, SValue *sv)
527 int v, ft, fc, fr, sign;
528 uint32_t op;
529 SValue v1;
531 fr = sv->r;
532 ft = sv->type.t;
533 fc = sv->c.ul;
535 if(fc>=0)
536 sign=0;
537 else {
538 sign=1;
539 fc=-fc;
542 v = fr & VT_VALMASK;
543 if (fr & VT_LVAL) {
544 uint32_t base = 0xB; // fp
545 if(v == VT_LLOCAL) {
546 v1.type.t = VT_PTR;
547 v1.r = VT_LOCAL | VT_LVAL;
548 v1.c.ul = sv->c.ul;
549 load(base=14 /* lr */, &v1);
550 fc=sign=0;
551 v=VT_LOCAL;
552 } else if(v == VT_CONST) {
553 v1.type.t = VT_PTR;
554 v1.r = fr&~VT_LVAL;
555 v1.c.ul = sv->c.ul;
556 v1.sym=sv->sym;
557 load(base=14, &v1);
558 fc=sign=0;
559 v=VT_LOCAL;
560 } else if(v < VT_CONST) {
561 base=intr(v);
562 fc=sign=0;
563 v=VT_LOCAL;
565 if(v == VT_LOCAL) {
566 if(is_float(ft)) {
567 calcaddr(&base,&fc,&sign,1020,2);
568 #ifdef TCC_ARM_VFP
569 op=0xED100A00; /* flds */
570 if(!sign)
571 op|=0x800000;
572 if ((ft & VT_BTYPE) != VT_FLOAT)
573 op|=0x100; /* flds -> fldd */
574 o(op|(vfpr(r)<<12)|(fc>>2)|(base<<16));
575 #else
576 op=0xED100100;
577 if(!sign)
578 op|=0x800000;
579 #if LDOUBLE_SIZE == 8
580 if ((ft & VT_BTYPE) != VT_FLOAT)
581 op|=0x8000;
582 #else
583 if ((ft & VT_BTYPE) == VT_DOUBLE)
584 op|=0x8000;
585 else if ((ft & VT_BTYPE) == VT_LDOUBLE)
586 op|=0x400000;
587 #endif
588 o(op|(fpr(r)<<12)|(fc>>2)|(base<<16));
589 #endif
590 } else if((ft & (VT_BTYPE|VT_UNSIGNED)) == VT_BYTE
591 || (ft & VT_BTYPE) == VT_SHORT) {
592 calcaddr(&base,&fc,&sign,255,0);
593 op=0xE1500090;
594 if ((ft & VT_BTYPE) == VT_SHORT)
595 op|=0x20;
596 if ((ft & VT_UNSIGNED) == 0)
597 op|=0x40;
598 if(!sign)
599 op|=0x800000;
600 o(op|(intr(r)<<12)|(base<<16)|((fc&0xf0)<<4)|(fc&0xf));
601 } else {
602 calcaddr(&base,&fc,&sign,4095,0);
603 op=0xE5100000;
604 if(!sign)
605 op|=0x800000;
606 if ((ft & VT_BTYPE) == VT_BYTE || (ft & VT_BTYPE) == VT_BOOL)
607 op|=0x400000;
608 o(op|(intr(r)<<12)|fc|(base<<16));
610 return;
612 } else {
613 if (v == VT_CONST) {
614 op=stuff_const(0xE3A00000|(intr(r)<<12),sv->c.ul);
615 if (fr & VT_SYM || !op) {
616 o(0xE59F0000|(intr(r)<<12));
617 o(0xEA000000);
618 if(fr & VT_SYM)
619 greloc(cur_text_section, sv->sym, ind, R_ARM_ABS32);
620 o(sv->c.ul);
621 } else
622 o(op);
623 return;
624 } else if (v == VT_LOCAL) {
625 op=stuff_const(0xE28B0000|(intr(r)<<12),sv->c.ul);
626 if (fr & VT_SYM || !op) {
627 o(0xE59F0000|(intr(r)<<12));
628 o(0xEA000000);
629 if(fr & VT_SYM) // needed ?
630 greloc(cur_text_section, sv->sym, ind, R_ARM_ABS32);
631 o(sv->c.ul);
632 o(0xE08B0000|(intr(r)<<12)|intr(r));
633 } else
634 o(op);
635 return;
636 } else if(v == VT_CMP) {
637 o(mapcc(sv->c.ul)|0x3A00001|(intr(r)<<12));
638 o(mapcc(negcc(sv->c.ul))|0x3A00000|(intr(r)<<12));
639 return;
640 } else if (v == VT_JMP || v == VT_JMPI) {
641 int t;
642 t = v & 1;
643 o(0xE3A00000|(intr(r)<<12)|t);
644 o(0xEA000000);
645 gsym(sv->c.ul);
646 o(0xE3A00000|(intr(r)<<12)|(t^1));
647 return;
648 } else if (v < VT_CONST) {
649 if(is_float(ft))
650 #ifdef TCC_ARM_VFP
651 o(0xEEB00A40|(vfpr(r)<<12)|vfpr(v)|T2CPR(ft)); /* fcpyX */
652 #else
653 o(0xEE008180|(fpr(r)<<12)|fpr(v));
654 #endif
655 else
656 o(0xE1A00000|(intr(r)<<12)|intr(v));
657 return;
660 tcc_error("load unimplemented!");
663 /* store register 'r' in lvalue 'v' */
664 void store(int r, SValue *sv)
666 SValue v1;
667 int v, ft, fc, fr, sign;
668 uint32_t op;
670 fr = sv->r;
671 ft = sv->type.t;
672 fc = sv->c.ul;
674 if(fc>=0)
675 sign=0;
676 else {
677 sign=1;
678 fc=-fc;
681 v = fr & VT_VALMASK;
682 if (fr & VT_LVAL || fr == VT_LOCAL) {
683 uint32_t base = 0xb;
684 if(v < VT_CONST) {
685 base=intr(v);
686 v=VT_LOCAL;
687 fc=sign=0;
688 } else if(v == VT_CONST) {
689 v1.type.t = ft;
690 v1.r = fr&~VT_LVAL;
691 v1.c.ul = sv->c.ul;
692 v1.sym=sv->sym;
693 load(base=14, &v1);
694 fc=sign=0;
695 v=VT_LOCAL;
697 if(v == VT_LOCAL) {
698 if(is_float(ft)) {
699 calcaddr(&base,&fc,&sign,1020,2);
700 #ifdef TCC_ARM_VFP
701 op=0xED000A00; /* fsts */
702 if(!sign)
703 op|=0x800000;
704 if ((ft & VT_BTYPE) != VT_FLOAT)
705 op|=0x100; /* fsts -> fstd */
706 o(op|(vfpr(r)<<12)|(fc>>2)|(base<<16));
707 #else
708 op=0xED000100;
709 if(!sign)
710 op|=0x800000;
711 #if LDOUBLE_SIZE == 8
712 if ((ft & VT_BTYPE) != VT_FLOAT)
713 op|=0x8000;
714 #else
715 if ((ft & VT_BTYPE) == VT_DOUBLE)
716 op|=0x8000;
717 if ((ft & VT_BTYPE) == VT_LDOUBLE)
718 op|=0x400000;
719 #endif
720 o(op|(fpr(r)<<12)|(fc>>2)|(base<<16));
721 #endif
722 return;
723 } else if((ft & VT_BTYPE) == VT_SHORT) {
724 calcaddr(&base,&fc,&sign,255,0);
725 op=0xE14000B0;
726 if(!sign)
727 op|=0x800000;
728 o(op|(intr(r)<<12)|(base<<16)|((fc&0xf0)<<4)|(fc&0xf));
729 } else {
730 calcaddr(&base,&fc,&sign,4095,0);
731 op=0xE5000000;
732 if(!sign)
733 op|=0x800000;
734 if ((ft & VT_BTYPE) == VT_BYTE || (ft & VT_BTYPE) == VT_BOOL)
735 op|=0x400000;
736 o(op|(intr(r)<<12)|fc|(base<<16));
738 return;
741 tcc_error("store unimplemented");
744 static void gadd_sp(int val)
746 stuff_const_harder(0xE28DD000,val);
749 /* 'is_jmp' is '1' if it is a jump */
750 static void gcall_or_jmp(int is_jmp)
752 int r;
753 if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
754 uint32_t x;
755 /* constant case */
756 x=encbranch(ind,ind+vtop->c.ul,0);
757 if(x) {
758 if (vtop->r & VT_SYM) {
759 /* relocation case */
760 greloc(cur_text_section, vtop->sym, ind, R_ARM_PC24);
761 } else
762 put_elf_reloc(symtab_section, cur_text_section, ind, R_ARM_PC24, 0);
763 o(x|(is_jmp?0xE0000000:0xE1000000));
764 } else {
765 if(!is_jmp)
766 o(0xE28FE004); // add lr,pc,#4
767 o(0xE51FF004); // ldr pc,[pc,#-4]
768 if (vtop->r & VT_SYM)
769 greloc(cur_text_section, vtop->sym, ind, R_ARM_ABS32);
770 o(vtop->c.ul);
772 } else {
773 /* otherwise, indirect call */
774 r = gv(RC_INT);
775 if(!is_jmp)
776 o(0xE1A0E00F); // mov lr,pc
777 o(0xE1A0F000|intr(r)); // mov pc,r
781 /* Return whether a structure is an homogeneous float aggregate or not.
782 The answer is true if all the elements of the structure are of the same
783 primitive float type and there is less than 4 elements.
785 type: the type corresponding to the structure to be tested */
786 static int is_hgen_float_aggr(CType *type)
788 if ((type->t & VT_BTYPE) == VT_STRUCT) {
789 struct Sym *ref;
790 int btype, nb_fields = 0;
792 ref = type->ref->next;
793 btype = ref->type.t & VT_BTYPE;
794 if (btype == VT_FLOAT || btype == VT_DOUBLE) {
795 for(; ref && btype == (ref->type.t & VT_BTYPE); ref = ref->next, nb_fields++);
796 return !ref && nb_fields <= 4;
799 return 0;
802 struct avail_regs {
803 signed char avail[3]; /* 3 holes max with only float and double alignments */
804 int first_hole; /* first available hole */
805 int last_hole; /* last available hole (none if equal to first_hole) */
806 int first_free_reg; /* next free register in the sequence, hole excluded */
809 #define AVAIL_REGS_INITIALIZER (struct avail_regs) { { 0, 0, 0}, 0, 0, 0 }
811 /* Find suitable registers for a VFP Co-Processor Register Candidate (VFP CPRC
812 param) according to the rules described in the procedure call standard for
813 the ARM architecture (AAPCS). If found, the registers are assigned to this
814 VFP CPRC parameter. Registers are allocated in sequence unless a hole exists
815 and the parameter is a single float.
817 avregs: opaque structure to keep track of available VFP co-processor regs
818 align: alignment contraints for the param, as returned by type_size()
819 size: size of the parameter, as returned by type_size() */
820 int assign_vfpreg(struct avail_regs *avregs, int align, int size)
822 int first_reg = 0;
824 if (avregs->first_free_reg == -1)
825 return -1;
826 if (align >> 3) { /* double alignment */
827 first_reg = avregs->first_free_reg;
828 /* alignment contraint not respected so use next reg and record hole */
829 if (first_reg & 1)
830 avregs->avail[avregs->last_hole++] = first_reg++;
831 } else { /* no special alignment (float or array of float) */
832 /* if single float and a hole is available, assign the param to it */
833 if (size == 4 && avregs->first_hole != avregs->last_hole)
834 return avregs->avail[avregs->first_hole++];
835 else
836 first_reg = avregs->first_free_reg;
838 if (first_reg + size / 4 <= 16) {
839 avregs->first_free_reg = first_reg + size / 4;
840 return first_reg;
842 avregs->first_free_reg = -1;
843 return -1;
846 /* Returns whether all params need to be passed in core registers or not.
847 This is the case for function part of the runtime ABI. */
848 int floats_in_core_regs(SValue *sval)
850 if (!sval->sym)
851 return 0;
853 switch (sval->sym->v) {
854 case TOK___floatundisf:
855 case TOK___floatundidf:
856 case TOK___fixunssfdi:
857 case TOK___fixunsdfdi:
858 #ifndef TCC_ARM_VFP
859 case TOK___fixunsxfdi:
860 #endif
861 case TOK___floatdisf:
862 case TOK___floatdidf:
863 case TOK___fixsfdi:
864 case TOK___fixdfdi:
865 return 1;
867 default:
868 return 0;
872 ST_FUNC int regargs_nregs(RegArgs *args)
874 return *args;
877 /* Return the number of registers needed to return the struct, or 0 if
878 returning via struct pointer. */
879 ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize, RegArgs *args) {
880 #ifdef TCC_ARM_EABI
881 int size, align;
882 size = type_size(vt, &align);
883 if (float_abi == ARM_HARD_FLOAT && !variadic &&
884 (is_float(vt->t) || is_hgen_float_aggr(vt))) {
885 *ret_align = 8;
886 *regsize = 8;
887 ret->ref = NULL;
888 ret->t = VT_DOUBLE;
889 *args = (size + 7) >> 3;
890 } else if (size <= 4) {
891 *ret_align = 4;
892 *regsize = 4;
893 ret->ref = NULL;
894 ret->t = VT_INT;
895 *args = 1;
896 } else
897 *args = 0;
898 #else
899 *args = 0;
900 #endif
902 return *args != 0;
905 /* Parameters are classified according to how they are copied to their final
906 destination for the function call. Because the copying is performed class
907 after class according to the order in the union below, it is important that
908 some constraints about the order of the members of this union are respected:
909 - CORE_STRUCT_CLASS must come after STACK_CLASS;
910 - CORE_CLASS must come after STACK_CLASS, CORE_STRUCT_CLASS and
911 VFP_STRUCT_CLASS;
912 - VFP_STRUCT_CLASS must come after VFP_CLASS.
913 See the comment for the main loop in copy_params() for the reason. */
914 enum reg_class {
915 STACK_CLASS = 0,
916 CORE_STRUCT_CLASS,
917 VFP_CLASS,
918 VFP_STRUCT_CLASS,
919 CORE_CLASS,
920 NB_CLASSES
923 struct param_plan {
924 int start; /* first reg or addr used depending on the class */
925 int end; /* last reg used or next free addr depending on the class */
926 SValue *sval; /* pointer to SValue on the value stack */
927 struct param_plan *prev; /* previous element in this class */
930 struct plan {
931 struct param_plan *pplans; /* array of all the param plans */
932 struct param_plan *clsplans[NB_CLASSES]; /* per class lists of param plans */
935 #define add_param_plan(plan,pplan,class) \
936 do { \
937 pplan.prev = plan->clsplans[class]; \
938 plan->pplans[plan ## _nb] = pplan; \
939 plan->clsplans[class] = &plan->pplans[plan ## _nb++]; \
940 } while(0)
942 /* Assign parameters to registers and stack with alignment according to the
943 rules in the procedure call standard for the ARM architecture (AAPCS).
944 The overall assignment is recorded in an array of per parameter structures
945 called parameter plans. The parameter plans are also further organized in a
946 number of linked lists, one per class of parameter (see the comment for the
947 definition of union reg_class).
949 nb_args: number of parameters of the function for which a call is generated
950 float_abi: float ABI in use for this function call
951 plan: the structure where the overall assignment is recorded
952 todo: a bitmap that record which core registers hold a parameter
954 Returns the amount of stack space needed for parameter passing
956 Note: this function allocated an array in plan->pplans with tcc_malloc. It
957 is the responsibility of the caller to free this array once used (ie not
958 before copy_params). */
959 static int assign_regs(int nb_args, int float_abi, struct plan *plan, int *todo)
961 int i, size, align;
962 int ncrn /* next core register number */, nsaa /* next stacked argument address*/;
963 int plan_nb = 0;
964 struct param_plan pplan;
965 struct avail_regs avregs = AVAIL_REGS_INITIALIZER;
967 ncrn = nsaa = 0;
968 *todo = 0;
969 plan->pplans = tcc_malloc(nb_args * sizeof(*plan->pplans));
970 memset(plan->clsplans, 0, sizeof(plan->clsplans));
971 for(i = nb_args; i-- ;) {
972 int j, start_vfpreg = 0;
973 CType type = vtop[-i].type;
974 type.t &= ~VT_ARRAY;
975 size = type_size(&type, &align);
976 size = (size + 3) & ~3;
977 align = (align + 3) & ~3;
978 switch(vtop[-i].type.t & VT_BTYPE) {
979 case VT_STRUCT:
980 case VT_FLOAT:
981 case VT_DOUBLE:
982 case VT_LDOUBLE:
983 if (float_abi == ARM_HARD_FLOAT) {
984 int is_hfa = 0; /* Homogeneous float aggregate */
986 if (is_float(vtop[-i].type.t)
987 || (is_hfa = is_hgen_float_aggr(&vtop[-i].type))) {
988 int end_vfpreg;
990 start_vfpreg = assign_vfpreg(&avregs, align, size);
991 end_vfpreg = start_vfpreg + ((size - 1) >> 2);
992 if (start_vfpreg >= 0) {
993 pplan = (struct param_plan) {start_vfpreg, end_vfpreg, &vtop[-i]};
994 if (is_hfa)
995 add_param_plan(plan, pplan, VFP_STRUCT_CLASS);
996 else
997 add_param_plan(plan, pplan, VFP_CLASS);
998 continue;
999 } else
1000 break;
1003 ncrn = (ncrn + (align-1)/4) & ~((align/4) - 1);
1004 if (ncrn + size/4 <= 4 || (ncrn < 4 && start_vfpreg != -1)) {
1005 /* The parameter is allocated both in core register and on stack. As
1006 * such, it can be of either class: it would either be the last of
1007 * CORE_STRUCT_CLASS or the first of STACK_CLASS. */
1008 for (j = ncrn; j < 4 && j < ncrn + size / 4; j++)
1009 *todo|=(1<<j);
1010 pplan = (struct param_plan) {ncrn, j, &vtop[-i]};
1011 add_param_plan(plan, pplan, CORE_STRUCT_CLASS);
1012 ncrn += size/4;
1013 if (ncrn > 4)
1014 nsaa = (ncrn - 4) * 4;
1015 } else {
1016 ncrn = 4;
1017 break;
1019 continue;
1020 default:
1021 if (ncrn < 4) {
1022 int is_long = (vtop[-i].type.t & VT_BTYPE) == VT_LLONG;
1024 if (is_long) {
1025 ncrn = (ncrn + 1) & -2;
1026 if (ncrn == 4)
1027 break;
1029 pplan = (struct param_plan) {ncrn, ncrn, &vtop[-i]};
1030 ncrn++;
1031 if (is_long)
1032 pplan.end = ncrn++;
1033 add_param_plan(plan, pplan, CORE_CLASS);
1034 continue;
1037 nsaa = (nsaa + (align - 1)) & ~(align - 1);
1038 pplan = (struct param_plan) {nsaa, nsaa + size, &vtop[-i]};
1039 add_param_plan(plan, pplan, STACK_CLASS);
1040 nsaa += size; /* size already rounded up before */
1042 return nsaa;
1045 #undef add_param_plan
1047 /* Copy parameters to their final destination (core reg, VFP reg or stack) for
1048 function call.
1050 nb_args: number of parameters the function take
1051 plan: the overall assignment plan for parameters
1052 todo: a bitmap indicating what core reg will hold a parameter
1054 Returns the number of SValue added by this function on the value stack */
1055 static int copy_params(int nb_args, struct plan *plan, int todo)
1057 int size, align, r, i, nb_extra_sval = 0;
1058 struct param_plan *pplan;
1060 /* Several constraints require parameters to be copied in a specific order:
1061 - structures are copied to the stack before being loaded in a reg;
1062 - floats loaded to an odd numbered VFP reg are first copied to the
1063 preceding even numbered VFP reg and then moved to the next VFP reg.
1065 It is thus important that:
1066 - structures assigned to core regs must be copied after parameters
1067 assigned to the stack but before structures assigned to VFP regs because
1068 a structure can lie partly in core registers and partly on the stack;
1069 - parameters assigned to the stack and all structures be copied before
1070 parameters assigned to a core reg since copying a parameter to the stack
1071 require using a core reg;
1072 - parameters assigned to VFP regs be copied before structures assigned to
1073 VFP regs as the copy might use an even numbered VFP reg that already
1074 holds part of a structure. */
1075 for(i = 0; i < NB_CLASSES; i++) {
1076 for(pplan = plan->clsplans[i]; pplan; pplan = pplan->prev) {
1077 vpushv(pplan->sval);
1078 pplan->sval->r = pplan->sval->r2 = VT_CONST; /* disable entry */
1079 switch(i) {
1080 case STACK_CLASS:
1081 case CORE_STRUCT_CLASS:
1082 case VFP_STRUCT_CLASS:
1083 if ((pplan->sval->type.t & VT_BTYPE) == VT_STRUCT) {
1084 int padding = 0;
1085 size = type_size(&pplan->sval->type, &align);
1086 /* align to stack align size */
1087 size = (size + 3) & ~3;
1088 if (i == STACK_CLASS && pplan->prev)
1089 padding = pplan->start - pplan->prev->end;
1090 size += padding; /* Add padding if any */
1091 /* allocate the necessary size on stack */
1092 gadd_sp(-size);
1093 /* generate structure store */
1094 r = get_reg(RC_INT);
1095 o(0xE28D0000|(intr(r)<<12)|padding); /* add r, sp, padding */
1096 vset(&vtop->type, r | VT_LVAL, 0);
1097 vswap();
1098 vstore(); /* memcpy to current sp + potential padding */
1100 /* Homogeneous float aggregate are loaded to VFP registers
1101 immediately since there is no way of loading data in multiple
1102 non consecutive VFP registers as what is done for other
1103 structures (see the use of todo). */
1104 if (i == VFP_STRUCT_CLASS) {
1105 int first = pplan->start, nb = pplan->end - first + 1;
1106 /* vpop.32 {pplan->start, ..., pplan->end} */
1107 o(0xECBD0A00|(first&1)<<22|(first>>1)<<12|nb);
1108 /* No need to write the register used to a SValue since VFP regs
1109 cannot be used for gcall_or_jmp */
1111 } else {
1112 if (is_float(pplan->sval->type.t)) {
1113 #ifdef TCC_ARM_VFP
1114 r = vfpr(gv(RC_FLOAT)) << 12;
1115 if ((pplan->sval->type.t & VT_BTYPE) == VT_FLOAT)
1116 size = 4;
1117 else {
1118 size = 8;
1119 r |= 0x101; /* vpush.32 -> vpush.64 */
1121 o(0xED2D0A01 + r); /* vpush */
1122 #else
1123 r = fpr(gv(RC_FLOAT)) << 12;
1124 if ((pplan->sval->type.t & VT_BTYPE) == VT_FLOAT)
1125 size = 4;
1126 else if ((pplan->sval->type.t & VT_BTYPE) == VT_DOUBLE)
1127 size = 8;
1128 else
1129 size = LDOUBLE_SIZE;
1131 if (size == 12)
1132 r |= 0x400000;
1133 else if(size == 8)
1134 r|=0x8000;
1136 o(0xED2D0100|r|(size>>2)); /* some kind of vpush for FPA */
1137 #endif
1138 } else {
1139 /* simple type (currently always same size) */
1140 /* XXX: implicit cast ? */
1141 size=4;
1142 if ((pplan->sval->type.t & VT_BTYPE) == VT_LLONG) {
1143 lexpand_nr();
1144 size = 8;
1145 r = gv(RC_INT);
1146 o(0xE52D0004|(intr(r)<<12)); /* push r */
1147 vtop--;
1149 r = gv(RC_INT);
1150 o(0xE52D0004|(intr(r)<<12)); /* push r */
1152 if (i == STACK_CLASS && pplan->prev)
1153 gadd_sp(pplan->prev->end - pplan->start); /* Add padding if any */
1155 break;
1157 case VFP_CLASS:
1158 gv(regmask(TREG_F0 + (pplan->start >> 1)));
1159 if (pplan->start & 1) { /* Must be in upper part of double register */
1160 o(0xEEF00A40|((pplan->start>>1)<<12)|(pplan->start>>1)); /* vmov.f32 s(n+1), sn */
1161 vtop->r = VT_CONST; /* avoid being saved on stack by gv for next float */
1163 break;
1165 case CORE_CLASS:
1166 if ((pplan->sval->type.t & VT_BTYPE) == VT_LLONG) {
1167 lexpand_nr();
1168 gv(regmask(pplan->end));
1169 pplan->sval->r2 = vtop->r;
1170 vtop--;
1172 gv(regmask(pplan->start));
1173 /* Mark register as used so that gcall_or_jmp use another one
1174 (regs >=4 are free as never used to pass parameters) */
1175 pplan->sval->r = vtop->r;
1176 break;
1178 vtop--;
1182 /* Manually free remaining registers since next parameters are loaded
1183 * manually, without the help of gv(int). */
1184 save_regs(nb_args);
1186 if(todo) {
1187 o(0xE8BD0000|todo); /* pop {todo} */
1188 for(pplan = plan->clsplans[CORE_STRUCT_CLASS]; pplan; pplan = pplan->prev) {
1189 int r;
1190 pplan->sval->r = pplan->start;
1191 /* An SValue can only pin 2 registers at best (r and r2) but a structure
1192 can occupy more than 2 registers. Thus, we need to push on the value
1193 stack some fake parameter to have on SValue for each registers used
1194 by a structure (r2 is not used). */
1195 for (r = pplan->start + 1; r <= pplan->end; r++) {
1196 if (todo & (1 << r)) {
1197 nb_extra_sval++;
1198 vpushi(0);
1199 vtop->r = r;
1204 return nb_extra_sval;
1207 /* Generate function call. The function address is pushed first, then
1208 all the parameters in call order. This functions pops all the
1209 parameters and the function address. */
1210 void gfunc_call(int nb_args)
1212 int r, args_size;
1213 int def_float_abi = float_abi;
1214 int todo;
1215 struct plan plan;
1217 #ifdef TCC_ARM_EABI
1218 int variadic;
1220 if (float_abi == ARM_HARD_FLOAT) {
1221 variadic = (vtop[-nb_args].type.ref->c == FUNC_ELLIPSIS);
1222 if (variadic || floats_in_core_regs(&vtop[-nb_args]))
1223 float_abi = ARM_SOFTFP_FLOAT;
1225 #endif
1226 /* cannot let cpu flags if other instruction are generated. Also avoid leaving
1227 VT_JMP anywhere except on the top of the stack because it would complicate
1228 the code generator. */
1229 r = vtop->r & VT_VALMASK;
1230 if (r == VT_CMP || (r & ~1) == VT_JMP)
1231 gv(RC_INT);
1233 args_size = assign_regs(nb_args, float_abi, &plan, &todo);
1235 #ifdef TCC_ARM_EABI
1236 if (args_size & 7) { /* Stack must be 8 byte aligned at fct call for EABI */
1237 args_size = (args_size + 7) & ~7;
1238 o(0xE24DD004); /* sub sp, sp, #4 */
1240 #endif
1242 nb_args += copy_params(nb_args, &plan, todo);
1243 tcc_free(plan.pplans);
1245 /* Move fct SValue on top as required by gcall_or_jmp */
1246 vrotb(nb_args + 1);
1247 gcall_or_jmp(0);
1248 if (args_size)
1249 gadd_sp(args_size); /* pop all parameters passed on the stack */
1250 #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
1251 if(float_abi == ARM_SOFTFP_FLOAT && is_float(vtop->type.ref->type.t)) {
1252 if((vtop->type.ref->type.t & VT_BTYPE) == VT_FLOAT) {
1253 o(0xEE000A10); /*vmov s0, r0 */
1254 } else {
1255 o(0xEE000B10); /* vmov.32 d0[0], r0 */
1256 o(0xEE201B10); /* vmov.32 d0[1], r1 */
1259 #endif
1260 vtop -= nb_args + 1; /* Pop all params and fct address from value stack */
1261 leaffunc = 0; /* we are calling a function, so we aren't in a leaf function */
1262 float_abi = def_float_abi;
1265 /* generate function prolog of type 't' */
1266 void gfunc_prolog(CType *func_type)
1268 Sym *sym,*sym2;
1269 int n, nf, size, align, rs, struct_ret = 0;
1270 int addr, pn, sn; /* pn=core, sn=stack */
1271 CType ret_type;
1272 RegArgs dummy;
1274 #ifdef TCC_ARM_EABI
1275 struct avail_regs avregs = AVAIL_REGS_INITIALIZER;
1276 #endif
1278 sym = func_type->ref;
1279 func_vt = sym->type;
1280 func_var = (func_type->ref->c == FUNC_ELLIPSIS);
1282 n = nf = 0;
1283 if ((func_vt.t & VT_BTYPE) == VT_STRUCT &&
1284 !gfunc_sret(&func_vt, func_var, &ret_type, &align, &rs, &dummy))
1286 n++;
1287 struct_ret = 1;
1288 func_vc = 12; /* Offset from fp of the place to store the result */
1290 for(sym2 = sym->next; sym2 && (n < 4 || nf < 16); sym2 = sym2->next) {
1291 size = type_size(&sym2->type, &align);
1292 #ifdef TCC_ARM_EABI
1293 if (float_abi == ARM_HARD_FLOAT && !func_var &&
1294 (is_float(sym2->type.t) || is_hgen_float_aggr(&sym2->type))) {
1295 int tmpnf = assign_vfpreg(&avregs, align, size);
1296 tmpnf += (size + 3) / 4;
1297 nf = (tmpnf > nf) ? tmpnf : nf;
1298 } else
1299 #endif
1300 if (n < 4)
1301 n += (size + 3) / 4;
1303 o(0xE1A0C00D); /* mov ip,sp */
1304 if (func_var)
1305 n=4;
1306 if (n) {
1307 if(n>4)
1308 n=4;
1309 #ifdef TCC_ARM_EABI
1310 n=(n+1)&-2;
1311 #endif
1312 o(0xE92D0000|((1<<n)-1)); /* save r0-r4 on stack if needed */
1314 if (nf) {
1315 if (nf>16)
1316 nf=16;
1317 nf=(nf+1)&-2; /* nf => HARDFLOAT => EABI */
1318 o(0xED2D0A00|nf); /* save s0-s15 on stack if needed */
1320 o(0xE92D5800); /* save fp, ip, lr */
1321 o(0xE1A0B00D); /* mov fp, sp */
1322 func_sub_sp_offset = ind;
1323 o(0xE1A00000); /* nop, leave space for stack adjustment in epilog */
1325 #ifdef TCC_ARM_EABI
1326 if (float_abi == ARM_HARD_FLOAT) {
1327 func_vc += nf * 4;
1328 avregs = AVAIL_REGS_INITIALIZER;
1330 #endif
1331 pn = struct_ret, sn = 0;
1332 while ((sym = sym->next)) {
1333 CType *type;
1334 type = &sym->type;
1335 size = type_size(type, &align);
1336 size = (size + 3) >> 2;
1337 align = (align + 3) & ~3;
1338 #ifdef TCC_ARM_EABI
1339 if (float_abi == ARM_HARD_FLOAT && !func_var && (is_float(sym->type.t)
1340 || is_hgen_float_aggr(&sym->type))) {
1341 int fpn = assign_vfpreg(&avregs, align, size << 2);
1342 if (fpn >= 0)
1343 addr = fpn * 4;
1344 else
1345 goto from_stack;
1346 } else
1347 #endif
1348 if (pn < 4) {
1349 #ifdef TCC_ARM_EABI
1350 pn = (pn + (align-1)/4) & -(align/4);
1351 #endif
1352 addr = (nf + pn) * 4;
1353 pn += size;
1354 if (!sn && pn > 4)
1355 sn = (pn - 4);
1356 } else {
1357 #ifdef TCC_ARM_EABI
1358 from_stack:
1359 sn = (sn + (align-1)/4) & -(align/4);
1360 #endif
1361 addr = (n + nf + sn) * 4;
1362 sn += size;
1364 sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | lvalue_type(type->t),
1365 addr + 12);
1367 last_itod_magic=0;
1368 leaffunc = 1;
1369 loc = 0;
1372 /* generate function epilog */
1373 void gfunc_epilog(void)
1375 uint32_t x;
1376 int diff;
1377 /* Copy float return value to core register if base standard is used and
1378 float computation is made with VFP */
1379 #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
1380 if ((float_abi == ARM_SOFTFP_FLOAT || func_var) && is_float(func_vt.t)) {
1381 if((func_vt.t & VT_BTYPE) == VT_FLOAT)
1382 o(0xEE100A10); /* fmrs r0, s0 */
1383 else {
1384 o(0xEE100B10); /* fmrdl r0, d0 */
1385 o(0xEE301B10); /* fmrdh r1, d0 */
1388 #endif
1389 o(0xE89BA800); /* restore fp, sp, pc */
1390 diff = (-loc + 3) & -4;
1391 #ifdef TCC_ARM_EABI
1392 if(!leaffunc)
1393 diff = ((diff + 11) & -8) - 4;
1394 #endif
1395 if(diff > 0) {
1396 x=stuff_const(0xE24BD000, diff); /* sub sp,fp,# */
1397 if(x)
1398 *(uint32_t *)(cur_text_section->data + func_sub_sp_offset) = x;
1399 else {
1400 int addr;
1401 addr=ind;
1402 o(0xE59FC004); /* ldr ip,[pc+4] */
1403 o(0xE04BD00C); /* sub sp,fp,ip */
1404 o(0xE1A0F00E); /* mov pc,lr */
1405 o(diff);
1406 *(uint32_t *)(cur_text_section->data + func_sub_sp_offset) = 0xE1000000|encbranch(func_sub_sp_offset,addr,1);
1411 /* generate a jump to a label */
1412 int gjmp(int t)
1414 int r;
1415 r=ind;
1416 o(0xE0000000|encbranch(r,t,1));
1417 return r;
1420 /* generate a jump to a fixed address */
1421 void gjmp_addr(int a)
1423 gjmp(a);
1426 /* generate a test. set 'inv' to invert test. Stack entry is popped */
1427 int gtst(int inv, int t)
1429 int v, r;
1430 uint32_t op;
1431 v = vtop->r & VT_VALMASK;
1432 r=ind;
1433 if (v == VT_CMP) {
1434 op=mapcc(inv?negcc(vtop->c.i):vtop->c.i);
1435 op|=encbranch(r,t,1);
1436 o(op);
1437 t=r;
1438 } else if (v == VT_JMP || v == VT_JMPI) {
1439 if ((v & 1) == inv) {
1440 if(!vtop->c.i)
1441 vtop->c.i=t;
1442 else {
1443 uint32_t *x;
1444 int p,lp;
1445 if(t) {
1446 p = vtop->c.i;
1447 do {
1448 p = decbranch(lp=p);
1449 } while(p);
1450 x = (uint32_t *)(cur_text_section->data + lp);
1451 *x &= 0xff000000;
1452 *x |= encbranch(lp,t,1);
1454 t = vtop->c.i;
1456 } else {
1457 t = gjmp(t);
1458 gsym(vtop->c.i);
1461 vtop--;
1462 return t;
1465 /* generate an integer binary operation */
1466 void gen_opi(int op)
1468 int c, func = 0;
1469 uint32_t opc = 0, r, fr;
1470 unsigned short retreg = REG_IRET;
1472 c=0;
1473 switch(op) {
1474 case '+':
1475 opc = 0x8;
1476 c=1;
1477 break;
1478 case TOK_ADDC1: /* add with carry generation */
1479 opc = 0x9;
1480 c=1;
1481 break;
1482 case '-':
1483 opc = 0x4;
1484 c=1;
1485 break;
1486 case TOK_SUBC1: /* sub with carry generation */
1487 opc = 0x5;
1488 c=1;
1489 break;
1490 case TOK_ADDC2: /* add with carry use */
1491 opc = 0xA;
1492 c=1;
1493 break;
1494 case TOK_SUBC2: /* sub with carry use */
1495 opc = 0xC;
1496 c=1;
1497 break;
1498 case '&':
1499 opc = 0x0;
1500 c=1;
1501 break;
1502 case '^':
1503 opc = 0x2;
1504 c=1;
1505 break;
1506 case '|':
1507 opc = 0x18;
1508 c=1;
1509 break;
1510 case '*':
1511 gv2(RC_INT, RC_INT);
1512 r = vtop[-1].r;
1513 fr = vtop[0].r;
1514 vtop--;
1515 o(0xE0000090|(intr(r)<<16)|(intr(r)<<8)|intr(fr));
1516 return;
1517 case TOK_SHL:
1518 opc = 0;
1519 c=2;
1520 break;
1521 case TOK_SHR:
1522 opc = 1;
1523 c=2;
1524 break;
1525 case TOK_SAR:
1526 opc = 2;
1527 c=2;
1528 break;
1529 case '/':
1530 case TOK_PDIV:
1531 func=TOK___divsi3;
1532 c=3;
1533 break;
1534 case TOK_UDIV:
1535 func=TOK___udivsi3;
1536 c=3;
1537 break;
1538 case '%':
1539 #ifdef TCC_ARM_EABI
1540 func=TOK___aeabi_idivmod;
1541 retreg=REG_LRET;
1542 #else
1543 func=TOK___modsi3;
1544 #endif
1545 c=3;
1546 break;
1547 case TOK_UMOD:
1548 #ifdef TCC_ARM_EABI
1549 func=TOK___aeabi_uidivmod;
1550 retreg=REG_LRET;
1551 #else
1552 func=TOK___umodsi3;
1553 #endif
1554 c=3;
1555 break;
1556 case TOK_UMULL:
1557 gv2(RC_INT, RC_INT);
1558 r=intr(vtop[-1].r2=get_reg(RC_INT));
1559 c=vtop[-1].r;
1560 vtop[-1].r=get_reg_ex(RC_INT,regmask(c));
1561 vtop--;
1562 o(0xE0800090|(r<<16)|(intr(vtop->r)<<12)|(intr(c)<<8)|intr(vtop[1].r));
1563 return;
1564 default:
1565 opc = 0x15;
1566 c=1;
1567 break;
1569 switch(c) {
1570 case 1:
1571 if((vtop[-1].r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
1572 if(opc == 4 || opc == 5 || opc == 0xc) {
1573 vswap();
1574 opc|=2; // sub -> rsb
1577 if ((vtop->r & VT_VALMASK) == VT_CMP ||
1578 (vtop->r & (VT_VALMASK & ~1)) == VT_JMP)
1579 gv(RC_INT);
1580 vswap();
1581 c=intr(gv(RC_INT));
1582 vswap();
1583 opc=0xE0000000|(opc<<20)|(c<<16);
1584 if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
1585 uint32_t x;
1586 x=stuff_const(opc|0x2000000,vtop->c.i);
1587 if(x) {
1588 r=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r)));
1589 o(x|(r<<12));
1590 goto done;
1593 fr=intr(gv(RC_INT));
1594 r=intr(vtop[-1].r=get_reg_ex(RC_INT,two2mask(vtop->r,vtop[-1].r)));
1595 o(opc|(r<<12)|fr);
1596 done:
1597 vtop--;
1598 if (op >= TOK_ULT && op <= TOK_GT) {
1599 vtop->r = VT_CMP;
1600 vtop->c.i = op;
1602 break;
1603 case 2:
1604 opc=0xE1A00000|(opc<<5);
1605 if ((vtop->r & VT_VALMASK) == VT_CMP ||
1606 (vtop->r & (VT_VALMASK & ~1)) == VT_JMP)
1607 gv(RC_INT);
1608 vswap();
1609 r=intr(gv(RC_INT));
1610 vswap();
1611 opc|=r;
1612 if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
1613 fr=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r)));
1614 c = vtop->c.i & 0x1f;
1615 o(opc|(c<<7)|(fr<<12));
1616 } else {
1617 fr=intr(gv(RC_INT));
1618 c=intr(vtop[-1].r=get_reg_ex(RC_INT,two2mask(vtop->r,vtop[-1].r)));
1619 o(opc|(c<<12)|(fr<<8)|0x10);
1621 vtop--;
1622 break;
1623 case 3:
1624 vpush_global_sym(&func_old_type, func);
1625 vrott(3);
1626 gfunc_call(2);
1627 vpushi(0);
1628 vtop->r = retreg;
1629 break;
1630 default:
1631 tcc_error("gen_opi %i unimplemented!",op);
1635 #ifdef TCC_ARM_VFP
1636 static int is_zero(int i)
1638 if((vtop[i].r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST)
1639 return 0;
1640 if (vtop[i].type.t == VT_FLOAT)
1641 return (vtop[i].c.f == 0.f);
1642 else if (vtop[i].type.t == VT_DOUBLE)
1643 return (vtop[i].c.d == 0.0);
1644 return (vtop[i].c.ld == 0.l);
1647 /* generate a floating point operation 'v = t1 op t2' instruction. The
1648 * two operands are guaranted to have the same floating point type */
1649 void gen_opf(int op)
1651 uint32_t x;
1652 int fneg=0,r;
1653 x=0xEE000A00|T2CPR(vtop->type.t);
1654 switch(op) {
1655 case '+':
1656 if(is_zero(-1))
1657 vswap();
1658 if(is_zero(0)) {
1659 vtop--;
1660 return;
1662 x|=0x300000;
1663 break;
1664 case '-':
1665 x|=0x300040;
1666 if(is_zero(0)) {
1667 vtop--;
1668 return;
1670 if(is_zero(-1)) {
1671 x|=0x810000; /* fsubX -> fnegX */
1672 vswap();
1673 vtop--;
1674 fneg=1;
1676 break;
1677 case '*':
1678 x|=0x200000;
1679 break;
1680 case '/':
1681 x|=0x800000;
1682 break;
1683 default:
1684 if(op < TOK_ULT || op > TOK_GT) {
1685 tcc_error("unknown fp op %x!",op);
1686 return;
1688 if(is_zero(-1)) {
1689 vswap();
1690 switch(op) {
1691 case TOK_LT: op=TOK_GT; break;
1692 case TOK_GE: op=TOK_ULE; break;
1693 case TOK_LE: op=TOK_GE; break;
1694 case TOK_GT: op=TOK_ULT; break;
1697 x|=0xB40040; /* fcmpX */
1698 if(op!=TOK_EQ && op!=TOK_NE)
1699 x|=0x80; /* fcmpX -> fcmpeX */
1700 if(is_zero(0)) {
1701 vtop--;
1702 o(x|0x10000|(vfpr(gv(RC_FLOAT))<<12)); /* fcmp(e)X -> fcmp(e)zX */
1703 } else {
1704 x|=vfpr(gv(RC_FLOAT));
1705 vswap();
1706 o(x|(vfpr(gv(RC_FLOAT))<<12));
1707 vtop--;
1709 o(0xEEF1FA10); /* fmstat */
1711 switch(op) {
1712 case TOK_LE: op=TOK_ULE; break;
1713 case TOK_LT: op=TOK_ULT; break;
1714 case TOK_UGE: op=TOK_GE; break;
1715 case TOK_UGT: op=TOK_GT; break;
1718 vtop->r = VT_CMP;
1719 vtop->c.i = op;
1720 return;
1722 r=gv(RC_FLOAT);
1723 x|=vfpr(r);
1724 r=regmask(r);
1725 if(!fneg) {
1726 int r2;
1727 vswap();
1728 r2=gv(RC_FLOAT);
1729 x|=vfpr(r2)<<16;
1730 r|=regmask(r2);
1732 vtop->r=get_reg_ex(RC_FLOAT,r);
1733 if(!fneg)
1734 vtop--;
1735 o(x|(vfpr(vtop->r)<<12));
1738 #else
1739 static uint32_t is_fconst()
1741 long double f;
1742 uint32_t r;
1743 if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST)
1744 return 0;
1745 if (vtop->type.t == VT_FLOAT)
1746 f = vtop->c.f;
1747 else if (vtop->type.t == VT_DOUBLE)
1748 f = vtop->c.d;
1749 else
1750 f = vtop->c.ld;
1751 if(!ieee_finite(f))
1752 return 0;
1753 r=0x8;
1754 if(f<0.0) {
1755 r=0x18;
1756 f=-f;
1758 if(f==0.0)
1759 return r;
1760 if(f==1.0)
1761 return r|1;
1762 if(f==2.0)
1763 return r|2;
1764 if(f==3.0)
1765 return r|3;
1766 if(f==4.0)
1767 return r|4;
1768 if(f==5.0)
1769 return r|5;
1770 if(f==0.5)
1771 return r|6;
1772 if(f==10.0)
1773 return r|7;
1774 return 0;
1777 /* generate a floating point operation 'v = t1 op t2' instruction. The
1778 two operands are guaranted to have the same floating point type */
1779 void gen_opf(int op)
1781 uint32_t x, r, r2, c1, c2;
1782 //fputs("gen_opf\n",stderr);
1783 vswap();
1784 c1 = is_fconst();
1785 vswap();
1786 c2 = is_fconst();
1787 x=0xEE000100;
1788 #if LDOUBLE_SIZE == 8
1789 if ((vtop->type.t & VT_BTYPE) != VT_FLOAT)
1790 x|=0x80;
1791 #else
1792 if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE)
1793 x|=0x80;
1794 else if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE)
1795 x|=0x80000;
1796 #endif
1797 switch(op)
1799 case '+':
1800 if(!c2) {
1801 vswap();
1802 c2=c1;
1804 vswap();
1805 r=fpr(gv(RC_FLOAT));
1806 vswap();
1807 if(c2) {
1808 if(c2>0xf)
1809 x|=0x200000; // suf
1810 r2=c2&0xf;
1811 } else {
1812 r2=fpr(gv(RC_FLOAT));
1814 break;
1815 case '-':
1816 if(c2) {
1817 if(c2<=0xf)
1818 x|=0x200000; // suf
1819 r2=c2&0xf;
1820 vswap();
1821 r=fpr(gv(RC_FLOAT));
1822 vswap();
1823 } else if(c1 && c1<=0xf) {
1824 x|=0x300000; // rsf
1825 r2=c1;
1826 r=fpr(gv(RC_FLOAT));
1827 vswap();
1828 } else {
1829 x|=0x200000; // suf
1830 vswap();
1831 r=fpr(gv(RC_FLOAT));
1832 vswap();
1833 r2=fpr(gv(RC_FLOAT));
1835 break;
1836 case '*':
1837 if(!c2 || c2>0xf) {
1838 vswap();
1839 c2=c1;
1841 vswap();
1842 r=fpr(gv(RC_FLOAT));
1843 vswap();
1844 if(c2 && c2<=0xf)
1845 r2=c2;
1846 else
1847 r2=fpr(gv(RC_FLOAT));
1848 x|=0x100000; // muf
1849 break;
1850 case '/':
1851 if(c2 && c2<=0xf) {
1852 x|=0x400000; // dvf
1853 r2=c2;
1854 vswap();
1855 r=fpr(gv(RC_FLOAT));
1856 vswap();
1857 } else if(c1 && c1<=0xf) {
1858 x|=0x500000; // rdf
1859 r2=c1;
1860 r=fpr(gv(RC_FLOAT));
1861 vswap();
1862 } else {
1863 x|=0x400000; // dvf
1864 vswap();
1865 r=fpr(gv(RC_FLOAT));
1866 vswap();
1867 r2=fpr(gv(RC_FLOAT));
1869 break;
1870 default:
1871 if(op >= TOK_ULT && op <= TOK_GT) {
1872 x|=0xd0f110; // cmfe
1873 /* bug (intention?) in Linux FPU emulator
1874 doesn't set carry if equal */
1875 switch(op) {
1876 case TOK_ULT:
1877 case TOK_UGE:
1878 case TOK_ULE:
1879 case TOK_UGT:
1880 tcc_error("unsigned comparison on floats?");
1881 break;
1882 case TOK_LT:
1883 op=TOK_Nset;
1884 break;
1885 case TOK_LE:
1886 op=TOK_ULE; /* correct in unordered case only if AC bit in FPSR set */
1887 break;
1888 case TOK_EQ:
1889 case TOK_NE:
1890 x&=~0x400000; // cmfe -> cmf
1891 break;
1893 if(c1 && !c2) {
1894 c2=c1;
1895 vswap();
1896 switch(op) {
1897 case TOK_Nset:
1898 op=TOK_GT;
1899 break;
1900 case TOK_GE:
1901 op=TOK_ULE;
1902 break;
1903 case TOK_ULE:
1904 op=TOK_GE;
1905 break;
1906 case TOK_GT:
1907 op=TOK_Nset;
1908 break;
1911 vswap();
1912 r=fpr(gv(RC_FLOAT));
1913 vswap();
1914 if(c2) {
1915 if(c2>0xf)
1916 x|=0x200000;
1917 r2=c2&0xf;
1918 } else {
1919 r2=fpr(gv(RC_FLOAT));
1921 vtop[-1].r = VT_CMP;
1922 vtop[-1].c.i = op;
1923 } else {
1924 tcc_error("unknown fp op %x!",op);
1925 return;
1928 if(vtop[-1].r == VT_CMP)
1929 c1=15;
1930 else {
1931 c1=vtop->r;
1932 if(r2&0x8)
1933 c1=vtop[-1].r;
1934 vtop[-1].r=get_reg_ex(RC_FLOAT,two2mask(vtop[-1].r,c1));
1935 c1=fpr(vtop[-1].r);
1937 vtop--;
1938 o(x|(r<<16)|(c1<<12)|r2);
1940 #endif
1942 /* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
1943 and 'long long' cases. */
1944 ST_FUNC void gen_cvt_itof1(int t)
1946 uint32_t r, r2;
1947 int bt;
1948 bt=vtop->type.t & VT_BTYPE;
1949 if(bt == VT_INT || bt == VT_SHORT || bt == VT_BYTE) {
1950 #ifndef TCC_ARM_VFP
1951 uint32_t dsize = 0;
1952 #endif
1953 r=intr(gv(RC_INT));
1954 #ifdef TCC_ARM_VFP
1955 r2=vfpr(vtop->r=get_reg(RC_FLOAT));
1956 o(0xEE000A10|(r<<12)|(r2<<16)); /* fmsr */
1957 r2|=r2<<12;
1958 if(!(vtop->type.t & VT_UNSIGNED))
1959 r2|=0x80; /* fuitoX -> fsituX */
1960 o(0xEEB80A40|r2|T2CPR(t)); /* fYitoX*/
1961 #else
1962 r2=fpr(vtop->r=get_reg(RC_FLOAT));
1963 if((t & VT_BTYPE) != VT_FLOAT)
1964 dsize=0x80; /* flts -> fltd */
1965 o(0xEE000110|dsize|(r2<<16)|(r<<12)); /* flts */
1966 if((vtop->type.t & (VT_UNSIGNED|VT_BTYPE)) == (VT_UNSIGNED|VT_INT)) {
1967 uint32_t off = 0;
1968 o(0xE3500000|(r<<12)); /* cmp */
1969 r=fpr(get_reg(RC_FLOAT));
1970 if(last_itod_magic) {
1971 off=ind+8-last_itod_magic;
1972 off/=4;
1973 if(off>255)
1974 off=0;
1976 o(0xBD1F0100|(r<<12)|off); /* ldflts */
1977 if(!off) {
1978 o(0xEA000000); /* b */
1979 last_itod_magic=ind;
1980 o(0x4F800000); /* 4294967296.0f */
1982 o(0xBE000100|dsize|(r2<<16)|(r2<<12)|r); /* adflt */
1984 #endif
1985 return;
1986 } else if(bt == VT_LLONG) {
1987 int func;
1988 CType *func_type = 0;
1989 if((t & VT_BTYPE) == VT_FLOAT) {
1990 func_type = &func_float_type;
1991 if(vtop->type.t & VT_UNSIGNED)
1992 func=TOK___floatundisf;
1993 else
1994 func=TOK___floatdisf;
1995 #if LDOUBLE_SIZE != 8
1996 } else if((t & VT_BTYPE) == VT_LDOUBLE) {
1997 func_type = &func_ldouble_type;
1998 if(vtop->type.t & VT_UNSIGNED)
1999 func=TOK___floatundixf;
2000 else
2001 func=TOK___floatdixf;
2002 } else if((t & VT_BTYPE) == VT_DOUBLE) {
2003 #else
2004 } else if((t & VT_BTYPE) == VT_DOUBLE || (t & VT_BTYPE) == VT_LDOUBLE) {
2005 #endif
2006 func_type = &func_double_type;
2007 if(vtop->type.t & VT_UNSIGNED)
2008 func=TOK___floatundidf;
2009 else
2010 func=TOK___floatdidf;
2012 if(func_type) {
2013 vpush_global_sym(func_type, func);
2014 vswap();
2015 gfunc_call(1);
2016 vpushi(0);
2017 vtop->r=TREG_F0;
2018 return;
2021 tcc_error("unimplemented gen_cvt_itof %x!",vtop->type.t);
2024 /* convert fp to int 't' type */
2025 void gen_cvt_ftoi(int t)
2027 uint32_t r, r2;
2028 int u, func = 0;
2029 u=t&VT_UNSIGNED;
2030 t&=VT_BTYPE;
2031 r2=vtop->type.t & VT_BTYPE;
2032 if(t==VT_INT) {
2033 #ifdef TCC_ARM_VFP
2034 r=vfpr(gv(RC_FLOAT));
2035 u=u?0:0x10000;
2036 o(0xEEBC0AC0|(r<<12)|r|T2CPR(r2)|u); /* ftoXizY */
2037 r2=intr(vtop->r=get_reg(RC_INT));
2038 o(0xEE100A10|(r<<16)|(r2<<12));
2039 return;
2040 #else
2041 if(u) {
2042 if(r2 == VT_FLOAT)
2043 func=TOK___fixunssfsi;
2044 #if LDOUBLE_SIZE != 8
2045 else if(r2 == VT_LDOUBLE)
2046 func=TOK___fixunsxfsi;
2047 else if(r2 == VT_DOUBLE)
2048 #else
2049 else if(r2 == VT_LDOUBLE || r2 == VT_DOUBLE)
2050 #endif
2051 func=TOK___fixunsdfsi;
2052 } else {
2053 r=fpr(gv(RC_FLOAT));
2054 r2=intr(vtop->r=get_reg(RC_INT));
2055 o(0xEE100170|(r2<<12)|r);
2056 return;
2058 #endif
2059 } else if(t == VT_LLONG) { // unsigned handled in gen_cvt_ftoi1
2060 if(r2 == VT_FLOAT)
2061 func=TOK___fixsfdi;
2062 #if LDOUBLE_SIZE != 8
2063 else if(r2 == VT_LDOUBLE)
2064 func=TOK___fixxfdi;
2065 else if(r2 == VT_DOUBLE)
2066 #else
2067 else if(r2 == VT_LDOUBLE || r2 == VT_DOUBLE)
2068 #endif
2069 func=TOK___fixdfdi;
2071 if(func) {
2072 vpush_global_sym(&func_old_type, func);
2073 vswap();
2074 gfunc_call(1);
2075 vpushi(0);
2076 if(t == VT_LLONG)
2077 vtop->r2 = REG_LRET;
2078 vtop->r = REG_IRET;
2079 return;
2081 tcc_error("unimplemented gen_cvt_ftoi!");
2084 /* convert from one floating point type to another */
2085 void gen_cvt_ftof(int t)
2087 #ifdef TCC_ARM_VFP
2088 if(((vtop->type.t & VT_BTYPE) == VT_FLOAT) != ((t & VT_BTYPE) == VT_FLOAT)) {
2089 uint32_t r = vfpr(gv(RC_FLOAT));
2090 o(0xEEB70AC0|(r<<12)|r|T2CPR(vtop->type.t));
2092 #else
2093 /* all we have to do on i386 and FPA ARM is to put the float in a register */
2094 gv(RC_FLOAT);
2095 #endif
2098 /* computed goto support */
2099 void ggoto(void)
2101 gcall_or_jmp(1);
2102 vtop--;
2105 /* Save the stack pointer onto the stack and return the location of its address */
2106 ST_FUNC void gen_vla_sp_save(int addr) {
2107 tcc_error("variable length arrays unsupported for this target");
2110 /* Restore the SP from a location on the stack */
2111 ST_FUNC void gen_vla_sp_restore(int addr) {
2112 tcc_error("variable length arrays unsupported for this target");
2115 /* Subtract from the stack pointer, and push the resulting value onto the stack */
2116 ST_FUNC void gen_vla_alloc(CType *type, int align) {
2117 tcc_error("variable length arrays unsupported for this target");
2120 /* end of ARM code generator */
2121 /*************************************************************/
2122 #endif
2123 /*************************************************************/