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
26 #if defined(TCC_ARM_EABI) && !defined(TCC_ARM_VFP)
27 #error "Currently TinyCC only supports float computation with VFP instructions"
30 /* number of available registers */
37 #ifndef TCC_ARM_VERSION
38 # define TCC_ARM_VERSION 5
41 /* a register can belong to several classes. The classes must be
42 sorted from more general to more precise (see gv2() code which does
43 assumptions on it). */
44 #define RC_INT 0x0001 /* generic integer register */
45 #define RC_FLOAT 0x0002 /* generic float register */
61 #define RC_IRET RC_R0 /* function return: integer register */
62 #define RC_LRET RC_R1 /* function return: second integer register */
63 #define RC_FRET RC_F0 /* function return: float register */
65 /* pretty names for the registers */
85 #define T2CPR(t) (((t) & VT_BTYPE) != VT_FLOAT ? 0x100 : 0)
88 /* return registers for function */
89 #define REG_IRET TREG_R0 /* single word int return register */
90 #define REG_LRET TREG_R1 /* second word return register (for long long) */
91 #define REG_FRET TREG_F0 /* float return register */
94 #define TOK___divdi3 TOK___aeabi_ldivmod
95 #define TOK___moddi3 TOK___aeabi_ldivmod
96 #define TOK___udivdi3 TOK___aeabi_uldivmod
97 #define TOK___umoddi3 TOK___aeabi_uldivmod
100 /* defined if function parameters must be evaluated in reverse order */
101 #define INVERT_FUNC_PARAMS
103 /* defined if structures are passed as pointers. Otherwise structures
104 are directly pushed on stack. */
105 /* #define FUNC_STRUCT_PARAM_AS_PTR */
107 /* pointer size, in bytes */
110 /* long double size and alignment, in bytes */
112 #define LDOUBLE_SIZE 8
116 #define LDOUBLE_SIZE 8
120 #define LDOUBLE_ALIGN 8
122 #define LDOUBLE_ALIGN 4
125 /* maximum alignment (for aligned attribute support) */
128 #define CHAR_IS_UNSIGNED
130 /******************************************************/
133 #define EM_TCC_TARGET EM_ARM
135 /* relocation type for 32 bit data relocation */
136 #define R_DATA_32 R_ARM_ABS32
137 #define R_DATA_PTR R_ARM_ABS32
138 #define R_JMP_SLOT R_ARM_JUMP_SLOT
139 #define R_COPY R_ARM_COPY
141 #define ELF_START_ADDR 0x00008000
142 #define ELF_PAGE_SIZE 0x1000
149 /******************************************************/
150 #else /* ! TARGET_DEFS_ONLY */
151 /******************************************************/
154 enum float_abi float_abi
;
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 static int func_sub_sp_offset
, last_itod_magic
;
177 #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
178 static CType float_type
, double_type
, func_float_type
, func_double_type
;
179 ST_FUNC
void arm_init(struct TCCState
*s
)
181 float_type
.t
= VT_FLOAT
;
182 double_type
.t
= VT_DOUBLE
;
183 func_float_type
.t
= VT_FUNC
;
184 func_float_type
.ref
= sym_push(SYM_FIELD
, &float_type
, FUNC_CDECL
, FUNC_OLD
);
185 func_double_type
.t
= VT_FUNC
;
186 func_double_type
.ref
= sym_push(SYM_FIELD
, &double_type
, FUNC_CDECL
, FUNC_OLD
);
188 float_abi
= s
->float_abi
;
191 #define func_float_type func_old_type
192 #define func_double_type func_old_type
193 #define func_ldouble_type func_old_type
194 ST_FUNC
void arm_init(struct TCCState
*s
)
196 #if !defined (TCC_ARM_VFP)
197 tcc_warning("Support for FPA is deprecated and will be removed in next"
200 #if !defined (TCC_ARM_EABI)
201 tcc_warning("Support for OABI is deprecated and will be removed in next"
207 static int two2mask(int a
,int b
) {
208 return (reg_classes
[a
]|reg_classes
[b
])&~(RC_INT
|RC_FLOAT
);
211 static int regmask(int r
) {
212 return reg_classes
[r
]&~(RC_INT
|RC_FLOAT
);
215 /******************************************************/
218 char *default_elfinterp(struct TCCState
*s
)
220 if (s
->float_abi
== ARM_HARD_FLOAT
)
221 return "/lib/ld-linux-armhf.so.3";
223 return "/lib/ld-linux.so.3";
229 /* this is a good place to start adding big-endian support*/
233 if (!cur_text_section
)
234 tcc_error("compiler error! This happens f.ex. if the compiler\n"
235 "can't evaluate constant expressions outside of a function.");
236 if (ind1
> cur_text_section
->data_allocated
)
237 section_realloc(cur_text_section
, ind1
);
238 cur_text_section
->data
[ind
++] = i
&255;
240 cur_text_section
->data
[ind
++] = i
&255;
242 cur_text_section
->data
[ind
++] = i
&255;
244 cur_text_section
->data
[ind
++] = i
;
247 static uint32_t stuff_const(uint32_t op
, uint32_t c
)
250 uint32_t nc
= 0, negop
= 0;
260 case 0x1A00000: //mov
261 case 0x1E00000: //mvn
268 return (op
&0xF010F000)|((op
>>16)&0xF)|0x1E00000;
272 return (op
&0xF010F000)|((op
>>16)&0xF)|0x1A00000;
273 case 0x1C00000: //bic
278 case 0x1800000: //orr
280 return (op
&0xFFF0FFFF)|0x1E00000;
286 if(c
<256) /* catch undefined <<32 */
289 m
=(0xff>>i
)|(0xff<<(32-i
));
291 return op
|(i
<<7)|(c
<<i
)|(c
>>(32-i
));
301 void stuff_const_harder(uint32_t op
, uint32_t v
) {
307 uint32_t a
[16], nv
, no
, o2
, n2
;
310 o2
=(op
&0xfff0ffff)|((op
&0xf000)<<4);;
312 a
[i
]=(a
[i
-1]>>2)|(a
[i
-1]<<30);
314 for(j
=i
<4?i
+12:15;j
>=i
+4;j
--)
315 if((v
&(a
[i
]|a
[j
]))==v
) {
316 o(stuff_const(op
,v
&a
[i
]));
317 o(stuff_const(o2
,v
&a
[j
]));
324 for(j
=i
<4?i
+12:15;j
>=i
+4;j
--)
325 if((nv
&(a
[i
]|a
[j
]))==nv
) {
326 o(stuff_const(no
,nv
&a
[i
]));
327 o(stuff_const(n2
,nv
&a
[j
]));
332 for(k
=i
<4?i
+12:15;k
>=j
+4;k
--)
333 if((v
&(a
[i
]|a
[j
]|a
[k
]))==v
) {
334 o(stuff_const(op
,v
&a
[i
]));
335 o(stuff_const(o2
,v
&a
[j
]));
336 o(stuff_const(o2
,v
&a
[k
]));
343 for(k
=i
<4?i
+12:15;k
>=j
+4;k
--)
344 if((nv
&(a
[i
]|a
[j
]|a
[k
]))==nv
) {
345 o(stuff_const(no
,nv
&a
[i
]));
346 o(stuff_const(n2
,nv
&a
[j
]));
347 o(stuff_const(n2
,nv
&a
[k
]));
350 o(stuff_const(op
,v
&a
[0]));
351 o(stuff_const(o2
,v
&a
[4]));
352 o(stuff_const(o2
,v
&a
[8]));
353 o(stuff_const(o2
,v
&a
[12]));
357 ST_FUNC
uint32_t encbranch(int pos
, int addr
, int fail
)
361 if(addr
>=0x1000000 || addr
<-0x1000000) {
363 tcc_error("FIXME: function bigger than 32MB");
366 return 0x0A000000|(addr
&0xffffff);
369 int decbranch(int pos
)
372 x
=*(uint32_t *)(cur_text_section
->data
+ pos
);
379 /* output a symbol and patch all calls to it */
380 void gsym_addr(int t
, int a
)
385 x
=(uint32_t *)(cur_text_section
->data
+ t
);
388 *x
=0xE1A00000; // nop
391 *x
|= encbranch(lt
,a
,1);
402 static uint32_t vfpr(int r
)
404 if(r
<TREG_F0
|| r
>TREG_F7
)
405 tcc_error("compiler error! register %i is no vfp register",r
);
409 static uint32_t fpr(int r
)
411 if(r
<TREG_F0
|| r
>TREG_F3
)
412 tcc_error("compiler error! register %i is no fpa register",r
);
417 static uint32_t intr(int r
)
421 if((r
<0 || r
>4) && r
!=14)
422 tcc_error("compiler error! register %i is no int register",r
);
426 static void calcaddr(uint32_t *base
, int *off
, int *sgn
, int maxoff
, unsigned shift
)
428 if(*off
>maxoff
|| *off
&((1<<shift
)-1)) {
435 y
=stuff_const(x
,*off
&~maxoff
);
441 y
=stuff_const(x
,(*off
+maxoff
)&~maxoff
);
445 *off
=((*off
+maxoff
)&~maxoff
)-*off
;
448 stuff_const_harder(x
,*off
&~maxoff
);
453 static uint32_t mapcc(int cc
)
458 return 0x30000000; /* CC/LO */
460 return 0x20000000; /* CS/HS */
462 return 0x00000000; /* EQ */
464 return 0x10000000; /* NE */
466 return 0x90000000; /* LS */
468 return 0x80000000; /* HI */
470 return 0x40000000; /* MI */
472 return 0x50000000; /* PL */
474 return 0xB0000000; /* LT */
476 return 0xA0000000; /* GE */
478 return 0xD0000000; /* LE */
480 return 0xC0000000; /* GT */
482 tcc_error("unexpected condition code");
483 return 0xE0000000; /* AL */
486 static int negcc(int cc
)
515 tcc_error("unexpected condition code");
519 /* load 'r' from value 'sv' */
520 void load(int r
, SValue
*sv
)
522 int v
, ft
, fc
, fr
, sign
;
539 uint32_t base
= 0xB; // fp
542 v1
.r
= VT_LOCAL
| VT_LVAL
;
544 load(base
=14 /* lr */, &v1
);
547 } else if(v
== VT_CONST
) {
555 } else if(v
< VT_CONST
) {
562 calcaddr(&base
,&fc
,&sign
,1020,2);
564 op
=0xED100A00; /* flds */
567 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
568 op
|=0x100; /* flds -> fldd */
569 o(op
|(vfpr(r
)<<12)|(fc
>>2)|(base
<<16));
574 #if LDOUBLE_SIZE == 8
575 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
578 if ((ft
& VT_BTYPE
) == VT_DOUBLE
)
580 else if ((ft
& VT_BTYPE
) == VT_LDOUBLE
)
583 o(op
|(fpr(r
)<<12)|(fc
>>2)|(base
<<16));
585 } else if((ft
& (VT_BTYPE
|VT_UNSIGNED
)) == VT_BYTE
586 || (ft
& VT_BTYPE
) == VT_SHORT
) {
587 calcaddr(&base
,&fc
,&sign
,255,0);
589 if ((ft
& VT_BTYPE
) == VT_SHORT
)
591 if ((ft
& VT_UNSIGNED
) == 0)
595 o(op
|(intr(r
)<<12)|(base
<<16)|((fc
&0xf0)<<4)|(fc
&0xf));
597 calcaddr(&base
,&fc
,&sign
,4095,0);
601 if ((ft
& VT_BTYPE
) == VT_BYTE
|| (ft
& VT_BTYPE
) == VT_BOOL
)
603 o(op
|(intr(r
)<<12)|fc
|(base
<<16));
609 op
=stuff_const(0xE3A00000|(intr(r
)<<12),sv
->c
.ul
);
610 if (fr
& VT_SYM
|| !op
) {
611 o(0xE59F0000|(intr(r
)<<12));
614 greloc(cur_text_section
, sv
->sym
, ind
, R_ARM_ABS32
);
619 } else if (v
== VT_LOCAL
) {
620 op
=stuff_const(0xE28B0000|(intr(r
)<<12),sv
->c
.ul
);
621 if (fr
& VT_SYM
|| !op
) {
622 o(0xE59F0000|(intr(r
)<<12));
624 if(fr
& VT_SYM
) // needed ?
625 greloc(cur_text_section
, sv
->sym
, ind
, R_ARM_ABS32
);
627 o(0xE08B0000|(intr(r
)<<12)|intr(r
));
631 } else if(v
== VT_CMP
) {
632 o(mapcc(sv
->c
.ul
)|0x3A00001|(intr(r
)<<12));
633 o(mapcc(negcc(sv
->c
.ul
))|0x3A00000|(intr(r
)<<12));
635 } else if (v
== VT_JMP
|| v
== VT_JMPI
) {
638 o(0xE3A00000|(intr(r
)<<12)|t
);
641 o(0xE3A00000|(intr(r
)<<12)|(t
^1));
643 } else if (v
< VT_CONST
) {
646 o(0xEEB00A40|(vfpr(r
)<<12)|vfpr(v
)|T2CPR(ft
)); /* fcpyX */
648 o(0xEE008180|(fpr(r
)<<12)|fpr(v
));
651 o(0xE1A00000|(intr(r
)<<12)|intr(v
));
655 tcc_error("load unimplemented!");
658 /* store register 'r' in lvalue 'v' */
659 void store(int r
, SValue
*sv
)
662 int v
, ft
, fc
, fr
, sign
;
677 if (fr
& VT_LVAL
|| fr
== VT_LOCAL
) {
683 } else if(v
== VT_CONST
) {
694 calcaddr(&base
,&fc
,&sign
,1020,2);
696 op
=0xED000A00; /* fsts */
699 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
700 op
|=0x100; /* fsts -> fstd */
701 o(op
|(vfpr(r
)<<12)|(fc
>>2)|(base
<<16));
706 #if LDOUBLE_SIZE == 8
707 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
710 if ((ft
& VT_BTYPE
) == VT_DOUBLE
)
712 if ((ft
& VT_BTYPE
) == VT_LDOUBLE
)
715 o(op
|(fpr(r
)<<12)|(fc
>>2)|(base
<<16));
718 } else if((ft
& VT_BTYPE
) == VT_SHORT
) {
719 calcaddr(&base
,&fc
,&sign
,255,0);
723 o(op
|(intr(r
)<<12)|(base
<<16)|((fc
&0xf0)<<4)|(fc
&0xf));
725 calcaddr(&base
,&fc
,&sign
,4095,0);
729 if ((ft
& VT_BTYPE
) == VT_BYTE
|| (ft
& VT_BTYPE
) == VT_BOOL
)
731 o(op
|(intr(r
)<<12)|fc
|(base
<<16));
736 tcc_error("store unimplemented");
739 static void gadd_sp(int val
)
741 stuff_const_harder(0xE28DD000,val
);
744 /* 'is_jmp' is '1' if it is a jump */
745 static void gcall_or_jmp(int is_jmp
)
748 if ((vtop
->r
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
) {
751 x
=encbranch(ind
,ind
+vtop
->c
.ul
,0);
753 if (vtop
->r
& VT_SYM
) {
754 /* relocation case */
755 greloc(cur_text_section
, vtop
->sym
, ind
, R_ARM_PC24
);
757 put_elf_reloc(symtab_section
, cur_text_section
, ind
, R_ARM_PC24
, 0);
758 o(x
|(is_jmp
?0xE0000000:0xE1000000));
761 o(0xE28FE004); // add lr,pc,#4
762 o(0xE51FF004); // ldr pc,[pc,#-4]
763 if (vtop
->r
& VT_SYM
)
764 greloc(cur_text_section
, vtop
->sym
, ind
, R_ARM_ABS32
);
768 /* otherwise, indirect call */
771 o(0xE1A0E00F); // mov lr,pc
772 o(0xE1A0F000|intr(r
)); // mov pc,r
776 /* Return whether a structure is an homogeneous float aggregate or not.
777 The answer is true if all the elements of the structure are of the same
778 primitive float type and there is less than 4 elements.
780 type: the type corresponding to the structure to be tested */
781 static int is_hgen_float_aggr(CType
*type
)
783 if ((type
->t
& VT_BTYPE
) == VT_STRUCT
) {
785 int btype
, nb_fields
= 0;
787 ref
= type
->ref
->next
;
788 btype
= ref
->type
.t
& VT_BTYPE
;
789 if (btype
== VT_FLOAT
|| btype
== VT_DOUBLE
) {
790 for(; ref
&& btype
== (ref
->type
.t
& VT_BTYPE
); ref
= ref
->next
, nb_fields
++);
791 return !ref
&& nb_fields
<= 4;
798 signed char avail
[3]; /* 3 holes max with only float and double alignments */
799 int first_hole
; /* first available hole */
800 int last_hole
; /* last available hole (none if equal to first_hole) */
801 int first_free_reg
; /* next free register in the sequence, hole excluded */
804 #define AVAIL_REGS_INITIALIZER (struct avail_regs) { { 0, 0, 0}, 0, 0, 0 }
806 /* Find suitable registers for a VFP Co-Processor Register Candidate (VFP CPRC
807 param) according to the rules described in the procedure call standard for
808 the ARM architecture (AAPCS). If found, the registers are assigned to this
809 VFP CPRC parameter. Registers are allocated in sequence unless a hole exists
810 and the parameter is a single float.
812 avregs: opaque structure to keep track of available VFP co-processor regs
813 align: alignment contraints for the param, as returned by type_size()
814 size: size of the parameter, as returned by type_size() */
815 int assign_vfpreg(struct avail_regs
*avregs
, int align
, int size
)
819 if (avregs
->first_free_reg
== -1)
821 if (align
>> 3) { /* double alignment */
822 first_reg
= avregs
->first_free_reg
;
823 /* alignment contraint not respected so use next reg and record hole */
825 avregs
->avail
[avregs
->last_hole
++] = first_reg
++;
826 } else { /* no special alignment (float or array of float) */
827 /* if single float and a hole is available, assign the param to it */
828 if (size
== 4 && avregs
->first_hole
!= avregs
->last_hole
)
829 return avregs
->avail
[avregs
->first_hole
++];
831 first_reg
= avregs
->first_free_reg
;
833 if (first_reg
+ size
/ 4 <= 16) {
834 avregs
->first_free_reg
= first_reg
+ size
/ 4;
837 avregs
->first_free_reg
= -1;
841 /* Returns whether all params need to be passed in core registers or not.
842 This is the case for function part of the runtime ABI. */
843 int floats_in_core_regs(SValue
*sval
)
848 switch (sval
->sym
->v
) {
849 case TOK___floatundisf
:
850 case TOK___floatundidf
:
851 case TOK___fixunssfdi
:
852 case TOK___fixunsdfdi
:
854 case TOK___fixunsxfdi
:
856 case TOK___floatdisf
:
857 case TOK___floatdidf
:
867 /* Return the number of registers needed to return the struct, or 0 if
868 returning via struct pointer. */
869 ST_FUNC
int gfunc_sret(CType
*vt
, int variadic
, CType
*ret
, int *ret_align
) {
872 size
= type_size(vt
, &align
);
873 if (float_abi
== ARM_HARD_FLOAT
&& !variadic
&&
874 (is_float(vt
->t
) || is_hgen_float_aggr(vt
))) {
878 return (size
+ 7) >> 3;
879 } else if (size
<= 4) {
891 /* Parameters are classified according to how they are copied to their final
892 destination for the function call. Because the copying is performed class
893 after class according to the order in the union below, it is important that
894 some constraints about the order of the members of this union are respected:
895 - CORE_STRUCT_CLASS must come after STACK_CLASS;
896 - CORE_CLASS must come after STACK_CLASS, CORE_STRUCT_CLASS and
898 - VFP_STRUCT_CLASS must come after VFP_CLASS.
899 See the comment for the main loop in copy_params() for the reason. */
910 int start
; /* first reg or addr used depending on the class */
911 int end
; /* last reg used or next free addr depending on the class */
912 SValue
*sval
; /* pointer to SValue on the value stack */
913 struct param_plan
*prev
; /* previous element in this class */
917 struct param_plan
*pplans
; /* array of all the param plans */
918 struct param_plan
*clsplans
[NB_CLASSES
]; /* per class lists of param plans */
921 #define add_param_plan(plan,pplan,class) \
923 pplan.prev = plan->clsplans[class]; \
924 plan->pplans[plan ## _nb] = pplan; \
925 plan->clsplans[class] = &plan->pplans[plan ## _nb++]; \
928 /* Assign parameters to registers and stack with alignment according to the
929 rules in the procedure call standard for the ARM architecture (AAPCS).
930 The overall assignment is recorded in an array of per parameter structures
931 called parameter plans. The parameter plans are also further organized in a
932 number of linked lists, one per class of parameter (see the comment for the
933 definition of union reg_class).
935 nb_args: number of parameters of the function for which a call is generated
936 float_abi: float ABI in use for this function call
937 plan: the structure where the overall assignment is recorded
938 todo: a bitmap that record which core registers hold a parameter
940 Returns the amount of stack space needed for parameter passing
942 Note: this function allocated an array in plan->pplans with tcc_malloc. It
943 is the responsability of the caller to free this array once used (ie not
944 before copy_params). */
945 static int assign_regs(int nb_args
, int float_abi
, struct plan
*plan
, int *todo
)
948 int ncrn
/* next core register number */, nsaa
/* next stacked argument address*/;
950 struct param_plan pplan
;
951 struct avail_regs avregs
= AVAIL_REGS_INITIALIZER
;
955 plan
->pplans
= tcc_malloc(nb_args
* sizeof(*plan
->pplans
));
956 memset(plan
->clsplans
, 0, sizeof(plan
->clsplans
));
957 for(i
= nb_args
; i
-- ;) {
958 int j
, start_vfpreg
= 0;
959 size
= type_size(&vtop
[-i
].type
, &align
);
960 size
= (size
+ 3) & ~3;
961 align
= (align
+ 3) & ~3;
962 switch(vtop
[-i
].type
.t
& VT_BTYPE
) {
967 if (float_abi
== ARM_HARD_FLOAT
) {
968 int is_hfa
= 0; /* Homogeneous float aggregate */
970 if (is_float(vtop
[-i
].type
.t
)
971 || (is_hfa
= is_hgen_float_aggr(&vtop
[-i
].type
))) {
974 start_vfpreg
= assign_vfpreg(&avregs
, align
, size
);
975 end_vfpreg
= start_vfpreg
+ ((size
- 1) >> 2);
976 if (start_vfpreg
>= 0) {
977 pplan
= (struct param_plan
) {start_vfpreg
, end_vfpreg
, &vtop
[-i
]};
979 add_param_plan(plan
, pplan
, VFP_STRUCT_CLASS
);
981 add_param_plan(plan
, pplan
, VFP_CLASS
);
987 ncrn
= (ncrn
+ (align
-1)/4) & ~((align
/4) - 1);
988 if (ncrn
+ size
/4 <= 4 || (ncrn
< 4 && start_vfpreg
!= -1)) {
989 /* The parameter is allocated both in core register and on stack. As
990 * such, it can be of either class: it would either be the last of
991 * CORE_STRUCT_CLASS or the first of STACK_CLASS. */
992 for (j
= ncrn
; j
< 4 && j
< ncrn
+ size
/ 4; j
++)
994 pplan
= (struct param_plan
) {ncrn
, j
, &vtop
[-i
]};
995 add_param_plan(plan
, pplan
, CORE_STRUCT_CLASS
);
998 nsaa
= (ncrn
- 4) * 4;
1006 int is_long
= (vtop
[-i
].type
.t
& VT_BTYPE
) == VT_LLONG
;
1009 ncrn
= (ncrn
+ 1) & -2;
1013 pplan
= (struct param_plan
) {ncrn
, ncrn
, &vtop
[-i
]};
1017 add_param_plan(plan
, pplan
, CORE_CLASS
);
1021 nsaa
= (nsaa
+ (align
- 1)) & ~(align
- 1);
1022 pplan
= (struct param_plan
) {nsaa
, nsaa
+ size
, &vtop
[-i
]};
1023 add_param_plan(plan
, pplan
, STACK_CLASS
);
1024 nsaa
+= size
; /* size already rounded up before */
1029 #undef add_param_plan
1031 /* Copy parameters to their final destination (core reg, VFP reg or stack) for
1034 nb_args: number of parameters the function take
1035 plan: the overall assignment plan for parameters
1036 todo: a bitmap indicating what core reg will hold a parameter
1038 Returns the number of SValue added by this function on the value stack */
1039 static int copy_params(int nb_args
, struct plan
*plan
, int todo
)
1041 int size
, align
, r
, i
, nb_extra_sval
= 0;
1042 struct param_plan
*pplan
;
1044 /* Several constraints require parameters to be copied in a specific order:
1045 - structures are copied to the stack before being loaded in a reg;
1046 - floats loaded to an odd numbered VFP reg are first copied to the
1047 preceding even numbered VFP reg and then moved to the next VFP reg.
1049 It is thus important that:
1050 - structures assigned to core regs must be copied after parameters
1051 assigned to the stack but before structures assigned to VFP regs because
1052 a structure can lie partly in core registers and partly on the stack;
1053 - parameters assigned to the stack and all structures be copied before
1054 parameters assigned to a core reg since copying a parameter to the stack
1055 require using a core reg;
1056 - parameters assigned to VFP regs be copied before structures assigned to
1057 VFP regs as the copy might use an even numbered VFP reg that already
1058 holds part of a structure. */
1059 for(i
= 0; i
< NB_CLASSES
; i
++) {
1060 for(pplan
= plan
->clsplans
[i
]; pplan
; pplan
= pplan
->prev
) {
1061 vpushv(pplan
->sval
);
1062 pplan
->sval
->r
= pplan
->sval
->r2
= VT_CONST
; /* disable entry */
1065 case CORE_STRUCT_CLASS
:
1066 case VFP_STRUCT_CLASS
:
1067 if ((pplan
->sval
->type
.t
& VT_BTYPE
) == VT_STRUCT
) {
1069 size
= type_size(&pplan
->sval
->type
, &align
);
1070 /* align to stack align size */
1071 size
= (size
+ 3) & ~3;
1072 if (i
== STACK_CLASS
&& pplan
->prev
)
1073 padding
= pplan
->start
- pplan
->prev
->end
;
1074 size
+= padding
; /* Add padding if any */
1075 /* allocate the necessary size on stack */
1077 /* generate structure store */
1078 r
= get_reg(RC_INT
);
1079 o(0xE28D0000|(intr(r
)<<12)|padding
); /* add r, sp, padding */
1080 vset(&vtop
->type
, r
| VT_LVAL
, 0);
1082 vstore(); /* memcpy to current sp + potential padding */
1084 /* Homogeneous float aggregate are loaded to VFP registers
1085 immediately since there is no way of loading data in multiple
1086 non consecutive VFP registers as what is done for other
1087 structures (see the use of todo). */
1088 if (i
== VFP_STRUCT_CLASS
) {
1089 int first
= pplan
->start
, nb
= pplan
->end
- first
+ 1;
1090 /* vpop.32 {pplan->start, ..., pplan->end} */
1091 o(0xECBD0A00|(first
&1)<<22|(first
>>1)<<12|nb
);
1092 /* No need to write the register used to a SValue since VFP regs
1093 cannot be used for gcall_or_jmp */
1096 if (is_float(pplan
->sval
->type
.t
)) {
1098 r
= vfpr(gv(RC_FLOAT
)) << 12;
1099 if ((pplan
->sval
->type
.t
& VT_BTYPE
) == VT_FLOAT
)
1103 r
|= 0x101; /* vpush.32 -> vpush.64 */
1105 o(0xED2D0A01 + r
); /* vpush */
1107 r
= fpr(gv(RC_FLOAT
)) << 12;
1108 if ((pplan
->sval
->type
.t
& VT_BTYPE
) == VT_FLOAT
)
1110 else if ((pplan
->sval
->type
.t
& VT_BTYPE
) == VT_DOUBLE
)
1113 size
= LDOUBLE_SIZE
;
1120 o(0xED2D0100|r
|(size
>>2)); /* some kind of vpush for FPA */
1123 /* simple type (currently always same size) */
1124 /* XXX: implicit cast ? */
1126 if ((pplan
->sval
->type
.t
& VT_BTYPE
) == VT_LLONG
) {
1130 o(0xE52D0004|(intr(r
)<<12)); /* push r */
1134 o(0xE52D0004|(intr(r
)<<12)); /* push r */
1136 if (i
== STACK_CLASS
&& pplan
->prev
)
1137 gadd_sp(pplan
->prev
->end
- pplan
->start
); /* Add padding if any */
1142 gv(regmask(TREG_F0
+ (pplan
->start
>> 1)));
1143 if (pplan
->start
& 1) { /* Must be in upper part of double register */
1144 o(0xEEF00A40|((pplan
->start
>>1)<<12)|(pplan
->start
>>1)); /* vmov.f32 s(n+1), sn */
1145 vtop
->r
= VT_CONST
; /* avoid being saved on stack by gv for next float */
1150 if ((pplan
->sval
->type
.t
& VT_BTYPE
) == VT_LLONG
) {
1152 gv(regmask(pplan
->end
));
1153 pplan
->sval
->r2
= vtop
->r
;
1156 gv(regmask(pplan
->start
));
1157 /* Mark register as used so that gcall_or_jmp use another one
1158 (regs >=4 are free as never used to pass parameters) */
1159 pplan
->sval
->r
= vtop
->r
;
1166 /* Manually free remaining registers since next parameters are loaded
1167 * manually, without the help of gv(int). */
1171 o(0xE8BD0000|todo
); /* pop {todo} */
1172 for(pplan
= plan
->clsplans
[CORE_STRUCT_CLASS
]; pplan
; pplan
= pplan
->prev
) {
1174 pplan
->sval
->r
= pplan
->start
;
1175 /* An SValue can only pin 2 registers at best (r and r2) but a structure
1176 can occupy more than 2 registers. Thus, we need to push on the value
1177 stack some fake parameter to have on SValue for each registers used
1178 by a structure (r2 is not used). */
1179 for (r
= pplan
->start
+ 1; r
<= pplan
->end
; r
++) {
1180 if (todo
& (1 << r
)) {
1188 return nb_extra_sval
;
1191 /* Generate function call. The function address is pushed first, then
1192 all the parameters in call order. This functions pops all the
1193 parameters and the function address. */
1194 void gfunc_call(int nb_args
)
1197 int variadic
, def_float_abi
= float_abi
;
1202 if (float_abi
== ARM_HARD_FLOAT
) {
1203 variadic
= (vtop
[-nb_args
].type
.ref
->c
== FUNC_ELLIPSIS
);
1204 if (variadic
|| floats_in_core_regs(&vtop
[-nb_args
]))
1205 float_abi
= ARM_SOFTFP_FLOAT
;
1208 /* cannot let cpu flags if other instruction are generated. Also avoid leaving
1209 VT_JMP anywhere except on the top of the stack because it would complicate
1210 the code generator. */
1211 r
= vtop
->r
& VT_VALMASK
;
1212 if (r
== VT_CMP
|| (r
& ~1) == VT_JMP
)
1215 args_size
= assign_regs(nb_args
, float_abi
, &plan
, &todo
);
1218 if (args_size
& 7) { /* Stack must be 8 byte aligned at fct call for EABI */
1219 args_size
= (args_size
+ 7) & ~7;
1220 o(0xE24DD004); /* sub sp, sp, #4 */
1224 nb_args
+= copy_params(nb_args
, &plan
, todo
);
1225 tcc_free(plan
.pplans
);
1227 /* Move fct SValue on top as required by gcall_or_jmp */
1231 gadd_sp(args_size
); /* pop all parameters passed on the stack */
1232 #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
1233 if(float_abi
== ARM_SOFTFP_FLOAT
&& is_float(vtop
->type
.ref
->type
.t
)) {
1234 if((vtop
->type
.ref
->type
.t
& VT_BTYPE
) == VT_FLOAT
) {
1235 o(0xEE000A10); /*vmov s0, r0 */
1237 o(0xEE000B10); /* vmov.32 d0[0], r0 */
1238 o(0xEE201B10); /* vmov.32 d0[1], r1 */
1242 vtop
-= nb_args
+ 1; /* Pop all params and fct address from value stack */
1243 leaffunc
= 0; /* we are calling a function, so we aren't in a leaf function */
1244 float_abi
= def_float_abi
;
1247 /* generate function prolog of type 't' */
1248 void gfunc_prolog(CType
*func_type
)
1251 int n
, nf
, size
, align
, struct_ret
= 0;
1252 int addr
, pn
, sn
; /* pn=core, sn=stack */
1253 struct avail_regs avregs
= AVAIL_REGS_INITIALIZER
;
1256 sym
= func_type
->ref
;
1257 func_vt
= sym
->type
;
1258 func_var
= (func_type
->ref
->c
== FUNC_ELLIPSIS
);
1261 if ((func_vt
.t
& VT_BTYPE
) == VT_STRUCT
&&
1262 !gfunc_sret(&func_vt
, func_var
, &ret_type
, &align
))
1266 func_vc
= 12; /* Offset from fp of the place to store the result */
1268 for(sym2
= sym
->next
; sym2
&& (n
< 4 || nf
< 16); sym2
= sym2
->next
) {
1269 size
= type_size(&sym2
->type
, &align
);
1271 if (float_abi
== ARM_HARD_FLOAT
&& !func_var
&&
1272 (is_float(sym2
->type
.t
) || is_hgen_float_aggr(&sym2
->type
))) {
1273 int tmpnf
= assign_vfpreg(&avregs
, align
, size
);
1274 tmpnf
+= (size
+ 3) / 4;
1275 nf
= (tmpnf
> nf
) ? tmpnf
: nf
;
1279 n
+= (size
+ 3) / 4;
1281 o(0xE1A0C00D); /* mov ip,sp */
1290 o(0xE92D0000|((1<<n
)-1)); /* save r0-r4 on stack if needed */
1295 nf
=(nf
+1)&-2; /* nf => HARDFLOAT => EABI */
1296 o(0xED2D0A00|nf
); /* save s0-s15 on stack if needed */
1298 o(0xE92D5800); /* save fp, ip, lr */
1299 o(0xE1A0B00D); /* mov fp, sp */
1300 func_sub_sp_offset
= ind
;
1301 o(0xE1A00000); /* nop, leave space for stack adjustment in epilog */
1304 if (float_abi
== ARM_HARD_FLOAT
) {
1306 avregs
= AVAIL_REGS_INITIALIZER
;
1309 pn
= struct_ret
, sn
= 0;
1310 while ((sym
= sym
->next
)) {
1313 size
= type_size(type
, &align
);
1314 size
= (size
+ 3) >> 2;
1315 align
= (align
+ 3) & ~3;
1317 if (float_abi
== ARM_HARD_FLOAT
&& !func_var
&& (is_float(sym
->type
.t
)
1318 || is_hgen_float_aggr(&sym
->type
))) {
1319 int fpn
= assign_vfpreg(&avregs
, align
, size
<< 2);
1328 pn
= (pn
+ (align
-1)/4) & -(align
/4);
1330 addr
= (nf
+ pn
) * 4;
1337 sn
= (sn
+ (align
-1)/4) & -(align
/4);
1339 addr
= (n
+ nf
+ sn
) * 4;
1342 sym_push(sym
->v
& ~SYM_FIELD
, type
, VT_LOCAL
| lvalue_type(type
->t
),
1350 /* generate function epilog */
1351 void gfunc_epilog(void)
1355 /* Copy float return value to core register if base standard is used and
1356 float computation is made with VFP */
1357 #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
1358 if ((float_abi
== ARM_SOFTFP_FLOAT
|| func_var
) && is_float(func_vt
.t
)) {
1359 if((func_vt
.t
& VT_BTYPE
) == VT_FLOAT
)
1360 o(0xEE100A10); /* fmrs r0, s0 */
1362 o(0xEE100B10); /* fmrdl r0, d0 */
1363 o(0xEE301B10); /* fmrdh r1, d0 */
1367 o(0xE89BA800); /* restore fp, sp, pc */
1368 diff
= (-loc
+ 3) & -4;
1371 diff
= ((diff
+ 11) & -8) - 4;
1374 x
=stuff_const(0xE24BD000, diff
); /* sub sp,fp,# */
1376 *(uint32_t *)(cur_text_section
->data
+ func_sub_sp_offset
) = x
;
1380 o(0xE59FC004); /* ldr ip,[pc+4] */
1381 o(0xE04BD00C); /* sub sp,fp,ip */
1382 o(0xE1A0F00E); /* mov pc,lr */
1384 *(uint32_t *)(cur_text_section
->data
+ func_sub_sp_offset
) = 0xE1000000|encbranch(func_sub_sp_offset
,addr
,1);
1389 /* generate a jump to a label */
1394 o(0xE0000000|encbranch(r
,t
,1));
1398 /* generate a jump to a fixed address */
1399 void gjmp_addr(int a
)
1404 /* generate a test. set 'inv' to invert test. Stack entry is popped */
1405 int gtst(int inv
, int t
)
1409 v
= vtop
->r
& VT_VALMASK
;
1412 op
=mapcc(inv
?negcc(vtop
->c
.i
):vtop
->c
.i
);
1413 op
|=encbranch(r
,t
,1);
1416 } else { /* VT_JMP || VT_JMPI */
1417 if ((v
& 1) == inv
) {
1426 p
= decbranch(lp
=p
);
1428 x
= (uint32_t *)(cur_text_section
->data
+ lp
);
1430 *x
|= encbranch(lp
,t
,1);
1443 /* generate an integer binary operation */
1444 void gen_opi(int op
)
1447 uint32_t opc
= 0, r
, fr
;
1448 unsigned short retreg
= REG_IRET
;
1456 case TOK_ADDC1
: /* add with carry generation */
1464 case TOK_SUBC1
: /* sub with carry generation */
1468 case TOK_ADDC2
: /* add with carry use */
1472 case TOK_SUBC2
: /* sub with carry use */
1489 gv2(RC_INT
, RC_INT
);
1493 o(0xE0000090|(intr(r
)<<16)|(intr(r
)<<8)|intr(fr
));
1518 func
=TOK___aeabi_idivmod
;
1527 func
=TOK___aeabi_uidivmod
;
1535 gv2(RC_INT
, RC_INT
);
1536 r
=intr(vtop
[-1].r2
=get_reg(RC_INT
));
1538 vtop
[-1].r
=get_reg_ex(RC_INT
,regmask(c
));
1540 o(0xE0800090|(r
<<16)|(intr(vtop
->r
)<<12)|(intr(c
)<<8)|intr(vtop
[1].r
));
1549 if((vtop
[-1].r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1550 if(opc
== 4 || opc
== 5 || opc
== 0xc) {
1552 opc
|=2; // sub -> rsb
1555 if ((vtop
->r
& VT_VALMASK
) == VT_CMP
||
1556 (vtop
->r
& (VT_VALMASK
& ~1)) == VT_JMP
)
1561 opc
=0xE0000000|(opc
<<20)|(c
<<16);
1562 if((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1564 x
=stuff_const(opc
|0x2000000,vtop
->c
.i
);
1566 r
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,regmask(vtop
[-1].r
)));
1571 fr
=intr(gv(RC_INT
));
1572 r
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,two2mask(vtop
->r
,vtop
[-1].r
)));
1576 if (op
>= TOK_ULT
&& op
<= TOK_GT
) {
1582 opc
=0xE1A00000|(opc
<<5);
1583 if ((vtop
->r
& VT_VALMASK
) == VT_CMP
||
1584 (vtop
->r
& (VT_VALMASK
& ~1)) == VT_JMP
)
1590 if ((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1591 fr
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,regmask(vtop
[-1].r
)));
1592 c
= vtop
->c
.i
& 0x1f;
1593 o(opc
|(c
<<7)|(fr
<<12));
1595 fr
=intr(gv(RC_INT
));
1596 c
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,two2mask(vtop
->r
,vtop
[-1].r
)));
1597 o(opc
|(c
<<12)|(fr
<<8)|0x10);
1602 vpush_global_sym(&func_old_type
, func
);
1609 tcc_error("gen_opi %i unimplemented!",op
);
1614 static int is_zero(int i
)
1616 if((vtop
[i
].r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) != VT_CONST
)
1618 if (vtop
[i
].type
.t
== VT_FLOAT
)
1619 return (vtop
[i
].c
.f
== 0.f
);
1620 else if (vtop
[i
].type
.t
== VT_DOUBLE
)
1621 return (vtop
[i
].c
.d
== 0.0);
1622 return (vtop
[i
].c
.ld
== 0.l
);
1625 /* generate a floating point operation 'v = t1 op t2' instruction. The
1626 * two operands are guaranted to have the same floating point type */
1627 void gen_opf(int op
)
1631 x
=0xEE000A00|T2CPR(vtop
->type
.t
);
1649 x
|=0x810000; /* fsubX -> fnegX */
1662 if(op
< TOK_ULT
|| op
> TOK_GT
) {
1663 tcc_error("unknown fp op %x!",op
);
1669 case TOK_LT
: op
=TOK_GT
; break;
1670 case TOK_GE
: op
=TOK_ULE
; break;
1671 case TOK_LE
: op
=TOK_GE
; break;
1672 case TOK_GT
: op
=TOK_ULT
; break;
1675 x
|=0xB40040; /* fcmpX */
1676 if(op
!=TOK_EQ
&& op
!=TOK_NE
)
1677 x
|=0x80; /* fcmpX -> fcmpeX */
1680 o(x
|0x10000|(vfpr(gv(RC_FLOAT
))<<12)); /* fcmp(e)X -> fcmp(e)zX */
1682 x
|=vfpr(gv(RC_FLOAT
));
1684 o(x
|(vfpr(gv(RC_FLOAT
))<<12));
1687 o(0xEEF1FA10); /* fmstat */
1690 case TOK_LE
: op
=TOK_ULE
; break;
1691 case TOK_LT
: op
=TOK_ULT
; break;
1692 case TOK_UGE
: op
=TOK_GE
; break;
1693 case TOK_UGT
: op
=TOK_GT
; break;
1710 vtop
->r
=get_reg_ex(RC_FLOAT
,r
);
1713 o(x
|(vfpr(vtop
->r
)<<12));
1717 static uint32_t is_fconst()
1721 if((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) != VT_CONST
)
1723 if (vtop
->type
.t
== VT_FLOAT
)
1725 else if (vtop
->type
.t
== VT_DOUBLE
)
1755 /* generate a floating point operation 'v = t1 op t2' instruction. The
1756 two operands are guaranted to have the same floating point type */
1757 void gen_opf(int op
)
1759 uint32_t x
, r
, r2
, c1
, c2
;
1760 //fputs("gen_opf\n",stderr);
1766 #if LDOUBLE_SIZE == 8
1767 if ((vtop
->type
.t
& VT_BTYPE
) != VT_FLOAT
)
1770 if ((vtop
->type
.t
& VT_BTYPE
) == VT_DOUBLE
)
1772 else if ((vtop
->type
.t
& VT_BTYPE
) == VT_LDOUBLE
)
1783 r
=fpr(gv(RC_FLOAT
));
1790 r2
=fpr(gv(RC_FLOAT
));
1799 r
=fpr(gv(RC_FLOAT
));
1801 } else if(c1
&& c1
<=0xf) {
1804 r
=fpr(gv(RC_FLOAT
));
1809 r
=fpr(gv(RC_FLOAT
));
1811 r2
=fpr(gv(RC_FLOAT
));
1820 r
=fpr(gv(RC_FLOAT
));
1825 r2
=fpr(gv(RC_FLOAT
));
1833 r
=fpr(gv(RC_FLOAT
));
1835 } else if(c1
&& c1
<=0xf) {
1838 r
=fpr(gv(RC_FLOAT
));
1843 r
=fpr(gv(RC_FLOAT
));
1845 r2
=fpr(gv(RC_FLOAT
));
1849 if(op
>= TOK_ULT
&& op
<= TOK_GT
) {
1850 x
|=0xd0f110; // cmfe
1851 /* bug (intention?) in Linux FPU emulator
1852 doesn't set carry if equal */
1858 tcc_error("unsigned comparision on floats?");
1864 op
=TOK_ULE
; /* correct in unordered case only if AC bit in FPSR set */
1868 x
&=~0x400000; // cmfe -> cmf
1890 r
=fpr(gv(RC_FLOAT
));
1897 r2
=fpr(gv(RC_FLOAT
));
1899 vtop
[-1].r
= VT_CMP
;
1902 tcc_error("unknown fp op %x!",op
);
1906 if(vtop
[-1].r
== VT_CMP
)
1912 vtop
[-1].r
=get_reg_ex(RC_FLOAT
,two2mask(vtop
[-1].r
,c1
));
1916 o(x
|(r
<<16)|(c1
<<12)|r2
);
1920 /* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
1921 and 'long long' cases. */
1922 ST_FUNC
void gen_cvt_itof1(int t
)
1926 bt
=vtop
->type
.t
& VT_BTYPE
;
1927 if(bt
== VT_INT
|| bt
== VT_SHORT
|| bt
== VT_BYTE
) {
1933 r2
=vfpr(vtop
->r
=get_reg(RC_FLOAT
));
1934 o(0xEE000A10|(r
<<12)|(r2
<<16)); /* fmsr */
1936 if(!(vtop
->type
.t
& VT_UNSIGNED
))
1937 r2
|=0x80; /* fuitoX -> fsituX */
1938 o(0xEEB80A40|r2
|T2CPR(t
)); /* fYitoX*/
1940 r2
=fpr(vtop
->r
=get_reg(RC_FLOAT
));
1941 if((t
& VT_BTYPE
) != VT_FLOAT
)
1942 dsize
=0x80; /* flts -> fltd */
1943 o(0xEE000110|dsize
|(r2
<<16)|(r
<<12)); /* flts */
1944 if((vtop
->type
.t
& (VT_UNSIGNED
|VT_BTYPE
)) == (VT_UNSIGNED
|VT_INT
)) {
1946 o(0xE3500000|(r
<<12)); /* cmp */
1947 r
=fpr(get_reg(RC_FLOAT
));
1948 if(last_itod_magic
) {
1949 off
=ind
+8-last_itod_magic
;
1954 o(0xBD1F0100|(r
<<12)|off
); /* ldflts */
1956 o(0xEA000000); /* b */
1957 last_itod_magic
=ind
;
1958 o(0x4F800000); /* 4294967296.0f */
1960 o(0xBE000100|dsize
|(r2
<<16)|(r2
<<12)|r
); /* adflt */
1964 } else if(bt
== VT_LLONG
) {
1966 CType
*func_type
= 0;
1967 if((t
& VT_BTYPE
) == VT_FLOAT
) {
1968 func_type
= &func_float_type
;
1969 if(vtop
->type
.t
& VT_UNSIGNED
)
1970 func
=TOK___floatundisf
;
1972 func
=TOK___floatdisf
;
1973 #if LDOUBLE_SIZE != 8
1974 } else if((t
& VT_BTYPE
) == VT_LDOUBLE
) {
1975 func_type
= &func_ldouble_type
;
1976 if(vtop
->type
.t
& VT_UNSIGNED
)
1977 func
=TOK___floatundixf
;
1979 func
=TOK___floatdixf
;
1980 } else if((t
& VT_BTYPE
) == VT_DOUBLE
) {
1982 } else if((t
& VT_BTYPE
) == VT_DOUBLE
|| (t
& VT_BTYPE
) == VT_LDOUBLE
) {
1984 func_type
= &func_double_type
;
1985 if(vtop
->type
.t
& VT_UNSIGNED
)
1986 func
=TOK___floatundidf
;
1988 func
=TOK___floatdidf
;
1991 vpush_global_sym(func_type
, func
);
1999 tcc_error("unimplemented gen_cvt_itof %x!",vtop
->type
.t
);
2002 /* convert fp to int 't' type */
2003 void gen_cvt_ftoi(int t
)
2009 r2
=vtop
->type
.t
& VT_BTYPE
;
2012 r
=vfpr(gv(RC_FLOAT
));
2014 o(0xEEBC0AC0|(r
<<12)|r
|T2CPR(r2
)|u
); /* ftoXizY */
2015 r2
=intr(vtop
->r
=get_reg(RC_INT
));
2016 o(0xEE100A10|(r
<<16)|(r2
<<12));
2021 func
=TOK___fixunssfsi
;
2022 #if LDOUBLE_SIZE != 8
2023 else if(r2
== VT_LDOUBLE
)
2024 func
=TOK___fixunsxfsi
;
2025 else if(r2
== VT_DOUBLE
)
2027 else if(r2
== VT_LDOUBLE
|| r2
== VT_DOUBLE
)
2029 func
=TOK___fixunsdfsi
;
2031 r
=fpr(gv(RC_FLOAT
));
2032 r2
=intr(vtop
->r
=get_reg(RC_INT
));
2033 o(0xEE100170|(r2
<<12)|r
);
2037 } else if(t
== VT_LLONG
) { // unsigned handled in gen_cvt_ftoi1
2040 #if LDOUBLE_SIZE != 8
2041 else if(r2
== VT_LDOUBLE
)
2043 else if(r2
== VT_DOUBLE
)
2045 else if(r2
== VT_LDOUBLE
|| r2
== VT_DOUBLE
)
2050 vpush_global_sym(&func_old_type
, func
);
2055 vtop
->r2
= REG_LRET
;
2059 tcc_error("unimplemented gen_cvt_ftoi!");
2062 /* convert from one floating point type to another */
2063 void gen_cvt_ftof(int t
)
2066 if(((vtop
->type
.t
& VT_BTYPE
) == VT_FLOAT
) != ((t
& VT_BTYPE
) == VT_FLOAT
)) {
2067 uint32_t r
= vfpr(gv(RC_FLOAT
));
2068 o(0xEEB70AC0|(r
<<12)|r
|T2CPR(vtop
->type
.t
));
2071 /* all we have to do on i386 and FPA ARM is to put the float in a register */
2076 /* computed goto support */
2083 /* Save the stack pointer onto the stack and return the location of its address */
2084 ST_FUNC
void gen_vla_sp_save(int addr
) {
2085 tcc_error("variable length arrays unsupported for this target");
2088 /* Restore the SP from a location on the stack */
2089 ST_FUNC
void gen_vla_sp_restore(int addr
) {
2090 tcc_error("variable length arrays unsupported for this target");
2093 /* Subtract from the stack pointer, and push the resulting value onto the stack */
2094 ST_FUNC
void gen_vla_alloc(CType
*type
, int align
) {
2095 tcc_error("variable length arrays unsupported for this target");
2098 /* end of ARM code generator */
2099 /*************************************************************/
2101 /*************************************************************/