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
27 #ifndef TCC_ARM_VFP // Avoid useless warning
32 /* number of available registers */
39 /* a register can belong to several classes. The classes must be
40 sorted from more general to more precise (see gv2() code which does
41 assumptions on it). */
42 #define RC_INT 0x0001 /* generic integer register */
43 #define RC_FLOAT 0x0002 /* generic float register */
59 #define RC_IRET RC_R0 /* function return: integer register */
60 #define RC_LRET RC_R1 /* function return: second integer register */
61 #define RC_FRET RC_F0 /* function return: float register */
63 /* pretty names for the registers */
83 #define T2CPR(t) (((t) & VT_BTYPE) != VT_FLOAT ? 0x100 : 0)
86 /* return registers for function */
87 #define REG_IRET TREG_R0 /* single word int return register */
88 #define REG_LRET TREG_R1 /* second word return register (for long long) */
89 #define REG_FRET TREG_F0 /* float return register */
92 #define TOK___divdi3 TOK___aeabi_ldivmod
93 #define TOK___moddi3 TOK___aeabi_ldivmod
94 #define TOK___udivdi3 TOK___aeabi_uldivmod
95 #define TOK___umoddi3 TOK___aeabi_uldivmod
98 /* defined if function parameters must be evaluated in reverse order */
99 #define INVERT_FUNC_PARAMS
101 /* defined if structures are passed as pointers. Otherwise structures
102 are directly pushed on stack. */
103 //#define FUNC_STRUCT_PARAM_AS_PTR
105 #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
106 ST_DATA CType float_type
, double_type
, func_float_type
, func_double_type
;
107 #define func_ldouble_type func_double_type
109 #define func_float_type func_old_type
110 #define func_double_type func_old_type
111 #define func_ldouble_type func_old_type
114 /* pointer size, in bytes */
117 /* long double size and alignment, in bytes */
119 #define LDOUBLE_SIZE 8
123 #define LDOUBLE_SIZE 8
127 #define LDOUBLE_ALIGN 8
129 #define LDOUBLE_ALIGN 4
132 /* maximum alignment (for aligned attribute support) */
135 #define CHAR_IS_UNSIGNED
137 /******************************************************/
140 #define EM_TCC_TARGET EM_ARM
142 /* relocation type for 32 bit data relocation */
143 #define R_DATA_32 R_ARM_ABS32
144 #define R_DATA_PTR R_ARM_ABS32
145 #define R_JMP_SLOT R_ARM_JUMP_SLOT
146 #define R_COPY R_ARM_COPY
148 #define ELF_START_ADDR 0x00008000
149 #define ELF_PAGE_SIZE 0x1000
151 /******************************************************/
152 #else /* ! TARGET_DEFS_ONLY */
153 /******************************************************/
156 ST_DATA
const int reg_classes
[NB_REGS
] = {
157 /* r0 */ RC_INT
| RC_R0
,
158 /* r1 */ RC_INT
| RC_R1
,
159 /* r2 */ RC_INT
| RC_R2
,
160 /* r3 */ RC_INT
| RC_R3
,
161 /* r12 */ RC_INT
| RC_R12
,
162 /* f0 */ RC_FLOAT
| RC_F0
,
163 /* f1 */ RC_FLOAT
| RC_F1
,
164 /* f2 */ RC_FLOAT
| RC_F2
,
165 /* f3 */ RC_FLOAT
| RC_F3
,
167 /* d4/s8 */ RC_FLOAT
| RC_F4
,
168 /* d5/s10 */ RC_FLOAT
| RC_F5
,
169 /* d6/s12 */ RC_FLOAT
| RC_F6
,
170 /* d7/s14 */ RC_FLOAT
| RC_F7
,
174 /* keep in sync with line 104 above */
175 #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
176 ST_DATA CType float_type
, double_type
, func_float_type
, func_double_type
;
179 static int func_sub_sp_offset
, last_itod_magic
;
182 static int two2mask(int a
,int b
) {
183 return (reg_classes
[a
]|reg_classes
[b
])&~(RC_INT
|RC_FLOAT
);
186 static int regmask(int r
) {
187 return reg_classes
[r
]&~(RC_INT
|RC_FLOAT
);
190 /******************************************************/
194 /* this is a good place to start adding big-endian support*/
198 if (!cur_text_section
)
199 tcc_error("compiler error! This happens f.ex. if the compiler\n"
200 "can't evaluate constant expressions outside of a function.");
201 if (ind1
> cur_text_section
->data_allocated
)
202 section_realloc(cur_text_section
, ind1
);
203 cur_text_section
->data
[ind
++] = i
&255;
205 cur_text_section
->data
[ind
++] = i
&255;
207 cur_text_section
->data
[ind
++] = i
&255;
209 cur_text_section
->data
[ind
++] = i
;
212 static uint32_t stuff_const(uint32_t op
, uint32_t c
)
215 uint32_t nc
= 0, negop
= 0;
225 case 0x1A00000: //mov
226 case 0x1E00000: //mvn
233 return (op
&0xF010F000)|((op
>>16)&0xF)|0x1E00000;
237 return (op
&0xF010F000)|((op
>>16)&0xF)|0x1A00000;
238 case 0x1C00000: //bic
243 case 0x1800000: //orr
245 return (op
&0xFFF0FFFF)|0x1E00000;
251 if(c
<256) /* catch undefined <<32 */
254 m
=(0xff>>i
)|(0xff<<(32-i
));
256 return op
|(i
<<7)|(c
<<i
)|(c
>>(32-i
));
266 void stuff_const_harder(uint32_t op
, uint32_t v
) {
272 uint32_t a
[16], nv
, no
, o2
, n2
;
275 o2
=(op
&0xfff0ffff)|((op
&0xf000)<<4);;
277 a
[i
]=(a
[i
-1]>>2)|(a
[i
-1]<<30);
279 for(j
=i
<4?i
+12:15;j
>=i
+4;j
--)
280 if((v
&(a
[i
]|a
[j
]))==v
) {
281 o(stuff_const(op
,v
&a
[i
]));
282 o(stuff_const(o2
,v
&a
[j
]));
289 for(j
=i
<4?i
+12:15;j
>=i
+4;j
--)
290 if((nv
&(a
[i
]|a
[j
]))==nv
) {
291 o(stuff_const(no
,nv
&a
[i
]));
292 o(stuff_const(n2
,nv
&a
[j
]));
297 for(k
=i
<4?i
+12:15;k
>=j
+4;k
--)
298 if((v
&(a
[i
]|a
[j
]|a
[k
]))==v
) {
299 o(stuff_const(op
,v
&a
[i
]));
300 o(stuff_const(o2
,v
&a
[j
]));
301 o(stuff_const(o2
,v
&a
[k
]));
308 for(k
=i
<4?i
+12:15;k
>=j
+4;k
--)
309 if((nv
&(a
[i
]|a
[j
]|a
[k
]))==nv
) {
310 o(stuff_const(no
,nv
&a
[i
]));
311 o(stuff_const(n2
,nv
&a
[j
]));
312 o(stuff_const(n2
,nv
&a
[k
]));
315 o(stuff_const(op
,v
&a
[0]));
316 o(stuff_const(o2
,v
&a
[4]));
317 o(stuff_const(o2
,v
&a
[8]));
318 o(stuff_const(o2
,v
&a
[12]));
322 ST_FUNC
uint32_t encbranch(int pos
, int addr
, int fail
)
326 if(addr
>=0x1000000 || addr
<-0x1000000) {
328 tcc_error("FIXME: function bigger than 32MB");
331 return 0x0A000000|(addr
&0xffffff);
334 int decbranch(int pos
)
337 x
=*(uint32_t *)(cur_text_section
->data
+ pos
);
344 /* output a symbol and patch all calls to it */
345 void gsym_addr(int t
, int a
)
350 x
=(uint32_t *)(cur_text_section
->data
+ t
);
353 *x
=0xE1A00000; // nop
356 *x
|= encbranch(lt
,a
,1);
367 static uint32_t vfpr(int r
)
369 if(r
<TREG_F0
|| r
>TREG_F7
)
370 tcc_error("compiler error! register %i is no vfp register",r
);
374 static uint32_t fpr(int r
)
376 if(r
<TREG_F0
|| r
>TREG_F3
)
377 tcc_error("compiler error! register %i is no fpa register",r
);
382 static uint32_t intr(int r
)
386 if((r
<0 || r
>4) && r
!=14)
387 tcc_error("compiler error! register %i is no int register",r
);
391 static void calcaddr(uint32_t *base
, int *off
, int *sgn
, int maxoff
, unsigned shift
)
393 if(*off
>maxoff
|| *off
&((1<<shift
)-1)) {
400 y
=stuff_const(x
,*off
&~maxoff
);
406 y
=stuff_const(x
,(*off
+maxoff
)&~maxoff
);
410 *off
=((*off
+maxoff
)&~maxoff
)-*off
;
413 stuff_const_harder(x
,*off
&~maxoff
);
418 static uint32_t mapcc(int cc
)
423 return 0x30000000; /* CC/LO */
425 return 0x20000000; /* CS/HS */
427 return 0x00000000; /* EQ */
429 return 0x10000000; /* NE */
431 return 0x90000000; /* LS */
433 return 0x80000000; /* HI */
435 return 0x40000000; /* MI */
437 return 0x50000000; /* PL */
439 return 0xB0000000; /* LT */
441 return 0xA0000000; /* GE */
443 return 0xD0000000; /* LE */
445 return 0xC0000000; /* GT */
447 tcc_error("unexpected condition code");
448 return 0xE0000000; /* AL */
451 static int negcc(int cc
)
480 tcc_error("unexpected condition code");
484 /* load 'r' from value 'sv' */
485 void load(int r
, SValue
*sv
)
487 int v
, ft
, fc
, fr
, sign
;
504 uint32_t base
= 0xB; // fp
507 v1
.r
= VT_LOCAL
| VT_LVAL
;
509 load(base
=14 /* lr */, &v1
);
512 } else if(v
== VT_CONST
) {
520 } else if(v
< VT_CONST
) {
527 calcaddr(&base
,&fc
,&sign
,1020,2);
529 op
=0xED100A00; /* flds */
532 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
533 op
|=0x100; /* flds -> fldd */
534 o(op
|(vfpr(r
)<<12)|(fc
>>2)|(base
<<16));
539 #if LDOUBLE_SIZE == 8
540 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
543 if ((ft
& VT_BTYPE
) == VT_DOUBLE
)
545 else if ((ft
& VT_BTYPE
) == VT_LDOUBLE
)
548 o(op
|(fpr(r
)<<12)|(fc
>>2)|(base
<<16));
550 } else if((ft
& (VT_BTYPE
|VT_UNSIGNED
)) == VT_BYTE
551 || (ft
& VT_BTYPE
) == VT_SHORT
) {
552 calcaddr(&base
,&fc
,&sign
,255,0);
554 if ((ft
& VT_BTYPE
) == VT_SHORT
)
556 if ((ft
& VT_UNSIGNED
) == 0)
560 o(op
|(intr(r
)<<12)|(base
<<16)|((fc
&0xf0)<<4)|(fc
&0xf));
562 calcaddr(&base
,&fc
,&sign
,4095,0);
566 if ((ft
& VT_BTYPE
) == VT_BYTE
)
568 o(op
|(intr(r
)<<12)|fc
|(base
<<16));
574 op
=stuff_const(0xE3A00000|(intr(r
)<<12),sv
->c
.ul
);
575 if (fr
& VT_SYM
|| !op
) {
576 o(0xE59F0000|(intr(r
)<<12));
579 greloc(cur_text_section
, sv
->sym
, ind
, R_ARM_ABS32
);
584 } else if (v
== VT_LOCAL
) {
585 op
=stuff_const(0xE28B0000|(intr(r
)<<12),sv
->c
.ul
);
586 if (fr
& VT_SYM
|| !op
) {
587 o(0xE59F0000|(intr(r
)<<12));
589 if(fr
& VT_SYM
) // needed ?
590 greloc(cur_text_section
, sv
->sym
, ind
, R_ARM_ABS32
);
592 o(0xE08B0000|(intr(r
)<<12)|intr(r
));
596 } else if(v
== VT_CMP
) {
597 o(mapcc(sv
->c
.ul
)|0x3A00001|(intr(r
)<<12));
598 o(mapcc(negcc(sv
->c
.ul
))|0x3A00000|(intr(r
)<<12));
600 } else if (v
== VT_JMP
|| v
== VT_JMPI
) {
603 o(0xE3A00000|(intr(r
)<<12)|t
);
606 o(0xE3A00000|(intr(r
)<<12)|(t
^1));
608 } else if (v
< VT_CONST
) {
611 o(0xEEB00A40|(vfpr(r
)<<12)|vfpr(v
)|T2CPR(ft
)); /* fcpyX */
613 o(0xEE008180|(fpr(r
)<<12)|fpr(v
));
616 o(0xE1A00000|(intr(r
)<<12)|intr(v
));
620 tcc_error("load unimplemented!");
623 /* store register 'r' in lvalue 'v' */
624 void store(int r
, SValue
*sv
)
627 int v
, ft
, fc
, fr
, sign
;
642 if (fr
& VT_LVAL
|| fr
== VT_LOCAL
) {
648 } else if(v
== VT_CONST
) {
659 calcaddr(&base
,&fc
,&sign
,1020,2);
661 op
=0xED000A00; /* fsts */
664 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
665 op
|=0x100; /* fsts -> fstd */
666 o(op
|(vfpr(r
)<<12)|(fc
>>2)|(base
<<16));
671 #if LDOUBLE_SIZE == 8
672 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
675 if ((ft
& VT_BTYPE
) == VT_DOUBLE
)
677 if ((ft
& VT_BTYPE
) == VT_LDOUBLE
)
680 o(op
|(fpr(r
)<<12)|(fc
>>2)|(base
<<16));
683 } else if((ft
& VT_BTYPE
) == VT_SHORT
) {
684 calcaddr(&base
,&fc
,&sign
,255,0);
688 o(op
|(intr(r
)<<12)|(base
<<16)|((fc
&0xf0)<<4)|(fc
&0xf));
690 calcaddr(&base
,&fc
,&sign
,4095,0);
694 if ((ft
& VT_BTYPE
) == VT_BYTE
)
696 o(op
|(intr(r
)<<12)|fc
|(base
<<16));
701 tcc_error("store unimplemented");
704 static void gadd_sp(int val
)
706 stuff_const_harder(0xE28DD000,val
);
709 /* 'is_jmp' is '1' if it is a jump */
710 static void gcall_or_jmp(int is_jmp
)
713 if ((vtop
->r
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
) {
716 x
=encbranch(ind
,ind
+vtop
->c
.ul
,0);
718 if (vtop
->r
& VT_SYM
) {
719 /* relocation case */
720 greloc(cur_text_section
, vtop
->sym
, ind
, R_ARM_PC24
);
722 put_elf_reloc(symtab_section
, cur_text_section
, ind
, R_ARM_PC24
, 0);
723 o(x
|(is_jmp
?0xE0000000:0xE1000000));
726 o(0xE28FE004); // add lr,pc,#4
727 o(0xE51FF004); // ldr pc,[pc,#-4]
728 if (vtop
->r
& VT_SYM
)
729 greloc(cur_text_section
, vtop
->sym
, ind
, R_ARM_ABS32
);
733 /* otherwise, indirect call */
736 o(0xE1A0E00F); // mov lr,pc
737 o(0xE1A0F000|intr(r
)); // mov pc,r
741 #ifdef TCC_ARM_HARDFLOAT
742 static int is_float_hgen_aggr(CType
*type
)
744 if ((type
->t
& VT_BTYPE
) == VT_STRUCT
) {
746 int btype
, nb_fields
= 0;
749 btype
= ref
->type
.t
& VT_BTYPE
;
750 if (btype
== VT_FLOAT
|| btype
== VT_DOUBLE
) {
751 for(; ref
&& btype
== (ref
->type
.t
& VT_BTYPE
); ref
= ref
->next
, nb_fields
++);
752 return !ref
&& nb_fields
<= 4;
759 /* worst case: f(float, double, 3 float struct, double, 3 float struct, double) */
760 signed char avail
[3];
766 #define AVAIL_REGS_INITIALIZER (struct avail_regs) { { 0, 0, 0}, 0, 0, 0 }
768 /* Assign a register for a CPRC param with correct size and alignment
769 * size and align are in bytes, as returned by type_size */
770 int assign_fpreg(struct avail_regs
*avregs
, int align
, int size
)
774 if (avregs
->first_free_reg
== -1)
776 if (align
>> 3) { // alignment needed (base type: double)
777 first_reg
= avregs
->first_free_reg
;
779 avregs
->avail
[avregs
->last_hole
++] = first_reg
++;
781 if (size
== 4 && avregs
->first_hole
!= avregs
->last_hole
)
782 return avregs
->avail
[avregs
->first_hole
++];
784 first_reg
= avregs
->first_free_reg
;
786 if (first_reg
+ size
/ 4 <= 16) {
787 avregs
->first_free_reg
= first_reg
+ size
/ 4;
790 avregs
->first_free_reg
= -1;
795 /* Generate function call. The function address is pushed first, then
796 all the parameters in call order. This functions pops all the
797 parameters and the function address. */
798 void gfunc_call(int nb_args
)
800 int size
, align
, r
, args_size
, i
, ncrn
, ncprn
, argno
, vfp_argno
;
801 signed char plan
[4][2]={{-1,-1},{-1,-1},{-1,-1},{-1,-1}};
802 SValue
*before_stack
= NULL
; /* SValue before first on stack argument */
803 SValue
*before_vfpreg_hfa
= NULL
; /* SValue before first in VFP reg hfa argument */
804 #ifdef TCC_ARM_HARDFLOAT
805 struct avail_regs avregs
= AVAIL_REGS_INITIALIZER
;
806 signed char vfp_plan
[16];
810 int plan2
[4]={0,0,0,0};
815 #ifdef TCC_ARM_HARDFLOAT
816 memset(vfp_plan
, -1, sizeof(vfp_plan
));
817 memset(plan2
, 0, sizeof(plan2
));
818 variadic
= (vtop
[-nb_args
].type
.ref
->c
== FUNC_ELLIPSIS
);
820 r
= vtop
->r
& VT_VALMASK
;
821 if (r
== VT_CMP
|| (r
& ~1) == VT_JMP
)
824 if((vtop
[-nb_args
].type
.ref
->type
.t
& VT_BTYPE
) == VT_STRUCT
825 && type_size(&vtop
[-nb_args
].type
.ref
->type
, &align
) <= 4) {
828 vtop
[-nb_args
]=vtop
[-nb_args
+1];
829 vtop
[-nb_args
+1]=tmp
;
833 vpushi(0), nb_args
++;
834 vtop
->type
.t
= VT_LLONG
;
837 ncrn
= ncprn
= argno
= vfp_argno
= 0;
838 /* Assign argument to registers and stack with alignment.
839 If, considering alignment constraints, enough registers of the correct type
840 (core or VFP) are free for the current argument, assign them to it, else
841 allocate on stack with correct alignment. Whenever a structure is allocated
842 in registers or on stack, it is always put on the stack at this stage. The
843 stack is divided in 3 zones. The zone are, from low addresses to high
844 addresses: structures to be loaded in core registers, structures to be
845 loaded in VFP registers, argument allocated to stack. SValue's representing
846 structures in the first zone are moved just after the SValue pointed by
847 before_vfpreg_hfa. SValue's representing structures in the second zone are
848 moved just after the SValue pointer by before_stack. */
849 for(i
= nb_args
; i
-- ;) {
850 int j
, assigned_vfpreg
= 0;
851 size
= type_size(&vtop
[-i
].type
, &align
);
852 switch(vtop
[-i
].type
.t
& VT_BTYPE
) {
857 #ifdef TCC_ARM_HARDFLOAT
859 int hfa
= 0; /* Homogeneous float aggregate */
861 if (is_float(vtop
[-i
].type
.t
)
862 || (hfa
= is_float_hgen_aggr(&vtop
[-i
].type
))) {
865 assigned_vfpreg
= assign_fpreg(&avregs
, align
, size
);
866 end_reg
= assigned_vfpreg
+ (size
- 1) / 4;
867 if (assigned_vfpreg
>= 0) {
868 vfp_plan
[vfp_argno
++]=TREG_F0
+ assigned_vfpreg
/2;
870 /* before_stack can only have been set because all core registers
871 are assigned, so no need to care about before_vfpreg_hfa if
872 before_stack is set */
874 vrote(&vtop
[-i
], &vtop
[-i
] - before_stack
);
876 } else if (!before_vfpreg_hfa
)
877 before_vfpreg_hfa
= &vtop
[-i
-1];
878 for (j
= assigned_vfpreg
; j
<= end_reg
; j
++)
885 /* No need to update before_stack as no more hfa can be allocated in
887 if (!before_vfpreg_hfa
)
888 before_vfpreg_hfa
= &vtop
[-i
-1];
894 ncrn
= (ncrn
+ (align
-1)/4) & -(align
/4);
895 size
= (size
+ 3) & -4;
896 if (ncrn
+ size
/4 <= 4 || (ncrn
< 4 && assigned_vfpreg
!= -1)) {
897 /* Either there is HFA in VFP registers, or there is arguments on stack,
898 it cannot be both. Hence either before_stack already points after
899 the slot where the vtop[-i] SValue is moved, or before_stack will not
901 if (before_vfpreg_hfa
) {
902 vrote(&vtop
[-i
], &vtop
[-i
] - before_vfpreg_hfa
);
905 for (j
= ncrn
; j
< 4 && j
< ncrn
+ size
/ 4; j
++)
909 args_size
= (ncrn
- 4) * 4;
911 before_stack
= &vtop
[-i
-1];
916 /* No need to set before_vfpreg_hfa if not set since there will no
917 longer be any structure assigned to core registers */
919 before_stack
= &vtop
[-i
-1];
930 int is_long
= (vtop
[-i
].type
.t
& VT_BTYPE
) == VT_LLONG
;
933 ncrn
= (ncrn
+ 1) & -2;
939 plan
[argno
++][0]=ncrn
++;
941 plan
[argno
-1][1]=ncrn
++;
948 if(args_size
& (align
-1)) {
950 vtop
->type
.t
= VT_VOID
; /* padding */
957 args_size
+= (size
+ 3) & -4;
962 args_size
= keep
= 0;
963 for(i
= 0;i
< nb_args
; i
++) {
965 if ((vtop
->type
.t
& VT_BTYPE
) == VT_STRUCT
) {
966 size
= type_size(&vtop
->type
, &align
);
967 /* align to stack align size */
968 size
= (size
+ 3) & -4;
969 /* allocate the necessary size on stack */
971 /* generate structure store */
973 o(0xE1A0000D|(intr(r
)<<12));
974 vset(&vtop
->type
, r
| VT_LVAL
, 0);
979 } else if (is_float(vtop
->type
.t
)) {
980 #ifdef TCC_ARM_HARDFLOAT
981 if (!variadic
&& --vfp_argno
<16 && vfp_plan
[vfp_argno
]!=-1) {
982 plan2
[keep
++]=vfp_plan
[vfp_argno
];
987 r
=vfpr(gv(RC_FLOAT
))<<12;
989 if ((vtop
->type
.t
& VT_BTYPE
) != VT_FLOAT
)
992 r
|=0x101; /* fstms -> fstmd */
996 r
=fpr(gv(RC_FLOAT
))<<12;
997 if ((vtop
->type
.t
& VT_BTYPE
) == VT_FLOAT
)
999 else if ((vtop
->type
.t
& VT_BTYPE
) == VT_DOUBLE
)
1002 size
= LDOUBLE_SIZE
;
1009 o(0xED2D0100|r
|(size
>>2));
1015 /* simple type (currently always same size) */
1016 /* XXX: implicit cast ? */
1018 if ((vtop
->type
.t
& VT_BTYPE
) == VT_LLONG
) {
1021 if(--argno
<4 && plan
[argno
][1]!=-1)
1027 o(0xE52D0004|(intr(r
)<<12)); /* str r,[sp,#-4]! */
1037 if(--argno
<4 && plan
[argno
][0]!=-1)
1040 if(vtop
->type
.t
== VT_VOID
) {
1042 o(0xE24DD004); /* sub sp,sp,#4 */
1048 o(0xE52D0004|(intr(r
)<<12)); /* str r,[sp,#-4]! */
1058 for(i
= 0; i
< keep
; i
++) {
1060 gv(regmask(plan2
[i
]));
1061 #ifdef TCC_ARM_HARDFLOAT
1062 /* arg is in s(2d+1): plan2[i]<plan2[i+1] => alignment occured (ex f,d,f) */
1063 if (i
< keep
- 1 && is_float(vtop
->type
.t
) && (plan2
[i
] <= plan2
[i
+ 1])) {
1064 o(0xEEF00A40|(vfpr(plan2
[i
])<<12)|vfpr(plan2
[i
]));
1068 save_regs(keep
); /* save used temporary registers */
1074 todo
&=((1<<ncrn
)-1);
1086 args_size
-=nb_regs
*4;
1092 if(vfp_todo
&(1<<i
)) {
1093 o(0xED9D0A00|(i
&1)<<22|(i
>>1)<<12|nb_fregs
);
1095 /* There might be 2 floats in a double VFP reg but that doesn't seem
1098 vtop
->r
=TREG_F0
+i
/2;
1103 gadd_sp(nb_fregs
*4);
1104 args_size
-=nb_fregs
*4;
1112 if((vtop
->type
.ref
->type
.t
& VT_BTYPE
) == VT_STRUCT
1113 && type_size(&vtop
->type
.ref
->type
, &align
) <= 4)
1115 store(REG_IRET
,vtop
-keep
);
1119 #ifdef TCC_ARM_HARDFLOAT
1120 else if(variadic
&& is_float(vtop
->type
.ref
->type
.t
)) {
1122 else if(is_float(vtop
->type
.ref
->type
.t
)) {
1124 if((vtop
->type
.ref
->type
.t
& VT_BTYPE
) == VT_FLOAT
) {
1125 o(0xEE000A10); /* fmsr s0,r0 */
1127 o(0xEE000B10); /* fmdlr d0,r0 */
1128 o(0xEE201B10); /* fmdhr d0,r1 */
1137 /* generate function prolog of type 't' */
1138 void gfunc_prolog(CType
*func_type
)
1141 int n
,nf
,size
,align
, variadic
, struct_ret
= 0;
1142 #ifdef TCC_ARM_HARDFLOAT
1143 struct avail_regs avregs
= AVAIL_REGS_INITIALIZER
;
1146 sym
= func_type
->ref
;
1147 func_vt
= sym
->type
;
1150 variadic
= (func_type
->ref
->c
== FUNC_ELLIPSIS
);
1151 if((func_vt
.t
& VT_BTYPE
) == VT_STRUCT
1152 && type_size(&func_vt
,&align
) > 4)
1156 func_vc
= 12; /* Offset from fp of the place to store the result */
1158 for(sym2
=sym
->next
;sym2
&& (n
<4 || nf
<16);sym2
=sym2
->next
) {
1159 size
= type_size(&sym2
->type
, &align
);
1160 #ifdef TCC_ARM_HARDFLOAT
1161 if (!variadic
&& (is_float(sym2
->type
.t
)
1162 || is_float_hgen_aggr(&sym2
->type
))) {
1163 int tmpnf
= assign_fpreg(&avregs
, align
, size
) + 1;
1164 nf
= (tmpnf
> nf
) ? tmpnf
: nf
;
1168 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(0xE1A0B00D); /* mov fp, sp */
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
+12);
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(0xE89BA800); /* restore fp, sp, pc */
1256 diff
= (-loc
+ 3) & -4;
1259 diff
= ((diff
+ 11) & -8) - 4;
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 /*************************************************************/