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
;
832 vpushi(0), nb_args
++;
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
; 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];
929 int is_long
= (vtop
[-i
].type
.t
& VT_BTYPE
) == VT_LLONG
;
932 ncrn
= (ncrn
+ 1) & -2;
938 plan
[argno
++][0]=ncrn
++;
940 plan
[argno
-1][1]=ncrn
++;
947 if(args_size
& (align
-1)) {
949 vtop
->type
.t
= VT_VOID
; /* padding */
956 args_size
+= (size
+ 3) & -4;
961 args_size
= keep
= 0;
962 for(i
= 0;i
< nb_args
; i
++) {
964 if ((vtop
->type
.t
& VT_BTYPE
) == VT_STRUCT
) {
965 size
= type_size(&vtop
->type
, &align
);
966 /* align to stack align size */
967 size
= (size
+ 3) & -4;
968 /* allocate the necessary size on stack */
970 /* generate structure store */
972 o(0xE1A0000D|(intr(r
)<<12));
973 vset(&vtop
->type
, r
| VT_LVAL
, 0);
978 } else if (is_float(vtop
->type
.t
)) {
979 #ifdef TCC_ARM_HARDFLOAT
980 if (!variadic
&& --vfp_argno
<16 && vfp_plan
[vfp_argno
]!=-1) {
981 plan2
[keep
++]=vfp_plan
[vfp_argno
];
986 r
=vfpr(gv(RC_FLOAT
))<<12;
988 if ((vtop
->type
.t
& VT_BTYPE
) != VT_FLOAT
)
991 r
|=0x101; /* fstms -> fstmd */
995 r
=fpr(gv(RC_FLOAT
))<<12;
996 if ((vtop
->type
.t
& VT_BTYPE
) == VT_FLOAT
)
998 else if ((vtop
->type
.t
& VT_BTYPE
) == VT_DOUBLE
)
1001 size
= LDOUBLE_SIZE
;
1008 o(0xED2D0100|r
|(size
>>2));
1014 /* simple type (currently always same size) */
1015 /* XXX: implicit cast ? */
1017 if ((vtop
->type
.t
& VT_BTYPE
) == VT_LLONG
) {
1020 if(--argno
<4 && plan
[argno
][1]!=-1)
1026 o(0xE52D0004|(intr(r
)<<12)); /* str r,[sp,#-4]! */
1036 if(--argno
<4 && plan
[argno
][0]!=-1)
1039 if(vtop
->type
.t
== VT_VOID
) {
1041 o(0xE24DD004); /* sub sp,sp,#4 */
1047 o(0xE52D0004|(intr(r
)<<12)); /* str r,[sp,#-4]! */
1057 for(i
= 0; i
< keep
; i
++) {
1059 gv(regmask(plan2
[i
]));
1060 #ifdef TCC_ARM_HARDFLOAT
1061 /* arg is in s(2d+1): plan2[i]<plan2[i+1] => alignment occured (ex f,d,f) */
1062 if (i
< keep
- 1 && is_float(vtop
->type
.t
) && (plan2
[i
] <= plan2
[i
+ 1])) {
1063 o(0xEEF00A40|(vfpr(plan2
[i
])<<12)|vfpr(plan2
[i
]));
1067 save_regs(keep
); /* save used temporary registers */
1073 todo
&=((1<<ncrn
)-1);
1085 args_size
-=nb_regs
*4;
1091 if(vfp_todo
&(1<<i
)) {
1092 o(0xED9D0A00|(i
&1)<<22|(i
>>1)<<12|nb_fregs
);
1094 /* There might be 2 floats in a double VFP reg but that doesn't seem
1097 vtop
->r
=TREG_F0
+i
/2;
1102 gadd_sp(nb_fregs
*4);
1103 args_size
-=nb_fregs
*4;
1111 if((vtop
->type
.ref
->type
.t
& VT_BTYPE
) == VT_STRUCT
1112 && type_size(&vtop
->type
.ref
->type
, &align
) <= 4)
1114 store(REG_IRET
,vtop
-keep
);
1118 #ifdef TCC_ARM_HARDFLOAT
1119 else if(variadic
&& is_float(vtop
->type
.ref
->type
.t
)) {
1121 else if(is_float(vtop
->type
.ref
->type
.t
)) {
1123 if((vtop
->type
.ref
->type
.t
& VT_BTYPE
) == VT_FLOAT
) {
1124 o(0xEE000A10); /* fmsr s0,r0 */
1126 o(0xEE000B10); /* fmdlr d0,r0 */
1127 o(0xEE201B10); /* fmdhr d0,r1 */
1136 /* generate function prolog of type 't' */
1137 void gfunc_prolog(CType
*func_type
)
1140 int n
,nf
,size
,align
, variadic
, struct_ret
= 0;
1141 #ifdef TCC_ARM_HARDFLOAT
1142 struct avail_regs avregs
= AVAIL_REGS_INITIALIZER
;
1145 sym
= func_type
->ref
;
1146 func_vt
= sym
->type
;
1149 variadic
= (func_type
->ref
->c
== FUNC_ELLIPSIS
);
1150 if((func_vt
.t
& VT_BTYPE
) == VT_STRUCT
1151 && type_size(&func_vt
,&align
) > 4)
1156 for(sym2
=sym
->next
;sym2
&& (n
<4 || nf
<16);sym2
=sym2
->next
) {
1157 size
= type_size(&sym2
->type
, &align
);
1158 #ifdef TCC_ARM_HARDFLOAT
1159 if (!variadic
&& (is_float(sym2
->type
.t
)
1160 || is_float_hgen_aggr(&sym2
->type
))) {
1161 int tmpnf
= assign_fpreg(&avregs
, align
, size
) + 1;
1162 nf
= (tmpnf
> nf
) ? tmpnf
: nf
;
1166 n
+= (size
+ 3) / 4;
1170 o(0xE1A0C00D); /* mov ip,sp */
1179 o(0xE92D0000|((1<<n
)-1)); /* save r0-r4 on stack if needed */
1184 nf
=(nf
+1)&-2; /* nf => HARDFLOAT => EABI */
1185 o(0xED2D0A00|nf
); /* save s0-s15 on stack if needed */
1187 o(0xE92D5800); /* save fp, ip, lr */
1188 o(0xE28DB00C); /* add fp, sp, #12 */
1189 func_sub_sp_offset
= ind
;
1190 o(0xE1A00000); /* nop, leave space for stack adjustment in epilogue */
1192 int addr
, pn
= struct_ret
, sn
= 0; /* pn=core, sn=stack */
1194 #ifdef TCC_ARM_HARDFLOAT
1195 avregs
= AVAIL_REGS_INITIALIZER
;
1197 while ((sym
= sym
->next
)) {
1200 size
= type_size(type
, &align
);
1201 size
= (size
+ 3) >> 2;
1202 #ifdef TCC_ARM_HARDFLOAT
1203 if (!variadic
&& (is_float(sym
->type
.t
)
1204 || is_float_hgen_aggr(&sym
->type
))) {
1205 int fpn
= assign_fpreg(&avregs
, align
, size
<< 2);
1214 pn
= (pn
+ (align
-1)/4) & -(align
/4);
1216 addr
= (nf
+ pn
) * 4;
1221 #ifdef TCC_ARM_HARDFLOAT
1225 sn
= (sn
+ (align
-1)/4) & -(align
/4);
1227 addr
= (n
+ nf
+ sn
) * 4;
1230 sym_push(sym
->v
& ~SYM_FIELD
, type
, VT_LOCAL
| lvalue_type(type
->t
), addr
);
1238 /* generate function epilog */
1239 void gfunc_epilog(void)
1244 /* Useless but harmless copy of the float result into main register(s) in case
1245 of variadic function in the hardfloat variant */
1246 if(is_float(func_vt
.t
)) {
1247 if((func_vt
.t
& VT_BTYPE
) == VT_FLOAT
)
1248 o(0xEE100A10); /* fmrs r0, s0 */
1250 o(0xEE100B10); /* fmrdl r0, d0 */
1251 o(0xEE301B10); /* fmrdh r1, d0 */
1255 o(0xE91BA800); /* restore fp, sp, pc */
1256 diff
= (-loc
+ 3) & -4;
1259 diff
= (diff
+ 7) & -8;
1262 x
=stuff_const(0xE24BD000, diff
); /* sub sp,fp,# */
1264 *(uint32_t *)(cur_text_section
->data
+ func_sub_sp_offset
) = x
;
1268 o(0xE59FC004); /* ldr ip,[pc+4] */
1269 o(0xE04BD00C); /* sub sp,fp,ip */
1270 o(0xE1A0F00E); /* mov pc,lr */
1272 *(uint32_t *)(cur_text_section
->data
+ func_sub_sp_offset
) = 0xE1000000|encbranch(func_sub_sp_offset
,addr
,1);
1277 /* generate a jump to a label */
1282 o(0xE0000000|encbranch(r
,t
,1));
1286 /* generate a jump to a fixed address */
1287 void gjmp_addr(int a
)
1292 /* generate a test. set 'inv' to invert test. Stack entry is popped */
1293 int gtst(int inv
, int t
)
1297 v
= vtop
->r
& VT_VALMASK
;
1300 op
=mapcc(inv
?negcc(vtop
->c
.i
):vtop
->c
.i
);
1301 op
|=encbranch(r
,t
,1);
1304 } else if (v
== VT_JMP
|| v
== VT_JMPI
) {
1305 if ((v
& 1) == inv
) {
1314 p
= decbranch(lp
=p
);
1316 x
= (uint32_t *)(cur_text_section
->data
+ lp
);
1318 *x
|= encbranch(lp
,t
,1);
1327 if (is_float(vtop
->type
.t
)) {
1330 o(0xEEB50A40|(vfpr(r
)<<12)|T2CPR(vtop
->type
.t
)); /* fcmpzX */
1331 o(0xEEF1FA10); /* fmstat */
1333 o(0xEE90F118|(fpr(r
)<<16));
1337 return gtst(inv
, t
);
1338 } else if ((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1339 /* constant jmp optimization */
1340 if ((vtop
->c
.i
!= 0) != inv
)
1344 o(0xE3300000|(intr(v
)<<16));
1347 return gtst(inv
, t
);
1354 /* generate an integer binary operation */
1355 void gen_opi(int op
)
1358 uint32_t opc
= 0, r
, fr
;
1359 unsigned short retreg
= REG_IRET
;
1367 case TOK_ADDC1
: /* add with carry generation */
1375 case TOK_SUBC1
: /* sub with carry generation */
1379 case TOK_ADDC2
: /* add with carry use */
1383 case TOK_SUBC2
: /* sub with carry use */
1400 gv2(RC_INT
, RC_INT
);
1404 o(0xE0000090|(intr(r
)<<16)|(intr(r
)<<8)|intr(fr
));
1429 func
=TOK___aeabi_idivmod
;
1438 func
=TOK___aeabi_uidivmod
;
1446 gv2(RC_INT
, RC_INT
);
1447 r
=intr(vtop
[-1].r2
=get_reg(RC_INT
));
1449 vtop
[-1].r
=get_reg_ex(RC_INT
,regmask(c
));
1451 o(0xE0800090|(r
<<16)|(intr(vtop
->r
)<<12)|(intr(c
)<<8)|intr(vtop
[1].r
));
1460 if((vtop
[-1].r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1461 if(opc
== 4 || opc
== 5 || opc
== 0xc) {
1463 opc
|=2; // sub -> rsb
1466 if ((vtop
->r
& VT_VALMASK
) == VT_CMP
||
1467 (vtop
->r
& (VT_VALMASK
& ~1)) == VT_JMP
)
1472 opc
=0xE0000000|(opc
<<20)|(c
<<16);
1473 if((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1475 x
=stuff_const(opc
|0x2000000,vtop
->c
.i
);
1477 r
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,regmask(vtop
[-1].r
)));
1482 fr
=intr(gv(RC_INT
));
1483 r
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,two2mask(vtop
->r
,vtop
[-1].r
)));
1487 if (op
>= TOK_ULT
&& op
<= TOK_GT
) {
1493 opc
=0xE1A00000|(opc
<<5);
1494 if ((vtop
->r
& VT_VALMASK
) == VT_CMP
||
1495 (vtop
->r
& (VT_VALMASK
& ~1)) == VT_JMP
)
1501 if ((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1502 fr
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,regmask(vtop
[-1].r
)));
1503 c
= vtop
->c
.i
& 0x1f;
1504 o(opc
|(c
<<7)|(fr
<<12));
1506 fr
=intr(gv(RC_INT
));
1507 c
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,two2mask(vtop
->r
,vtop
[-1].r
)));
1508 o(opc
|(c
<<12)|(fr
<<8)|0x10);
1513 vpush_global_sym(&func_old_type
, func
);
1520 tcc_error("gen_opi %i unimplemented!",op
);
1525 static int is_zero(int i
)
1527 if((vtop
[i
].r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) != VT_CONST
)
1529 if (vtop
[i
].type
.t
== VT_FLOAT
)
1530 return (vtop
[i
].c
.f
== 0.f
);
1531 else if (vtop
[i
].type
.t
== VT_DOUBLE
)
1532 return (vtop
[i
].c
.d
== 0.0);
1533 return (vtop
[i
].c
.ld
== 0.l
);
1536 /* generate a floating point operation 'v = t1 op t2' instruction. The
1537 * two operands are guaranted to have the same floating point type */
1538 void gen_opf(int op
)
1542 x
=0xEE000A00|T2CPR(vtop
->type
.t
);
1560 x
|=0x810000; /* fsubX -> fnegX */
1573 if(op
< TOK_ULT
|| op
> TOK_GT
) {
1574 tcc_error("unknown fp op %x!",op
);
1580 case TOK_LT
: op
=TOK_GT
; break;
1581 case TOK_GE
: op
=TOK_ULE
; break;
1582 case TOK_LE
: op
=TOK_GE
; break;
1583 case TOK_GT
: op
=TOK_ULT
; break;
1586 x
|=0xB40040; /* fcmpX */
1587 if(op
!=TOK_EQ
&& op
!=TOK_NE
)
1588 x
|=0x80; /* fcmpX -> fcmpeX */
1591 o(x
|0x10000|(vfpr(gv(RC_FLOAT
))<<12)); /* fcmp(e)X -> fcmp(e)zX */
1593 x
|=vfpr(gv(RC_FLOAT
));
1595 o(x
|(vfpr(gv(RC_FLOAT
))<<12));
1598 o(0xEEF1FA10); /* fmstat */
1601 case TOK_LE
: op
=TOK_ULE
; break;
1602 case TOK_LT
: op
=TOK_ULT
; break;
1603 case TOK_UGE
: op
=TOK_GE
; break;
1604 case TOK_UGT
: op
=TOK_GT
; break;
1621 vtop
->r
=get_reg_ex(RC_FLOAT
,r
);
1624 o(x
|(vfpr(vtop
->r
)<<12));
1628 static uint32_t is_fconst()
1632 if((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) != VT_CONST
)
1634 if (vtop
->type
.t
== VT_FLOAT
)
1636 else if (vtop
->type
.t
== VT_DOUBLE
)
1666 /* generate a floating point operation 'v = t1 op t2' instruction. The
1667 two operands are guaranted to have the same floating point type */
1668 void gen_opf(int op
)
1670 uint32_t x
, r
, r2
, c1
, c2
;
1671 //fputs("gen_opf\n",stderr);
1677 #if LDOUBLE_SIZE == 8
1678 if ((vtop
->type
.t
& VT_BTYPE
) != VT_FLOAT
)
1681 if ((vtop
->type
.t
& VT_BTYPE
) == VT_DOUBLE
)
1683 else if ((vtop
->type
.t
& VT_BTYPE
) == VT_LDOUBLE
)
1694 r
=fpr(gv(RC_FLOAT
));
1701 r2
=fpr(gv(RC_FLOAT
));
1710 r
=fpr(gv(RC_FLOAT
));
1712 } else if(c1
&& c1
<=0xf) {
1715 r
=fpr(gv(RC_FLOAT
));
1720 r
=fpr(gv(RC_FLOAT
));
1722 r2
=fpr(gv(RC_FLOAT
));
1731 r
=fpr(gv(RC_FLOAT
));
1736 r2
=fpr(gv(RC_FLOAT
));
1744 r
=fpr(gv(RC_FLOAT
));
1746 } else if(c1
&& c1
<=0xf) {
1749 r
=fpr(gv(RC_FLOAT
));
1754 r
=fpr(gv(RC_FLOAT
));
1756 r2
=fpr(gv(RC_FLOAT
));
1760 if(op
>= TOK_ULT
&& op
<= TOK_GT
) {
1761 x
|=0xd0f110; // cmfe
1762 /* bug (intention?) in Linux FPU emulator
1763 doesn't set carry if equal */
1769 tcc_error("unsigned comparision on floats?");
1775 op
=TOK_ULE
; /* correct in unordered case only if AC bit in FPSR set */
1779 x
&=~0x400000; // cmfe -> cmf
1801 r
=fpr(gv(RC_FLOAT
));
1808 r2
=fpr(gv(RC_FLOAT
));
1810 vtop
[-1].r
= VT_CMP
;
1813 tcc_error("unknown fp op %x!",op
);
1817 if(vtop
[-1].r
== VT_CMP
)
1823 vtop
[-1].r
=get_reg_ex(RC_FLOAT
,two2mask(vtop
[-1].r
,c1
));
1827 o(x
|(r
<<16)|(c1
<<12)|r2
);
1831 /* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
1832 and 'long long' cases. */
1833 ST_FUNC
void gen_cvt_itof1(int t
)
1837 bt
=vtop
->type
.t
& VT_BTYPE
;
1838 if(bt
== VT_INT
|| bt
== VT_SHORT
|| bt
== VT_BYTE
) {
1844 r2
=vfpr(vtop
->r
=get_reg(RC_FLOAT
));
1845 o(0xEE000A10|(r
<<12)|(r2
<<16)); /* fmsr */
1847 if(!(vtop
->type
.t
& VT_UNSIGNED
))
1848 r2
|=0x80; /* fuitoX -> fsituX */
1849 o(0xEEB80A40|r2
|T2CPR(t
)); /* fYitoX*/
1851 r2
=fpr(vtop
->r
=get_reg(RC_FLOAT
));
1852 if((t
& VT_BTYPE
) != VT_FLOAT
)
1853 dsize
=0x80; /* flts -> fltd */
1854 o(0xEE000110|dsize
|(r2
<<16)|(r
<<12)); /* flts */
1855 if((vtop
->type
.t
& (VT_UNSIGNED
|VT_BTYPE
)) == (VT_UNSIGNED
|VT_INT
)) {
1857 o(0xE3500000|(r
<<12)); /* cmp */
1858 r
=fpr(get_reg(RC_FLOAT
));
1859 if(last_itod_magic
) {
1860 off
=ind
+8-last_itod_magic
;
1865 o(0xBD1F0100|(r
<<12)|off
); /* ldflts */
1867 o(0xEA000000); /* b */
1868 last_itod_magic
=ind
;
1869 o(0x4F800000); /* 4294967296.0f */
1871 o(0xBE000100|dsize
|(r2
<<16)|(r2
<<12)|r
); /* adflt */
1875 } else if(bt
== VT_LLONG
) {
1877 CType
*func_type
= 0;
1878 if((t
& VT_BTYPE
) == VT_FLOAT
) {
1879 func_type
= &func_float_type
;
1880 if(vtop
->type
.t
& VT_UNSIGNED
)
1881 func
=TOK___floatundisf
;
1883 func
=TOK___floatdisf
;
1884 #if LDOUBLE_SIZE != 8
1885 } else if((t
& VT_BTYPE
) == VT_LDOUBLE
) {
1886 func_type
= &func_ldouble_type
;
1887 if(vtop
->type
.t
& VT_UNSIGNED
)
1888 func
=TOK___floatundixf
;
1890 func
=TOK___floatdixf
;
1891 } else if((t
& VT_BTYPE
) == VT_DOUBLE
) {
1893 } else if((t
& VT_BTYPE
) == VT_DOUBLE
|| (t
& VT_BTYPE
) == VT_LDOUBLE
) {
1895 func_type
= &func_double_type
;
1896 if(vtop
->type
.t
& VT_UNSIGNED
)
1897 func
=TOK___floatundidf
;
1899 func
=TOK___floatdidf
;
1902 vpush_global_sym(func_type
, func
);
1910 tcc_error("unimplemented gen_cvt_itof %x!",vtop
->type
.t
);
1913 /* convert fp to int 't' type */
1914 void gen_cvt_ftoi(int t
)
1920 r2
=vtop
->type
.t
& VT_BTYPE
;
1923 r
=vfpr(gv(RC_FLOAT
));
1925 o(0xEEBC0A40|(r
<<12)|r
|T2CPR(r2
)); /* ftoXiY */
1926 r2
=intr(vtop
->r
=get_reg(RC_INT
));
1927 o(0xEE100A10|(r
<<16)|(r2
<<12));
1932 func
=TOK___fixunssfsi
;
1933 #if LDOUBLE_SIZE != 8
1934 else if(r2
== VT_LDOUBLE
)
1935 func
=TOK___fixunsxfsi
;
1936 else if(r2
== VT_DOUBLE
)
1938 else if(r2
== VT_LDOUBLE
|| r2
== VT_DOUBLE
)
1940 func
=TOK___fixunsdfsi
;
1942 r
=fpr(gv(RC_FLOAT
));
1943 r2
=intr(vtop
->r
=get_reg(RC_INT
));
1944 o(0xEE100170|(r2
<<12)|r
);
1948 } else if(t
== VT_LLONG
) { // unsigned handled in gen_cvt_ftoi1
1951 #if LDOUBLE_SIZE != 8
1952 else if(r2
== VT_LDOUBLE
)
1954 else if(r2
== VT_DOUBLE
)
1956 else if(r2
== VT_LDOUBLE
|| r2
== VT_DOUBLE
)
1961 vpush_global_sym(&func_old_type
, func
);
1966 vtop
->r2
= REG_LRET
;
1970 tcc_error("unimplemented gen_cvt_ftoi!");
1973 /* convert from one floating point type to another */
1974 void gen_cvt_ftof(int t
)
1977 if(((vtop
->type
.t
& VT_BTYPE
) == VT_FLOAT
) != ((t
& VT_BTYPE
) == VT_FLOAT
)) {
1978 uint32_t r
= vfpr(gv(RC_FLOAT
));
1979 o(0xEEB70AC0|(r
<<12)|r
|T2CPR(vtop
->type
.t
));
1982 /* all we have to do on i386 and FPA ARM is to put the float in a register */
1987 /* computed goto support */
1994 /* end of ARM code generator */
1995 /*************************************************************/
1997 /*************************************************************/