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 align
= (align
+ 3) & ~3;
1206 #ifdef TCC_ARM_HARDFLOAT
1207 if (!variadic
&& (is_float(sym
->type
.t
)
1208 || is_float_hgen_aggr(&sym
->type
))) {
1209 int fpn
= assign_fpreg(&avregs
, align
, size
<< 2);
1218 pn
= (pn
+ (align
-1)/4) & -(align
/4);
1220 addr
= (nf
+ pn
) * 4;
1225 #ifdef TCC_ARM_HARDFLOAT
1229 sn
= (sn
+ (align
-1)/4) & -(align
/4);
1231 addr
= (n
+ nf
+ sn
) * 4;
1234 sym_push(sym
->v
& ~SYM_FIELD
, type
, VT_LOCAL
| lvalue_type(type
->t
), addr
+12);
1242 /* generate function epilog */
1243 void gfunc_epilog(void)
1248 /* Useless but harmless copy of the float result into main register(s) in case
1249 of variadic function in the hardfloat variant */
1250 if(is_float(func_vt
.t
)) {
1251 if((func_vt
.t
& VT_BTYPE
) == VT_FLOAT
)
1252 o(0xEE100A10); /* fmrs r0, s0 */
1254 o(0xEE100B10); /* fmrdl r0, d0 */
1255 o(0xEE301B10); /* fmrdh r1, d0 */
1259 o(0xE89BA800); /* restore fp, sp, pc */
1260 diff
= (-loc
+ 3) & -4;
1263 diff
= ((diff
+ 11) & -8) - 4;
1266 x
=stuff_const(0xE24BD000, diff
); /* sub sp,fp,# */
1268 *(uint32_t *)(cur_text_section
->data
+ func_sub_sp_offset
) = x
;
1272 o(0xE59FC004); /* ldr ip,[pc+4] */
1273 o(0xE04BD00C); /* sub sp,fp,ip */
1274 o(0xE1A0F00E); /* mov pc,lr */
1276 *(uint32_t *)(cur_text_section
->data
+ func_sub_sp_offset
) = 0xE1000000|encbranch(func_sub_sp_offset
,addr
,1);
1281 /* generate a jump to a label */
1286 o(0xE0000000|encbranch(r
,t
,1));
1290 /* generate a jump to a fixed address */
1291 void gjmp_addr(int a
)
1296 /* generate a test. set 'inv' to invert test. Stack entry is popped */
1297 int gtst(int inv
, int t
)
1301 v
= vtop
->r
& VT_VALMASK
;
1304 op
=mapcc(inv
?negcc(vtop
->c
.i
):vtop
->c
.i
);
1305 op
|=encbranch(r
,t
,1);
1308 } else if (v
== VT_JMP
|| v
== VT_JMPI
) {
1309 if ((v
& 1) == inv
) {
1318 p
= decbranch(lp
=p
);
1320 x
= (uint32_t *)(cur_text_section
->data
+ lp
);
1322 *x
|= encbranch(lp
,t
,1);
1331 if (is_float(vtop
->type
.t
)) {
1334 o(0xEEB50A40|(vfpr(r
)<<12)|T2CPR(vtop
->type
.t
)); /* fcmpzX */
1335 o(0xEEF1FA10); /* fmstat */
1337 o(0xEE90F118|(fpr(r
)<<16));
1341 return gtst(inv
, t
);
1342 } else if ((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1343 /* constant jmp optimization */
1344 if ((vtop
->c
.i
!= 0) != inv
)
1348 o(0xE3300000|(intr(v
)<<16));
1351 return gtst(inv
, t
);
1358 /* generate an integer binary operation */
1359 void gen_opi(int op
)
1362 uint32_t opc
= 0, r
, fr
;
1363 unsigned short retreg
= REG_IRET
;
1371 case TOK_ADDC1
: /* add with carry generation */
1379 case TOK_SUBC1
: /* sub with carry generation */
1383 case TOK_ADDC2
: /* add with carry use */
1387 case TOK_SUBC2
: /* sub with carry use */
1404 gv2(RC_INT
, RC_INT
);
1408 o(0xE0000090|(intr(r
)<<16)|(intr(r
)<<8)|intr(fr
));
1433 func
=TOK___aeabi_idivmod
;
1442 func
=TOK___aeabi_uidivmod
;
1450 gv2(RC_INT
, RC_INT
);
1451 r
=intr(vtop
[-1].r2
=get_reg(RC_INT
));
1453 vtop
[-1].r
=get_reg_ex(RC_INT
,regmask(c
));
1455 o(0xE0800090|(r
<<16)|(intr(vtop
->r
)<<12)|(intr(c
)<<8)|intr(vtop
[1].r
));
1464 if((vtop
[-1].r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1465 if(opc
== 4 || opc
== 5 || opc
== 0xc) {
1467 opc
|=2; // sub -> rsb
1470 if ((vtop
->r
& VT_VALMASK
) == VT_CMP
||
1471 (vtop
->r
& (VT_VALMASK
& ~1)) == VT_JMP
)
1476 opc
=0xE0000000|(opc
<<20)|(c
<<16);
1477 if((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1479 x
=stuff_const(opc
|0x2000000,vtop
->c
.i
);
1481 r
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,regmask(vtop
[-1].r
)));
1486 fr
=intr(gv(RC_INT
));
1487 r
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,two2mask(vtop
->r
,vtop
[-1].r
)));
1491 if (op
>= TOK_ULT
&& op
<= TOK_GT
) {
1497 opc
=0xE1A00000|(opc
<<5);
1498 if ((vtop
->r
& VT_VALMASK
) == VT_CMP
||
1499 (vtop
->r
& (VT_VALMASK
& ~1)) == VT_JMP
)
1505 if ((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1506 fr
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,regmask(vtop
[-1].r
)));
1507 c
= vtop
->c
.i
& 0x1f;
1508 o(opc
|(c
<<7)|(fr
<<12));
1510 fr
=intr(gv(RC_INT
));
1511 c
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,two2mask(vtop
->r
,vtop
[-1].r
)));
1512 o(opc
|(c
<<12)|(fr
<<8)|0x10);
1517 vpush_global_sym(&func_old_type
, func
);
1524 tcc_error("gen_opi %i unimplemented!",op
);
1529 static int is_zero(int i
)
1531 if((vtop
[i
].r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) != VT_CONST
)
1533 if (vtop
[i
].type
.t
== VT_FLOAT
)
1534 return (vtop
[i
].c
.f
== 0.f
);
1535 else if (vtop
[i
].type
.t
== VT_DOUBLE
)
1536 return (vtop
[i
].c
.d
== 0.0);
1537 return (vtop
[i
].c
.ld
== 0.l
);
1540 /* generate a floating point operation 'v = t1 op t2' instruction. The
1541 * two operands are guaranted to have the same floating point type */
1542 void gen_opf(int op
)
1546 x
=0xEE000A00|T2CPR(vtop
->type
.t
);
1564 x
|=0x810000; /* fsubX -> fnegX */
1577 if(op
< TOK_ULT
|| op
> TOK_GT
) {
1578 tcc_error("unknown fp op %x!",op
);
1584 case TOK_LT
: op
=TOK_GT
; break;
1585 case TOK_GE
: op
=TOK_ULE
; break;
1586 case TOK_LE
: op
=TOK_GE
; break;
1587 case TOK_GT
: op
=TOK_ULT
; break;
1590 x
|=0xB40040; /* fcmpX */
1591 if(op
!=TOK_EQ
&& op
!=TOK_NE
)
1592 x
|=0x80; /* fcmpX -> fcmpeX */
1595 o(x
|0x10000|(vfpr(gv(RC_FLOAT
))<<12)); /* fcmp(e)X -> fcmp(e)zX */
1597 x
|=vfpr(gv(RC_FLOAT
));
1599 o(x
|(vfpr(gv(RC_FLOAT
))<<12));
1602 o(0xEEF1FA10); /* fmstat */
1605 case TOK_LE
: op
=TOK_ULE
; break;
1606 case TOK_LT
: op
=TOK_ULT
; break;
1607 case TOK_UGE
: op
=TOK_GE
; break;
1608 case TOK_UGT
: op
=TOK_GT
; break;
1625 vtop
->r
=get_reg_ex(RC_FLOAT
,r
);
1628 o(x
|(vfpr(vtop
->r
)<<12));
1632 static uint32_t is_fconst()
1636 if((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) != VT_CONST
)
1638 if (vtop
->type
.t
== VT_FLOAT
)
1640 else if (vtop
->type
.t
== VT_DOUBLE
)
1670 /* generate a floating point operation 'v = t1 op t2' instruction. The
1671 two operands are guaranted to have the same floating point type */
1672 void gen_opf(int op
)
1674 uint32_t x
, r
, r2
, c1
, c2
;
1675 //fputs("gen_opf\n",stderr);
1681 #if LDOUBLE_SIZE == 8
1682 if ((vtop
->type
.t
& VT_BTYPE
) != VT_FLOAT
)
1685 if ((vtop
->type
.t
& VT_BTYPE
) == VT_DOUBLE
)
1687 else if ((vtop
->type
.t
& VT_BTYPE
) == VT_LDOUBLE
)
1698 r
=fpr(gv(RC_FLOAT
));
1705 r2
=fpr(gv(RC_FLOAT
));
1714 r
=fpr(gv(RC_FLOAT
));
1716 } else if(c1
&& c1
<=0xf) {
1719 r
=fpr(gv(RC_FLOAT
));
1724 r
=fpr(gv(RC_FLOAT
));
1726 r2
=fpr(gv(RC_FLOAT
));
1735 r
=fpr(gv(RC_FLOAT
));
1740 r2
=fpr(gv(RC_FLOAT
));
1748 r
=fpr(gv(RC_FLOAT
));
1750 } else if(c1
&& c1
<=0xf) {
1753 r
=fpr(gv(RC_FLOAT
));
1758 r
=fpr(gv(RC_FLOAT
));
1760 r2
=fpr(gv(RC_FLOAT
));
1764 if(op
>= TOK_ULT
&& op
<= TOK_GT
) {
1765 x
|=0xd0f110; // cmfe
1766 /* bug (intention?) in Linux FPU emulator
1767 doesn't set carry if equal */
1773 tcc_error("unsigned comparision on floats?");
1779 op
=TOK_ULE
; /* correct in unordered case only if AC bit in FPSR set */
1783 x
&=~0x400000; // cmfe -> cmf
1805 r
=fpr(gv(RC_FLOAT
));
1812 r2
=fpr(gv(RC_FLOAT
));
1814 vtop
[-1].r
= VT_CMP
;
1817 tcc_error("unknown fp op %x!",op
);
1821 if(vtop
[-1].r
== VT_CMP
)
1827 vtop
[-1].r
=get_reg_ex(RC_FLOAT
,two2mask(vtop
[-1].r
,c1
));
1831 o(x
|(r
<<16)|(c1
<<12)|r2
);
1835 /* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
1836 and 'long long' cases. */
1837 ST_FUNC
void gen_cvt_itof1(int t
)
1841 bt
=vtop
->type
.t
& VT_BTYPE
;
1842 if(bt
== VT_INT
|| bt
== VT_SHORT
|| bt
== VT_BYTE
) {
1848 r2
=vfpr(vtop
->r
=get_reg(RC_FLOAT
));
1849 o(0xEE000A10|(r
<<12)|(r2
<<16)); /* fmsr */
1851 if(!(vtop
->type
.t
& VT_UNSIGNED
))
1852 r2
|=0x80; /* fuitoX -> fsituX */
1853 o(0xEEB80A40|r2
|T2CPR(t
)); /* fYitoX*/
1855 r2
=fpr(vtop
->r
=get_reg(RC_FLOAT
));
1856 if((t
& VT_BTYPE
) != VT_FLOAT
)
1857 dsize
=0x80; /* flts -> fltd */
1858 o(0xEE000110|dsize
|(r2
<<16)|(r
<<12)); /* flts */
1859 if((vtop
->type
.t
& (VT_UNSIGNED
|VT_BTYPE
)) == (VT_UNSIGNED
|VT_INT
)) {
1861 o(0xE3500000|(r
<<12)); /* cmp */
1862 r
=fpr(get_reg(RC_FLOAT
));
1863 if(last_itod_magic
) {
1864 off
=ind
+8-last_itod_magic
;
1869 o(0xBD1F0100|(r
<<12)|off
); /* ldflts */
1871 o(0xEA000000); /* b */
1872 last_itod_magic
=ind
;
1873 o(0x4F800000); /* 4294967296.0f */
1875 o(0xBE000100|dsize
|(r2
<<16)|(r2
<<12)|r
); /* adflt */
1879 } else if(bt
== VT_LLONG
) {
1881 CType
*func_type
= 0;
1882 if((t
& VT_BTYPE
) == VT_FLOAT
) {
1883 func_type
= &func_float_type
;
1884 if(vtop
->type
.t
& VT_UNSIGNED
)
1885 func
=TOK___floatundisf
;
1887 func
=TOK___floatdisf
;
1888 #if LDOUBLE_SIZE != 8
1889 } else if((t
& VT_BTYPE
) == VT_LDOUBLE
) {
1890 func_type
= &func_ldouble_type
;
1891 if(vtop
->type
.t
& VT_UNSIGNED
)
1892 func
=TOK___floatundixf
;
1894 func
=TOK___floatdixf
;
1895 } else if((t
& VT_BTYPE
) == VT_DOUBLE
) {
1897 } else if((t
& VT_BTYPE
) == VT_DOUBLE
|| (t
& VT_BTYPE
) == VT_LDOUBLE
) {
1899 func_type
= &func_double_type
;
1900 if(vtop
->type
.t
& VT_UNSIGNED
)
1901 func
=TOK___floatundidf
;
1903 func
=TOK___floatdidf
;
1906 vpush_global_sym(func_type
, func
);
1914 tcc_error("unimplemented gen_cvt_itof %x!",vtop
->type
.t
);
1917 /* convert fp to int 't' type */
1918 void gen_cvt_ftoi(int t
)
1924 r2
=vtop
->type
.t
& VT_BTYPE
;
1927 r
=vfpr(gv(RC_FLOAT
));
1929 o(0xEEBC0AC0|(r
<<12)|r
|T2CPR(r2
)|u
); /* ftoXizY */
1930 r2
=intr(vtop
->r
=get_reg(RC_INT
));
1931 o(0xEE100A10|(r
<<16)|(r2
<<12));
1936 func
=TOK___fixunssfsi
;
1937 #if LDOUBLE_SIZE != 8
1938 else if(r2
== VT_LDOUBLE
)
1939 func
=TOK___fixunsxfsi
;
1940 else if(r2
== VT_DOUBLE
)
1942 else if(r2
== VT_LDOUBLE
|| r2
== VT_DOUBLE
)
1944 func
=TOK___fixunsdfsi
;
1946 r
=fpr(gv(RC_FLOAT
));
1947 r2
=intr(vtop
->r
=get_reg(RC_INT
));
1948 o(0xEE100170|(r2
<<12)|r
);
1952 } else if(t
== VT_LLONG
) { // unsigned handled in gen_cvt_ftoi1
1955 #if LDOUBLE_SIZE != 8
1956 else if(r2
== VT_LDOUBLE
)
1958 else if(r2
== VT_DOUBLE
)
1960 else if(r2
== VT_LDOUBLE
|| r2
== VT_DOUBLE
)
1965 vpush_global_sym(&func_old_type
, func
);
1970 vtop
->r2
= REG_LRET
;
1974 tcc_error("unimplemented gen_cvt_ftoi!");
1977 /* convert from one floating point type to another */
1978 void gen_cvt_ftof(int t
)
1981 if(((vtop
->type
.t
& VT_BTYPE
) == VT_FLOAT
) != ((t
& VT_BTYPE
) == VT_FLOAT
)) {
1982 uint32_t r
= vfpr(gv(RC_FLOAT
));
1983 o(0xEEB70AC0|(r
<<12)|r
|T2CPR(vtop
->type
.t
));
1986 /* all we have to do on i386 and FPA ARM is to put the float in a register */
1991 /* computed goto support */
1998 /* end of ARM code generator */
1999 /*************************************************************/
2001 /*************************************************************/