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 #ifndef TCC_ARM_VERSION
40 # define TCC_ARM_VERSION 5
43 /* a register can belong to several classes. The classes must be
44 sorted from more general to more precise (see gv2() code which does
45 assumptions on it). */
46 #define RC_INT 0x0001 /* generic integer register */
47 #define RC_FLOAT 0x0002 /* generic float register */
63 #define RC_IRET RC_R0 /* function return: integer register */
64 #define RC_LRET RC_R1 /* function return: second integer register */
65 #define RC_FRET RC_F0 /* function return: float register */
67 /* pretty names for the registers */
87 #define T2CPR(t) (((t) & VT_BTYPE) != VT_FLOAT ? 0x100 : 0)
90 /* return registers for function */
91 #define REG_IRET TREG_R0 /* single word int return register */
92 #define REG_LRET TREG_R1 /* second word return register (for long long) */
93 #define REG_FRET TREG_F0 /* float return register */
96 #define TOK___divdi3 TOK___aeabi_ldivmod
97 #define TOK___moddi3 TOK___aeabi_ldivmod
98 #define TOK___udivdi3 TOK___aeabi_uldivmod
99 #define TOK___umoddi3 TOK___aeabi_uldivmod
102 /* defined if function parameters must be evaluated in reverse order */
103 #define INVERT_FUNC_PARAMS
105 /* defined if structures are passed as pointers. Otherwise structures
106 are directly pushed on stack. */
107 //#define FUNC_STRUCT_PARAM_AS_PTR
109 #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
110 ST_DATA CType float_type
, double_type
, func_float_type
, func_double_type
;
111 #define func_ldouble_type func_double_type
113 #define func_float_type func_old_type
114 #define func_double_type func_old_type
115 #define func_ldouble_type func_old_type
118 /* pointer size, in bytes */
121 /* long double size and alignment, in bytes */
123 #define LDOUBLE_SIZE 8
127 #define LDOUBLE_SIZE 8
131 #define LDOUBLE_ALIGN 8
133 #define LDOUBLE_ALIGN 4
136 /* maximum alignment (for aligned attribute support) */
139 #define CHAR_IS_UNSIGNED
141 /******************************************************/
144 #define EM_TCC_TARGET EM_ARM
146 /* relocation type for 32 bit data relocation */
147 #define R_DATA_32 R_ARM_ABS32
148 #define R_DATA_PTR R_ARM_ABS32
149 #define R_JMP_SLOT R_ARM_JUMP_SLOT
150 #define R_COPY R_ARM_COPY
152 #define ELF_START_ADDR 0x00008000
153 #define ELF_PAGE_SIZE 0x1000
155 /******************************************************/
156 #else /* ! TARGET_DEFS_ONLY */
157 /******************************************************/
160 ST_DATA
const int reg_classes
[NB_REGS
] = {
161 /* r0 */ RC_INT
| RC_R0
,
162 /* r1 */ RC_INT
| RC_R1
,
163 /* r2 */ RC_INT
| RC_R2
,
164 /* r3 */ RC_INT
| RC_R3
,
165 /* r12 */ RC_INT
| RC_R12
,
166 /* f0 */ RC_FLOAT
| RC_F0
,
167 /* f1 */ RC_FLOAT
| RC_F1
,
168 /* f2 */ RC_FLOAT
| RC_F2
,
169 /* f3 */ RC_FLOAT
| RC_F3
,
171 /* d4/s8 */ RC_FLOAT
| RC_F4
,
172 /* d5/s10 */ RC_FLOAT
| RC_F5
,
173 /* d6/s12 */ RC_FLOAT
| RC_F6
,
174 /* d7/s14 */ RC_FLOAT
| RC_F7
,
178 /* keep in sync with line 104 above */
179 #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
180 ST_DATA CType float_type
, double_type
, func_float_type
, func_double_type
;
183 static int func_sub_sp_offset
, last_itod_magic
;
186 static int two2mask(int a
,int b
) {
187 return (reg_classes
[a
]|reg_classes
[b
])&~(RC_INT
|RC_FLOAT
);
190 static int regmask(int r
) {
191 return reg_classes
[r
]&~(RC_INT
|RC_FLOAT
);
194 /******************************************************/
198 /* this is a good place to start adding big-endian support*/
202 if (!cur_text_section
)
203 tcc_error("compiler error! This happens f.ex. if the compiler\n"
204 "can't evaluate constant expressions outside of a function.");
205 if (ind1
> cur_text_section
->data_allocated
)
206 section_realloc(cur_text_section
, ind1
);
207 cur_text_section
->data
[ind
++] = i
&255;
209 cur_text_section
->data
[ind
++] = i
&255;
211 cur_text_section
->data
[ind
++] = i
&255;
213 cur_text_section
->data
[ind
++] = i
;
216 static uint32_t stuff_const(uint32_t op
, uint32_t c
)
219 uint32_t nc
= 0, negop
= 0;
229 case 0x1A00000: //mov
230 case 0x1E00000: //mvn
237 return (op
&0xF010F000)|((op
>>16)&0xF)|0x1E00000;
241 return (op
&0xF010F000)|((op
>>16)&0xF)|0x1A00000;
242 case 0x1C00000: //bic
247 case 0x1800000: //orr
249 return (op
&0xFFF0FFFF)|0x1E00000;
255 if(c
<256) /* catch undefined <<32 */
258 m
=(0xff>>i
)|(0xff<<(32-i
));
260 return op
|(i
<<7)|(c
<<i
)|(c
>>(32-i
));
270 void stuff_const_harder(uint32_t op
, uint32_t v
) {
276 uint32_t a
[16], nv
, no
, o2
, n2
;
279 o2
=(op
&0xfff0ffff)|((op
&0xf000)<<4);;
281 a
[i
]=(a
[i
-1]>>2)|(a
[i
-1]<<30);
283 for(j
=i
<4?i
+12:15;j
>=i
+4;j
--)
284 if((v
&(a
[i
]|a
[j
]))==v
) {
285 o(stuff_const(op
,v
&a
[i
]));
286 o(stuff_const(o2
,v
&a
[j
]));
293 for(j
=i
<4?i
+12:15;j
>=i
+4;j
--)
294 if((nv
&(a
[i
]|a
[j
]))==nv
) {
295 o(stuff_const(no
,nv
&a
[i
]));
296 o(stuff_const(n2
,nv
&a
[j
]));
301 for(k
=i
<4?i
+12:15;k
>=j
+4;k
--)
302 if((v
&(a
[i
]|a
[j
]|a
[k
]))==v
) {
303 o(stuff_const(op
,v
&a
[i
]));
304 o(stuff_const(o2
,v
&a
[j
]));
305 o(stuff_const(o2
,v
&a
[k
]));
312 for(k
=i
<4?i
+12:15;k
>=j
+4;k
--)
313 if((nv
&(a
[i
]|a
[j
]|a
[k
]))==nv
) {
314 o(stuff_const(no
,nv
&a
[i
]));
315 o(stuff_const(n2
,nv
&a
[j
]));
316 o(stuff_const(n2
,nv
&a
[k
]));
319 o(stuff_const(op
,v
&a
[0]));
320 o(stuff_const(o2
,v
&a
[4]));
321 o(stuff_const(o2
,v
&a
[8]));
322 o(stuff_const(o2
,v
&a
[12]));
326 ST_FUNC
uint32_t encbranch(int pos
, int addr
, int fail
)
330 if(addr
>=0x1000000 || addr
<-0x1000000) {
332 tcc_error("FIXME: function bigger than 32MB");
335 return 0x0A000000|(addr
&0xffffff);
338 int decbranch(int pos
)
341 x
=*(uint32_t *)(cur_text_section
->data
+ pos
);
348 /* output a symbol and patch all calls to it */
349 void gsym_addr(int t
, int a
)
354 x
=(uint32_t *)(cur_text_section
->data
+ t
);
357 *x
=0xE1A00000; // nop
360 *x
|= encbranch(lt
,a
,1);
371 static uint32_t vfpr(int r
)
373 if(r
<TREG_F0
|| r
>TREG_F7
)
374 tcc_error("compiler error! register %i is no vfp register",r
);
378 static uint32_t fpr(int r
)
380 if(r
<TREG_F0
|| r
>TREG_F3
)
381 tcc_error("compiler error! register %i is no fpa register",r
);
386 static uint32_t intr(int r
)
390 if((r
<0 || r
>4) && r
!=14)
391 tcc_error("compiler error! register %i is no int register",r
);
395 static void calcaddr(uint32_t *base
, int *off
, int *sgn
, int maxoff
, unsigned shift
)
397 if(*off
>maxoff
|| *off
&((1<<shift
)-1)) {
404 y
=stuff_const(x
,*off
&~maxoff
);
410 y
=stuff_const(x
,(*off
+maxoff
)&~maxoff
);
414 *off
=((*off
+maxoff
)&~maxoff
)-*off
;
417 stuff_const_harder(x
,*off
&~maxoff
);
422 static uint32_t mapcc(int cc
)
427 return 0x30000000; /* CC/LO */
429 return 0x20000000; /* CS/HS */
431 return 0x00000000; /* EQ */
433 return 0x10000000; /* NE */
435 return 0x90000000; /* LS */
437 return 0x80000000; /* HI */
439 return 0x40000000; /* MI */
441 return 0x50000000; /* PL */
443 return 0xB0000000; /* LT */
445 return 0xA0000000; /* GE */
447 return 0xD0000000; /* LE */
449 return 0xC0000000; /* GT */
451 tcc_error("unexpected condition code");
452 return 0xE0000000; /* AL */
455 static int negcc(int cc
)
484 tcc_error("unexpected condition code");
488 /* load 'r' from value 'sv' */
489 void load(int r
, SValue
*sv
)
491 int v
, ft
, fc
, fr
, sign
;
508 uint32_t base
= 0xB; // fp
511 v1
.r
= VT_LOCAL
| VT_LVAL
;
513 load(base
=14 /* lr */, &v1
);
516 } else if(v
== VT_CONST
) {
524 } else if(v
< VT_CONST
) {
531 calcaddr(&base
,&fc
,&sign
,1020,2);
533 op
=0xED100A00; /* flds */
536 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
537 op
|=0x100; /* flds -> fldd */
538 o(op
|(vfpr(r
)<<12)|(fc
>>2)|(base
<<16));
543 #if LDOUBLE_SIZE == 8
544 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
547 if ((ft
& VT_BTYPE
) == VT_DOUBLE
)
549 else if ((ft
& VT_BTYPE
) == VT_LDOUBLE
)
552 o(op
|(fpr(r
)<<12)|(fc
>>2)|(base
<<16));
554 } else if((ft
& (VT_BTYPE
|VT_UNSIGNED
)) == VT_BYTE
555 || (ft
& VT_BTYPE
) == VT_SHORT
) {
556 calcaddr(&base
,&fc
,&sign
,255,0);
558 if ((ft
& VT_BTYPE
) == VT_SHORT
)
560 if ((ft
& VT_UNSIGNED
) == 0)
564 o(op
|(intr(r
)<<12)|(base
<<16)|((fc
&0xf0)<<4)|(fc
&0xf));
566 calcaddr(&base
,&fc
,&sign
,4095,0);
570 if ((ft
& VT_BTYPE
) == VT_BYTE
)
572 o(op
|(intr(r
)<<12)|fc
|(base
<<16));
578 op
=stuff_const(0xE3A00000|(intr(r
)<<12),sv
->c
.ul
);
579 if (fr
& VT_SYM
|| !op
) {
580 o(0xE59F0000|(intr(r
)<<12));
583 greloc(cur_text_section
, sv
->sym
, ind
, R_ARM_ABS32
);
588 } else if (v
== VT_LOCAL
) {
589 op
=stuff_const(0xE28B0000|(intr(r
)<<12),sv
->c
.ul
);
590 if (fr
& VT_SYM
|| !op
) {
591 o(0xE59F0000|(intr(r
)<<12));
593 if(fr
& VT_SYM
) // needed ?
594 greloc(cur_text_section
, sv
->sym
, ind
, R_ARM_ABS32
);
596 o(0xE08B0000|(intr(r
)<<12)|intr(r
));
600 } else if(v
== VT_CMP
) {
601 o(mapcc(sv
->c
.ul
)|0x3A00001|(intr(r
)<<12));
602 o(mapcc(negcc(sv
->c
.ul
))|0x3A00000|(intr(r
)<<12));
604 } else if (v
== VT_JMP
|| v
== VT_JMPI
) {
607 o(0xE3A00000|(intr(r
)<<12)|t
);
610 o(0xE3A00000|(intr(r
)<<12)|(t
^1));
612 } else if (v
< VT_CONST
) {
615 o(0xEEB00A40|(vfpr(r
)<<12)|vfpr(v
)|T2CPR(ft
)); /* fcpyX */
617 o(0xEE008180|(fpr(r
)<<12)|fpr(v
));
620 o(0xE1A00000|(intr(r
)<<12)|intr(v
));
624 tcc_error("load unimplemented!");
627 /* store register 'r' in lvalue 'v' */
628 void store(int r
, SValue
*sv
)
631 int v
, ft
, fc
, fr
, sign
;
646 if (fr
& VT_LVAL
|| fr
== VT_LOCAL
) {
652 } else if(v
== VT_CONST
) {
663 calcaddr(&base
,&fc
,&sign
,1020,2);
665 op
=0xED000A00; /* fsts */
668 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
669 op
|=0x100; /* fsts -> fstd */
670 o(op
|(vfpr(r
)<<12)|(fc
>>2)|(base
<<16));
675 #if LDOUBLE_SIZE == 8
676 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
679 if ((ft
& VT_BTYPE
) == VT_DOUBLE
)
681 if ((ft
& VT_BTYPE
) == VT_LDOUBLE
)
684 o(op
|(fpr(r
)<<12)|(fc
>>2)|(base
<<16));
687 } else if((ft
& VT_BTYPE
) == VT_SHORT
) {
688 calcaddr(&base
,&fc
,&sign
,255,0);
692 o(op
|(intr(r
)<<12)|(base
<<16)|((fc
&0xf0)<<4)|(fc
&0xf));
694 calcaddr(&base
,&fc
,&sign
,4095,0);
698 if ((ft
& VT_BTYPE
) == VT_BYTE
)
700 o(op
|(intr(r
)<<12)|fc
|(base
<<16));
705 tcc_error("store unimplemented");
708 static void gadd_sp(int val
)
710 stuff_const_harder(0xE28DD000,val
);
713 /* 'is_jmp' is '1' if it is a jump */
714 static void gcall_or_jmp(int is_jmp
)
717 if ((vtop
->r
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
) {
720 x
=encbranch(ind
,ind
+vtop
->c
.ul
,0);
722 if (vtop
->r
& VT_SYM
) {
723 /* relocation case */
724 greloc(cur_text_section
, vtop
->sym
, ind
, R_ARM_PC24
);
726 put_elf_reloc(symtab_section
, cur_text_section
, ind
, R_ARM_PC24
, 0);
727 o(x
|(is_jmp
?0xE0000000:0xE1000000));
730 o(0xE28FE004); // add lr,pc,#4
731 o(0xE51FF004); // ldr pc,[pc,#-4]
732 if (vtop
->r
& VT_SYM
)
733 greloc(cur_text_section
, vtop
->sym
, ind
, R_ARM_ABS32
);
737 /* otherwise, indirect call */
740 o(0xE1A0E00F); // mov lr,pc
741 o(0xE1A0F000|intr(r
)); // mov pc,r
745 #ifdef TCC_ARM_HARDFLOAT
746 static int is_float_hgen_aggr(CType
*type
)
748 if ((type
->t
& VT_BTYPE
) == VT_STRUCT
) {
750 int btype
, nb_fields
= 0;
753 btype
= ref
->type
.t
& VT_BTYPE
;
754 if (btype
== VT_FLOAT
|| btype
== VT_DOUBLE
) {
755 for(; ref
&& btype
== (ref
->type
.t
& VT_BTYPE
); ref
= ref
->next
, nb_fields
++);
756 return !ref
&& nb_fields
<= 4;
763 /* worst case: f(float, double, 3 float struct, double, 3 float struct, double) */
764 signed char avail
[3];
770 #define AVAIL_REGS_INITIALIZER (struct avail_regs) { { 0, 0, 0}, 0, 0, 0 }
772 /* Assign a register for a CPRC param with correct size and alignment
773 * size and align are in bytes, as returned by type_size */
774 int assign_fpreg(struct avail_regs
*avregs
, int align
, int size
)
778 if (avregs
->first_free_reg
== -1)
780 if (align
>> 3) { // alignment needed (base type: double)
781 first_reg
= avregs
->first_free_reg
;
783 avregs
->avail
[avregs
->last_hole
++] = first_reg
++;
785 if (size
== 4 && avregs
->first_hole
!= avregs
->last_hole
)
786 return avregs
->avail
[avregs
->first_hole
++];
788 first_reg
= avregs
->first_free_reg
;
790 if (first_reg
+ size
/ 4 <= 16) {
791 avregs
->first_free_reg
= first_reg
+ size
/ 4;
794 avregs
->first_free_reg
= -1;
799 /* Generate function call. The function address is pushed first, then
800 all the parameters in call order. This functions pops all the
801 parameters and the function address. */
802 void gfunc_call(int nb_args
)
804 int size
, align
, r
, args_size
, i
, ncrn
, ncprn
, argno
, vfp_argno
;
805 signed char plan
[4][2]={{-1,-1},{-1,-1},{-1,-1},{-1,-1}};
806 SValue
*before_stack
= NULL
; /* SValue before first on stack argument */
807 SValue
*before_vfpreg_hfa
= NULL
; /* SValue before first in VFP reg hfa argument */
808 #ifdef TCC_ARM_HARDFLOAT
809 struct avail_regs avregs
= AVAIL_REGS_INITIALIZER
;
810 signed char vfp_plan
[16];
814 int plan2
[4]={0,0,0,0};
819 #ifdef TCC_ARM_HARDFLOAT
820 memset(vfp_plan
, -1, sizeof(vfp_plan
));
821 memset(plan2
, 0, sizeof(plan2
));
822 variadic
= (vtop
[-nb_args
].type
.ref
->c
== FUNC_ELLIPSIS
);
824 r
= vtop
->r
& VT_VALMASK
;
825 if (r
== VT_CMP
|| (r
& ~1) == VT_JMP
)
828 if((vtop
[-nb_args
].type
.ref
->type
.t
& VT_BTYPE
) == VT_STRUCT
829 && type_size(&vtop
[-nb_args
].type
.ref
->type
, &align
) <= 4) {
832 vtop
[-nb_args
]=vtop
[-nb_args
+1];
833 vtop
[-nb_args
+1]=tmp
;
837 vpushi(0), nb_args
++;
838 vtop
->type
.t
= VT_LLONG
;
840 ncrn
= ncprn
= argno
= vfp_argno
= args_size
= 0;
841 /* Assign argument to registers and stack with alignment.
842 If, considering alignment constraints, enough registers of the correct type
843 (core or VFP) are free for the current argument, assign them to it, else
844 allocate on stack with correct alignment. Whenever a structure is allocated
845 in registers or on stack, it is always put on the stack at this stage. The
846 stack is divided in 3 zones. The zone are, from low addresses to high
847 addresses: structures to be loaded in core registers, structures to be
848 loaded in VFP registers, argument allocated to stack. SValue's representing
849 structures in the first zone are moved just after the SValue pointed by
850 before_vfpreg_hfa. SValue's representing structures in the second zone are
851 moved just after the SValue pointer by before_stack. */
852 for(i
= nb_args
; i
-- ;) {
853 int j
, assigned_vfpreg
= 0;
854 size
= type_size(&vtop
[-i
].type
, &align
);
855 switch(vtop
[-i
].type
.t
& VT_BTYPE
) {
860 #ifdef TCC_ARM_HARDFLOAT
862 int hfa
= 0; /* Homogeneous float aggregate */
864 if (is_float(vtop
[-i
].type
.t
)
865 || (hfa
= is_float_hgen_aggr(&vtop
[-i
].type
))) {
868 assigned_vfpreg
= assign_fpreg(&avregs
, align
, size
);
869 end_reg
= assigned_vfpreg
+ (size
- 1) / 4;
870 if (assigned_vfpreg
>= 0) {
871 vfp_plan
[vfp_argno
++]=TREG_F0
+ assigned_vfpreg
/2;
873 /* before_stack can only have been set because all core registers
874 are assigned, so no need to care about before_vfpreg_hfa if
875 before_stack is set */
877 vrote(&vtop
[-i
], &vtop
[-i
] - before_stack
);
879 } else if (!before_vfpreg_hfa
)
880 before_vfpreg_hfa
= &vtop
[-i
-1];
881 for (j
= assigned_vfpreg
; j
<= end_reg
; j
++)
888 /* No need to update before_stack as no more hfa can be allocated in
890 if (!before_vfpreg_hfa
)
891 before_vfpreg_hfa
= &vtop
[-i
-1];
897 ncrn
= (ncrn
+ (align
-1)/4) & -(align
/4);
898 size
= (size
+ 3) & -4;
899 if (ncrn
+ size
/4 <= 4 || (ncrn
< 4 && assigned_vfpreg
!= -1)) {
900 /* Either there is HFA in VFP registers, or there is arguments on stack,
901 it cannot be both. Hence either before_stack already points after
902 the slot where the vtop[-i] SValue is moved, or before_stack will not
904 if (before_vfpreg_hfa
) {
905 vrote(&vtop
[-i
], &vtop
[-i
] - before_vfpreg_hfa
);
908 for (j
= ncrn
; j
< 4 && j
< ncrn
+ size
/ 4; j
++)
912 args_size
= (ncrn
- 4) * 4;
914 before_stack
= &vtop
[-i
-1];
919 /* No need to set before_vfpreg_hfa if not set since there will no
920 longer be any structure assigned to core registers */
922 before_stack
= &vtop
[-i
-1];
933 int is_long
= (vtop
[-i
].type
.t
& VT_BTYPE
) == VT_LLONG
;
936 ncrn
= (ncrn
+ 1) & -2;
942 plan
[argno
++][0]=ncrn
++;
944 plan
[argno
-1][1]=ncrn
++;
951 if(args_size
& (align
-1)) {
953 vtop
->type
.t
= VT_VOID
; /* padding */
960 args_size
+= (size
+ 3) & -4;
965 args_size
= keep
= 0;
966 for(i
= 0;i
< nb_args
; i
++) {
968 if ((vtop
->type
.t
& VT_BTYPE
) == VT_STRUCT
) {
969 size
= type_size(&vtop
->type
, &align
);
970 /* align to stack align size */
971 size
= (size
+ 3) & -4;
972 /* allocate the necessary size on stack */
974 /* generate structure store */
976 o(0xE1A0000D|(intr(r
)<<12));
977 vset(&vtop
->type
, r
| VT_LVAL
, 0);
982 } else if (is_float(vtop
->type
.t
)) {
983 #ifdef TCC_ARM_HARDFLOAT
984 if (!variadic
&& --vfp_argno
<16 && vfp_plan
[vfp_argno
]!=-1) {
985 plan2
[keep
++]=vfp_plan
[vfp_argno
];
990 r
=vfpr(gv(RC_FLOAT
))<<12;
992 if ((vtop
->type
.t
& VT_BTYPE
) != VT_FLOAT
)
995 r
|=0x101; /* fstms -> fstmd */
999 r
=fpr(gv(RC_FLOAT
))<<12;
1000 if ((vtop
->type
.t
& VT_BTYPE
) == VT_FLOAT
)
1002 else if ((vtop
->type
.t
& VT_BTYPE
) == VT_DOUBLE
)
1005 size
= LDOUBLE_SIZE
;
1012 o(0xED2D0100|r
|(size
>>2));
1018 /* simple type (currently always same size) */
1019 /* XXX: implicit cast ? */
1021 if ((vtop
->type
.t
& VT_BTYPE
) == VT_LLONG
) {
1024 if(--argno
<4 && plan
[argno
][1]!=-1)
1030 o(0xE52D0004|(intr(r
)<<12)); /* str r,[sp,#-4]! */
1040 if(--argno
<4 && plan
[argno
][0]!=-1)
1043 if(vtop
->type
.t
== VT_VOID
) {
1045 o(0xE24DD004); /* sub sp,sp,#4 */
1051 o(0xE52D0004|(intr(r
)<<12)); /* str r,[sp,#-4]! */
1061 for(i
= 0; i
< keep
; i
++) {
1063 gv(regmask(plan2
[i
]));
1064 #ifdef TCC_ARM_HARDFLOAT
1065 /* arg is in s(2d+1): plan2[i]<plan2[i+1] => alignment occured (ex f,d,f) */
1066 if (i
< keep
- 1 && is_float(vtop
->type
.t
) && (plan2
[i
] <= plan2
[i
+ 1])) {
1067 o(0xEEF00A40|(vfpr(plan2
[i
])<<12)|vfpr(plan2
[i
]));
1071 save_regs(keep
); /* save used temporary registers */
1077 todo
&=((1<<ncrn
)-1);
1089 args_size
-=nb_regs
*4;
1095 if(vfp_todo
&(1<<i
)) {
1096 o(0xED9D0A00|(i
&1)<<22|(i
>>1)<<12|nb_fregs
);
1098 /* There might be 2 floats in a double VFP reg but that doesn't seem
1101 vtop
->r
=TREG_F0
+i
/2;
1106 gadd_sp(nb_fregs
*4);
1107 args_size
-=nb_fregs
*4;
1115 if((vtop
->type
.ref
->type
.t
& VT_BTYPE
) == VT_STRUCT
1116 && type_size(&vtop
->type
.ref
->type
, &align
) <= 4)
1118 store(REG_IRET
,vtop
-keep
);
1122 #ifdef TCC_ARM_HARDFLOAT
1123 else if(variadic
&& is_float(vtop
->type
.ref
->type
.t
)) {
1125 else if(is_float(vtop
->type
.ref
->type
.t
)) {
1127 if((vtop
->type
.ref
->type
.t
& VT_BTYPE
) == VT_FLOAT
) {
1128 o(0xEE000A10); /* fmsr s0,r0 */
1130 o(0xEE000B10); /* fmdlr d0,r0 */
1131 o(0xEE201B10); /* fmdhr d0,r1 */
1140 /* generate function prolog of type 't' */
1141 void gfunc_prolog(CType
*func_type
)
1144 int n
,nf
,size
,align
, variadic
, struct_ret
= 0;
1145 #ifdef TCC_ARM_HARDFLOAT
1146 struct avail_regs avregs
= AVAIL_REGS_INITIALIZER
;
1149 sym
= func_type
->ref
;
1150 func_vt
= sym
->type
;
1153 variadic
= (func_type
->ref
->c
== FUNC_ELLIPSIS
);
1154 if((func_vt
.t
& VT_BTYPE
) == VT_STRUCT
1155 && type_size(&func_vt
,&align
) > 4)
1159 func_vc
= 12; /* Offset from fp of the place to store the result */
1161 for(sym2
=sym
->next
;sym2
&& (n
<4 || nf
<16);sym2
=sym2
->next
) {
1162 size
= type_size(&sym2
->type
, &align
);
1163 #ifdef TCC_ARM_HARDFLOAT
1164 if (!variadic
&& (is_float(sym2
->type
.t
)
1165 || is_float_hgen_aggr(&sym2
->type
))) {
1166 int tmpnf
= assign_fpreg(&avregs
, align
, size
) + 1;
1167 nf
= (tmpnf
> nf
) ? tmpnf
: nf
;
1171 n
+= (size
+ 3) / 4;
1173 o(0xE1A0C00D); /* mov ip,sp */
1182 o(0xE92D0000|((1<<n
)-1)); /* save r0-r4 on stack if needed */
1187 nf
=(nf
+1)&-2; /* nf => HARDFLOAT => EABI */
1188 o(0xED2D0A00|nf
); /* save s0-s15 on stack if needed */
1190 o(0xE92D5800); /* save fp, ip, lr */
1191 o(0xE1A0B00D); /* mov fp, sp */
1192 func_sub_sp_offset
= ind
;
1193 o(0xE1A00000); /* nop, leave space for stack adjustment in epilogue */
1195 int addr
, pn
= struct_ret
, sn
= 0; /* pn=core, sn=stack */
1197 #ifdef TCC_ARM_HARDFLOAT
1198 avregs
= AVAIL_REGS_INITIALIZER
;
1200 while ((sym
= sym
->next
)) {
1203 size
= type_size(type
, &align
);
1204 size
= (size
+ 3) >> 2;
1205 #ifdef TCC_ARM_HARDFLOAT
1206 if (!variadic
&& (is_float(sym
->type
.t
)
1207 || is_float_hgen_aggr(&sym
->type
))) {
1208 int fpn
= assign_fpreg(&avregs
, align
, size
<< 2);
1217 pn
= (pn
+ (align
-1)/4) & -(align
/4);
1219 addr
= (nf
+ pn
) * 4;
1224 #ifdef TCC_ARM_HARDFLOAT
1228 sn
= (sn
+ (align
-1)/4) & -(align
/4);
1230 addr
= (n
+ nf
+ sn
) * 4;
1233 sym_push(sym
->v
& ~SYM_FIELD
, type
, VT_LOCAL
| lvalue_type(type
->t
), addr
+12);
1241 /* generate function epilog */
1242 void gfunc_epilog(void)
1247 /* Useless but harmless copy of the float result into main register(s) in case
1248 of variadic function in the hardfloat variant */
1249 if(is_float(func_vt
.t
)) {
1250 if((func_vt
.t
& VT_BTYPE
) == VT_FLOAT
)
1251 o(0xEE100A10); /* fmrs r0, s0 */
1253 o(0xEE100B10); /* fmrdl r0, d0 */
1254 o(0xEE301B10); /* fmrdh r1, d0 */
1258 o(0xE89BA800); /* restore fp, sp, pc */
1259 diff
= (-loc
+ 3) & -4;
1262 diff
= ((diff
+ 11) & -8) - 4;
1265 x
=stuff_const(0xE24BD000, diff
); /* sub sp,fp,# */
1267 *(uint32_t *)(cur_text_section
->data
+ func_sub_sp_offset
) = x
;
1271 o(0xE59FC004); /* ldr ip,[pc+4] */
1272 o(0xE04BD00C); /* sub sp,fp,ip */
1273 o(0xE1A0F00E); /* mov pc,lr */
1275 *(uint32_t *)(cur_text_section
->data
+ func_sub_sp_offset
) = 0xE1000000|encbranch(func_sub_sp_offset
,addr
,1);
1280 /* generate a jump to a label */
1285 o(0xE0000000|encbranch(r
,t
,1));
1289 /* generate a jump to a fixed address */
1290 void gjmp_addr(int a
)
1295 /* generate a test. set 'inv' to invert test. Stack entry is popped */
1296 int gtst(int inv
, int t
)
1300 v
= vtop
->r
& VT_VALMASK
;
1303 op
=mapcc(inv
?negcc(vtop
->c
.i
):vtop
->c
.i
);
1304 op
|=encbranch(r
,t
,1);
1307 } else if (v
== VT_JMP
|| v
== VT_JMPI
) {
1308 if ((v
& 1) == inv
) {
1317 p
= decbranch(lp
=p
);
1319 x
= (uint32_t *)(cur_text_section
->data
+ lp
);
1321 *x
|= encbranch(lp
,t
,1);
1330 if (is_float(vtop
->type
.t
)) {
1333 o(0xEEB50A40|(vfpr(r
)<<12)|T2CPR(vtop
->type
.t
)); /* fcmpzX */
1334 o(0xEEF1FA10); /* fmstat */
1336 o(0xEE90F118|(fpr(r
)<<16));
1340 return gtst(inv
, t
);
1341 } else if ((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1342 /* constant jmp optimization */
1343 if ((vtop
->c
.i
!= 0) != inv
)
1347 o(0xE3300000|(intr(v
)<<16));
1350 return gtst(inv
, t
);
1357 /* generate an integer binary operation */
1358 void gen_opi(int op
)
1361 uint32_t opc
= 0, r
, fr
;
1362 unsigned short retreg
= REG_IRET
;
1370 case TOK_ADDC1
: /* add with carry generation */
1378 case TOK_SUBC1
: /* sub with carry generation */
1382 case TOK_ADDC2
: /* add with carry use */
1386 case TOK_SUBC2
: /* sub with carry use */
1403 gv2(RC_INT
, RC_INT
);
1407 o(0xE0000090|(intr(r
)<<16)|(intr(r
)<<8)|intr(fr
));
1432 func
=TOK___aeabi_idivmod
;
1441 func
=TOK___aeabi_uidivmod
;
1449 gv2(RC_INT
, RC_INT
);
1450 r
=intr(vtop
[-1].r2
=get_reg(RC_INT
));
1452 vtop
[-1].r
=get_reg_ex(RC_INT
,regmask(c
));
1454 o(0xE0800090|(r
<<16)|(intr(vtop
->r
)<<12)|(intr(c
)<<8)|intr(vtop
[1].r
));
1463 if((vtop
[-1].r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1464 if(opc
== 4 || opc
== 5 || opc
== 0xc) {
1466 opc
|=2; // sub -> rsb
1469 if ((vtop
->r
& VT_VALMASK
) == VT_CMP
||
1470 (vtop
->r
& (VT_VALMASK
& ~1)) == VT_JMP
)
1475 opc
=0xE0000000|(opc
<<20)|(c
<<16);
1476 if((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1478 x
=stuff_const(opc
|0x2000000,vtop
->c
.i
);
1480 r
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,regmask(vtop
[-1].r
)));
1485 fr
=intr(gv(RC_INT
));
1486 r
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,two2mask(vtop
->r
,vtop
[-1].r
)));
1490 if (op
>= TOK_ULT
&& op
<= TOK_GT
) {
1496 opc
=0xE1A00000|(opc
<<5);
1497 if ((vtop
->r
& VT_VALMASK
) == VT_CMP
||
1498 (vtop
->r
& (VT_VALMASK
& ~1)) == VT_JMP
)
1504 if ((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1505 fr
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,regmask(vtop
[-1].r
)));
1506 c
= vtop
->c
.i
& 0x1f;
1507 o(opc
|(c
<<7)|(fr
<<12));
1509 fr
=intr(gv(RC_INT
));
1510 c
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,two2mask(vtop
->r
,vtop
[-1].r
)));
1511 o(opc
|(c
<<12)|(fr
<<8)|0x10);
1516 vpush_global_sym(&func_old_type
, func
);
1523 tcc_error("gen_opi %i unimplemented!",op
);
1528 static int is_zero(int i
)
1530 if((vtop
[i
].r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) != VT_CONST
)
1532 if (vtop
[i
].type
.t
== VT_FLOAT
)
1533 return (vtop
[i
].c
.f
== 0.f
);
1534 else if (vtop
[i
].type
.t
== VT_DOUBLE
)
1535 return (vtop
[i
].c
.d
== 0.0);
1536 return (vtop
[i
].c
.ld
== 0.l
);
1539 /* generate a floating point operation 'v = t1 op t2' instruction. The
1540 * two operands are guaranted to have the same floating point type */
1541 void gen_opf(int op
)
1545 x
=0xEE000A00|T2CPR(vtop
->type
.t
);
1563 x
|=0x810000; /* fsubX -> fnegX */
1576 if(op
< TOK_ULT
|| op
> TOK_GT
) {
1577 tcc_error("unknown fp op %x!",op
);
1583 case TOK_LT
: op
=TOK_GT
; break;
1584 case TOK_GE
: op
=TOK_ULE
; break;
1585 case TOK_LE
: op
=TOK_GE
; break;
1586 case TOK_GT
: op
=TOK_ULT
; break;
1589 x
|=0xB40040; /* fcmpX */
1590 if(op
!=TOK_EQ
&& op
!=TOK_NE
)
1591 x
|=0x80; /* fcmpX -> fcmpeX */
1594 o(x
|0x10000|(vfpr(gv(RC_FLOAT
))<<12)); /* fcmp(e)X -> fcmp(e)zX */
1596 x
|=vfpr(gv(RC_FLOAT
));
1598 o(x
|(vfpr(gv(RC_FLOAT
))<<12));
1601 o(0xEEF1FA10); /* fmstat */
1604 case TOK_LE
: op
=TOK_ULE
; break;
1605 case TOK_LT
: op
=TOK_ULT
; break;
1606 case TOK_UGE
: op
=TOK_GE
; break;
1607 case TOK_UGT
: op
=TOK_GT
; break;
1624 vtop
->r
=get_reg_ex(RC_FLOAT
,r
);
1627 o(x
|(vfpr(vtop
->r
)<<12));
1631 static uint32_t is_fconst()
1635 if((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) != VT_CONST
)
1637 if (vtop
->type
.t
== VT_FLOAT
)
1639 else if (vtop
->type
.t
== VT_DOUBLE
)
1669 /* generate a floating point operation 'v = t1 op t2' instruction. The
1670 two operands are guaranted to have the same floating point type */
1671 void gen_opf(int op
)
1673 uint32_t x
, r
, r2
, c1
, c2
;
1674 //fputs("gen_opf\n",stderr);
1680 #if LDOUBLE_SIZE == 8
1681 if ((vtop
->type
.t
& VT_BTYPE
) != VT_FLOAT
)
1684 if ((vtop
->type
.t
& VT_BTYPE
) == VT_DOUBLE
)
1686 else if ((vtop
->type
.t
& VT_BTYPE
) == VT_LDOUBLE
)
1697 r
=fpr(gv(RC_FLOAT
));
1704 r2
=fpr(gv(RC_FLOAT
));
1713 r
=fpr(gv(RC_FLOAT
));
1715 } else if(c1
&& c1
<=0xf) {
1718 r
=fpr(gv(RC_FLOAT
));
1723 r
=fpr(gv(RC_FLOAT
));
1725 r2
=fpr(gv(RC_FLOAT
));
1734 r
=fpr(gv(RC_FLOAT
));
1739 r2
=fpr(gv(RC_FLOAT
));
1747 r
=fpr(gv(RC_FLOAT
));
1749 } else if(c1
&& c1
<=0xf) {
1752 r
=fpr(gv(RC_FLOAT
));
1757 r
=fpr(gv(RC_FLOAT
));
1759 r2
=fpr(gv(RC_FLOAT
));
1763 if(op
>= TOK_ULT
&& op
<= TOK_GT
) {
1764 x
|=0xd0f110; // cmfe
1765 /* bug (intention?) in Linux FPU emulator
1766 doesn't set carry if equal */
1772 tcc_error("unsigned comparision on floats?");
1778 op
=TOK_ULE
; /* correct in unordered case only if AC bit in FPSR set */
1782 x
&=~0x400000; // cmfe -> cmf
1804 r
=fpr(gv(RC_FLOAT
));
1811 r2
=fpr(gv(RC_FLOAT
));
1813 vtop
[-1].r
= VT_CMP
;
1816 tcc_error("unknown fp op %x!",op
);
1820 if(vtop
[-1].r
== VT_CMP
)
1826 vtop
[-1].r
=get_reg_ex(RC_FLOAT
,two2mask(vtop
[-1].r
,c1
));
1830 o(x
|(r
<<16)|(c1
<<12)|r2
);
1834 /* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
1835 and 'long long' cases. */
1836 ST_FUNC
void gen_cvt_itof1(int t
)
1840 bt
=vtop
->type
.t
& VT_BTYPE
;
1841 if(bt
== VT_INT
|| bt
== VT_SHORT
|| bt
== VT_BYTE
) {
1847 r2
=vfpr(vtop
->r
=get_reg(RC_FLOAT
));
1848 o(0xEE000A10|(r
<<12)|(r2
<<16)); /* fmsr */
1850 if(!(vtop
->type
.t
& VT_UNSIGNED
))
1851 r2
|=0x80; /* fuitoX -> fsituX */
1852 o(0xEEB80A40|r2
|T2CPR(t
)); /* fYitoX*/
1854 r2
=fpr(vtop
->r
=get_reg(RC_FLOAT
));
1855 if((t
& VT_BTYPE
) != VT_FLOAT
)
1856 dsize
=0x80; /* flts -> fltd */
1857 o(0xEE000110|dsize
|(r2
<<16)|(r
<<12)); /* flts */
1858 if((vtop
->type
.t
& (VT_UNSIGNED
|VT_BTYPE
)) == (VT_UNSIGNED
|VT_INT
)) {
1860 o(0xE3500000|(r
<<12)); /* cmp */
1861 r
=fpr(get_reg(RC_FLOAT
));
1862 if(last_itod_magic
) {
1863 off
=ind
+8-last_itod_magic
;
1868 o(0xBD1F0100|(r
<<12)|off
); /* ldflts */
1870 o(0xEA000000); /* b */
1871 last_itod_magic
=ind
;
1872 o(0x4F800000); /* 4294967296.0f */
1874 o(0xBE000100|dsize
|(r2
<<16)|(r2
<<12)|r
); /* adflt */
1878 } else if(bt
== VT_LLONG
) {
1880 CType
*func_type
= 0;
1881 if((t
& VT_BTYPE
) == VT_FLOAT
) {
1882 func_type
= &func_float_type
;
1883 if(vtop
->type
.t
& VT_UNSIGNED
)
1884 func
=TOK___floatundisf
;
1886 func
=TOK___floatdisf
;
1887 #if LDOUBLE_SIZE != 8
1888 } else if((t
& VT_BTYPE
) == VT_LDOUBLE
) {
1889 func_type
= &func_ldouble_type
;
1890 if(vtop
->type
.t
& VT_UNSIGNED
)
1891 func
=TOK___floatundixf
;
1893 func
=TOK___floatdixf
;
1894 } else if((t
& VT_BTYPE
) == VT_DOUBLE
) {
1896 } else if((t
& VT_BTYPE
) == VT_DOUBLE
|| (t
& VT_BTYPE
) == VT_LDOUBLE
) {
1898 func_type
= &func_double_type
;
1899 if(vtop
->type
.t
& VT_UNSIGNED
)
1900 func
=TOK___floatundidf
;
1902 func
=TOK___floatdidf
;
1905 vpush_global_sym(func_type
, func
);
1913 tcc_error("unimplemented gen_cvt_itof %x!",vtop
->type
.t
);
1916 /* convert fp to int 't' type */
1917 void gen_cvt_ftoi(int t
)
1923 r2
=vtop
->type
.t
& VT_BTYPE
;
1926 r
=vfpr(gv(RC_FLOAT
));
1928 o(0xEEBC0AC0|(r
<<12)|r
|T2CPR(r2
)|u
); /* ftoXizY */
1929 r2
=intr(vtop
->r
=get_reg(RC_INT
));
1930 o(0xEE100A10|(r
<<16)|(r2
<<12));
1935 func
=TOK___fixunssfsi
;
1936 #if LDOUBLE_SIZE != 8
1937 else if(r2
== VT_LDOUBLE
)
1938 func
=TOK___fixunsxfsi
;
1939 else if(r2
== VT_DOUBLE
)
1941 else if(r2
== VT_LDOUBLE
|| r2
== VT_DOUBLE
)
1943 func
=TOK___fixunsdfsi
;
1945 r
=fpr(gv(RC_FLOAT
));
1946 r2
=intr(vtop
->r
=get_reg(RC_INT
));
1947 o(0xEE100170|(r2
<<12)|r
);
1951 } else if(t
== VT_LLONG
) { // unsigned handled in gen_cvt_ftoi1
1954 #if LDOUBLE_SIZE != 8
1955 else if(r2
== VT_LDOUBLE
)
1957 else if(r2
== VT_DOUBLE
)
1959 else if(r2
== VT_LDOUBLE
|| r2
== VT_DOUBLE
)
1964 vpush_global_sym(&func_old_type
, func
);
1969 vtop
->r2
= REG_LRET
;
1973 tcc_error("unimplemented gen_cvt_ftoi!");
1976 /* convert from one floating point type to another */
1977 void gen_cvt_ftof(int t
)
1980 if(((vtop
->type
.t
& VT_BTYPE
) == VT_FLOAT
) != ((t
& VT_BTYPE
) == VT_FLOAT
)) {
1981 uint32_t r
= vfpr(gv(RC_FLOAT
));
1982 o(0xEEB70AC0|(r
<<12)|r
|T2CPR(vtop
->type
.t
));
1985 /* all we have to do on i386 and FPA ARM is to put the float in a register */
1990 /* computed goto support */
1997 /* end of ARM code generator */
1998 /*************************************************************/
2000 /*************************************************************/