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_CPU_VERSION
38 # define TCC_CPU_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_IRE2 RC_R1 /* function return: second integer register */
63 #define RC_FRET RC_F0 /* function return: float register */
65 /* 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_IRE2 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 /* pointer size, in bytes */
112 /* long double size and alignment, in bytes */
114 #define LDOUBLE_SIZE 8
118 #define LDOUBLE_SIZE 8
122 #define LDOUBLE_ALIGN 8
124 #define LDOUBLE_ALIGN 4
127 /* maximum alignment (for aligned attribute support) */
130 #define CHAR_IS_UNSIGNED
132 /******************************************************/
133 #else /* ! TARGET_DEFS_ONLY */
134 /******************************************************/
135 #define USING_GLOBALS
138 enum float_abi float_abi
;
140 ST_DATA
const int reg_classes
[NB_REGS
] = {
141 /* r0 */ RC_INT
| RC_R0
,
142 /* r1 */ RC_INT
| RC_R1
,
143 /* r2 */ RC_INT
| RC_R2
,
144 /* r3 */ RC_INT
| RC_R3
,
145 /* r12 */ RC_INT
| RC_R12
,
146 /* f0 */ RC_FLOAT
| RC_F0
,
147 /* f1 */ RC_FLOAT
| RC_F1
,
148 /* f2 */ RC_FLOAT
| RC_F2
,
149 /* f3 */ RC_FLOAT
| RC_F3
,
151 /* d4/s8 */ RC_FLOAT
| RC_F4
,
152 /* d5/s10 */ RC_FLOAT
| RC_F5
,
153 /* d6/s12 */ RC_FLOAT
| RC_F6
,
154 /* d7/s14 */ RC_FLOAT
| RC_F7
,
158 static int func_sub_sp_offset
, last_itod_magic
;
161 #if defined(CONFIG_TCC_BCHECK)
162 static addr_t func_bound_offset
;
163 static unsigned long func_bound_ind
;
164 ST_DATA
int func_bound_add_epilog
;
167 #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
168 static CType float_type
, double_type
, func_float_type
, func_double_type
;
169 ST_FUNC
void arm_init(struct TCCState
*s
)
171 float_type
.t
= VT_FLOAT
;
172 double_type
.t
= VT_DOUBLE
;
173 func_float_type
.t
= VT_FUNC
;
174 func_float_type
.ref
= sym_push(SYM_FIELD
, &float_type
, FUNC_CDECL
, FUNC_OLD
);
175 func_double_type
.t
= VT_FUNC
;
176 func_double_type
.ref
= sym_push(SYM_FIELD
, &double_type
, FUNC_CDECL
, FUNC_OLD
);
178 float_abi
= s
->float_abi
;
179 #ifndef TCC_ARM_HARDFLOAT
180 # warning "soft float ABI currently not supported: default to softfp"
184 #define func_float_type func_old_type
185 #define func_double_type func_old_type
186 #define func_ldouble_type func_old_type
187 ST_FUNC
void arm_init(struct TCCState
*s
)
190 #if !defined (TCC_ARM_VFP)
191 tcc_warning("Support for FPA is deprecated and will be removed in next"
194 #if !defined (TCC_ARM_EABI)
195 tcc_warning("Support for OABI is deprecated and will be removed in next"
202 #define CHECK_R(r) ((r) >= TREG_R0 && (r) <= TREG_LR)
204 static int two2mask(int a
,int b
) {
205 if (!CHECK_R(a
) || !CHECK_R(b
))
206 tcc_error("compiler error! registers %i,%i is not valid",a
,b
);
207 return (reg_classes
[a
]|reg_classes
[b
])&~(RC_INT
|RC_FLOAT
);
210 static int regmask(int r
) {
212 tcc_error("compiler error! register %i is not valid",r
);
213 return reg_classes
[r
]&~(RC_INT
|RC_FLOAT
);
216 /******************************************************/
218 #if defined(TCC_ARM_EABI) && !defined(CONFIG_TCC_ELFINTERP)
219 const char *default_elfinterp(struct TCCState
*s
)
221 if (s
->float_abi
== ARM_HARD_FLOAT
)
222 return "/lib/ld-linux-armhf.so.3";
224 return "/lib/ld-linux.so.3";
230 /* this is a good place to start adding big-endian support*/
235 if (!cur_text_section
)
236 tcc_error("compiler error! This happens f.ex. if the compiler\n"
237 "can't evaluate constant expressions outside of a function.");
238 if (ind1
> cur_text_section
->data_allocated
)
239 section_realloc(cur_text_section
, ind1
);
240 cur_text_section
->data
[ind
++] = i
&255;
242 cur_text_section
->data
[ind
++] = i
&255;
244 cur_text_section
->data
[ind
++] = i
&255;
246 cur_text_section
->data
[ind
++] = i
;
249 static uint32_t stuff_const(uint32_t op
, uint32_t c
)
252 uint32_t nc
= 0, negop
= 0;
262 case 0x1A00000: //mov
263 case 0x1E00000: //mvn
270 return (op
&0xF010F000)|((op
>>16)&0xF)|0x1E00000;
274 return (op
&0xF010F000)|((op
>>16)&0xF)|0x1A00000;
275 case 0x1C00000: //bic
280 case 0x1800000: //orr
282 return (op
&0xFFF0FFFF)|0x1E00000;
288 if(c
<256) /* catch undefined <<32 */
291 m
=(0xff>>i
)|(0xff<<(32-i
));
293 return op
|(i
<<7)|(c
<<i
)|(c
>>(32-i
));
303 void stuff_const_harder(uint32_t op
, uint32_t v
) {
309 uint32_t a
[16], nv
, no
, o2
, n2
;
312 o2
=(op
&0xfff0ffff)|((op
&0xf000)<<4);;
314 a
[i
]=(a
[i
-1]>>2)|(a
[i
-1]<<30);
316 for(j
=i
<4?i
+12:15;j
>=i
+4;j
--)
317 if((v
&(a
[i
]|a
[j
]))==v
) {
318 o(stuff_const(op
,v
&a
[i
]));
319 o(stuff_const(o2
,v
&a
[j
]));
326 for(j
=i
<4?i
+12:15;j
>=i
+4;j
--)
327 if((nv
&(a
[i
]|a
[j
]))==nv
) {
328 o(stuff_const(no
,nv
&a
[i
]));
329 o(stuff_const(n2
,nv
&a
[j
]));
334 for(k
=i
<4?i
+12:15;k
>=j
+4;k
--)
335 if((v
&(a
[i
]|a
[j
]|a
[k
]))==v
) {
336 o(stuff_const(op
,v
&a
[i
]));
337 o(stuff_const(o2
,v
&a
[j
]));
338 o(stuff_const(o2
,v
&a
[k
]));
345 for(k
=i
<4?i
+12:15;k
>=j
+4;k
--)
346 if((nv
&(a
[i
]|a
[j
]|a
[k
]))==nv
) {
347 o(stuff_const(no
,nv
&a
[i
]));
348 o(stuff_const(n2
,nv
&a
[j
]));
349 o(stuff_const(n2
,nv
&a
[k
]));
352 o(stuff_const(op
,v
&a
[0]));
353 o(stuff_const(o2
,v
&a
[4]));
354 o(stuff_const(o2
,v
&a
[8]));
355 o(stuff_const(o2
,v
&a
[12]));
359 uint32_t encbranch(int pos
, int addr
, int fail
)
363 if(addr
>=0x1000000 || addr
<-0x1000000) {
365 tcc_error("FIXME: function bigger than 32MB");
368 return 0x0A000000|(addr
&0xffffff);
371 int decbranch(int pos
)
374 x
=*(uint32_t *)(cur_text_section
->data
+ pos
);
381 /* output a symbol and patch all calls to it */
382 void gsym_addr(int t
, int a
)
387 x
=(uint32_t *)(cur_text_section
->data
+ t
);
390 *x
=0xE1A00000; // nop
393 *x
|= encbranch(lt
,a
,1);
399 static uint32_t vfpr(int r
)
401 if(r
<TREG_F0
|| r
>TREG_F7
)
402 tcc_error("compiler error! register %i is no vfp register",r
);
406 static uint32_t fpr(int r
)
408 if(r
<TREG_F0
|| r
>TREG_F3
)
409 tcc_error("compiler error! register %i is no fpa register",r
);
414 static uint32_t intr(int r
)
418 if(r
>= TREG_R0
&& r
<= TREG_R3
)
420 if (!(r
>= TREG_SP
&& r
<= TREG_LR
))
421 tcc_error("compiler error! register %i is no int register",r
);
422 return r
+ (13 - TREG_SP
);
425 static void calcaddr(uint32_t *base
, int *off
, int *sgn
, int maxoff
, unsigned shift
)
427 if(*off
>maxoff
|| *off
&((1<<shift
)-1)) {
434 y
=stuff_const(x
,*off
&~maxoff
);
440 y
=stuff_const(x
,(*off
+maxoff
)&~maxoff
);
444 *off
=((*off
+maxoff
)&~maxoff
)-*off
;
447 stuff_const_harder(x
,*off
&~maxoff
);
452 static uint32_t mapcc(int cc
)
457 return 0x30000000; /* CC/LO */
459 return 0x20000000; /* CS/HS */
461 return 0x00000000; /* EQ */
463 return 0x10000000; /* NE */
465 return 0x90000000; /* LS */
467 return 0x80000000; /* HI */
469 return 0x40000000; /* MI */
471 return 0x50000000; /* PL */
473 return 0xB0000000; /* LT */
475 return 0xA0000000; /* GE */
477 return 0xD0000000; /* LE */
479 return 0xC0000000; /* GT */
481 tcc_error("unexpected condition code");
482 return 0xE0000000; /* AL */
485 static int negcc(int cc
)
514 tcc_error("unexpected condition code");
518 /* load 'r' from value 'sv' */
519 void load(int r
, SValue
*sv
)
521 int v
, ft
, fc
, fr
, sign
;
538 uint32_t base
= 0xB; // fp
541 v1
.r
= VT_LOCAL
| VT_LVAL
;
547 } else if(v
== VT_CONST
) {
556 } else if(v
< VT_CONST
) {
563 calcaddr(&base
,&fc
,&sign
,1020,2);
565 op
=0xED100A00; /* flds */
568 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
569 op
|=0x100; /* flds -> fldd */
570 o(op
|(vfpr(r
)<<12)|(fc
>>2)|(base
<<16));
575 #if LDOUBLE_SIZE == 8
576 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
579 if ((ft
& VT_BTYPE
) == VT_DOUBLE
)
581 else if ((ft
& VT_BTYPE
) == VT_LDOUBLE
)
584 o(op
|(fpr(r
)<<12)|(fc
>>2)|(base
<<16));
586 } else if((ft
& (VT_BTYPE
|VT_UNSIGNED
)) == VT_BYTE
587 || (ft
& VT_BTYPE
) == VT_SHORT
) {
588 calcaddr(&base
,&fc
,&sign
,255,0);
590 if ((ft
& VT_BTYPE
) == VT_SHORT
)
592 if ((ft
& VT_UNSIGNED
) == 0)
596 o(op
|(intr(r
)<<12)|(base
<<16)|((fc
&0xf0)<<4)|(fc
&0xf));
598 calcaddr(&base
,&fc
,&sign
,4095,0);
602 if ((ft
& VT_BTYPE
) == VT_BYTE
|| (ft
& VT_BTYPE
) == VT_BOOL
)
604 o(op
|(intr(r
)<<12)|fc
|(base
<<16));
610 op
=stuff_const(0xE3A00000|(intr(r
)<<12),sv
->c
.i
);
611 if (fr
& VT_SYM
|| !op
) {
612 o(0xE59F0000|(intr(r
)<<12));
615 greloc(cur_text_section
, sv
->sym
, ind
, R_ARM_ABS32
);
620 } else if (v
== VT_LOCAL
) {
621 op
=stuff_const(0xE28B0000|(intr(r
)<<12),sv
->c
.i
);
622 if (fr
& VT_SYM
|| !op
) {
623 o(0xE59F0000|(intr(r
)<<12));
625 if(fr
& VT_SYM
) // needed ?
626 greloc(cur_text_section
, sv
->sym
, ind
, R_ARM_ABS32
);
628 o(0xE08B0000|(intr(r
)<<12)|intr(r
));
632 } else if(v
== VT_CMP
) {
633 o(mapcc(sv
->c
.i
)|0x3A00001|(intr(r
)<<12));
634 o(mapcc(negcc(sv
->c
.i
))|0x3A00000|(intr(r
)<<12));
636 } else if (v
== VT_JMP
|| v
== VT_JMPI
) {
639 o(0xE3A00000|(intr(r
)<<12)|t
);
642 o(0xE3A00000|(intr(r
)<<12)|(t
^1));
644 } else if (v
< VT_CONST
) {
647 o(0xEEB00A40|(vfpr(r
)<<12)|vfpr(v
)|T2CPR(ft
)); /* fcpyX */
649 o(0xEE008180|(fpr(r
)<<12)|fpr(v
));
652 o(0xE1A00000|(intr(r
)<<12)|intr(v
));
656 tcc_error("load unimplemented!");
659 /* store register 'r' in lvalue 'v' */
660 void store(int r
, SValue
*sv
)
663 int v
, ft
, fc
, fr
, sign
;
678 if (fr
& VT_LVAL
|| fr
== VT_LOCAL
) {
679 uint32_t base
= 0xb; /* fp */
684 } else if(v
== VT_CONST
) {
696 calcaddr(&base
,&fc
,&sign
,1020,2);
698 op
=0xED000A00; /* fsts */
701 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
702 op
|=0x100; /* fsts -> fstd */
703 o(op
|(vfpr(r
)<<12)|(fc
>>2)|(base
<<16));
708 #if LDOUBLE_SIZE == 8
709 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
712 if ((ft
& VT_BTYPE
) == VT_DOUBLE
)
714 if ((ft
& VT_BTYPE
) == VT_LDOUBLE
)
717 o(op
|(fpr(r
)<<12)|(fc
>>2)|(base
<<16));
720 } else if((ft
& VT_BTYPE
) == VT_SHORT
) {
721 calcaddr(&base
,&fc
,&sign
,255,0);
725 o(op
|(intr(r
)<<12)|(base
<<16)|((fc
&0xf0)<<4)|(fc
&0xf));
727 calcaddr(&base
,&fc
,&sign
,4095,0);
731 if ((ft
& VT_BTYPE
) == VT_BYTE
|| (ft
& VT_BTYPE
) == VT_BOOL
)
733 o(op
|(intr(r
)<<12)|fc
|(base
<<16));
738 tcc_error("store unimplemented");
741 static void gadd_sp(int val
)
743 stuff_const_harder(0xE28DD000,val
);
746 /* 'is_jmp' is '1' if it is a jump */
747 static void gcall_or_jmp(int is_jmp
)
751 if ((vtop
->r
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
) {
753 if(vtop
->r
& VT_SYM
){
754 x
=encbranch(ind
,ind
+vtop
->c
.i
,0);
756 /* relocation case */
757 greloc(cur_text_section
, vtop
->sym
, ind
, R_ARM_PC24
);
758 o(x
|(is_jmp
?0xE0000000:0xE1000000));
761 o(0xE28FE004); // add lr,pc,#4
762 o(0xE51FF004); // ldr pc,[pc,#-4]
763 greloc(cur_text_section
, vtop
->sym
, ind
, R_ARM_ABS32
);
768 o(0xE28FE004); // add lr,pc,#4
769 o(0xE51FF004); // ldr pc,[pc,#-4]
773 /* otherwise, indirect call */
774 #ifdef CONFIG_TCC_BCHECK
775 vtop
->r
&= ~VT_MUSTBOUND
;
779 o(0xE1A0E00F); // mov lr,pc
780 o(0xE1A0F000|intr(r
)); // mov pc,r
784 #if defined(CONFIG_TCC_BCHECK)
786 static void gen_bounds_call(int v
)
788 Sym
*sym
= external_helper_sym(v
);
790 greloc(cur_text_section
, sym
, ind
, R_ARM_PC24
);
794 static void gen_bounds_prolog(void)
796 /* leave some room for bound checking code */
797 func_bound_offset
= lbounds_section
->data_offset
;
798 func_bound_ind
= ind
;
799 func_bound_add_epilog
= 0;
800 o(0xe1a00000); /* ld r0,lbounds_section->data_offset */
803 o(0xe1a00000); /* call __bound_local_new */
806 static void gen_bounds_epilog(void)
811 int offset_modified
= func_bound_offset
!= lbounds_section
->data_offset
;
813 if (!offset_modified
&& !func_bound_add_epilog
)
816 /* add end of table info */
817 bounds_ptr
= section_ptr_add(lbounds_section
, sizeof(addr_t
));
820 sym_data
= get_sym_ref(&char_pointer_type
, lbounds_section
,
821 func_bound_offset
, lbounds_section
->data_offset
);
823 /* generate bound local allocation */
824 if (offset_modified
) {
826 ind
= func_bound_ind
;
827 o(0xe59f0000); /* ldr r0, [pc] */
828 o(0xea000000); /* b $+4 */
829 greloc(cur_text_section
, sym_data
, ind
, R_ARM_ABS32
);
830 o(0x00000000); /* lbounds_section->data_offset */
831 gen_bounds_call(TOK___bound_local_new
);
835 /* generate bound check local freeing */
836 o(0xe92d0003); /* push {r0,r1} */
837 o(0xed2d0b02); /* vpush {d0} */
838 o(0xe59f0000); /* ldr r0, [pc] */
839 o(0xea000000); /* b $+4 */
840 greloc(cur_text_section
, sym_data
, ind
, R_ARM_ABS32
);
841 o(0x00000000); /* lbounds_section->data_offset */
842 gen_bounds_call(TOK___bound_local_delete
);
843 o(0xecbd0b02); /* vpop {d0} */
844 o(0xe8bd0003); /* pop {r0,r1} */
848 static int unalias_ldbl(int btype
)
850 #if LDOUBLE_SIZE == 8
851 if (btype
== VT_LDOUBLE
)
857 /* Return whether a structure is an homogeneous float aggregate or not.
858 The answer is true if all the elements of the structure are of the same
859 primitive float type and there is less than 4 elements.
861 type: the type corresponding to the structure to be tested */
862 static int is_hgen_float_aggr(CType
*type
)
864 if ((type
->t
& VT_BTYPE
) == VT_STRUCT
) {
866 int btype
, nb_fields
= 0;
868 ref
= type
->ref
->next
;
870 btype
= unalias_ldbl(ref
->type
.t
& VT_BTYPE
);
871 if (btype
== VT_FLOAT
|| btype
== VT_DOUBLE
) {
872 for(; ref
&& btype
== unalias_ldbl(ref
->type
.t
& VT_BTYPE
); ref
= ref
->next
, nb_fields
++);
873 return !ref
&& nb_fields
<= 4;
881 signed char avail
[3]; /* 3 holes max with only float and double alignments */
882 int first_hole
; /* first available hole */
883 int last_hole
; /* last available hole (none if equal to first_hole) */
884 int first_free_reg
; /* next free register in the sequence, hole excluded */
887 /* Find suitable registers for a VFP Co-Processor Register Candidate (VFP CPRC
888 param) according to the rules described in the procedure call standard for
889 the ARM architecture (AAPCS). If found, the registers are assigned to this
890 VFP CPRC parameter. Registers are allocated in sequence unless a hole exists
891 and the parameter is a single float.
893 avregs: opaque structure to keep track of available VFP co-processor regs
894 align: alignment constraints for the param, as returned by type_size()
895 size: size of the parameter, as returned by type_size() */
896 int assign_vfpreg(struct avail_regs
*avregs
, int align
, int size
)
900 if (avregs
->first_free_reg
== -1)
902 if (align
>> 3) { /* double alignment */
903 first_reg
= avregs
->first_free_reg
;
904 /* alignment constraint not respected so use next reg and record hole */
906 avregs
->avail
[avregs
->last_hole
++] = first_reg
++;
907 } else { /* no special alignment (float or array of float) */
908 /* if single float and a hole is available, assign the param to it */
909 if (size
== 4 && avregs
->first_hole
!= avregs
->last_hole
)
910 return avregs
->avail
[avregs
->first_hole
++];
912 first_reg
= avregs
->first_free_reg
;
914 if (first_reg
+ size
/ 4 <= 16) {
915 avregs
->first_free_reg
= first_reg
+ size
/ 4;
918 avregs
->first_free_reg
= -1;
922 /* Returns whether all params need to be passed in core registers or not.
923 This is the case for function part of the runtime ABI. */
924 int floats_in_core_regs(SValue
*sval
)
929 switch (sval
->sym
->v
) {
930 case TOK___floatundisf
:
931 case TOK___floatundidf
:
932 case TOK___fixunssfdi
:
933 case TOK___fixunsdfdi
:
935 case TOK___fixunsxfdi
:
937 case TOK___floatdisf
:
938 case TOK___floatdidf
:
948 /* Return the number of registers needed to return the struct, or 0 if
949 returning via struct pointer. */
950 ST_FUNC
int gfunc_sret(CType
*vt
, int variadic
, CType
*ret
, int *ret_align
, int *regsize
) {
953 size
= type_size(vt
, &align
);
954 if (float_abi
== ARM_HARD_FLOAT
&& !variadic
&&
955 (is_float(vt
->t
) || is_hgen_float_aggr(vt
))) {
960 return (size
+ 7) >> 3;
961 } else if (size
> 0 && size
<= 4) {
974 /* Parameters are classified according to how they are copied to their final
975 destination for the function call. Because the copying is performed class
976 after class according to the order in the union below, it is important that
977 some constraints about the order of the members of this union are respected:
978 - CORE_STRUCT_CLASS must come after STACK_CLASS;
979 - CORE_CLASS must come after STACK_CLASS, CORE_STRUCT_CLASS and
981 - VFP_STRUCT_CLASS must come after VFP_CLASS.
982 See the comment for the main loop in copy_params() for the reason. */
993 int start
; /* first reg or addr used depending on the class */
994 int end
; /* last reg used or next free addr depending on the class */
995 SValue
*sval
; /* pointer to SValue on the value stack */
996 struct param_plan
*prev
; /* previous element in this class */
1000 struct param_plan
*pplans
; /* array of all the param plans */
1001 struct param_plan
*clsplans
[NB_CLASSES
]; /* per class lists of param plans */
1005 static void add_param_plan(struct plan
* plan
, int cls
, int start
, int end
, SValue
*v
)
1007 struct param_plan
*p
= &plan
->pplans
[plan
->nb_plans
++];
1008 p
->prev
= plan
->clsplans
[cls
];
1009 plan
->clsplans
[cls
] = p
;
1010 p
->start
= start
, p
->end
= end
, p
->sval
= v
;
1013 /* Assign parameters to registers and stack with alignment according to the
1014 rules in the procedure call standard for the ARM architecture (AAPCS).
1015 The overall assignment is recorded in an array of per parameter structures
1016 called parameter plans. The parameter plans are also further organized in a
1017 number of linked lists, one per class of parameter (see the comment for the
1018 definition of union reg_class).
1020 nb_args: number of parameters of the function for which a call is generated
1021 float_abi: float ABI in use for this function call
1022 plan: the structure where the overall assignment is recorded
1023 todo: a bitmap that record which core registers hold a parameter
1025 Returns the amount of stack space needed for parameter passing
1027 Note: this function allocated an array in plan->pplans with tcc_malloc. It
1028 is the responsibility of the caller to free this array once used (ie not
1029 before copy_params). */
1030 static int assign_regs(int nb_args
, int float_abi
, struct plan
*plan
, int *todo
)
1033 int ncrn
/* next core register number */, nsaa
/* next stacked argument address*/;
1034 struct avail_regs avregs
= {{0}};
1039 for(i
= nb_args
; i
-- ;) {
1040 int j
, start_vfpreg
= 0;
1041 CType type
= vtop
[-i
].type
;
1042 type
.t
&= ~VT_ARRAY
;
1043 size
= type_size(&type
, &align
);
1044 size
= (size
+ 3) & ~3;
1045 align
= (align
+ 3) & ~3;
1046 switch(vtop
[-i
].type
.t
& VT_BTYPE
) {
1051 if (float_abi
== ARM_HARD_FLOAT
) {
1052 int is_hfa
= 0; /* Homogeneous float aggregate */
1054 if (is_float(vtop
[-i
].type
.t
)
1055 || (is_hfa
= is_hgen_float_aggr(&vtop
[-i
].type
))) {
1058 start_vfpreg
= assign_vfpreg(&avregs
, align
, size
);
1059 end_vfpreg
= start_vfpreg
+ ((size
- 1) >> 2);
1060 if (start_vfpreg
>= 0) {
1061 add_param_plan(plan
, is_hfa
? VFP_STRUCT_CLASS
: VFP_CLASS
,
1062 start_vfpreg
, end_vfpreg
, &vtop
[-i
]);
1068 ncrn
= (ncrn
+ (align
-1)/4) & ~((align
/4) - 1);
1069 if (ncrn
+ size
/4 <= 4 || (ncrn
< 4 && start_vfpreg
!= -1)) {
1070 /* The parameter is allocated both in core register and on stack. As
1071 * such, it can be of either class: it would either be the last of
1072 * CORE_STRUCT_CLASS or the first of STACK_CLASS. */
1073 for (j
= ncrn
; j
< 4 && j
< ncrn
+ size
/ 4; j
++)
1075 add_param_plan(plan
, CORE_STRUCT_CLASS
, ncrn
, j
, &vtop
[-i
]);
1078 nsaa
= (ncrn
- 4) * 4;
1086 int is_long
= (vtop
[-i
].type
.t
& VT_BTYPE
) == VT_LLONG
;
1089 ncrn
= (ncrn
+ 1) & -2;
1093 add_param_plan(plan
, CORE_CLASS
, ncrn
, ncrn
+ is_long
, &vtop
[-i
]);
1094 ncrn
+= 1 + is_long
;
1098 nsaa
= (nsaa
+ (align
- 1)) & ~(align
- 1);
1099 add_param_plan(plan
, STACK_CLASS
, nsaa
, nsaa
+ size
, &vtop
[-i
]);
1100 nsaa
+= size
; /* size already rounded up before */
1105 /* Copy parameters to their final destination (core reg, VFP reg or stack) for
1108 nb_args: number of parameters the function take
1109 plan: the overall assignment plan for parameters
1110 todo: a bitmap indicating what core reg will hold a parameter
1112 Returns the number of SValue added by this function on the value stack */
1113 static int copy_params(int nb_args
, struct plan
*plan
, int todo
)
1115 int size
, align
, r
, i
, nb_extra_sval
= 0;
1116 struct param_plan
*pplan
;
1119 /* Several constraints require parameters to be copied in a specific order:
1120 - structures are copied to the stack before being loaded in a reg;
1121 - floats loaded to an odd numbered VFP reg are first copied to the
1122 preceding even numbered VFP reg and then moved to the next VFP reg.
1124 It is thus important that:
1125 - structures assigned to core regs must be copied after parameters
1126 assigned to the stack but before structures assigned to VFP regs because
1127 a structure can lie partly in core registers and partly on the stack;
1128 - parameters assigned to the stack and all structures be copied before
1129 parameters assigned to a core reg since copying a parameter to the stack
1130 require using a core reg;
1131 - parameters assigned to VFP regs be copied before structures assigned to
1132 VFP regs as the copy might use an even numbered VFP reg that already
1133 holds part of a structure. */
1135 for(i
= 0; i
< NB_CLASSES
; i
++) {
1136 for(pplan
= plan
->clsplans
[i
]; pplan
; pplan
= pplan
->prev
) {
1139 && (i
!= CORE_CLASS
|| pplan
->sval
->r
< VT_CONST
))
1142 vpushv(pplan
->sval
);
1143 pplan
->sval
->r
= pplan
->sval
->r2
= VT_CONST
; /* disable entry */
1146 case CORE_STRUCT_CLASS
:
1147 case VFP_STRUCT_CLASS
:
1148 if ((pplan
->sval
->type
.t
& VT_BTYPE
) == VT_STRUCT
) {
1150 size
= type_size(&pplan
->sval
->type
, &align
);
1151 /* align to stack align size */
1152 size
= (size
+ 3) & ~3;
1153 if (i
== STACK_CLASS
&& pplan
->prev
)
1154 padding
= pplan
->start
- pplan
->prev
->end
;
1155 size
+= padding
; /* Add padding if any */
1156 /* allocate the necessary size on stack */
1158 /* generate structure store */
1159 r
= get_reg(RC_INT
);
1160 o(0xE28D0000|(intr(r
)<<12)|padding
); /* add r, sp, padding */
1161 vset(&vtop
->type
, r
| VT_LVAL
, 0);
1163 vstore(); /* memcpy to current sp + potential padding */
1165 /* Homogeneous float aggregate are loaded to VFP registers
1166 immediately since there is no way of loading data in multiple
1167 non consecutive VFP registers as what is done for other
1168 structures (see the use of todo). */
1169 if (i
== VFP_STRUCT_CLASS
) {
1170 int first
= pplan
->start
, nb
= pplan
->end
- first
+ 1;
1171 /* vpop.32 {pplan->start, ..., pplan->end} */
1172 o(0xECBD0A00|(first
&1)<<22|(first
>>1)<<12|nb
);
1173 /* No need to write the register used to a SValue since VFP regs
1174 cannot be used for gcall_or_jmp */
1177 if (is_float(pplan
->sval
->type
.t
)) {
1179 r
= vfpr(gv(RC_FLOAT
)) << 12;
1180 if ((pplan
->sval
->type
.t
& VT_BTYPE
) == VT_FLOAT
)
1184 r
|= 0x101; /* vpush.32 -> vpush.64 */
1186 o(0xED2D0A01 + r
); /* vpush */
1188 r
= fpr(gv(RC_FLOAT
)) << 12;
1189 if ((pplan
->sval
->type
.t
& VT_BTYPE
) == VT_FLOAT
)
1191 else if ((pplan
->sval
->type
.t
& VT_BTYPE
) == VT_DOUBLE
)
1194 size
= LDOUBLE_SIZE
;
1201 o(0xED2D0100|r
|(size
>>2)); /* some kind of vpush for FPA */
1204 /* simple type (currently always same size) */
1205 /* XXX: implicit cast ? */
1207 if ((pplan
->sval
->type
.t
& VT_BTYPE
) == VT_LLONG
) {
1211 o(0xE52D0004|(intr(r
)<<12)); /* push r */
1215 o(0xE52D0004|(intr(r
)<<12)); /* push r */
1217 if (i
== STACK_CLASS
&& pplan
->prev
)
1218 gadd_sp(pplan
->prev
->end
- pplan
->start
); /* Add padding if any */
1223 gv(regmask(TREG_F0
+ (pplan
->start
>> 1)));
1224 if (pplan
->start
& 1) { /* Must be in upper part of double register */
1225 o(0xEEF00A40|((pplan
->start
>>1)<<12)|(pplan
->start
>>1)); /* vmov.f32 s(n+1), sn */
1226 vtop
->r
= VT_CONST
; /* avoid being saved on stack by gv for next float */
1231 if ((pplan
->sval
->type
.t
& VT_BTYPE
) == VT_LLONG
) {
1233 gv(regmask(pplan
->end
));
1234 pplan
->sval
->r2
= vtop
->r
;
1237 gv(regmask(pplan
->start
));
1238 /* Mark register as used so that gcall_or_jmp use another one
1239 (regs >=4 are free as never used to pass parameters) */
1240 pplan
->sval
->r
= vtop
->r
;
1247 /* second pass to restore registers that were saved on stack by accident.
1248 Maybe redundant after the "lvalue_save" patch in tccgen.c:gv() */
1252 /* Manually free remaining registers since next parameters are loaded
1253 * manually, without the help of gv(int). */
1257 o(0xE8BD0000|todo
); /* pop {todo} */
1258 for(pplan
= plan
->clsplans
[CORE_STRUCT_CLASS
]; pplan
; pplan
= pplan
->prev
) {
1260 pplan
->sval
->r
= pplan
->start
;
1261 /* An SValue can only pin 2 registers at best (r and r2) but a structure
1262 can occupy more than 2 registers. Thus, we need to push on the value
1263 stack some fake parameter to have on SValue for each registers used
1264 by a structure (r2 is not used). */
1265 for (r
= pplan
->start
+ 1; r
<= pplan
->end
; r
++) {
1266 if (todo
& (1 << r
)) {
1274 return nb_extra_sval
;
1277 /* Generate function call. The function address is pushed first, then
1278 all the parameters in call order. This functions pops all the
1279 parameters and the function address. */
1280 void gfunc_call(int nb_args
)
1283 int def_float_abi
= float_abi
;
1290 #ifdef CONFIG_TCC_BCHECK
1291 if (tcc_state
->do_bounds_check
)
1292 gbound_args(nb_args
);
1296 if (float_abi
== ARM_HARD_FLOAT
) {
1297 variadic
= (vtop
[-nb_args
].type
.ref
->f
.func_type
== FUNC_ELLIPSIS
);
1298 if (variadic
|| floats_in_core_regs(&vtop
[-nb_args
]))
1299 float_abi
= ARM_SOFTFP_FLOAT
;
1302 /* cannot let cpu flags if other instruction are generated. Also avoid leaving
1303 VT_JMP anywhere except on the top of the stack because it would complicate
1304 the code generator. */
1305 r
= vtop
->r
& VT_VALMASK
;
1306 if (r
== VT_CMP
|| (r
& ~1) == VT_JMP
)
1309 memset(&plan
, 0, sizeof plan
);
1311 plan
.pplans
= tcc_malloc(nb_args
* sizeof(*plan
.pplans
));
1313 args_size
= assign_regs(nb_args
, float_abi
, &plan
, &todo
);
1316 if (args_size
& 7) { /* Stack must be 8 byte aligned at fct call for EABI */
1317 args_size
= (args_size
+ 7) & ~7;
1318 o(0xE24DD004); /* sub sp, sp, #4 */
1322 nb_args
+= copy_params(nb_args
, &plan
, todo
);
1323 tcc_free(plan
.pplans
);
1325 /* Move fct SValue on top as required by gcall_or_jmp */
1329 gadd_sp(args_size
); /* pop all parameters passed on the stack */
1330 #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
1331 if(float_abi
== ARM_SOFTFP_FLOAT
&& is_float(vtop
->type
.ref
->type
.t
)) {
1332 if((vtop
->type
.ref
->type
.t
& VT_BTYPE
) == VT_FLOAT
) {
1333 o(0xEE000A10); /*vmov s0, r0 */
1335 o(0xEE000B10); /* vmov.32 d0[0], r0 */
1336 o(0xEE201B10); /* vmov.32 d0[1], r1 */
1340 vtop
-= nb_args
+ 1; /* Pop all params and fct address from value stack */
1341 leaffunc
= 0; /* we are calling a function, so we aren't in a leaf function */
1342 float_abi
= def_float_abi
;
1345 /* generate function prolog of type 't' */
1346 void gfunc_prolog(Sym
*func_sym
)
1348 CType
*func_type
= &func_sym
->type
;
1350 int n
, nf
, size
, align
, rs
, struct_ret
= 0;
1351 int addr
, pn
, sn
; /* pn=core, sn=stack */
1355 struct avail_regs avregs
= {{0}};
1358 sym
= func_type
->ref
;
1361 if ((func_vt
.t
& VT_BTYPE
) == VT_STRUCT
&&
1362 !gfunc_sret(&func_vt
, func_var
, &ret_type
, &align
, &rs
))
1366 func_vc
= 12; /* Offset from fp of the place to store the result */
1368 for(sym2
= sym
->next
; sym2
&& (n
< 4 || nf
< 16); sym2
= sym2
->next
) {
1369 size
= type_size(&sym2
->type
, &align
);
1371 if (float_abi
== ARM_HARD_FLOAT
&& !func_var
&&
1372 (is_float(sym2
->type
.t
) || is_hgen_float_aggr(&sym2
->type
))) {
1373 int tmpnf
= assign_vfpreg(&avregs
, align
, size
);
1374 tmpnf
+= (size
+ 3) / 4;
1375 nf
= (tmpnf
> nf
) ? tmpnf
: nf
;
1379 n
+= (size
+ 3) / 4;
1381 o(0xE1A0C00D); /* mov ip,sp */
1390 o(0xE92D0000|((1<<n
)-1)); /* save r0-r4 on stack if needed */
1395 nf
=(nf
+1)&-2; /* nf => HARDFLOAT => EABI */
1396 o(0xED2D0A00|nf
); /* save s0-s15 on stack if needed */
1398 o(0xE92D5800); /* save fp, ip, lr */
1399 o(0xE1A0B00D); /* mov fp, sp */
1400 func_sub_sp_offset
= ind
;
1401 o(0xE1A00000); /* nop, leave space for stack adjustment in epilog */
1404 if (float_abi
== ARM_HARD_FLOAT
) {
1406 memset(&avregs
, 0, sizeof avregs
);
1409 pn
= struct_ret
, sn
= 0;
1410 while ((sym
= sym
->next
)) {
1413 size
= type_size(type
, &align
);
1414 size
= (size
+ 3) >> 2;
1415 align
= (align
+ 3) & ~3;
1417 if (float_abi
== ARM_HARD_FLOAT
&& !func_var
&& (is_float(sym
->type
.t
)
1418 || is_hgen_float_aggr(&sym
->type
))) {
1419 int fpn
= assign_vfpreg(&avregs
, align
, size
<< 2);
1428 pn
= (pn
+ (align
-1)/4) & -(align
/4);
1430 addr
= (nf
+ pn
) * 4;
1437 sn
= (sn
+ (align
-1)/4) & -(align
/4);
1439 addr
= (n
+ nf
+ sn
) * 4;
1442 sym_push(sym
->v
& ~SYM_FIELD
, type
, VT_LOCAL
| VT_LVAL
,
1448 #ifdef CONFIG_TCC_BCHECK
1449 if (tcc_state
->do_bounds_check
)
1450 gen_bounds_prolog();
1454 /* generate function epilog */
1455 void gfunc_epilog(void)
1460 #ifdef CONFIG_TCC_BCHECK
1461 if (tcc_state
->do_bounds_check
)
1462 gen_bounds_epilog();
1464 /* Copy float return value to core register if base standard is used and
1465 float computation is made with VFP */
1466 #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
1467 if ((float_abi
== ARM_SOFTFP_FLOAT
|| func_var
) && is_float(func_vt
.t
)) {
1468 if((func_vt
.t
& VT_BTYPE
) == VT_FLOAT
)
1469 o(0xEE100A10); /* fmrs r0, s0 */
1471 o(0xEE100B10); /* fmrdl r0, d0 */
1472 o(0xEE301B10); /* fmrdh r1, d0 */
1476 o(0xE89BA800); /* restore fp, sp, pc */
1477 diff
= (-loc
+ 3) & -4;
1480 diff
= ((diff
+ 11) & -8) - 4;
1483 x
=stuff_const(0xE24BD000, diff
); /* sub sp,fp,# */
1485 *(uint32_t *)(cur_text_section
->data
+ func_sub_sp_offset
) = x
;
1489 o(0xE59FC004); /* ldr ip,[pc+4] */
1490 o(0xE04BD00C); /* sub sp,fp,ip */
1491 o(0xE1A0F00E); /* mov pc,lr */
1493 *(uint32_t *)(cur_text_section
->data
+ func_sub_sp_offset
) = 0xE1000000|encbranch(func_sub_sp_offset
,addr
,1);
1498 ST_FUNC
void gen_fill_nops(int bytes
)
1501 tcc_error("alignment of code section not multiple of 4");
1508 /* generate a jump to a label */
1509 ST_FUNC
int gjmp(int t
)
1515 o(0xE0000000|encbranch(r
,t
,1));
1519 /* generate a jump to a fixed address */
1520 ST_FUNC
void gjmp_addr(int a
)
1525 ST_FUNC
int gjmp_cond(int op
, int t
)
1532 op
|=encbranch(r
,t
,1);
1537 ST_FUNC
int gjmp_append(int n
, int t
)
1544 p
= decbranch(lp
=p
);
1546 x
= (uint32_t *)(cur_text_section
->data
+ lp
);
1548 *x
|= encbranch(lp
,t
,1);
1554 /* generate an integer binary operation */
1555 void gen_opi(int op
)
1558 uint32_t opc
= 0, r
, fr
;
1559 unsigned short retreg
= REG_IRET
;
1567 case TOK_ADDC1
: /* add with carry generation */
1575 case TOK_SUBC1
: /* sub with carry generation */
1579 case TOK_ADDC2
: /* add with carry use */
1583 case TOK_SUBC2
: /* sub with carry use */
1600 gv2(RC_INT
, RC_INT
);
1604 o(0xE0000090|(intr(r
)<<16)|(intr(r
)<<8)|intr(fr
));
1629 func
=TOK___aeabi_idivmod
;
1638 func
=TOK___aeabi_uidivmod
;
1646 gv2(RC_INT
, RC_INT
);
1647 r
=intr(vtop
[-1].r2
=get_reg(RC_INT
));
1649 vtop
[-1].r
=get_reg_ex(RC_INT
,regmask(c
));
1651 o(0xE0800090|(r
<<16)|(intr(vtop
->r
)<<12)|(intr(c
)<<8)|intr(vtop
[1].r
));
1660 if((vtop
[-1].r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1661 if(opc
== 4 || opc
== 5 || opc
== 0xc) {
1663 opc
|=2; // sub -> rsb
1666 if ((vtop
->r
& VT_VALMASK
) == VT_CMP
||
1667 (vtop
->r
& (VT_VALMASK
& ~1)) == VT_JMP
)
1672 opc
=0xE0000000|(opc
<<20);
1673 if((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1675 x
=stuff_const(opc
|0x2000000|(c
<<16),vtop
->c
.i
);
1677 r
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,regmask(vtop
[-1].r
)));
1682 fr
=intr(gv(RC_INT
));
1683 if ((vtop
[-1].r
& VT_VALMASK
) >= VT_CONST
) {
1688 r
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,two2mask(vtop
->r
,vtop
[-1].r
)));
1689 o(opc
|(c
<<16)|(r
<<12)|fr
);
1692 if (op
>= TOK_ULT
&& op
<= TOK_GT
)
1696 opc
=0xE1A00000|(opc
<<5);
1697 if ((vtop
->r
& VT_VALMASK
) == VT_CMP
||
1698 (vtop
->r
& (VT_VALMASK
& ~1)) == VT_JMP
)
1703 if ((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1704 fr
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,regmask(vtop
[-1].r
)));
1705 c
= vtop
->c
.i
& 0x1f;
1706 o(opc
|r
|(c
<<7)|(fr
<<12));
1708 fr
=intr(gv(RC_INT
));
1709 if ((vtop
[-1].r
& VT_VALMASK
) >= VT_CONST
) {
1714 c
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,two2mask(vtop
->r
,vtop
[-1].r
)));
1715 o(opc
|r
|(c
<<12)|(fr
<<8)|0x10);
1720 vpush_helper_func(func
);
1727 tcc_error("gen_opi %i unimplemented!",op
);
1732 static int is_zero(int i
)
1734 if((vtop
[i
].r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) != VT_CONST
)
1736 if (vtop
[i
].type
.t
== VT_FLOAT
)
1737 return (vtop
[i
].c
.f
== 0.f
);
1738 else if (vtop
[i
].type
.t
== VT_DOUBLE
)
1739 return (vtop
[i
].c
.d
== 0.0);
1740 return (vtop
[i
].c
.ld
== 0.l
);
1743 /* generate a floating point operation 'v = t1 op t2' instruction. The
1744 * two operands are guaranteed to have the same floating point type */
1745 void gen_opf(int op
)
1749 x
=0xEE000A00|T2CPR(vtop
->type
.t
);
1767 x
|=0x810000; /* fsubX -> fnegX */
1780 if(op
< TOK_ULT
|| op
> TOK_GT
) {
1781 tcc_error("unknown fp op %x!",op
);
1787 case TOK_LT
: op
=TOK_GT
; break;
1788 case TOK_GE
: op
=TOK_ULE
; break;
1789 case TOK_LE
: op
=TOK_GE
; break;
1790 case TOK_GT
: op
=TOK_ULT
; break;
1793 x
|=0xB40040; /* fcmpX */
1794 if(op
!=TOK_EQ
&& op
!=TOK_NE
)
1795 x
|=0x80; /* fcmpX -> fcmpeX */
1798 o(x
|0x10000|(vfpr(gv(RC_FLOAT
))<<12)); /* fcmp(e)X -> fcmp(e)zX */
1800 gv2(RC_FLOAT
,RC_FLOAT
);
1802 o(x
|(vfpr(vtop
[-1].r
) << 12));
1805 o(0xEEF1FA10); /* fmstat */
1808 case TOK_LE
: op
=TOK_ULE
; break;
1809 case TOK_LT
: op
=TOK_ULT
; break;
1810 case TOK_UGE
: op
=TOK_GE
; break;
1811 case TOK_UGT
: op
=TOK_GT
; break;
1825 if ((vtop
[-1].r
& VT_VALMASK
) >= VT_CONST
) {
1832 vtop
->r
=get_reg_ex(RC_FLOAT
,r
);
1835 o(x
|(vfpr(vtop
->r
)<<12));
1839 static uint32_t is_fconst()
1843 if((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) != VT_CONST
)
1845 if (vtop
->type
.t
== VT_FLOAT
)
1847 else if (vtop
->type
.t
== VT_DOUBLE
)
1877 /* generate a floating point operation 'v = t1 op t2' instruction. The
1878 two operands are guaranteed to have the same floating point type */
1879 void gen_opf(int op
)
1881 uint32_t x
, r
, r2
, c1
, c2
;
1882 //fputs("gen_opf\n",stderr);
1888 #if LDOUBLE_SIZE == 8
1889 if ((vtop
->type
.t
& VT_BTYPE
) != VT_FLOAT
)
1892 if ((vtop
->type
.t
& VT_BTYPE
) == VT_DOUBLE
)
1894 else if ((vtop
->type
.t
& VT_BTYPE
) == VT_LDOUBLE
)
1905 r
=fpr(gv(RC_FLOAT
));
1912 r2
=fpr(gv(RC_FLOAT
));
1913 if ((vtop
[-1].r
& VT_VALMASK
) >= VT_CONST
) {
1915 r
=fpr(gv(RC_FLOAT
));
1926 r
=fpr(gv(RC_FLOAT
));
1928 } else if(c1
&& c1
<=0xf) {
1931 r
=fpr(gv(RC_FLOAT
));
1936 r
=fpr(gv(RC_FLOAT
));
1938 r2
=fpr(gv(RC_FLOAT
));
1939 if ((vtop
[-1].r
& VT_VALMASK
) >= VT_CONST
) {
1941 r
=fpr(gv(RC_FLOAT
));
1952 r
=fpr(gv(RC_FLOAT
));
1957 r2
=fpr(gv(RC_FLOAT
));
1958 if ((vtop
[-1].r
& VT_VALMASK
) >= VT_CONST
) {
1960 r
=fpr(gv(RC_FLOAT
));
1971 r
=fpr(gv(RC_FLOAT
));
1973 } else if(c1
&& c1
<=0xf) {
1976 r
=fpr(gv(RC_FLOAT
));
1981 r
=fpr(gv(RC_FLOAT
));
1983 r2
=fpr(gv(RC_FLOAT
));
1984 if ((vtop
[-1].r
& VT_VALMASK
) >= VT_CONST
) {
1986 r
=fpr(gv(RC_FLOAT
));
1992 if(op
>= TOK_ULT
&& op
<= TOK_GT
) {
1993 x
|=0xd0f110; // cmfe
1994 /* bug (intention?) in Linux FPU emulator
1995 doesn't set carry if equal */
2001 tcc_error("unsigned comparison on floats?");
2007 op
=TOK_ULE
; /* correct in unordered case only if AC bit in FPSR set */
2011 x
&=~0x400000; // cmfe -> cmf
2033 r
=fpr(gv(RC_FLOAT
));
2040 r2
=fpr(gv(RC_FLOAT
));
2041 if ((vtop
[-1].r
& VT_VALMASK
) >= VT_CONST
) {
2043 r
=fpr(gv(RC_FLOAT
));
2051 tcc_error("unknown fp op %x!",op
);
2055 if(vtop
[-1].r
== VT_CMP
)
2061 vtop
[-1].r
=get_reg_ex(RC_FLOAT
,two2mask(vtop
[-1].r
,c1
));
2065 o(x
|(r
<<16)|(c1
<<12)|r2
);
2069 /* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
2070 and 'long long' cases. */
2071 ST_FUNC
void gen_cvt_itof(int t
)
2075 bt
=vtop
->type
.t
& VT_BTYPE
;
2076 if(bt
== VT_INT
|| bt
== VT_SHORT
|| bt
== VT_BYTE
) {
2082 r2
=vfpr(vtop
->r
=get_reg(RC_FLOAT
));
2083 o(0xEE000A10|(r
<<12)|(r2
<<16)); /* fmsr */
2085 if(!(vtop
->type
.t
& VT_UNSIGNED
))
2086 r2
|=0x80; /* fuitoX -> fsituX */
2087 o(0xEEB80A40|r2
|T2CPR(t
)); /* fYitoX*/
2089 r2
=fpr(vtop
->r
=get_reg(RC_FLOAT
));
2090 if((t
& VT_BTYPE
) != VT_FLOAT
)
2091 dsize
=0x80; /* flts -> fltd */
2092 o(0xEE000110|dsize
|(r2
<<16)|(r
<<12)); /* flts */
2093 if((vtop
->type
.t
& (VT_UNSIGNED
|VT_BTYPE
)) == (VT_UNSIGNED
|VT_INT
)) {
2095 o(0xE3500000|(r
<<12)); /* cmp */
2096 r
=fpr(get_reg(RC_FLOAT
));
2097 if(last_itod_magic
) {
2098 off
=ind
+8-last_itod_magic
;
2103 o(0xBD1F0100|(r
<<12)|off
); /* ldflts */
2105 o(0xEA000000); /* b */
2106 last_itod_magic
=ind
;
2107 o(0x4F800000); /* 4294967296.0f */
2109 o(0xBE000100|dsize
|(r2
<<16)|(r2
<<12)|r
); /* adflt */
2113 } else if(bt
== VT_LLONG
) {
2115 CType
*func_type
= 0;
2116 if((t
& VT_BTYPE
) == VT_FLOAT
) {
2117 func_type
= &func_float_type
;
2118 if(vtop
->type
.t
& VT_UNSIGNED
)
2119 func
=TOK___floatundisf
;
2121 func
=TOK___floatdisf
;
2122 #if LDOUBLE_SIZE != 8
2123 } else if((t
& VT_BTYPE
) == VT_LDOUBLE
) {
2124 func_type
= &func_ldouble_type
;
2125 if(vtop
->type
.t
& VT_UNSIGNED
)
2126 func
=TOK___floatundixf
;
2128 func
=TOK___floatdixf
;
2129 } else if((t
& VT_BTYPE
) == VT_DOUBLE
) {
2131 } else if((t
& VT_BTYPE
) == VT_DOUBLE
|| (t
& VT_BTYPE
) == VT_LDOUBLE
) {
2133 func_type
= &func_double_type
;
2134 if(vtop
->type
.t
& VT_UNSIGNED
)
2135 func
=TOK___floatundidf
;
2137 func
=TOK___floatdidf
;
2140 vpushsym(func_type
, external_helper_sym(func
));
2148 tcc_error("unimplemented gen_cvt_itof %x!",vtop
->type
.t
);
2151 /* convert fp to int 't' type */
2152 void gen_cvt_ftoi(int t
)
2158 r2
=vtop
->type
.t
& VT_BTYPE
;
2161 r
=vfpr(gv(RC_FLOAT
));
2163 o(0xEEBC0AC0|(r
<<12)|r
|T2CPR(r2
)|u
); /* ftoXizY */
2164 r2
=intr(vtop
->r
=get_reg(RC_INT
));
2165 o(0xEE100A10|(r
<<16)|(r2
<<12));
2170 func
=TOK___fixunssfsi
;
2171 #if LDOUBLE_SIZE != 8
2172 else if(r2
== VT_LDOUBLE
)
2173 func
=TOK___fixunsxfsi
;
2174 else if(r2
== VT_DOUBLE
)
2176 else if(r2
== VT_LDOUBLE
|| r2
== VT_DOUBLE
)
2178 func
=TOK___fixunsdfsi
;
2180 r
=fpr(gv(RC_FLOAT
));
2181 r2
=intr(vtop
->r
=get_reg(RC_INT
));
2182 o(0xEE100170|(r2
<<12)|r
);
2186 } else if(t
== VT_LLONG
) { // unsigned handled in gen_cvt_ftoi1
2189 #if LDOUBLE_SIZE != 8
2190 else if(r2
== VT_LDOUBLE
)
2192 else if(r2
== VT_DOUBLE
)
2194 else if(r2
== VT_LDOUBLE
|| r2
== VT_DOUBLE
)
2199 vpush_helper_func(func
);
2204 vtop
->r2
= REG_IRE2
;
2208 tcc_error("unimplemented gen_cvt_ftoi!");
2211 /* convert from one floating point type to another */
2212 void gen_cvt_ftof(int t
)
2215 if(((vtop
->type
.t
& VT_BTYPE
) == VT_FLOAT
) != ((t
& VT_BTYPE
) == VT_FLOAT
)) {
2216 uint32_t r
= vfpr(gv(RC_FLOAT
));
2217 o(0xEEB70AC0|(r
<<12)|r
|T2CPR(vtop
->type
.t
));
2220 /* all we have to do on i386 and FPA ARM is to put the float in a register */
2225 /* computed goto support */
2232 /* Save the stack pointer onto the stack and return the location of its address */
2233 ST_FUNC
void gen_vla_sp_save(int addr
) {
2236 v
.r
= VT_LOCAL
| VT_LVAL
;
2241 /* Restore the SP from a location on the stack */
2242 ST_FUNC
void gen_vla_sp_restore(int addr
) {
2245 v
.r
= VT_LOCAL
| VT_LVAL
;
2250 /* Subtract from the stack pointer, and push the resulting value onto the stack */
2251 ST_FUNC
void gen_vla_alloc(CType
*type
, int align
) {
2253 #if defined(CONFIG_TCC_BCHECK)
2254 if (tcc_state
->do_bounds_check
)
2257 r
= intr(gv(RC_INT
));
2258 #if defined(CONFIG_TCC_BCHECK)
2259 if (tcc_state
->do_bounds_check
)
2260 o(0xe2800001 | (r
<<16)|(r
<<12)); /* add r,r,#1 */
2262 o(0xE04D0000|(r
<<12)|r
); /* sub r, sp, r */
2270 if (align
& (align
- 1))
2271 tcc_error("alignment is not a power of 2: %i", align
);
2272 o(stuff_const(0xE3C0D000|(r
<<16), align
- 1)); /* bic sp, r, #align-1 */
2274 #if defined(CONFIG_TCC_BCHECK)
2275 if (tcc_state
->do_bounds_check
) {
2278 o(0xe1a0000d | (vtop
->r
<< 12)); // mov r0,sp
2280 vpush_helper_func(TOK___bound_new_region
);
2283 func_bound_add_epilog
= 1;
2288 /* end of ARM code generator */
2289 /*************************************************************/
2291 /*************************************************************/