2 * ARMv4 code generator for TCC
4 * Copyright (c) 2003 Daniel Glöckner
6 * Based on i386-gen.c by Fabrice Bellard
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #ifdef TARGET_DEFS_ONLY
26 #ifndef TCC_ARM_VFP // Avoid useless warning
31 /* number of available registers */
38 /* a register can belong to several classes. The classes must be
39 sorted from more general to more precise (see gv2() code which does
40 assumptions on it). */
41 #define RC_INT 0x0001 /* generic integer register */
42 #define RC_FLOAT 0x0002 /* generic float register */
58 #define RC_IRET RC_R0 /* function return: integer register */
59 #define RC_LRET RC_R1 /* function return: second integer register */
60 #define RC_FRET RC_F0 /* function return: float register */
62 /* pretty names for the registers */
82 #define T2CPR(t) (((t) & VT_BTYPE) != VT_FLOAT ? 0x100 : 0)
85 /* return registers for function */
86 #define REG_IRET TREG_R0 /* single word int return register */
87 #define REG_LRET TREG_R1 /* second word return register (for long long) */
88 #define REG_FRET TREG_F0 /* float return register */
91 #define TOK___divdi3 TOK___aeabi_ldivmod
92 #define TOK___moddi3 TOK___aeabi_ldivmod
93 #define TOK___udivdi3 TOK___aeabi_uldivmod
94 #define TOK___umoddi3 TOK___aeabi_uldivmod
97 /* defined if function parameters must be evaluated in reverse order */
98 #define INVERT_FUNC_PARAMS
100 /* defined if structures are passed as pointers. Otherwise structures
101 are directly pushed on stack. */
102 //#define FUNC_STRUCT_PARAM_AS_PTR
104 #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
105 ST_DATA CType float_type
, double_type
, func_float_type
, func_double_type
;
106 #define func_ldouble_type func_double_type
108 #define func_float_type func_old_type
109 #define func_double_type func_old_type
110 #define func_ldouble_type func_old_type
113 /* pointer size, in bytes */
116 /* long double size and alignment, in bytes */
118 #define LDOUBLE_SIZE 8
122 #define LDOUBLE_SIZE 8
126 #define LDOUBLE_ALIGN 8
128 #define LDOUBLE_ALIGN 4
131 /* maximum alignment (for aligned attribute support) */
134 #define CHAR_IS_UNSIGNED
136 /******************************************************/
139 #define EM_TCC_TARGET EM_ARM
141 /* relocation type for 32 bit data relocation */
142 #define R_DATA_32 R_ARM_ABS32
143 #define R_DATA_PTR R_ARM_ABS32
144 #define R_JMP_SLOT R_ARM_JUMP_SLOT
145 #define R_COPY R_ARM_COPY
147 #define ELF_START_ADDR 0x00008000
148 #define ELF_PAGE_SIZE 0x1000
150 /******************************************************/
151 #else /* ! TARGET_DEFS_ONLY */
152 /******************************************************/
155 ST_DATA
const int reg_classes
[NB_REGS
] = {
156 /* r0 */ RC_INT
| RC_R0
,
157 /* r1 */ RC_INT
| RC_R1
,
158 /* r2 */ RC_INT
| RC_R2
,
159 /* r3 */ RC_INT
| RC_R3
,
160 /* r12 */ RC_INT
| RC_R12
,
161 /* f0 */ RC_FLOAT
| RC_F0
,
162 /* f1 */ RC_FLOAT
| RC_F1
,
163 /* f2 */ RC_FLOAT
| RC_F2
,
164 /* f3 */ RC_FLOAT
| RC_F3
,
166 /* d4/s8 */ RC_FLOAT
| RC_F4
,
167 /* d5/s10 */ RC_FLOAT
| RC_F5
,
168 /* d6/s12 */ RC_FLOAT
| RC_F6
,
169 /* d7/s14 */ RC_FLOAT
| RC_F7
,
173 /* keep in sync with line 104 above */
174 #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
175 ST_DATA CType float_type
, double_type
, func_float_type
, func_double_type
;
178 static int func_sub_sp_offset
, last_itod_magic
;
181 static int two2mask(int a
,int b
) {
182 return (reg_classes
[a
]|reg_classes
[b
])&~(RC_INT
|RC_FLOAT
);
185 static int regmask(int r
) {
186 return reg_classes
[r
]&~(RC_INT
|RC_FLOAT
);
189 /******************************************************/
193 /* this is a good place to start adding big-endian support*/
197 if (!cur_text_section
)
198 tcc_error("compiler error! This happens f.ex. if the compiler\n"
199 "can't evaluate constant expressions outside of a function.");
200 if (ind1
> cur_text_section
->data_allocated
)
201 section_realloc(cur_text_section
, ind1
);
202 cur_text_section
->data
[ind
++] = i
&255;
204 cur_text_section
->data
[ind
++] = i
&255;
206 cur_text_section
->data
[ind
++] = i
&255;
208 cur_text_section
->data
[ind
++] = i
;
211 static uint32_t stuff_const(uint32_t op
, uint32_t c
)
214 uint32_t nc
= 0, negop
= 0;
224 case 0x1A00000: //mov
225 case 0x1E00000: //mvn
232 return (op
&0xF010F000)|((op
>>16)&0xF)|0x1E00000;
236 return (op
&0xF010F000)|((op
>>16)&0xF)|0x1A00000;
237 case 0x1C00000: //bic
242 case 0x1800000: //orr
244 return (op
&0xFFF0FFFF)|0x1E00000;
250 if(c
<256) /* catch undefined <<32 */
253 m
=(0xff>>i
)|(0xff<<(32-i
));
255 return op
|(i
<<7)|(c
<<i
)|(c
>>(32-i
));
265 void stuff_const_harder(uint32_t op
, uint32_t v
) {
271 uint32_t a
[16], nv
, no
, o2
, n2
;
274 o2
=(op
&0xfff0ffff)|((op
&0xf000)<<4);;
276 a
[i
]=(a
[i
-1]>>2)|(a
[i
-1]<<30);
278 for(j
=i
<4?i
+12:15;j
>=i
+4;j
--)
279 if((v
&(a
[i
]|a
[j
]))==v
) {
280 o(stuff_const(op
,v
&a
[i
]));
281 o(stuff_const(o2
,v
&a
[j
]));
288 for(j
=i
<4?i
+12:15;j
>=i
+4;j
--)
289 if((nv
&(a
[i
]|a
[j
]))==nv
) {
290 o(stuff_const(no
,nv
&a
[i
]));
291 o(stuff_const(n2
,nv
&a
[j
]));
296 for(k
=i
<4?i
+12:15;k
>=j
+4;k
--)
297 if((v
&(a
[i
]|a
[j
]|a
[k
]))==v
) {
298 o(stuff_const(op
,v
&a
[i
]));
299 o(stuff_const(o2
,v
&a
[j
]));
300 o(stuff_const(o2
,v
&a
[k
]));
307 for(k
=i
<4?i
+12:15;k
>=j
+4;k
--)
308 if((nv
&(a
[i
]|a
[j
]|a
[k
]))==nv
) {
309 o(stuff_const(no
,nv
&a
[i
]));
310 o(stuff_const(n2
,nv
&a
[j
]));
311 o(stuff_const(n2
,nv
&a
[k
]));
314 o(stuff_const(op
,v
&a
[0]));
315 o(stuff_const(o2
,v
&a
[4]));
316 o(stuff_const(o2
,v
&a
[8]));
317 o(stuff_const(o2
,v
&a
[12]));
321 ST_FUNC
uint32_t encbranch(int pos
, int addr
, int fail
)
325 if(addr
>=0x1000000 || addr
<-0x1000000) {
327 tcc_error("FIXME: function bigger than 32MB");
330 return 0x0A000000|(addr
&0xffffff);
333 int decbranch(int pos
)
336 x
=*(uint32_t *)(cur_text_section
->data
+ pos
);
343 /* output a symbol and patch all calls to it */
344 void gsym_addr(int t
, int a
)
349 x
=(uint32_t *)(cur_text_section
->data
+ t
);
352 *x
=0xE1A00000; // nop
355 *x
|= encbranch(lt
,a
,1);
366 static uint32_t vfpr(int r
)
368 if(r
<TREG_F0
|| r
>TREG_F7
)
369 tcc_error("compiler error! register %i is no vfp register",r
);
373 static uint32_t fpr(int r
)
375 if(r
<TREG_F0
|| r
>TREG_F3
)
376 tcc_error("compiler error! register %i is no fpa register",r
);
381 static uint32_t intr(int r
)
385 if((r
<0 || r
>4) && r
!=14)
386 tcc_error("compiler error! register %i is no int register",r
);
390 static void calcaddr(uint32_t *base
, int *off
, int *sgn
, int maxoff
, unsigned shift
)
392 if(*off
>maxoff
|| *off
&((1<<shift
)-1)) {
399 y
=stuff_const(x
,*off
&~maxoff
);
405 y
=stuff_const(x
,(*off
+maxoff
)&~maxoff
);
409 *off
=((*off
+maxoff
)&~maxoff
)-*off
;
412 stuff_const_harder(x
,*off
&~maxoff
);
417 static uint32_t mapcc(int cc
)
422 return 0x30000000; /* CC/LO */
424 return 0x20000000; /* CS/HS */
426 return 0x00000000; /* EQ */
428 return 0x10000000; /* NE */
430 return 0x90000000; /* LS */
432 return 0x80000000; /* HI */
434 return 0x40000000; /* MI */
436 return 0x50000000; /* PL */
438 return 0xB0000000; /* LT */
440 return 0xA0000000; /* GE */
442 return 0xD0000000; /* LE */
444 return 0xC0000000; /* GT */
446 tcc_error("unexpected condition code");
447 return 0xE0000000; /* AL */
450 static int negcc(int cc
)
479 tcc_error("unexpected condition code");
483 /* load 'r' from value 'sv' */
484 void load(int r
, SValue
*sv
)
486 int v
, ft
, fc
, fr
, sign
;
503 uint32_t base
= 0xB; // fp
506 v1
.r
= VT_LOCAL
| VT_LVAL
;
508 load(base
=14 /* lr */, &v1
);
511 } else if(v
== VT_CONST
) {
519 } else if(v
< VT_CONST
) {
526 calcaddr(&base
,&fc
,&sign
,1020,2);
528 op
=0xED100A00; /* flds */
531 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
532 op
|=0x100; /* flds -> fldd */
533 o(op
|(vfpr(r
)<<12)|(fc
>>2)|(base
<<16));
538 #if LDOUBLE_SIZE == 8
539 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
542 if ((ft
& VT_BTYPE
) == VT_DOUBLE
)
544 else if ((ft
& VT_BTYPE
) == VT_LDOUBLE
)
547 o(op
|(fpr(r
)<<12)|(fc
>>2)|(base
<<16));
549 } else if((ft
& (VT_BTYPE
|VT_UNSIGNED
)) == VT_BYTE
550 || (ft
& VT_BTYPE
) == VT_SHORT
) {
551 calcaddr(&base
,&fc
,&sign
,255,0);
553 if ((ft
& VT_BTYPE
) == VT_SHORT
)
555 if ((ft
& VT_UNSIGNED
) == 0)
559 o(op
|(intr(r
)<<12)|(base
<<16)|((fc
&0xf0)<<4)|(fc
&0xf));
561 calcaddr(&base
,&fc
,&sign
,4095,0);
565 if ((ft
& VT_BTYPE
) == VT_BYTE
)
567 o(op
|(intr(r
)<<12)|fc
|(base
<<16));
573 op
=stuff_const(0xE3A00000|(intr(r
)<<12),sv
->c
.ul
);
574 if (fr
& VT_SYM
|| !op
) {
575 o(0xE59F0000|(intr(r
)<<12));
578 greloc(cur_text_section
, sv
->sym
, ind
, R_ARM_ABS32
);
583 } else if (v
== VT_LOCAL
) {
584 op
=stuff_const(0xE28B0000|(intr(r
)<<12),sv
->c
.ul
);
585 if (fr
& VT_SYM
|| !op
) {
586 o(0xE59F0000|(intr(r
)<<12));
588 if(fr
& VT_SYM
) // needed ?
589 greloc(cur_text_section
, sv
->sym
, ind
, R_ARM_ABS32
);
591 o(0xE08B0000|(intr(r
)<<12)|intr(r
));
595 } else if(v
== VT_CMP
) {
596 o(mapcc(sv
->c
.ul
)|0x3A00001|(intr(r
)<<12));
597 o(mapcc(negcc(sv
->c
.ul
))|0x3A00000|(intr(r
)<<12));
599 } else if (v
== VT_JMP
|| v
== VT_JMPI
) {
602 o(0xE3A00000|(intr(r
)<<12)|t
);
605 o(0xE3A00000|(intr(r
)<<12)|(t
^1));
607 } else if (v
< VT_CONST
) {
610 o(0xEEB00A40|(vfpr(r
)<<12)|vfpr(v
)|T2CPR(ft
)); /* fcpyX */
612 o(0xEE008180|(fpr(r
)<<12)|fpr(v
));
615 o(0xE1A00000|(intr(r
)<<12)|intr(v
));
619 tcc_error("load unimplemented!");
622 /* store register 'r' in lvalue 'v' */
623 void store(int r
, SValue
*sv
)
626 int v
, ft
, fc
, fr
, sign
;
641 if (fr
& VT_LVAL
|| fr
== VT_LOCAL
) {
647 } else if(v
== VT_CONST
) {
658 calcaddr(&base
,&fc
,&sign
,1020,2);
660 op
=0xED000A00; /* fsts */
663 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
664 op
|=0x100; /* fsts -> fstd */
665 o(op
|(vfpr(r
)<<12)|(fc
>>2)|(base
<<16));
670 #if LDOUBLE_SIZE == 8
671 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
674 if ((ft
& VT_BTYPE
) == VT_DOUBLE
)
676 if ((ft
& VT_BTYPE
) == VT_LDOUBLE
)
679 o(op
|(fpr(r
)<<12)|(fc
>>2)|(base
<<16));
682 } else if((ft
& VT_BTYPE
) == VT_SHORT
) {
683 calcaddr(&base
,&fc
,&sign
,255,0);
687 o(op
|(intr(r
)<<12)|(base
<<16)|((fc
&0xf0)<<4)|(fc
&0xf));
689 calcaddr(&base
,&fc
,&sign
,4095,0);
693 if ((ft
& VT_BTYPE
) == VT_BYTE
)
695 o(op
|(intr(r
)<<12)|fc
|(base
<<16));
700 tcc_error("store unimplemented");
703 static void gadd_sp(int val
)
705 stuff_const_harder(0xE28DD000,val
);
708 /* 'is_jmp' is '1' if it is a jump */
709 static void gcall_or_jmp(int is_jmp
)
712 if ((vtop
->r
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
) {
715 x
=encbranch(ind
,ind
+vtop
->c
.ul
,0);
717 if (vtop
->r
& VT_SYM
) {
718 /* relocation case */
719 greloc(cur_text_section
, vtop
->sym
, ind
, R_ARM_PC24
);
721 put_elf_reloc(symtab_section
, cur_text_section
, ind
, R_ARM_PC24
, 0);
722 o(x
|(is_jmp
?0xE0000000:0xE1000000));
725 o(0xE28FE004); // add lr,pc,#4
726 o(0xE51FF004); // ldr pc,[pc,#-4]
727 if (vtop
->r
& VT_SYM
)
728 greloc(cur_text_section
, vtop
->sym
, ind
, R_ARM_ABS32
);
732 /* otherwise, indirect call */
735 o(0xE1A0E00F); // mov lr,pc
736 o(0xE1A0F000|intr(r
)); // mov pc,r
740 #ifdef TCC_ARM_HARDFLOAT
741 static int is_float_hgen_aggr(CType
*type
)
743 if ((type
->t
& VT_BTYPE
) == VT_STRUCT
) {
745 int btype
, nb_fields
= 0;
748 btype
= ref
->type
.t
& VT_BTYPE
;
749 if (btype
== VT_FLOAT
|| btype
== VT_DOUBLE
) {
750 for(; ref
&& btype
== (ref
->type
.t
& VT_BTYPE
); ref
= ref
->next
, nb_fields
++);
751 return !ref
&& nb_fields
<= 4;
758 /* worst case: f(float, double, 3 float struct, double, 3 float struct, double) */
759 signed char avail
[3];
765 #define AVAIL_REGS_INITIALIZER (struct avail_regs) { { 0, 0, 0}, 0, 0, 0 }
767 /* Assign a register for a CPRC param with correct size and alignment
768 * size and align are in bytes, as returned by type_size */
769 int assign_fpreg(struct avail_regs
*avregs
, int align
, int size
)
773 if (avregs
->first_free_reg
== -1)
775 if (align
>> 3) { // alignment needed (base type: double)
776 first_reg
= avregs
->first_free_reg
;
778 avregs
->avail
[avregs
->last_hole
++] = first_reg
++;
780 if (size
== 4 && avregs
->first_hole
!= avregs
->last_hole
)
781 return avregs
->avail
[avregs
->first_hole
++];
783 first_reg
= avregs
->first_free_reg
;
785 if (first_reg
+ size
/ 4 <= 16) {
786 avregs
->first_free_reg
= first_reg
+ size
/ 4;
789 avregs
->first_free_reg
= -1;
794 /* Generate function call. The function address is pushed first, then
795 all the parameters in call order. This functions pops all the
796 parameters and the function address. */
797 void gfunc_call(int nb_args
)
799 int size
, align
, r
, args_size
, i
, ncrn
, ncprn
, argno
, vfp_argno
;
800 signed char plan
[4][2]={{-1,-1},{-1,-1},{-1,-1},{-1,-1}};
801 SValue
*before_stack
= NULL
; /* SValue before first on stack argument */
802 SValue
*before_vfpreg_hfa
= NULL
; /* SValue before first in VFP reg hfa argument */
803 #ifdef TCC_ARM_HARDFLOAT
804 struct avail_regs avregs
= AVAIL_REGS_INITIALIZER
;
805 signed char vfp_plan
[16];
809 int plan2
[4]={0,0,0,0};
814 #ifdef TCC_ARM_HARDFLOAT
815 memset(vfp_plan
, -1, sizeof(vfp_plan
));
816 memset(plan2
, 0, sizeof(plan2
));
817 variadic
= (vtop
[-nb_args
].type
.ref
->c
== FUNC_ELLIPSIS
);
819 r
= vtop
->r
& VT_VALMASK
;
820 if (r
== VT_CMP
|| (r
& ~1) == VT_JMP
)
823 if((vtop
[-nb_args
].type
.ref
->type
.t
& VT_BTYPE
) == VT_STRUCT
824 && type_size(&vtop
[-nb_args
].type
.ref
->type
, &align
) <= 4) {
827 vtop
[-nb_args
]=vtop
[-nb_args
+1];
828 vtop
[-nb_args
+1]=tmp
;
833 vtop
->type
.t
= VT_LLONG
;
836 ncrn
= ncprn
= argno
= vfp_argno
= 0;
837 /* Assign argument to registers and stack with alignment.
838 If, considering alignment constraints, enough registers of the correct type
839 (core or VFP) are free for the current argument, assign them to it, else
840 allocate on stack with correct alignment. Whenever a structure is allocated
841 in registers or on stack, it is always put on the stack at this stage. The
842 stack is divided in 3 zones. The zone are, from low addresses to high
843 addresses: structures to be loaded in core registers, structures to be
844 loaded in VFP registers, argument allocated to stack. SValue's representing
845 structures in the first zone are moved just after the SValue pointed by
846 before_vfpreg_hfa. SValue's representing structures in the second zone are
847 moved just after the SValue pointer by before_stack. */
848 for(i
= nb_args
+ 1 ; i
-- ;) {
849 int j
, assigned_vfpreg
= 0;
850 size
= type_size(&vtop
[-i
].type
, &align
);
851 switch(vtop
[-i
].type
.t
& VT_BTYPE
) {
856 #ifdef TCC_ARM_HARDFLOAT
858 int hfa
= 0; /* Homogeneous float aggregate */
860 if (is_float(vtop
[-i
].type
.t
)
861 || (hfa
= is_float_hgen_aggr(&vtop
[-i
].type
))) {
864 assigned_vfpreg
= assign_fpreg(&avregs
, align
, size
);
865 end_reg
= assigned_vfpreg
+ (size
- 1) / 4;
866 if (assigned_vfpreg
>= 0) {
867 vfp_plan
[vfp_argno
++]=TREG_F0
+ assigned_vfpreg
/2;
869 /* before_stack can only have been set because all core registers
870 are assigned, so no need to care about before_vfpreg_hfa if
871 before_stack is set */
873 vrote(&vtop
[-i
], &vtop
[-i
] - before_stack
);
875 } else if (!before_vfpreg_hfa
)
876 before_vfpreg_hfa
= &vtop
[-i
-1];
877 for (j
= assigned_vfpreg
; j
<= end_reg
; j
++)
884 /* No need to update before_stack as no more hfa can be allocated in
886 if (!before_vfpreg_hfa
)
887 before_vfpreg_hfa
= &vtop
[-i
-1];
893 ncrn
= (ncrn
+ (align
-1)/4) & -(align
/4);
894 size
= (size
+ 3) & -4;
895 if (ncrn
+ size
/4 <= 4 || (ncrn
< 4 && assigned_vfpreg
!= -1)) {
896 /* Either there is HFA in VFP registers, or there is arguments on stack,
897 it cannot be both. Hence either before_stack already points after
898 the slot where the vtop[-i] SValue is moved, or before_stack will not
900 if (before_vfpreg_hfa
) {
901 vrote(&vtop
[-i
], &vtop
[-i
] - before_vfpreg_hfa
);
904 for (j
= ncrn
; j
< 4 && j
< ncrn
+ size
/ 4; j
++)
908 args_size
= (ncrn
- 4) * 4;
910 before_stack
= &vtop
[-i
-1];
915 /* No need to set before_vfpreg_hfa if not set since there will no
916 longer be any structure assigned to core registers */
918 before_stack
= &vtop
[-i
-1];
927 int is_long
= (vtop
[-i
].type
.t
& VT_BTYPE
) == VT_LLONG
;
930 ncrn
= (ncrn
+ 1) & -2;
936 plan
[argno
++][0]=ncrn
++;
938 plan
[argno
-1][1]=ncrn
++;
945 if(args_size
& (align
-1)) {
947 vtop
->type
.t
= VT_VOID
; /* padding */
954 args_size
+= (size
+ 3) & -4;
957 args_size
= keep
= 0;
958 for(i
= 0;i
< nb_args
; i
++) {
960 if ((vtop
->type
.t
& VT_BTYPE
) == VT_STRUCT
) {
961 size
= type_size(&vtop
->type
, &align
);
962 /* align to stack align size */
963 size
= (size
+ 3) & -4;
964 /* allocate the necessary size on stack */
966 /* generate structure store */
968 o(0xE1A0000D|(intr(r
)<<12));
969 vset(&vtop
->type
, r
| VT_LVAL
, 0);
974 } else if (is_float(vtop
->type
.t
)) {
975 #ifdef TCC_ARM_HARDFLOAT
976 if (!variadic
&& --vfp_argno
<16 && vfp_plan
[vfp_argno
]!=-1) {
977 plan2
[keep
++]=vfp_plan
[vfp_argno
];
982 r
=vfpr(gv(RC_FLOAT
))<<12;
984 if ((vtop
->type
.t
& VT_BTYPE
) != VT_FLOAT
)
987 r
|=0x101; /* fstms -> fstmd */
991 r
=fpr(gv(RC_FLOAT
))<<12;
992 if ((vtop
->type
.t
& VT_BTYPE
) == VT_FLOAT
)
994 else if ((vtop
->type
.t
& VT_BTYPE
) == VT_DOUBLE
)
1004 o(0xED2D0100|r
|(size
>>2));
1010 /* simple type (currently always same size) */
1011 /* XXX: implicit cast ? */
1013 if ((vtop
->type
.t
& VT_BTYPE
) == VT_LLONG
) {
1016 if(--argno
<4 && plan
[argno
][1]!=-1)
1022 o(0xE52D0004|(intr(r
)<<12)); /* str r,[sp,#-4]! */
1032 if(--argno
<4 && plan
[argno
][0]!=-1)
1035 if(vtop
->type
.t
== VT_VOID
) {
1037 o(0xE24DD004); /* sub sp,sp,#4 */
1043 o(0xE52D0004|(intr(r
)<<12)); /* str r,[sp,#-4]! */
1053 for(i
= 0; i
< keep
; i
++) {
1055 gv(regmask(plan2
[i
]));
1056 #ifdef TCC_ARM_HARDFLOAT
1057 /* arg is in s(2d+1): plan2[i]<plan2[i+1] => alignment occured (ex f,d,f) */
1058 if (i
< keep
- 1 && is_float(vtop
->type
.t
) && (plan2
[i
] <= plan2
[i
+ 1])) {
1059 o(0xEEF00A40|(vfpr(plan2
[i
])<<12)|vfpr(plan2
[i
]));
1063 save_regs(keep
); /* save used temporary registers */
1069 todo
&=((1<<ncrn
)-1);
1081 args_size
-=nb_regs
*4;
1087 if(vfp_todo
&(1<<i
)) {
1088 o(0xED9D0A00|(i
&1)<<22|(i
>>1)<<12|nb_fregs
);
1090 /* There might be 2 floats in a double VFP reg but that doesn't seem
1093 vtop
->r
=TREG_F0
+i
/2;
1098 gadd_sp(nb_fregs
*4);
1099 args_size
-=nb_fregs
*4;
1107 if((vtop
->type
.ref
->type
.t
& VT_BTYPE
) == VT_STRUCT
1108 && type_size(&vtop
->type
.ref
->type
, &align
) <= 4)
1110 store(REG_IRET
,vtop
-keep
);
1114 #ifdef TCC_ARM_HARDFLOAT
1115 else if(variadic
&& is_float(vtop
->type
.ref
->type
.t
)) {
1117 else if(is_float(vtop
->type
.ref
->type
.t
)) {
1119 if((vtop
->type
.ref
->type
.t
& VT_BTYPE
) == VT_FLOAT
) {
1120 o(0xEE000A10); /* fmsr s0,r0 */
1122 o(0xEE000B10); /* fmdlr d0,r0 */
1123 o(0xEE201B10); /* fmdhr d0,r1 */
1132 /* generate function prolog of type 't' */
1133 void gfunc_prolog(CType
*func_type
)
1136 int n
,nf
,size
,align
, variadic
, struct_ret
= 0;
1137 #ifdef TCC_ARM_HARDFLOAT
1138 struct avail_regs avregs
= AVAIL_REGS_INITIALIZER
;
1141 sym
= func_type
->ref
;
1142 func_vt
= sym
->type
;
1145 variadic
= (func_type
->ref
->c
== FUNC_ELLIPSIS
);
1146 if((func_vt
.t
& VT_BTYPE
) == VT_STRUCT
1147 && type_size(&func_vt
,&align
) > 4)
1152 for(sym2
=sym
->next
;sym2
&& (n
<4 || nf
<16);sym2
=sym2
->next
) {
1153 size
= type_size(&sym2
->type
, &align
);
1154 #ifdef TCC_ARM_HARDFLOAT
1155 if (!variadic
&& (is_float(sym2
->type
.t
)
1156 || is_float_hgen_aggr(&sym2
->type
))) {
1157 int tmpnf
= assign_fpreg(&avregs
, align
, size
) + 1;
1158 nf
= (tmpnf
> nf
) ? tmpnf
: nf
;
1162 n
+= (size
+ 3) / 4;
1166 o(0xE1A0C00D); /* mov ip,sp */
1175 o(0xE92D0000|((1<<n
)-1)); /* save r0-r4 on stack if needed */
1180 nf
=(nf
+1)&-2; /* nf => HARDFLOAT => EABI */
1181 o(0xED2D0A00|nf
); /* save s0-s15 on stack if needed */
1183 o(0xE92D5800); /* save fp, ip, lr */
1184 o(0xE28DB00C); /* add fp, sp, #12 */
1185 func_sub_sp_offset
= ind
;
1186 o(0xE1A00000); /* nop, leave space for stack adjustment in epilogue */
1188 int addr
, pn
= struct_ret
, sn
= 0; /* pn=core, sn=stack */
1190 #ifdef TCC_ARM_HARDFLOAT
1191 avregs
= AVAIL_REGS_INITIALIZER
;
1193 while ((sym
= sym
->next
)) {
1196 size
= type_size(type
, &align
);
1197 size
= (size
+ 3) >> 2;
1198 #ifdef TCC_ARM_HARDFLOAT
1199 if (!variadic
&& (is_float(sym
->type
.t
)
1200 || is_float_hgen_aggr(&sym
->type
))) {
1201 int fpn
= assign_fpreg(&avregs
, align
, size
<< 2);
1210 pn
= (pn
+ (align
-1)/4) & -(align
/4);
1212 addr
= (nf
+ pn
) * 4;
1217 #ifdef TCC_ARM_HARDFLOAT
1221 sn
= (sn
+ (align
-1)/4) & -(align
/4);
1223 addr
= (n
+ nf
+ sn
) * 4;
1226 sym_push(sym
->v
& ~SYM_FIELD
, type
, VT_LOCAL
| lvalue_type(type
->t
), addr
);
1234 /* generate function epilog */
1235 void gfunc_epilog(void)
1240 /* Useless but harmless copy of the float result into main register(s) in case
1241 of variadic function in the hardfloat variant */
1242 if(is_float(func_vt
.t
)) {
1243 if((func_vt
.t
& VT_BTYPE
) == VT_FLOAT
)
1244 o(0xEE100A10); /* fmrs r0, s0 */
1246 o(0xEE100B10); /* fmrdl r0, d0 */
1247 o(0xEE301B10); /* fmrdh r1, d0 */
1251 o(0xE91BA800); /* restore fp, sp, pc */
1252 diff
= (-loc
+ 3) & -4;
1255 diff
= (diff
+ 7) & -8;
1258 x
=stuff_const(0xE24BD000, diff
); /* sub sp,fp,# */
1260 *(uint32_t *)(cur_text_section
->data
+ func_sub_sp_offset
) = x
;
1264 o(0xE59FC004); /* ldr ip,[pc+4] */
1265 o(0xE04BD00C); /* sub sp,fp,ip */
1266 o(0xE1A0F00E); /* mov pc,lr */
1268 *(uint32_t *)(cur_text_section
->data
+ func_sub_sp_offset
) = 0xE1000000|encbranch(func_sub_sp_offset
,addr
,1);
1273 /* generate a jump to a label */
1278 o(0xE0000000|encbranch(r
,t
,1));
1282 /* generate a jump to a fixed address */
1283 void gjmp_addr(int a
)
1288 /* generate a test. set 'inv' to invert test. Stack entry is popped */
1289 int gtst(int inv
, int t
)
1293 v
= vtop
->r
& VT_VALMASK
;
1296 op
=mapcc(inv
?negcc(vtop
->c
.i
):vtop
->c
.i
);
1297 op
|=encbranch(r
,t
,1);
1300 } else if (v
== VT_JMP
|| v
== VT_JMPI
) {
1301 if ((v
& 1) == inv
) {
1310 p
= decbranch(lp
=p
);
1312 x
= (uint32_t *)(cur_text_section
->data
+ lp
);
1314 *x
|= encbranch(lp
,t
,1);
1323 if (is_float(vtop
->type
.t
)) {
1326 o(0xEEB50A40|(vfpr(r
)<<12)|T2CPR(vtop
->type
.t
)); /* fcmpzX */
1327 o(0xEEF1FA10); /* fmstat */
1329 o(0xEE90F118|(fpr(r
)<<16));
1333 return gtst(inv
, t
);
1334 } else if ((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1335 /* constant jmp optimization */
1336 if ((vtop
->c
.i
!= 0) != inv
)
1340 o(0xE3300000|(intr(v
)<<16));
1343 return gtst(inv
, t
);
1350 /* generate an integer binary operation */
1351 void gen_opi(int op
)
1354 uint32_t opc
= 0, r
, fr
;
1355 unsigned short retreg
= REG_IRET
;
1363 case TOK_ADDC1
: /* add with carry generation */
1371 case TOK_SUBC1
: /* sub with carry generation */
1375 case TOK_ADDC2
: /* add with carry use */
1379 case TOK_SUBC2
: /* sub with carry use */
1396 gv2(RC_INT
, RC_INT
);
1400 o(0xE0000090|(intr(r
)<<16)|(intr(r
)<<8)|intr(fr
));
1425 func
=TOK___aeabi_idivmod
;
1434 func
=TOK___aeabi_uidivmod
;
1442 gv2(RC_INT
, RC_INT
);
1443 r
=intr(vtop
[-1].r2
=get_reg(RC_INT
));
1445 vtop
[-1].r
=get_reg_ex(RC_INT
,regmask(c
));
1447 o(0xE0800090|(r
<<16)|(intr(vtop
->r
)<<12)|(intr(c
)<<8)|intr(vtop
[1].r
));
1456 if((vtop
[-1].r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1457 if(opc
== 4 || opc
== 5 || opc
== 0xc) {
1459 opc
|=2; // sub -> rsb
1462 if ((vtop
->r
& VT_VALMASK
) == VT_CMP
||
1463 (vtop
->r
& (VT_VALMASK
& ~1)) == VT_JMP
)
1468 opc
=0xE0000000|(opc
<<20)|(c
<<16);
1469 if((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1471 x
=stuff_const(opc
|0x2000000,vtop
->c
.i
);
1473 r
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,regmask(vtop
[-1].r
)));
1478 fr
=intr(gv(RC_INT
));
1479 r
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,two2mask(vtop
->r
,vtop
[-1].r
)));
1483 if (op
>= TOK_ULT
&& op
<= TOK_GT
) {
1489 opc
=0xE1A00000|(opc
<<5);
1490 if ((vtop
->r
& VT_VALMASK
) == VT_CMP
||
1491 (vtop
->r
& (VT_VALMASK
& ~1)) == VT_JMP
)
1497 if ((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1498 fr
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,regmask(vtop
[-1].r
)));
1499 c
= vtop
->c
.i
& 0x1f;
1500 o(opc
|(c
<<7)|(fr
<<12));
1502 fr
=intr(gv(RC_INT
));
1503 c
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,two2mask(vtop
->r
,vtop
[-1].r
)));
1504 o(opc
|(c
<<12)|(fr
<<8)|0x10);
1509 vpush_global_sym(&func_old_type
, func
);
1516 tcc_error("gen_opi %i unimplemented!",op
);
1521 static int is_zero(int i
)
1523 if((vtop
[i
].r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) != VT_CONST
)
1525 if (vtop
[i
].type
.t
== VT_FLOAT
)
1526 return (vtop
[i
].c
.f
== 0.f
);
1527 else if (vtop
[i
].type
.t
== VT_DOUBLE
)
1528 return (vtop
[i
].c
.d
== 0.0);
1529 return (vtop
[i
].c
.ld
== 0.l
);
1532 /* generate a floating point operation 'v = t1 op t2' instruction. The
1533 * two operands are guaranted to have the same floating point type */
1534 void gen_opf(int op
)
1538 x
=0xEE000A00|T2CPR(vtop
->type
.t
);
1556 x
|=0x810000; /* fsubX -> fnegX */
1569 if(op
< TOK_ULT
&& op
> TOK_GT
) {
1570 tcc_error("unknown fp op %x!",op
);
1576 case TOK_LT
: op
=TOK_GT
; break;
1577 case TOK_GE
: op
=TOK_ULE
; break;
1578 case TOK_LE
: op
=TOK_GE
; break;
1579 case TOK_GT
: op
=TOK_ULT
; break;
1582 x
|=0xB40040; /* fcmpX */
1583 if(op
!=TOK_EQ
&& op
!=TOK_NE
)
1584 x
|=0x80; /* fcmpX -> fcmpeX */
1587 o(x
|0x10000|(vfpr(gv(RC_FLOAT
))<<12)); /* fcmp(e)X -> fcmp(e)zX */
1589 x
|=vfpr(gv(RC_FLOAT
));
1591 o(x
|(vfpr(gv(RC_FLOAT
))<<12));
1594 o(0xEEF1FA10); /* fmstat */
1597 case TOK_LE
: op
=TOK_ULE
; break;
1598 case TOK_LT
: op
=TOK_ULT
; break;
1599 case TOK_UGE
: op
=TOK_GE
; break;
1600 case TOK_UGT
: op
=TOK_GT
; break;
1617 vtop
->r
=get_reg_ex(RC_FLOAT
,r
);
1620 o(x
|(vfpr(vtop
->r
)<<12));
1624 static uint32_t is_fconst()
1628 if((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) != VT_CONST
)
1630 if (vtop
->type
.t
== VT_FLOAT
)
1632 else if (vtop
->type
.t
== VT_DOUBLE
)
1662 /* generate a floating point operation 'v = t1 op t2' instruction. The
1663 two operands are guaranted to have the same floating point type */
1664 void gen_opf(int op
)
1666 uint32_t x
, r
, r2
, c1
, c2
;
1667 //fputs("gen_opf\n",stderr);
1673 #if LDOUBLE_SIZE == 8
1674 if ((vtop
->type
.t
& VT_BTYPE
) != VT_FLOAT
)
1677 if ((vtop
->type
.t
& VT_BTYPE
) == VT_DOUBLE
)
1679 else if ((vtop
->type
.t
& VT_BTYPE
) == VT_LDOUBLE
)
1690 r
=fpr(gv(RC_FLOAT
));
1697 r2
=fpr(gv(RC_FLOAT
));
1706 r
=fpr(gv(RC_FLOAT
));
1708 } else if(c1
&& c1
<=0xf) {
1711 r
=fpr(gv(RC_FLOAT
));
1716 r
=fpr(gv(RC_FLOAT
));
1718 r2
=fpr(gv(RC_FLOAT
));
1727 r
=fpr(gv(RC_FLOAT
));
1732 r2
=fpr(gv(RC_FLOAT
));
1740 r
=fpr(gv(RC_FLOAT
));
1742 } else if(c1
&& c1
<=0xf) {
1745 r
=fpr(gv(RC_FLOAT
));
1750 r
=fpr(gv(RC_FLOAT
));
1752 r2
=fpr(gv(RC_FLOAT
));
1756 if(op
>= TOK_ULT
&& op
<= TOK_GT
) {
1757 x
|=0xd0f110; // cmfe
1758 /* bug (intention?) in Linux FPU emulator
1759 doesn't set carry if equal */
1765 tcc_error("unsigned comparision on floats?");
1771 op
=TOK_ULE
; /* correct in unordered case only if AC bit in FPSR set */
1775 x
&=~0x400000; // cmfe -> cmf
1797 r
=fpr(gv(RC_FLOAT
));
1804 r2
=fpr(gv(RC_FLOAT
));
1806 vtop
[-1].r
= VT_CMP
;
1809 tcc_error("unknown fp op %x!",op
);
1813 if(vtop
[-1].r
== VT_CMP
)
1819 vtop
[-1].r
=get_reg_ex(RC_FLOAT
,two2mask(vtop
[-1].r
,c1
));
1823 o(x
|(r
<<16)|(c1
<<12)|r2
);
1827 /* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
1828 and 'long long' cases. */
1829 ST_FUNC
void gen_cvt_itof1(int t
)
1833 bt
=vtop
->type
.t
& VT_BTYPE
;
1834 if(bt
== VT_INT
|| bt
== VT_SHORT
|| bt
== VT_BYTE
) {
1840 r2
=vfpr(vtop
->r
=get_reg(RC_FLOAT
));
1841 o(0xEE000A10|(r
<<12)|(r2
<<16)); /* fmsr */
1843 if(!(vtop
->type
.t
& VT_UNSIGNED
))
1844 r2
|=0x80; /* fuitoX -> fsituX */
1845 o(0xEEB80A40|r2
|T2CPR(t
)); /* fYitoX*/
1847 r2
=fpr(vtop
->r
=get_reg(RC_FLOAT
));
1848 if((t
& VT_BTYPE
) != VT_FLOAT
)
1849 dsize
=0x80; /* flts -> fltd */
1850 o(0xEE000110|dsize
|(r2
<<16)|(r
<<12)); /* flts */
1851 if((vtop
->type
.t
& (VT_UNSIGNED
|VT_BTYPE
)) == (VT_UNSIGNED
|VT_INT
)) {
1853 o(0xE3500000|(r
<<12)); /* cmp */
1854 r
=fpr(get_reg(RC_FLOAT
));
1855 if(last_itod_magic
) {
1856 off
=ind
+8-last_itod_magic
;
1861 o(0xBD1F0100|(r
<<12)|off
); /* ldflts */
1863 o(0xEA000000); /* b */
1864 last_itod_magic
=ind
;
1865 o(0x4F800000); /* 4294967296.0f */
1867 o(0xBE000100|dsize
|(r2
<<16)|(r2
<<12)|r
); /* adflt */
1871 } else if(bt
== VT_LLONG
) {
1873 CType
*func_type
= 0;
1874 if((t
& VT_BTYPE
) == VT_FLOAT
) {
1875 func_type
= &func_float_type
;
1876 if(vtop
->type
.t
& VT_UNSIGNED
)
1877 func
=TOK___floatundisf
;
1879 func
=TOK___floatdisf
;
1880 #if LDOUBLE_SIZE != 8
1881 } else if((t
& VT_BTYPE
) == VT_LDOUBLE
) {
1882 func_type
= &func_ldouble_type
;
1883 if(vtop
->type
.t
& VT_UNSIGNED
)
1884 func
=TOK___floatundixf
;
1886 func
=TOK___floatdixf
;
1887 } else if((t
& VT_BTYPE
) == VT_DOUBLE
) {
1889 } else if((t
& VT_BTYPE
) == VT_DOUBLE
|| (t
& VT_BTYPE
) == VT_LDOUBLE
) {
1891 func_type
= &func_double_type
;
1892 if(vtop
->type
.t
& VT_UNSIGNED
)
1893 func
=TOK___floatundidf
;
1895 func
=TOK___floatdidf
;
1898 vpush_global_sym(func_type
, func
);
1906 tcc_error("unimplemented gen_cvt_itof %x!",vtop
->type
.t
);
1909 /* convert fp to int 't' type */
1910 void gen_cvt_ftoi(int t
)
1916 r2
=vtop
->type
.t
& VT_BTYPE
;
1919 r
=vfpr(gv(RC_FLOAT
));
1921 o(0xEEBC0A40|(r
<<12)|r
|T2CPR(r2
)); /* ftoXiY */
1922 r2
=intr(vtop
->r
=get_reg(RC_INT
));
1923 o(0xEE100A10|(r
<<16)|(r2
<<12));
1928 func
=TOK___fixunssfsi
;
1929 #if LDOUBLE_SIZE != 8
1930 else if(r2
== VT_LDOUBLE
)
1931 func
=TOK___fixunsxfsi
;
1932 else if(r2
== VT_DOUBLE
)
1934 else if(r2
== VT_LDOUBLE
|| r2
== VT_DOUBLE
)
1936 func
=TOK___fixunsdfsi
;
1938 r
=fpr(gv(RC_FLOAT
));
1939 r2
=intr(vtop
->r
=get_reg(RC_INT
));
1940 o(0xEE100170|(r2
<<12)|r
);
1944 } else if(t
== VT_LLONG
) { // unsigned handled in gen_cvt_ftoi1
1947 #if LDOUBLE_SIZE != 8
1948 else if(r2
== VT_LDOUBLE
)
1950 else if(r2
== VT_DOUBLE
)
1952 else if(r2
== VT_LDOUBLE
|| r2
== VT_DOUBLE
)
1957 vpush_global_sym(&func_old_type
, func
);
1962 vtop
->r2
= REG_LRET
;
1966 tcc_error("unimplemented gen_cvt_ftoi!");
1969 /* convert from one floating point type to another */
1970 void gen_cvt_ftof(int t
)
1973 if(((vtop
->type
.t
& VT_BTYPE
) == VT_FLOAT
) != ((t
& VT_BTYPE
) == VT_FLOAT
)) {
1974 uint32_t r
= vfpr(gv(RC_FLOAT
));
1975 o(0xEEB70AC0|(r
<<12)|r
|T2CPR(vtop
->type
.t
));
1978 /* all we have to do on i386 and FPA ARM is to put the float in a register */
1983 /* computed goto support */
1990 /* end of ARM code generator */
1991 /*************************************************************/
1993 /*************************************************************/