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 */
64 #define RC_MASK (RC_INT|RC_FLOAT)
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
;
189 #ifndef TCC_ARM_HARDFLOAT
190 tcc_warning("soft float ABI currently not supported: default to softfp");
194 #define func_float_type func_old_type
195 #define func_double_type func_old_type
196 #define func_ldouble_type func_old_type
197 ST_FUNC
void arm_init(struct TCCState
*s
)
199 #if !defined (TCC_ARM_VFP)
200 tcc_warning("Support for FPA is deprecated and will be removed in next"
203 #if !defined (TCC_ARM_EABI)
204 tcc_warning("Support for OABI is deprecated and will be removed in next"
210 static int two2mask(int a
,int b
) {
211 return (reg_classes
[a
]|reg_classes
[b
])&~(RC_INT
|RC_FLOAT
);
214 static int regmask(int r
) {
215 return reg_classes
[r
]&~(RC_INT
|RC_FLOAT
);
218 /******************************************************/
221 char *default_elfinterp(struct TCCState
*s
)
223 if (s
->float_abi
== ARM_HARD_FLOAT
)
224 return "/lib/ld-linux-armhf.so.3";
226 return "/lib/ld-linux.so.3";
232 /* this is a good place to start adding big-endian support*/
236 if (!cur_text_section
)
237 tcc_error("compiler error! This happens f.ex. if the compiler\n"
238 "can't evaluate constant expressions outside of a function.");
239 if (ind1
> cur_text_section
->data_allocated
)
240 section_realloc(cur_text_section
, ind1
);
241 cur_text_section
->data
[ind
++] = i
&255;
243 cur_text_section
->data
[ind
++] = i
&255;
245 cur_text_section
->data
[ind
++] = i
&255;
247 cur_text_section
->data
[ind
++] = i
;
250 static uint32_t stuff_const(uint32_t op
, uint32_t c
)
253 uint32_t nc
= 0, negop
= 0;
263 case 0x1A00000: //mov
264 case 0x1E00000: //mvn
271 return (op
&0xF010F000)|((op
>>16)&0xF)|0x1E00000;
275 return (op
&0xF010F000)|((op
>>16)&0xF)|0x1A00000;
276 case 0x1C00000: //bic
281 case 0x1800000: //orr
283 return (op
&0xFFF0FFFF)|0x1E00000;
289 if(c
<256) /* catch undefined <<32 */
292 m
=(0xff>>i
)|(0xff<<(32-i
));
294 return op
|(i
<<7)|(c
<<i
)|(c
>>(32-i
));
304 void stuff_const_harder(uint32_t op
, uint32_t v
) {
310 uint32_t a
[16], nv
, no
, o2
, n2
;
313 o2
=(op
&0xfff0ffff)|((op
&0xf000)<<4);;
315 a
[i
]=(a
[i
-1]>>2)|(a
[i
-1]<<30);
317 for(j
=i
<4?i
+12:15;j
>=i
+4;j
--)
318 if((v
&(a
[i
]|a
[j
]))==v
) {
319 o(stuff_const(op
,v
&a
[i
]));
320 o(stuff_const(o2
,v
&a
[j
]));
327 for(j
=i
<4?i
+12:15;j
>=i
+4;j
--)
328 if((nv
&(a
[i
]|a
[j
]))==nv
) {
329 o(stuff_const(no
,nv
&a
[i
]));
330 o(stuff_const(n2
,nv
&a
[j
]));
335 for(k
=i
<4?i
+12:15;k
>=j
+4;k
--)
336 if((v
&(a
[i
]|a
[j
]|a
[k
]))==v
) {
337 o(stuff_const(op
,v
&a
[i
]));
338 o(stuff_const(o2
,v
&a
[j
]));
339 o(stuff_const(o2
,v
&a
[k
]));
346 for(k
=i
<4?i
+12:15;k
>=j
+4;k
--)
347 if((nv
&(a
[i
]|a
[j
]|a
[k
]))==nv
) {
348 o(stuff_const(no
,nv
&a
[i
]));
349 o(stuff_const(n2
,nv
&a
[j
]));
350 o(stuff_const(n2
,nv
&a
[k
]));
353 o(stuff_const(op
,v
&a
[0]));
354 o(stuff_const(o2
,v
&a
[4]));
355 o(stuff_const(o2
,v
&a
[8]));
356 o(stuff_const(o2
,v
&a
[12]));
360 ST_FUNC
uint32_t encbranch(int pos
, int addr
, int fail
)
364 if(addr
>=0x1000000 || addr
<-0x1000000) {
366 tcc_error("FIXME: function bigger than 32MB");
369 return 0x0A000000|(addr
&0xffffff);
372 int decbranch(int pos
)
375 x
=*(uint32_t *)(cur_text_section
->data
+ pos
);
382 /* output a symbol and patch all calls to it */
383 void gsym_addr(int t
, int a
)
388 x
=(uint32_t *)(cur_text_section
->data
+ t
);
391 *x
=0xE1A00000; // nop
394 *x
|= encbranch(lt
,a
,1);
405 static uint32_t vfpr(int r
)
407 if(r
<TREG_F0
|| r
>TREG_F7
)
408 tcc_error("compiler error! register %i is no vfp register",r
);
412 static uint32_t fpr(int r
)
414 if(r
<TREG_F0
|| r
>TREG_F3
)
415 tcc_error("compiler error! register %i is no fpa register",r
);
420 static uint32_t intr(int r
)
424 if((r
<0 || r
>4) && r
!=14)
425 tcc_error("compiler error! register %i is no int register",r
);
429 static void calcaddr(uint32_t *base
, int *off
, int *sgn
, int maxoff
, unsigned shift
)
431 if(*off
>maxoff
|| *off
&((1<<shift
)-1)) {
438 y
=stuff_const(x
,*off
&~maxoff
);
444 y
=stuff_const(x
,(*off
+maxoff
)&~maxoff
);
448 *off
=((*off
+maxoff
)&~maxoff
)-*off
;
451 stuff_const_harder(x
,*off
&~maxoff
);
456 static uint32_t mapcc(int cc
)
461 return 0x30000000; /* CC/LO */
463 return 0x20000000; /* CS/HS */
465 return 0x00000000; /* EQ */
467 return 0x10000000; /* NE */
469 return 0x90000000; /* LS */
471 return 0x80000000; /* HI */
473 return 0x40000000; /* MI */
475 return 0x50000000; /* PL */
477 return 0xB0000000; /* LT */
479 return 0xA0000000; /* GE */
481 return 0xD0000000; /* LE */
483 return 0xC0000000; /* GT */
485 tcc_error("unexpected condition code");
486 return 0xE0000000; /* AL */
489 static int negcc(int cc
)
518 tcc_error("unexpected condition code");
522 /* load 'r' from value 'sv' */
523 void load(int r
, SValue
*sv
)
525 int v
, ft
, fc
, fr
, sign
;
542 uint32_t base
= 0xB; // fp
545 if((ft
& VT_BTYPE
) == VT_FUNC
)
548 size
= type_size(&sv
->type
, &align
);
553 v1
.r
= VT_LOCAL
| VT_LVAL
;
555 load(base
=14 /* lr */, &v1
);
558 } else if(v
== VT_CONST
) {
566 } else if(v
< VT_CONST
) {
573 calcaddr(&base
,&fc
,&sign
,1020,2);
575 op
=0xED100A00; /* flds */
578 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
579 op
|=0x100; /* flds -> fldd */
580 o(op
|(vfpr(r
)<<12)|(fc
>>2)|(base
<<16));
585 #if LDOUBLE_SIZE == 8
586 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
589 if ((ft
& VT_BTYPE
) == VT_DOUBLE
)
591 else if ((ft
& VT_BTYPE
) == VT_LDOUBLE
)
594 o(op
|(fpr(r
)<<12)|(fc
>>2)|(base
<<16));
596 } else if((ft
& (VT_BTYPE
|VT_UNSIGNED
)) == VT_BYTE
597 || (ft
& VT_BTYPE
) == VT_SHORT
) {
598 calcaddr(&base
,&fc
,&sign
,255,0);
600 if ((ft
& VT_BTYPE
) == VT_SHORT
)
602 if ((ft
& VT_UNSIGNED
) == 0)
606 o(op
|(intr(r
)<<12)|(base
<<16)|((fc
&0xf0)<<4)|(fc
&0xf));
608 calcaddr(&base
,&fc
,&sign
,4095,0);
612 if ((ft
& VT_BTYPE
) == VT_BYTE
|| (ft
& VT_BTYPE
) == VT_BOOL
)
614 o(op
|(intr(r
)<<12)|fc
|(base
<<16));
620 op
=stuff_const(0xE3A00000|(intr(r
)<<12),sv
->c
.ul
);
621 if (fr
& VT_SYM
|| !op
) {
622 o(0xE59F0000|(intr(r
)<<12));
625 greloc(cur_text_section
, sv
->sym
, ind
, R_ARM_ABS32
);
630 } else if (v
== VT_LOCAL
) {
631 op
=stuff_const(0xE28B0000|(intr(r
)<<12),sv
->c
.ul
);
632 if (fr
& VT_SYM
|| !op
) {
633 o(0xE59F0000|(intr(r
)<<12));
635 if(fr
& VT_SYM
) // needed ?
636 greloc(cur_text_section
, sv
->sym
, ind
, R_ARM_ABS32
);
638 o(0xE08B0000|(intr(r
)<<12)|intr(r
));
642 } else if(v
== VT_CMP
) {
643 o(mapcc(sv
->c
.ul
)|0x3A00001|(intr(r
)<<12));
644 o(mapcc(negcc(sv
->c
.ul
))|0x3A00000|(intr(r
)<<12));
646 } else if (v
== VT_JMP
|| v
== VT_JMPI
) {
649 o(0xE3A00000|(intr(r
)<<12)|t
);
652 o(0xE3A00000|(intr(r
)<<12)|(t
^1));
654 } else if (v
< VT_CONST
) {
657 o(0xEEB00A40|(vfpr(r
)<<12)|vfpr(v
)|T2CPR(ft
)); /* fcpyX */
659 o(0xEE008180|(fpr(r
)<<12)|fpr(v
));
662 o(0xE1A00000|(intr(r
)<<12)|intr(v
));
666 tcc_error("load unimplemented!");
669 /* store register 'r' in lvalue 'v' */
670 void store(int r
, SValue
*sv
)
673 int v
, ft
, fc
, fr
, sign
;
688 if (fr
& VT_LVAL
|| fr
== VT_LOCAL
) {
694 } else if(v
== VT_CONST
) {
705 calcaddr(&base
,&fc
,&sign
,1020,2);
707 op
=0xED000A00; /* fsts */
710 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
711 op
|=0x100; /* fsts -> fstd */
712 o(op
|(vfpr(r
)<<12)|(fc
>>2)|(base
<<16));
717 #if LDOUBLE_SIZE == 8
718 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
721 if ((ft
& VT_BTYPE
) == VT_DOUBLE
)
723 if ((ft
& VT_BTYPE
) == VT_LDOUBLE
)
726 o(op
|(fpr(r
)<<12)|(fc
>>2)|(base
<<16));
729 } else if((ft
& VT_BTYPE
) == VT_SHORT
) {
730 calcaddr(&base
,&fc
,&sign
,255,0);
734 o(op
|(intr(r
)<<12)|(base
<<16)|((fc
&0xf0)<<4)|(fc
&0xf));
736 calcaddr(&base
,&fc
,&sign
,4095,0);
740 if ((ft
& VT_BTYPE
) == VT_BYTE
|| (ft
& VT_BTYPE
) == VT_BOOL
)
742 o(op
|(intr(r
)<<12)|fc
|(base
<<16));
747 tcc_error("store unimplemented");
750 static void gadd_sp(int val
)
752 stuff_const_harder(0xE28DD000,val
);
755 /* 'is_jmp' is '1' if it is a jump */
756 static void gcall_or_jmp(int is_jmp
)
759 if ((vtop
->r
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
) {
762 x
=encbranch(ind
,ind
+vtop
->c
.ul
,0);
764 if (vtop
->r
& VT_SYM
) {
765 /* relocation case */
766 greloc(cur_text_section
, vtop
->sym
, ind
, R_ARM_PC24
);
768 put_elf_reloc(symtab_section
, cur_text_section
, ind
, R_ARM_PC24
, 0);
769 o(x
|(is_jmp
?0xE0000000:0xE1000000));
772 o(0xE28FE004); // add lr,pc,#4
773 o(0xE51FF004); // ldr pc,[pc,#-4]
774 if (vtop
->r
& VT_SYM
)
775 greloc(cur_text_section
, vtop
->sym
, ind
, R_ARM_ABS32
);
779 /* otherwise, indirect call */
782 o(0xE1A0E00F); // mov lr,pc
783 o(0xE1A0F000|intr(r
)); // mov pc,r
787 /* Return whether a structure is an homogeneous float aggregate or not.
788 The answer is true if all the elements of the structure are of the same
789 primitive float type and there is less than 4 elements.
791 type: the type corresponding to the structure to be tested */
792 static int is_hgen_float_aggr(CType
*type
)
794 if ((type
->t
& VT_BTYPE
) == VT_STRUCT
) {
796 int btype
, nb_fields
= 0;
798 ref
= type
->ref
->next
;
799 btype
= ref
->type
.t
& VT_BTYPE
;
800 if (btype
== VT_FLOAT
|| btype
== VT_DOUBLE
) {
801 for(; ref
&& btype
== (ref
->type
.t
& VT_BTYPE
); ref
= ref
->next
, nb_fields
++);
802 return !ref
&& nb_fields
<= 4;
809 signed char avail
[3]; /* 3 holes max with only float and double alignments */
810 int first_hole
; /* first available hole */
811 int last_hole
; /* last available hole (none if equal to first_hole) */
812 int first_free_reg
; /* next free register in the sequence, hole excluded */
815 #define AVAIL_REGS_INITIALIZER (struct avail_regs) { { 0, 0, 0}, 0, 0, 0 }
817 /* Find suitable registers for a VFP Co-Processor Register Candidate (VFP CPRC
818 param) according to the rules described in the procedure call standard for
819 the ARM architecture (AAPCS). If found, the registers are assigned to this
820 VFP CPRC parameter. Registers are allocated in sequence unless a hole exists
821 and the parameter is a single float.
823 avregs: opaque structure to keep track of available VFP co-processor regs
824 align: alignment contraints for the param, as returned by type_size()
825 size: size of the parameter, as returned by type_size() */
826 int assign_vfpreg(struct avail_regs
*avregs
, int align
, int size
)
830 if (avregs
->first_free_reg
== -1)
832 if (align
>> 3) { /* double alignment */
833 first_reg
= avregs
->first_free_reg
;
834 /* alignment contraint not respected so use next reg and record hole */
836 avregs
->avail
[avregs
->last_hole
++] = first_reg
++;
837 } else { /* no special alignment (float or array of float) */
838 /* if single float and a hole is available, assign the param to it */
839 if (size
== 4 && avregs
->first_hole
!= avregs
->last_hole
)
840 return avregs
->avail
[avregs
->first_hole
++];
842 first_reg
= avregs
->first_free_reg
;
844 if (first_reg
+ size
/ 4 <= 16) {
845 avregs
->first_free_reg
= first_reg
+ size
/ 4;
848 avregs
->first_free_reg
= -1;
852 /* Returns whether all params need to be passed in core registers or not.
853 This is the case for function part of the runtime ABI. */
854 int floats_in_core_regs(SValue
*sval
)
859 switch (sval
->sym
->v
) {
860 case TOK___floatundisf
:
861 case TOK___floatundidf
:
862 case TOK___fixunssfdi
:
863 case TOK___fixunsdfdi
:
865 case TOK___fixunsxfdi
:
867 case TOK___floatdisf
:
868 case TOK___floatdidf
:
878 /* Return the number of registers needed to return the struct, or 0 if
879 returning via struct pointer. */
880 ST_FUNC
int gfunc_sret(CType
*vt
, int variadic
, CType
*ret
, int *ret_align
) {
883 size
= type_size(vt
, &align
);
884 if (float_abi
== ARM_HARD_FLOAT
&& !variadic
&&
885 (is_float(vt
->t
) || is_hgen_float_aggr(vt
))) {
889 return (size
+ 7) >> 3;
890 } else if (size
<= 4) {
902 /* Parameters are classified according to how they are copied to their final
903 destination for the function call. Because the copying is performed class
904 after class according to the order in the union below, it is important that
905 some constraints about the order of the members of this union are respected:
906 - CORE_STRUCT_CLASS must come after STACK_CLASS;
907 - CORE_CLASS must come after STACK_CLASS, CORE_STRUCT_CLASS and
909 - VFP_STRUCT_CLASS must come after VFP_CLASS.
910 See the comment for the main loop in copy_params() for the reason. */
921 int start
; /* first reg or addr used depending on the class */
922 int end
; /* last reg used or next free addr depending on the class */
923 SValue
*sval
; /* pointer to SValue on the value stack */
924 struct param_plan
*prev
; /* previous element in this class */
928 struct param_plan
*pplans
; /* array of all the param plans */
929 struct param_plan
*clsplans
[NB_CLASSES
]; /* per class lists of param plans */
932 #define add_param_plan(plan,pplan,class) \
934 pplan.prev = plan->clsplans[class]; \
935 plan->pplans[plan ## _nb] = pplan; \
936 plan->clsplans[class] = &plan->pplans[plan ## _nb++]; \
939 /* Assign parameters to registers and stack with alignment according to the
940 rules in the procedure call standard for the ARM architecture (AAPCS).
941 The overall assignment is recorded in an array of per parameter structures
942 called parameter plans. The parameter plans are also further organized in a
943 number of linked lists, one per class of parameter (see the comment for the
944 definition of union reg_class).
946 nb_args: number of parameters of the function for which a call is generated
947 float_abi: float ABI in use for this function call
948 plan: the structure where the overall assignment is recorded
949 todo: a bitmap that record which core registers hold a parameter
951 Returns the amount of stack space needed for parameter passing
953 Note: this function allocated an array in plan->pplans with tcc_malloc. It
954 is the responsibility of the caller to free this array once used (ie not
955 before copy_params). */
956 static int assign_regs(int nb_args
, int float_abi
, struct plan
*plan
, int *todo
)
959 int ncrn
/* next core register number */, nsaa
/* next stacked argument address*/;
961 struct param_plan pplan
;
962 struct avail_regs avregs
= AVAIL_REGS_INITIALIZER
;
966 plan
->pplans
= tcc_malloc(nb_args
* sizeof(*plan
->pplans
));
967 memset(plan
->clsplans
, 0, sizeof(plan
->clsplans
));
968 for(i
= nb_args
; i
-- ;) {
969 int j
, start_vfpreg
= 0;
970 CType type
= vtop
[-i
].type
;
972 size
= type_size(&type
, &align
);
973 size
= (size
+ 3) & ~3;
974 align
= (align
+ 3) & ~3;
975 switch(vtop
[-i
].type
.t
& VT_BTYPE
) {
980 if (float_abi
== ARM_HARD_FLOAT
) {
981 int is_hfa
= 0; /* Homogeneous float aggregate */
983 if (is_float(vtop
[-i
].type
.t
)
984 || (is_hfa
= is_hgen_float_aggr(&vtop
[-i
].type
))) {
987 start_vfpreg
= assign_vfpreg(&avregs
, align
, size
);
988 end_vfpreg
= start_vfpreg
+ ((size
- 1) >> 2);
989 if (start_vfpreg
>= 0) {
990 pplan
= (struct param_plan
) {start_vfpreg
, end_vfpreg
, &vtop
[-i
]};
992 add_param_plan(plan
, pplan
, VFP_STRUCT_CLASS
);
994 add_param_plan(plan
, pplan
, VFP_CLASS
);
1000 ncrn
= (ncrn
+ (align
-1)/4) & ~((align
/4) - 1);
1001 if (ncrn
+ size
/4 <= 4 || (ncrn
< 4 && start_vfpreg
!= -1)) {
1002 /* The parameter is allocated both in core register and on stack. As
1003 * such, it can be of either class: it would either be the last of
1004 * CORE_STRUCT_CLASS or the first of STACK_CLASS. */
1005 for (j
= ncrn
; j
< 4 && j
< ncrn
+ size
/ 4; j
++)
1007 pplan
= (struct param_plan
) {ncrn
, j
, &vtop
[-i
]};
1008 add_param_plan(plan
, pplan
, CORE_STRUCT_CLASS
);
1011 nsaa
= (ncrn
- 4) * 4;
1019 int is_long
= (vtop
[-i
].type
.t
& VT_BTYPE
) == VT_LLONG
;
1022 ncrn
= (ncrn
+ 1) & -2;
1026 pplan
= (struct param_plan
) {ncrn
, ncrn
, &vtop
[-i
]};
1030 add_param_plan(plan
, pplan
, CORE_CLASS
);
1034 nsaa
= (nsaa
+ (align
- 1)) & ~(align
- 1);
1035 pplan
= (struct param_plan
) {nsaa
, nsaa
+ size
, &vtop
[-i
]};
1036 add_param_plan(plan
, pplan
, STACK_CLASS
);
1037 nsaa
+= size
; /* size already rounded up before */
1042 #undef add_param_plan
1044 /* Copy parameters to their final destination (core reg, VFP reg or stack) for
1047 nb_args: number of parameters the function take
1048 plan: the overall assignment plan for parameters
1049 todo: a bitmap indicating what core reg will hold a parameter
1051 Returns the number of SValue added by this function on the value stack */
1052 static int copy_params(int nb_args
, struct plan
*plan
, int todo
)
1054 int size
, align
, r
, i
, nb_extra_sval
= 0;
1055 struct param_plan
*pplan
;
1057 /* Several constraints require parameters to be copied in a specific order:
1058 - structures are copied to the stack before being loaded in a reg;
1059 - floats loaded to an odd numbered VFP reg are first copied to the
1060 preceding even numbered VFP reg and then moved to the next VFP reg.
1062 It is thus important that:
1063 - structures assigned to core regs must be copied after parameters
1064 assigned to the stack but before structures assigned to VFP regs because
1065 a structure can lie partly in core registers and partly on the stack;
1066 - parameters assigned to the stack and all structures be copied before
1067 parameters assigned to a core reg since copying a parameter to the stack
1068 require using a core reg;
1069 - parameters assigned to VFP regs be copied before structures assigned to
1070 VFP regs as the copy might use an even numbered VFP reg that already
1071 holds part of a structure. */
1072 for(i
= 0; i
< NB_CLASSES
; i
++) {
1073 for(pplan
= plan
->clsplans
[i
]; pplan
; pplan
= pplan
->prev
) {
1074 vpushv(pplan
->sval
);
1075 pplan
->sval
->r
= pplan
->sval
->r2
= VT_CONST
; /* disable entry */
1078 case CORE_STRUCT_CLASS
:
1079 case VFP_STRUCT_CLASS
:
1080 if ((pplan
->sval
->type
.t
& VT_BTYPE
) == VT_STRUCT
) {
1082 size
= type_size(&pplan
->sval
->type
, &align
);
1083 /* align to stack align size */
1084 size
= (size
+ 3) & ~3;
1085 if (i
== STACK_CLASS
&& pplan
->prev
)
1086 padding
= pplan
->start
- pplan
->prev
->end
;
1087 size
+= padding
; /* Add padding if any */
1088 /* allocate the necessary size on stack */
1090 /* generate structure store */
1091 r
= get_reg(RC_INT
);
1092 o(0xE28D0000|(intr(r
)<<12)|padding
); /* add r, sp, padding */
1093 vset(&vtop
->type
, r
| VT_LVAL
, 0);
1095 vstore(); /* memcpy to current sp + potential padding */
1097 /* Homogeneous float aggregate are loaded to VFP registers
1098 immediately since there is no way of loading data in multiple
1099 non consecutive VFP registers as what is done for other
1100 structures (see the use of todo). */
1101 if (i
== VFP_STRUCT_CLASS
) {
1102 int first
= pplan
->start
, nb
= pplan
->end
- first
+ 1;
1103 /* vpop.32 {pplan->start, ..., pplan->end} */
1104 o(0xECBD0A00|(first
&1)<<22|(first
>>1)<<12|nb
);
1105 /* No need to write the register used to a SValue since VFP regs
1106 cannot be used for gcall_or_jmp */
1109 if (is_float(pplan
->sval
->type
.t
)) {
1111 r
= vfpr(gv(RC_FLOAT
)) << 12;
1112 if ((pplan
->sval
->type
.t
& VT_BTYPE
) == VT_FLOAT
)
1116 r
|= 0x101; /* vpush.32 -> vpush.64 */
1118 o(0xED2D0A01 + r
); /* vpush */
1120 r
= fpr(gv(RC_FLOAT
)) << 12;
1121 if ((pplan
->sval
->type
.t
& VT_BTYPE
) == VT_FLOAT
)
1123 else if ((pplan
->sval
->type
.t
& VT_BTYPE
) == VT_DOUBLE
)
1126 size
= LDOUBLE_SIZE
;
1133 o(0xED2D0100|r
|(size
>>2)); /* some kind of vpush for FPA */
1136 /* simple type (currently always same size) */
1137 /* XXX: implicit cast ? */
1139 if ((pplan
->sval
->type
.t
& VT_BTYPE
) == VT_LLONG
) {
1143 o(0xE52D0004|(intr(r
)<<12)); /* push r */
1147 o(0xE52D0004|(intr(r
)<<12)); /* push r */
1149 if (i
== STACK_CLASS
&& pplan
->prev
)
1150 gadd_sp(pplan
->prev
->end
- pplan
->start
); /* Add padding if any */
1155 gv(regmask(TREG_F0
+ (pplan
->start
>> 1)));
1156 if (pplan
->start
& 1) { /* Must be in upper part of double register */
1157 o(0xEEF00A40|((pplan
->start
>>1)<<12)|(pplan
->start
>>1)); /* vmov.f32 s(n+1), sn */
1158 vtop
->r
= VT_CONST
; /* avoid being saved on stack by gv for next float */
1163 if ((pplan
->sval
->type
.t
& VT_BTYPE
) == VT_LLONG
) {
1165 gv(regmask(pplan
->end
));
1166 pplan
->sval
->r2
= vtop
->r
;
1169 gv(regmask(pplan
->start
));
1170 /* Mark register as used so that gcall_or_jmp use another one
1171 (regs >=4 are free as never used to pass parameters) */
1172 pplan
->sval
->r
= vtop
->r
;
1179 /* Manually free remaining registers since next parameters are loaded
1180 * manually, without the help of gv(int). */
1184 o(0xE8BD0000|todo
); /* pop {todo} */
1185 for(pplan
= plan
->clsplans
[CORE_STRUCT_CLASS
]; pplan
; pplan
= pplan
->prev
) {
1187 pplan
->sval
->r
= pplan
->start
;
1188 /* An SValue can only pin 2 registers at best (r and r2) but a structure
1189 can occupy more than 2 registers. Thus, we need to push on the value
1190 stack some fake parameter to have on SValue for each registers used
1191 by a structure (r2 is not used). */
1192 for (r
= pplan
->start
+ 1; r
<= pplan
->end
; r
++) {
1193 if (todo
& (1 << r
)) {
1201 return nb_extra_sval
;
1204 /* Generate function call. The function address is pushed first, then
1205 all the parameters in call order. This functions pops all the
1206 parameters and the function address. */
1207 void gfunc_call(int nb_args
)
1210 int variadic
, def_float_abi
= float_abi
;
1215 if (float_abi
== ARM_HARD_FLOAT
) {
1216 variadic
= (vtop
[-nb_args
].type
.ref
->c
== FUNC_ELLIPSIS
);
1217 if (variadic
|| floats_in_core_regs(&vtop
[-nb_args
]))
1218 float_abi
= ARM_SOFTFP_FLOAT
;
1221 /* cannot let cpu flags if other instruction are generated. Also avoid leaving
1222 VT_JMP anywhere except on the top of the stack because it would complicate
1223 the code generator. */
1224 r
= vtop
->r
& VT_VALMASK
;
1225 if (r
== VT_CMP
|| (r
& ~1) == VT_JMP
)
1228 args_size
= assign_regs(nb_args
, float_abi
, &plan
, &todo
);
1231 if (args_size
& 7) { /* Stack must be 8 byte aligned at fct call for EABI */
1232 args_size
= (args_size
+ 7) & ~7;
1233 o(0xE24DD004); /* sub sp, sp, #4 */
1237 nb_args
+= copy_params(nb_args
, &plan
, todo
);
1238 tcc_free(plan
.pplans
);
1240 /* Move fct SValue on top as required by gcall_or_jmp */
1244 gadd_sp(args_size
); /* pop all parameters passed on the stack */
1245 #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
1246 if(float_abi
== ARM_SOFTFP_FLOAT
&& is_float(vtop
->type
.ref
->type
.t
)) {
1247 if((vtop
->type
.ref
->type
.t
& VT_BTYPE
) == VT_FLOAT
) {
1248 o(0xEE000A10); /*vmov s0, r0 */
1250 o(0xEE000B10); /* vmov.32 d0[0], r0 */
1251 o(0xEE201B10); /* vmov.32 d0[1], r1 */
1255 vtop
-= nb_args
+ 1; /* Pop all params and fct address from value stack */
1256 leaffunc
= 0; /* we are calling a function, so we aren't in a leaf function */
1257 float_abi
= def_float_abi
;
1260 /* generate function prolog of type 't' */
1261 void gfunc_prolog(CType
*func_type
)
1264 int n
, nf
, size
, align
, struct_ret
= 0;
1265 int addr
, pn
, sn
; /* pn=core, sn=stack */
1266 struct avail_regs avregs
= AVAIL_REGS_INITIALIZER
;
1269 sym
= func_type
->ref
;
1270 func_vt
= sym
->type
;
1271 func_var
= (func_type
->ref
->c
== FUNC_ELLIPSIS
);
1274 if ((func_vt
.t
& VT_BTYPE
) == VT_STRUCT
&&
1275 !gfunc_sret(&func_vt
, func_var
, &ret_type
, &align
))
1279 func_vc
= 12; /* Offset from fp of the place to store the result */
1281 for(sym2
= sym
->next
; sym2
&& (n
< 4 || nf
< 16); sym2
= sym2
->next
) {
1282 size
= type_size(&sym2
->type
, &align
);
1284 if (float_abi
== ARM_HARD_FLOAT
&& !func_var
&&
1285 (is_float(sym2
->type
.t
) || is_hgen_float_aggr(&sym2
->type
))) {
1286 int tmpnf
= assign_vfpreg(&avregs
, align
, size
);
1287 tmpnf
+= (size
+ 3) / 4;
1288 nf
= (tmpnf
> nf
) ? tmpnf
: nf
;
1292 n
+= (size
+ 3) / 4;
1294 o(0xE1A0C00D); /* mov ip,sp */
1303 o(0xE92D0000|((1<<n
)-1)); /* save r0-r4 on stack if needed */
1308 nf
=(nf
+1)&-2; /* nf => HARDFLOAT => EABI */
1309 o(0xED2D0A00|nf
); /* save s0-s15 on stack if needed */
1311 o(0xE92D5800); /* save fp, ip, lr */
1312 o(0xE1A0B00D); /* mov fp, sp */
1313 func_sub_sp_offset
= ind
;
1314 o(0xE1A00000); /* nop, leave space for stack adjustment in epilog */
1317 if (float_abi
== ARM_HARD_FLOAT
) {
1319 avregs
= AVAIL_REGS_INITIALIZER
;
1322 pn
= struct_ret
, sn
= 0;
1323 while ((sym
= sym
->next
)) {
1326 size
= type_size(type
, &align
);
1327 size
= (size
+ 3) >> 2;
1328 align
= (align
+ 3) & ~3;
1330 if (float_abi
== ARM_HARD_FLOAT
&& !func_var
&& (is_float(sym
->type
.t
)
1331 || is_hgen_float_aggr(&sym
->type
))) {
1332 int fpn
= assign_vfpreg(&avregs
, align
, size
<< 2);
1341 pn
= (pn
+ (align
-1)/4) & -(align
/4);
1343 addr
= (nf
+ pn
) * 4;
1350 sn
= (sn
+ (align
-1)/4) & -(align
/4);
1352 addr
= (n
+ nf
+ sn
) * 4;
1355 sym_push(sym
->v
& ~SYM_FIELD
, type
, VT_LOCAL
| lvalue_type(type
->t
),
1363 /* generate function epilog */
1364 void gfunc_epilog(void)
1368 /* Copy float return value to core register if base standard is used and
1369 float computation is made with VFP */
1370 #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
1371 if ((float_abi
== ARM_SOFTFP_FLOAT
|| func_var
) && is_float(func_vt
.t
)) {
1372 if((func_vt
.t
& VT_BTYPE
) == VT_FLOAT
)
1373 o(0xEE100A10); /* fmrs r0, s0 */
1375 o(0xEE100B10); /* fmrdl r0, d0 */
1376 o(0xEE301B10); /* fmrdh r1, d0 */
1380 o(0xE89BA800); /* restore fp, sp, pc */
1381 diff
= (-loc
+ 3) & -4;
1384 diff
= ((diff
+ 11) & -8) - 4;
1387 x
=stuff_const(0xE24BD000, diff
); /* sub sp,fp,# */
1389 *(uint32_t *)(cur_text_section
->data
+ func_sub_sp_offset
) = x
;
1393 o(0xE59FC004); /* ldr ip,[pc+4] */
1394 o(0xE04BD00C); /* sub sp,fp,ip */
1395 o(0xE1A0F00E); /* mov pc,lr */
1397 *(uint32_t *)(cur_text_section
->data
+ func_sub_sp_offset
) = 0xE1000000|encbranch(func_sub_sp_offset
,addr
,1);
1402 /* generate a jump to a label */
1407 o(0xE0000000|encbranch(r
,t
,1));
1411 /* generate a jump to a fixed address */
1412 void gjmp_addr(int a
)
1417 /* generate a test. set 'inv' to invert test. Stack entry is popped */
1418 int gtst(int inv
, int t
)
1422 v
= vtop
->r
& VT_VALMASK
;
1425 op
=mapcc(inv
?negcc(vtop
->c
.i
):vtop
->c
.i
);
1426 op
|=encbranch(r
,t
,1);
1429 } else if (v
== VT_JMP
|| v
== VT_JMPI
) {
1430 if ((v
& 1) == inv
) {
1439 p
= decbranch(lp
=p
);
1441 x
= (uint32_t *)(cur_text_section
->data
+ lp
);
1443 *x
|= encbranch(lp
,t
,1);
1452 if (is_float(vtop
->type
.t
)) {
1455 o(0xEEB50A40|(vfpr(r
)<<12)|T2CPR(vtop
->type
.t
)); /* fcmpzX */
1456 o(0xEEF1FA10); /* fmstat */
1458 o(0xEE90F118|(fpr(r
)<<16));
1462 return gtst(inv
, t
);
1463 } else if ((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1464 /* constant jmp optimization */
1465 if ((vtop
->c
.i
!= 0) != inv
)
1469 o(0xE3300000|(intr(v
)<<16));
1472 return gtst(inv
, t
);
1479 /* generate an integer binary operation */
1480 void gen_opi(int op
)
1483 uint32_t opc
= 0, r
, fr
;
1484 unsigned short retreg
= REG_IRET
;
1492 case TOK_ADDC1
: /* add with carry generation */
1500 case TOK_SUBC1
: /* sub with carry generation */
1504 case TOK_ADDC2
: /* add with carry use */
1508 case TOK_SUBC2
: /* sub with carry use */
1525 gv2(RC_INT
, RC_INT
);
1529 o(0xE0000090|(intr(r
)<<16)|(intr(r
)<<8)|intr(fr
));
1554 func
=TOK___aeabi_idivmod
;
1563 func
=TOK___aeabi_uidivmod
;
1571 gv2(RC_INT
, RC_INT
);
1572 r
=intr(vtop
[-1].r2
=get_reg(RC_INT
));
1574 vtop
[-1].r
=get_reg_ex(RC_INT
,regmask(c
));
1576 o(0xE0800090|(r
<<16)|(intr(vtop
->r
)<<12)|(intr(c
)<<8)|intr(vtop
[1].r
));
1585 if((vtop
[-1].r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1586 if(opc
== 4 || opc
== 5 || opc
== 0xc) {
1588 opc
|=2; // sub -> rsb
1591 if ((vtop
->r
& VT_VALMASK
) == VT_CMP
||
1592 (vtop
->r
& (VT_VALMASK
& ~1)) == VT_JMP
)
1597 opc
=0xE0000000|(opc
<<20)|(c
<<16);
1598 if((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1600 x
=stuff_const(opc
|0x2000000,vtop
->c
.i
);
1602 r
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,regmask(vtop
[-1].r
)));
1607 fr
=intr(gv(RC_INT
));
1608 r
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,two2mask(vtop
->r
,vtop
[-1].r
)));
1612 if (op
>= TOK_ULT
&& op
<= TOK_GT
) {
1618 opc
=0xE1A00000|(opc
<<5);
1619 if ((vtop
->r
& VT_VALMASK
) == VT_CMP
||
1620 (vtop
->r
& (VT_VALMASK
& ~1)) == VT_JMP
)
1626 if ((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1627 fr
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,regmask(vtop
[-1].r
)));
1628 c
= vtop
->c
.i
& 0x1f;
1629 o(opc
|(c
<<7)|(fr
<<12));
1631 fr
=intr(gv(RC_INT
));
1632 c
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,two2mask(vtop
->r
,vtop
[-1].r
)));
1633 o(opc
|(c
<<12)|(fr
<<8)|0x10);
1638 vpush_global_sym(&func_old_type
, func
);
1645 tcc_error("gen_opi %i unimplemented!",op
);
1650 static int is_zero(int i
)
1652 if((vtop
[i
].r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) != VT_CONST
)
1654 if (vtop
[i
].type
.t
== VT_FLOAT
)
1655 return (vtop
[i
].c
.f
== 0.f
);
1656 else if (vtop
[i
].type
.t
== VT_DOUBLE
)
1657 return (vtop
[i
].c
.d
== 0.0);
1658 return (vtop
[i
].c
.ld
== 0.l
);
1661 /* generate a floating point operation 'v = t1 op t2' instruction. The
1662 * two operands are guaranted to have the same floating point type */
1663 void gen_opf(int op
)
1667 x
=0xEE000A00|T2CPR(vtop
->type
.t
);
1685 x
|=0x810000; /* fsubX -> fnegX */
1698 if(op
< TOK_ULT
|| op
> TOK_GT
) {
1699 tcc_error("unknown fp op %x!",op
);
1705 case TOK_LT
: op
=TOK_GT
; break;
1706 case TOK_GE
: op
=TOK_ULE
; break;
1707 case TOK_LE
: op
=TOK_GE
; break;
1708 case TOK_GT
: op
=TOK_ULT
; break;
1711 x
|=0xB40040; /* fcmpX */
1712 if(op
!=TOK_EQ
&& op
!=TOK_NE
)
1713 x
|=0x80; /* fcmpX -> fcmpeX */
1716 o(x
|0x10000|(vfpr(gv(RC_FLOAT
))<<12)); /* fcmp(e)X -> fcmp(e)zX */
1718 x
|=vfpr(gv(RC_FLOAT
));
1720 o(x
|(vfpr(gv(RC_FLOAT
))<<12));
1723 o(0xEEF1FA10); /* fmstat */
1726 case TOK_LE
: op
=TOK_ULE
; break;
1727 case TOK_LT
: op
=TOK_ULT
; break;
1728 case TOK_UGE
: op
=TOK_GE
; break;
1729 case TOK_UGT
: op
=TOK_GT
; break;
1746 vtop
->r
=get_reg_ex(RC_FLOAT
,r
);
1749 o(x
|(vfpr(vtop
->r
)<<12));
1753 static uint32_t is_fconst()
1757 if((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) != VT_CONST
)
1759 if (vtop
->type
.t
== VT_FLOAT
)
1761 else if (vtop
->type
.t
== VT_DOUBLE
)
1791 /* generate a floating point operation 'v = t1 op t2' instruction. The
1792 two operands are guaranted to have the same floating point type */
1793 void gen_opf(int op
)
1795 uint32_t x
, r
, r2
, c1
, c2
;
1796 //fputs("gen_opf\n",stderr);
1802 #if LDOUBLE_SIZE == 8
1803 if ((vtop
->type
.t
& VT_BTYPE
) != VT_FLOAT
)
1806 if ((vtop
->type
.t
& VT_BTYPE
) == VT_DOUBLE
)
1808 else if ((vtop
->type
.t
& VT_BTYPE
) == VT_LDOUBLE
)
1819 r
=fpr(gv(RC_FLOAT
));
1826 r2
=fpr(gv(RC_FLOAT
));
1835 r
=fpr(gv(RC_FLOAT
));
1837 } else if(c1
&& c1
<=0xf) {
1840 r
=fpr(gv(RC_FLOAT
));
1845 r
=fpr(gv(RC_FLOAT
));
1847 r2
=fpr(gv(RC_FLOAT
));
1856 r
=fpr(gv(RC_FLOAT
));
1861 r2
=fpr(gv(RC_FLOAT
));
1869 r
=fpr(gv(RC_FLOAT
));
1871 } else if(c1
&& c1
<=0xf) {
1874 r
=fpr(gv(RC_FLOAT
));
1879 r
=fpr(gv(RC_FLOAT
));
1881 r2
=fpr(gv(RC_FLOAT
));
1885 if(op
>= TOK_ULT
&& op
<= TOK_GT
) {
1886 x
|=0xd0f110; // cmfe
1887 /* bug (intention?) in Linux FPU emulator
1888 doesn't set carry if equal */
1894 tcc_error("unsigned comparison on floats?");
1900 op
=TOK_ULE
; /* correct in unordered case only if AC bit in FPSR set */
1904 x
&=~0x400000; // cmfe -> cmf
1926 r
=fpr(gv(RC_FLOAT
));
1933 r2
=fpr(gv(RC_FLOAT
));
1935 vtop
[-1].r
= VT_CMP
;
1938 tcc_error("unknown fp op %x!",op
);
1942 if(vtop
[-1].r
== VT_CMP
)
1948 vtop
[-1].r
=get_reg_ex(RC_FLOAT
,two2mask(vtop
[-1].r
,c1
));
1952 o(x
|(r
<<16)|(c1
<<12)|r2
);
1956 /* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
1957 and 'long long' cases. */
1958 ST_FUNC
void gen_cvt_itof1(int t
)
1962 bt
=vtop
->type
.t
& VT_BTYPE
;
1963 if(bt
== VT_INT
|| bt
== VT_SHORT
|| bt
== VT_BYTE
) {
1969 r2
=vfpr(vtop
->r
=get_reg(RC_FLOAT
));
1970 o(0xEE000A10|(r
<<12)|(r2
<<16)); /* fmsr */
1972 if(!(vtop
->type
.t
& VT_UNSIGNED
))
1973 r2
|=0x80; /* fuitoX -> fsituX */
1974 o(0xEEB80A40|r2
|T2CPR(t
)); /* fYitoX*/
1976 r2
=fpr(vtop
->r
=get_reg(RC_FLOAT
));
1977 if((t
& VT_BTYPE
) != VT_FLOAT
)
1978 dsize
=0x80; /* flts -> fltd */
1979 o(0xEE000110|dsize
|(r2
<<16)|(r
<<12)); /* flts */
1980 if((vtop
->type
.t
& (VT_UNSIGNED
|VT_BTYPE
)) == (VT_UNSIGNED
|VT_INT
)) {
1982 o(0xE3500000|(r
<<12)); /* cmp */
1983 r
=fpr(get_reg(RC_FLOAT
));
1984 if(last_itod_magic
) {
1985 off
=ind
+8-last_itod_magic
;
1990 o(0xBD1F0100|(r
<<12)|off
); /* ldflts */
1992 o(0xEA000000); /* b */
1993 last_itod_magic
=ind
;
1994 o(0x4F800000); /* 4294967296.0f */
1996 o(0xBE000100|dsize
|(r2
<<16)|(r2
<<12)|r
); /* adflt */
2000 } else if(bt
== VT_LLONG
) {
2002 CType
*func_type
= 0;
2003 if((t
& VT_BTYPE
) == VT_FLOAT
) {
2004 func_type
= &func_float_type
;
2005 if(vtop
->type
.t
& VT_UNSIGNED
)
2006 func
=TOK___floatundisf
;
2008 func
=TOK___floatdisf
;
2009 #if LDOUBLE_SIZE != 8
2010 } else if((t
& VT_BTYPE
) == VT_LDOUBLE
) {
2011 func_type
= &func_ldouble_type
;
2012 if(vtop
->type
.t
& VT_UNSIGNED
)
2013 func
=TOK___floatundixf
;
2015 func
=TOK___floatdixf
;
2016 } else if((t
& VT_BTYPE
) == VT_DOUBLE
) {
2018 } else if((t
& VT_BTYPE
) == VT_DOUBLE
|| (t
& VT_BTYPE
) == VT_LDOUBLE
) {
2020 func_type
= &func_double_type
;
2021 if(vtop
->type
.t
& VT_UNSIGNED
)
2022 func
=TOK___floatundidf
;
2024 func
=TOK___floatdidf
;
2027 vpush_global_sym(func_type
, func
);
2035 tcc_error("unimplemented gen_cvt_itof %x!",vtop
->type
.t
);
2038 /* convert fp to int 't' type */
2039 void gen_cvt_ftoi(int t
)
2045 r2
=vtop
->type
.t
& VT_BTYPE
;
2048 r
=vfpr(gv(RC_FLOAT
));
2050 o(0xEEBC0AC0|(r
<<12)|r
|T2CPR(r2
)|u
); /* ftoXizY */
2051 r2
=intr(vtop
->r
=get_reg(RC_INT
));
2052 o(0xEE100A10|(r
<<16)|(r2
<<12));
2057 func
=TOK___fixunssfsi
;
2058 #if LDOUBLE_SIZE != 8
2059 else if(r2
== VT_LDOUBLE
)
2060 func
=TOK___fixunsxfsi
;
2061 else if(r2
== VT_DOUBLE
)
2063 else if(r2
== VT_LDOUBLE
|| r2
== VT_DOUBLE
)
2065 func
=TOK___fixunsdfsi
;
2067 r
=fpr(gv(RC_FLOAT
));
2068 r2
=intr(vtop
->r
=get_reg(RC_INT
));
2069 o(0xEE100170|(r2
<<12)|r
);
2073 } else if(t
== VT_LLONG
) { // unsigned handled in gen_cvt_ftoi1
2076 #if LDOUBLE_SIZE != 8
2077 else if(r2
== VT_LDOUBLE
)
2079 else if(r2
== VT_DOUBLE
)
2081 else if(r2
== VT_LDOUBLE
|| r2
== VT_DOUBLE
)
2086 vpush_global_sym(&func_old_type
, func
);
2091 vtop
->r2
= REG_LRET
;
2095 tcc_error("unimplemented gen_cvt_ftoi!");
2098 /* convert from one floating point type to another */
2099 void gen_cvt_ftof(int t
)
2102 if(((vtop
->type
.t
& VT_BTYPE
) == VT_FLOAT
) != ((t
& VT_BTYPE
) == VT_FLOAT
)) {
2103 uint32_t r
= vfpr(gv(RC_FLOAT
));
2104 o(0xEEB70AC0|(r
<<12)|r
|T2CPR(vtop
->type
.t
));
2107 /* all we have to do on i386 and FPA ARM is to put the float in a register */
2112 /* computed goto support */
2119 /* Save the stack pointer onto the stack and return the location of its address */
2120 ST_FUNC
void gen_vla_sp_save(int addr
) {
2121 tcc_error("variable length arrays unsupported for this target");
2124 /* Restore the SP from a location on the stack */
2125 ST_FUNC
void gen_vla_sp_restore(int addr
) {
2126 tcc_error("variable length arrays unsupported for this target");
2129 /* Subtract from the stack pointer, and push the resulting value onto the stack */
2130 ST_FUNC
void gen_vla_alloc(CType
*type
, int align
) {
2131 tcc_error("variable length arrays unsupported for this target");
2134 /* end of ARM code generator */
2135 /*************************************************************/
2137 /*************************************************************/