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 #ifdef TCC_ARM_HARDFLOAT
133 # define ARM_FLOAT_ABI ARM_HARD_FLOAT
135 # define ARM_FLOAT_ABI ARM_SOFTFP_FLOAT
138 /******************************************************/
139 #else /* ! TARGET_DEFS_ONLY */
140 /******************************************************/
141 #define USING_GLOBALS
144 ST_DATA
const char * const target_machine_defs
=
154 #if defined TCC_ARM_EABI
159 enum float_abi float_abi
;
161 ST_DATA
const int reg_classes
[NB_REGS
] = {
162 /* r0 */ RC_INT
| RC_R0
,
163 /* r1 */ RC_INT
| RC_R1
,
164 /* r2 */ RC_INT
| RC_R2
,
165 /* r3 */ RC_INT
| RC_R3
,
166 /* r12 */ RC_INT
| RC_R12
,
167 /* f0 */ RC_FLOAT
| RC_F0
,
168 /* f1 */ RC_FLOAT
| RC_F1
,
169 /* f2 */ RC_FLOAT
| RC_F2
,
170 /* f3 */ RC_FLOAT
| RC_F3
,
172 /* d4/s8 */ RC_FLOAT
| RC_F4
,
173 /* d5/s10 */ RC_FLOAT
| RC_F5
,
174 /* d6/s12 */ RC_FLOAT
| RC_F6
,
175 /* d7/s14 */ RC_FLOAT
| RC_F7
,
179 static int func_sub_sp_offset
, last_itod_magic
;
182 #if defined(CONFIG_TCC_BCHECK)
183 static addr_t func_bound_offset
;
184 static unsigned long func_bound_ind
;
185 ST_DATA
int func_bound_add_epilog
;
188 #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
189 static CType float_type
, double_type
, func_float_type
, func_double_type
;
190 ST_FUNC
void arm_init(struct TCCState
*s
)
192 float_type
.t
= VT_FLOAT
;
193 double_type
.t
= VT_DOUBLE
;
194 func_float_type
.t
= VT_FUNC
;
195 func_float_type
.ref
= sym_push(SYM_FIELD
, &float_type
, FUNC_CDECL
, FUNC_OLD
);
196 func_double_type
.t
= VT_FUNC
;
197 func_double_type
.ref
= sym_push(SYM_FIELD
, &double_type
, FUNC_CDECL
, FUNC_OLD
);
199 float_abi
= s
->float_abi
;
200 #ifndef TCC_ARM_HARDFLOAT
201 // XXX: Works on OpenBSD
202 // # warning "soft float ABI currently not supported: default to softfp"
206 #define func_float_type func_old_type
207 #define func_double_type func_old_type
208 #define func_ldouble_type func_old_type
209 ST_FUNC
void arm_init(struct TCCState
*s
)
212 #if !defined (TCC_ARM_VFP)
213 tcc_warning("Support for FPA is deprecated and will be removed in next"
216 #if !defined (TCC_ARM_EABI)
217 tcc_warning("Support for OABI is deprecated and will be removed in next"
224 #define CHECK_R(r) ((r) >= TREG_R0 && (r) <= TREG_LR)
226 static int two2mask(int a
,int b
) {
227 if (!CHECK_R(a
) || !CHECK_R(b
))
228 tcc_error("compiler error! registers %i,%i is not valid",a
,b
);
229 return (reg_classes
[a
]|reg_classes
[b
])&~(RC_INT
|RC_FLOAT
);
232 static int regmask(int r
) {
234 tcc_error("compiler error! register %i is not valid",r
);
235 return reg_classes
[r
]&~(RC_INT
|RC_FLOAT
);
238 /******************************************************/
240 #if defined(TCC_ARM_EABI) && !defined(CONFIG_TCC_ELFINTERP)
241 const char *default_elfinterp(struct TCCState
*s
)
243 if (s
->float_abi
== ARM_HARD_FLOAT
)
244 return "/lib/ld-linux-armhf.so.3";
246 return "/lib/ld-linux.so.3";
252 /* this is a good place to start adding big-endian support*/
257 if (!cur_text_section
)
258 tcc_error("compiler error! This happens f.ex. if the compiler\n"
259 "can't evaluate constant expressions outside of a function.");
260 if (ind1
> cur_text_section
->data_allocated
)
261 section_realloc(cur_text_section
, ind1
);
262 cur_text_section
->data
[ind
++] = i
&255;
264 cur_text_section
->data
[ind
++] = i
&255;
266 cur_text_section
->data
[ind
++] = i
&255;
268 cur_text_section
->data
[ind
++] = i
;
271 static uint32_t stuff_const(uint32_t op
, uint32_t c
)
274 uint32_t nc
= 0, negop
= 0;
284 case 0x1A00000: //mov
285 case 0x1E00000: //mvn
292 return (op
&0xF010F000)|((op
>>16)&0xF)|0x1E00000;
296 return (op
&0xF010F000)|((op
>>16)&0xF)|0x1A00000;
297 case 0x1C00000: //bic
302 case 0x1800000: //orr
304 return (op
&0xFFF0FFFF)|0x1E00000;
310 if(c
<256) /* catch undefined <<32 */
313 m
=(0xff>>i
)|(0xff<<(32-i
));
315 return op
|(i
<<7)|(c
<<i
)|(c
>>(32-i
));
325 void stuff_const_harder(uint32_t op
, uint32_t v
) {
331 uint32_t a
[16], nv
, no
, o2
, n2
;
334 o2
=(op
&0xfff0ffff)|((op
&0xf000)<<4);;
336 a
[i
]=(a
[i
-1]>>2)|(a
[i
-1]<<30);
338 for(j
=i
<4?i
+12:15;j
>=i
+4;j
--)
339 if((v
&(a
[i
]|a
[j
]))==v
) {
340 o(stuff_const(op
,v
&a
[i
]));
341 o(stuff_const(o2
,v
&a
[j
]));
348 for(j
=i
<4?i
+12:15;j
>=i
+4;j
--)
349 if((nv
&(a
[i
]|a
[j
]))==nv
) {
350 o(stuff_const(no
,nv
&a
[i
]));
351 o(stuff_const(n2
,nv
&a
[j
]));
356 for(k
=i
<4?i
+12:15;k
>=j
+4;k
--)
357 if((v
&(a
[i
]|a
[j
]|a
[k
]))==v
) {
358 o(stuff_const(op
,v
&a
[i
]));
359 o(stuff_const(o2
,v
&a
[j
]));
360 o(stuff_const(o2
,v
&a
[k
]));
367 for(k
=i
<4?i
+12:15;k
>=j
+4;k
--)
368 if((nv
&(a
[i
]|a
[j
]|a
[k
]))==nv
) {
369 o(stuff_const(no
,nv
&a
[i
]));
370 o(stuff_const(n2
,nv
&a
[j
]));
371 o(stuff_const(n2
,nv
&a
[k
]));
374 o(stuff_const(op
,v
&a
[0]));
375 o(stuff_const(o2
,v
&a
[4]));
376 o(stuff_const(o2
,v
&a
[8]));
377 o(stuff_const(o2
,v
&a
[12]));
381 uint32_t encbranch(int pos
, int addr
, int fail
)
385 if(addr
>=0x1000000 || addr
<-0x1000000) {
387 tcc_error("FIXME: function bigger than 32MB");
390 return 0x0A000000|(addr
&0xffffff);
393 int decbranch(int pos
)
396 x
=*(uint32_t *)(cur_text_section
->data
+ pos
);
403 /* output a symbol and patch all calls to it */
404 void gsym_addr(int t
, int a
)
409 x
=(uint32_t *)(cur_text_section
->data
+ t
);
412 *x
=0xE1A00000; // nop
415 *x
|= encbranch(lt
,a
,1);
421 static uint32_t vfpr(int r
)
423 if(r
<TREG_F0
|| r
>TREG_F7
)
424 tcc_error("compiler error! register %i is no vfp register",r
);
428 static uint32_t fpr(int r
)
430 if(r
<TREG_F0
|| r
>TREG_F3
)
431 tcc_error("compiler error! register %i is no fpa register",r
);
436 static uint32_t intr(int r
)
440 if(r
>= TREG_R0
&& r
<= TREG_R3
)
442 if (!(r
>= TREG_SP
&& r
<= TREG_LR
))
443 tcc_error("compiler error! register %i is no int register",r
);
444 return r
+ (13 - TREG_SP
);
447 static void calcaddr(uint32_t *base
, int *off
, int *sgn
, int maxoff
, unsigned shift
)
449 if(*off
>maxoff
|| *off
&((1<<shift
)-1)) {
456 y
=stuff_const(x
,*off
&~maxoff
);
462 y
=stuff_const(x
,(*off
+maxoff
)&~maxoff
);
466 *off
=((*off
+maxoff
)&~maxoff
)-*off
;
469 stuff_const_harder(x
,*off
&~maxoff
);
474 static uint32_t mapcc(int cc
)
479 return 0x30000000; /* CC/LO */
481 return 0x20000000; /* CS/HS */
483 return 0x00000000; /* EQ */
485 return 0x10000000; /* NE */
487 return 0x90000000; /* LS */
489 return 0x80000000; /* HI */
491 return 0x40000000; /* MI */
493 return 0x50000000; /* PL */
495 return 0xB0000000; /* LT */
497 return 0xA0000000; /* GE */
499 return 0xD0000000; /* LE */
501 return 0xC0000000; /* GT */
503 tcc_error("unexpected condition code");
504 return 0xE0000000; /* AL */
507 static int negcc(int cc
)
536 tcc_error("unexpected condition code");
540 /* Load value into register r.
541 Use relative/got addressing to avoid setting DT_TEXTREL */
542 static void load_value(SValue
*sv
, int r
)
544 o(0xE59F0000|(intr(r
)<<12)); /* ldr r, [pc] */
545 o(0xEA000000); /* b $+4 */
546 #ifndef CONFIG_TCC_PIC
548 greloc(cur_text_section
, sv
->sym
, ind
, R_ARM_ABS32
);
552 if (sv
->sym
->type
.t
& VT_STATIC
) {
553 greloc(cur_text_section
, sv
->sym
, ind
, R_ARM_REL32
);
555 o(0xe080000f | (intr(r
)<<12) | (intr(r
)<<16)); // add rx,rx,pc
558 greloc(cur_text_section
, sv
->sym
, ind
, R_ARM_GOT_PREL
);
560 o(0xe080000f | (intr(r
)<<12) | (intr(r
)<<16)); // add rx,rx,pc
561 o(0xe5900000 | (intr(r
)<<12) | (intr(r
)<<16)); // ldr rx,[rx]
563 stuff_const_harder(0xe2800000 | (intr(r
)<<12) | (intr(r
)<<16),
572 /* load 'r' from value 'sv' */
573 void load(int r
, SValue
*sv
)
575 int v
, ft
, fc
, fr
, sign
;
592 uint32_t base
= 0xB; // fp
595 v1
.r
= VT_LOCAL
| VT_LVAL
;
601 } else if(v
== VT_CONST
) {
610 } else if(v
< VT_CONST
) {
617 calcaddr(&base
,&fc
,&sign
,1020,2);
619 op
=0xED100A00; /* flds */
622 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
623 op
|=0x100; /* flds -> fldd */
624 o(op
|(vfpr(r
)<<12)|(fc
>>2)|(base
<<16));
629 #if LDOUBLE_SIZE == 8
630 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
633 if ((ft
& VT_BTYPE
) == VT_DOUBLE
)
635 else if ((ft
& VT_BTYPE
) == VT_LDOUBLE
)
638 o(op
|(fpr(r
)<<12)|(fc
>>2)|(base
<<16));
640 } else if((ft
& (VT_BTYPE
|VT_UNSIGNED
)) == VT_BYTE
641 || (ft
& VT_BTYPE
) == VT_SHORT
) {
642 calcaddr(&base
,&fc
,&sign
,255,0);
644 if ((ft
& VT_BTYPE
) == VT_SHORT
)
646 if ((ft
& VT_UNSIGNED
) == 0)
650 o(op
|(intr(r
)<<12)|(base
<<16)|((fc
&0xf0)<<4)|(fc
&0xf));
652 calcaddr(&base
,&fc
,&sign
,4095,0);
656 if ((ft
& VT_BTYPE
) == VT_BYTE
|| (ft
& VT_BTYPE
) == VT_BOOL
)
658 o(op
|(intr(r
)<<12)|fc
|(base
<<16));
664 op
=stuff_const(0xE3A00000|(intr(r
)<<12),sv
->c
.i
);
665 if (fr
& VT_SYM
|| !op
)
670 } else if (v
== VT_LOCAL
) {
671 op
=stuff_const(0xE28B0000|(intr(r
)<<12),sv
->c
.i
);
672 if (fr
& VT_SYM
|| !op
) {
674 o(0xE08B0000|(intr(r
)<<12)|intr(r
));
678 } else if(v
== VT_CMP
) {
679 o(mapcc(sv
->c
.i
)|0x3A00001|(intr(r
)<<12));
680 o(mapcc(negcc(sv
->c
.i
))|0x3A00000|(intr(r
)<<12));
682 } else if (v
== VT_JMP
|| v
== VT_JMPI
) {
685 o(0xE3A00000|(intr(r
)<<12)|t
);
688 o(0xE3A00000|(intr(r
)<<12)|(t
^1));
690 } else if (v
< VT_CONST
) {
693 o(0xEEB00A40|(vfpr(r
)<<12)|vfpr(v
)|T2CPR(ft
)); /* fcpyX */
695 o(0xEE008180|(fpr(r
)<<12)|fpr(v
));
698 o(0xE1A00000|(intr(r
)<<12)|intr(v
));
702 tcc_error("load unimplemented!");
705 /* store register 'r' in lvalue 'v' */
706 void store(int r
, SValue
*sv
)
709 int v
, ft
, fc
, fr
, sign
;
724 if (fr
& VT_LVAL
|| fr
== VT_LOCAL
) {
725 uint32_t base
= 0xb; /* fp */
730 } else if(v
== VT_CONST
) {
742 calcaddr(&base
,&fc
,&sign
,1020,2);
744 op
=0xED000A00; /* fsts */
747 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
748 op
|=0x100; /* fsts -> fstd */
749 o(op
|(vfpr(r
)<<12)|(fc
>>2)|(base
<<16));
754 #if LDOUBLE_SIZE == 8
755 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
758 if ((ft
& VT_BTYPE
) == VT_DOUBLE
)
760 if ((ft
& VT_BTYPE
) == VT_LDOUBLE
)
763 o(op
|(fpr(r
)<<12)|(fc
>>2)|(base
<<16));
766 } else if((ft
& VT_BTYPE
) == VT_SHORT
) {
767 calcaddr(&base
,&fc
,&sign
,255,0);
771 o(op
|(intr(r
)<<12)|(base
<<16)|((fc
&0xf0)<<4)|(fc
&0xf));
773 calcaddr(&base
,&fc
,&sign
,4095,0);
777 if ((ft
& VT_BTYPE
) == VT_BYTE
|| (ft
& VT_BTYPE
) == VT_BOOL
)
779 o(op
|(intr(r
)<<12)|fc
|(base
<<16));
784 tcc_error("store unimplemented");
787 static void gadd_sp(int val
)
789 stuff_const_harder(0xE28DD000,val
);
792 /* 'is_jmp' is '1' if it is a jump */
793 static void gcall_or_jmp(int is_jmp
)
797 if ((vtop
->r
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
) {
799 if(vtop
->r
& VT_SYM
){
800 x
=encbranch(ind
,ind
+vtop
->c
.i
,0);
802 /* relocation case */
803 greloc(cur_text_section
, vtop
->sym
, ind
, R_ARM_PC24
);
804 o(x
|(is_jmp
?0xE0000000:0xE1000000));
809 o(0xE1A0F000 | intr(r
)); // mov pc, r
811 o(0xe12fff30 | intr(r
)); // blx r
815 o(0xE28FE004); // add lr,pc,#4
816 o(0xE51FF004); // ldr pc,[pc,#-4]
820 /* otherwise, indirect call */
821 #ifdef CONFIG_TCC_BCHECK
822 vtop
->r
&= ~VT_MUSTBOUND
;
826 o(0xE1A0E00F); // mov lr,pc
827 o(0xE1A0F000|intr(r
)); // mov pc,r
831 #if defined(CONFIG_TCC_BCHECK)
833 static void gen_bounds_call(int v
)
835 Sym
*sym
= external_helper_sym(v
);
837 greloc(cur_text_section
, sym
, ind
, R_ARM_PC24
);
841 static void gen_bounds_prolog(void)
843 /* leave some room for bound checking code */
844 func_bound_offset
= lbounds_section
->data_offset
;
845 func_bound_ind
= ind
;
846 func_bound_add_epilog
= 0;
847 o(0xe1a00000); /* ld r0,lbounds_section->data_offset */
851 o(0xe1a00000); /* call __bound_local_new */
854 static void gen_bounds_epilog(void)
859 int offset_modified
= func_bound_offset
!= lbounds_section
->data_offset
;
861 if (!offset_modified
&& !func_bound_add_epilog
)
864 /* add end of table info */
865 bounds_ptr
= section_ptr_add(lbounds_section
, sizeof(addr_t
));
868 sym_data
= get_sym_ref(&char_pointer_type
, lbounds_section
,
869 func_bound_offset
, PTR_SIZE
);
871 /* generate bound local allocation */
872 if (offset_modified
) {
874 ind
= func_bound_ind
;
875 o(0xe59f0000); /* ldr r0, [pc] */
876 o(0xea000000); /* b $+4 */
877 greloc(cur_text_section
, sym_data
, ind
, R_ARM_REL32
);
878 o(-12); /* lbounds_section->data_offset */
879 o(0xe080000f); /* add r0,r0,pc */
880 gen_bounds_call(TOK___bound_local_new
);
884 /* generate bound check local freeing */
885 o(0xe92d0003); /* push {r0,r1} */
886 o(0xed2d0b04); /* vpush {d0,d1} */
887 o(0xe59f0000); /* ldr r0, [pc] */
888 o(0xea000000); /* b $+4 */
889 greloc(cur_text_section
, sym_data
, ind
, R_ARM_REL32
);
890 o(-12); /* lbounds_section->data_offset */
891 o(0xe080000f); /* add r0,r0,pc */
892 gen_bounds_call(TOK___bound_local_delete
);
893 o(0xecbd0b04); /* vpop {d0,d1} */
894 o(0xe8bd0003); /* pop {r0,r1} */
898 static int unalias_ldbl(int btype
)
900 #if LDOUBLE_SIZE == 8
901 if (btype
== VT_LDOUBLE
)
907 /* Return whether a structure is an homogeneous float aggregate or not.
908 The answer is true if all the elements of the structure are of the same
909 primitive float type and there is less than 4 elements.
911 type: the type corresponding to the structure to be tested */
912 static int is_hgen_float_aggr(CType
*type
)
914 if ((type
->t
& VT_BTYPE
) == VT_STRUCT
) {
916 int btype
, nb_fields
= 0;
918 ref
= type
->ref
->next
;
920 btype
= unalias_ldbl(ref
->type
.t
& VT_BTYPE
);
921 if (btype
== VT_FLOAT
|| btype
== VT_DOUBLE
) {
922 for(; ref
&& btype
== unalias_ldbl(ref
->type
.t
& VT_BTYPE
); ref
= ref
->next
, nb_fields
++);
923 return !ref
&& nb_fields
<= 4;
931 signed char avail
[3]; /* 3 holes max with only float and double alignments */
932 int first_hole
; /* first available hole */
933 int last_hole
; /* last available hole (none if equal to first_hole) */
934 int first_free_reg
; /* next free register in the sequence, hole excluded */
937 /* Find suitable registers for a VFP Co-Processor Register Candidate (VFP CPRC
938 param) according to the rules described in the procedure call standard for
939 the ARM architecture (AAPCS). If found, the registers are assigned to this
940 VFP CPRC parameter. Registers are allocated in sequence unless a hole exists
941 and the parameter is a single float.
943 avregs: opaque structure to keep track of available VFP co-processor regs
944 align: alignment constraints for the param, as returned by type_size()
945 size: size of the parameter, as returned by type_size() */
946 int assign_vfpreg(struct avail_regs
*avregs
, int align
, int size
)
950 if (avregs
->first_free_reg
== -1)
952 if (align
>> 3) { /* double alignment */
953 first_reg
= avregs
->first_free_reg
;
954 /* alignment constraint not respected so use next reg and record hole */
956 avregs
->avail
[avregs
->last_hole
++] = first_reg
++;
957 } else { /* no special alignment (float or array of float) */
958 /* if single float and a hole is available, assign the param to it */
959 if (size
== 4 && avregs
->first_hole
!= avregs
->last_hole
)
960 return avregs
->avail
[avregs
->first_hole
++];
962 first_reg
= avregs
->first_free_reg
;
964 if (first_reg
+ size
/ 4 <= 16) {
965 avregs
->first_free_reg
= first_reg
+ size
/ 4;
968 avregs
->first_free_reg
= -1;
972 /* Returns whether all params need to be passed in core registers or not.
973 This is the case for function part of the runtime ABI. */
974 int floats_in_core_regs(SValue
*sval
)
979 switch (sval
->sym
->v
) {
980 case TOK___floatundisf
:
981 case TOK___floatundidf
:
982 case TOK___fixunssfdi
:
983 case TOK___fixunsdfdi
:
985 case TOK___fixunsxfdi
:
987 case TOK___floatdisf
:
988 case TOK___floatdidf
:
998 /* Return the number of registers needed to return the struct, or 0 if
999 returning via struct pointer. */
1000 ST_FUNC
int gfunc_sret(CType
*vt
, int variadic
, CType
*ret
, int *ret_align
, int *regsize
) {
1003 size
= type_size(vt
, &align
);
1004 if (float_abi
== ARM_HARD_FLOAT
&& !variadic
&&
1005 (is_float(vt
->t
) || is_hgen_float_aggr(vt
))) {
1010 return (size
+ 7) >> 3;
1011 } else if (size
> 0 && size
<= 4) {
1024 /* Parameters are classified according to how they are copied to their final
1025 destination for the function call. Because the copying is performed class
1026 after class according to the order in the union below, it is important that
1027 some constraints about the order of the members of this union are respected:
1028 - CORE_STRUCT_CLASS must come after STACK_CLASS;
1029 - CORE_CLASS must come after STACK_CLASS, CORE_STRUCT_CLASS and
1031 - VFP_STRUCT_CLASS must come after VFP_CLASS.
1032 See the comment for the main loop in copy_params() for the reason. */
1043 int start
; /* first reg or addr used depending on the class */
1044 int end
; /* last reg used or next free addr depending on the class */
1045 SValue
*sval
; /* pointer to SValue on the value stack */
1046 struct param_plan
*prev
; /* previous element in this class */
1050 struct param_plan
*pplans
; /* array of all the param plans */
1051 struct param_plan
*clsplans
[NB_CLASSES
]; /* per class lists of param plans */
1055 static void add_param_plan(struct plan
* plan
, int cls
, int start
, int end
, SValue
*v
)
1057 struct param_plan
*p
= &plan
->pplans
[plan
->nb_plans
++];
1058 p
->prev
= plan
->clsplans
[cls
];
1059 plan
->clsplans
[cls
] = p
;
1060 p
->start
= start
, p
->end
= end
, p
->sval
= v
;
1063 /* Assign parameters to registers and stack with alignment according to the
1064 rules in the procedure call standard for the ARM architecture (AAPCS).
1065 The overall assignment is recorded in an array of per parameter structures
1066 called parameter plans. The parameter plans are also further organized in a
1067 number of linked lists, one per class of parameter (see the comment for the
1068 definition of union reg_class).
1070 nb_args: number of parameters of the function for which a call is generated
1071 float_abi: float ABI in use for this function call
1072 plan: the structure where the overall assignment is recorded
1073 todo: a bitmap that record which core registers hold a parameter
1075 Returns the amount of stack space needed for parameter passing
1077 Note: this function allocated an array in plan->pplans with tcc_malloc. It
1078 is the responsibility of the caller to free this array once used (ie not
1079 before copy_params). */
1080 static int assign_regs(int nb_args
, int float_abi
, struct plan
*plan
, int *todo
)
1083 int ncrn
/* next core register number */, nsaa
/* next stacked argument address*/;
1084 struct avail_regs avregs
= {{0}};
1089 for(i
= nb_args
; i
-- ;) {
1090 int j
, start_vfpreg
= 0;
1091 CType type
= vtop
[-i
].type
;
1092 type
.t
&= ~VT_ARRAY
;
1093 size
= type_size(&type
, &align
);
1094 size
= (size
+ 3) & ~3;
1095 align
= (align
+ 3) & ~3;
1096 switch(vtop
[-i
].type
.t
& VT_BTYPE
) {
1101 if (float_abi
== ARM_HARD_FLOAT
) {
1102 int is_hfa
= 0; /* Homogeneous float aggregate */
1104 if (is_float(vtop
[-i
].type
.t
)
1105 || (is_hfa
= is_hgen_float_aggr(&vtop
[-i
].type
))) {
1108 start_vfpreg
= assign_vfpreg(&avregs
, align
, size
);
1109 end_vfpreg
= start_vfpreg
+ ((size
- 1) >> 2);
1110 if (start_vfpreg
>= 0) {
1111 add_param_plan(plan
, is_hfa
? VFP_STRUCT_CLASS
: VFP_CLASS
,
1112 start_vfpreg
, end_vfpreg
, &vtop
[-i
]);
1118 ncrn
= (ncrn
+ (align
-1)/4) & ~((align
/4) - 1);
1119 if (ncrn
+ size
/4 <= 4 || (ncrn
< 4 && start_vfpreg
!= -1)) {
1120 /* The parameter is allocated both in core register and on stack. As
1121 * such, it can be of either class: it would either be the last of
1122 * CORE_STRUCT_CLASS or the first of STACK_CLASS. */
1123 for (j
= ncrn
; j
< 4 && j
< ncrn
+ size
/ 4; j
++)
1125 add_param_plan(plan
, CORE_STRUCT_CLASS
, ncrn
, j
, &vtop
[-i
]);
1128 nsaa
= (ncrn
- 4) * 4;
1136 int is_long
= (vtop
[-i
].type
.t
& VT_BTYPE
) == VT_LLONG
;
1139 ncrn
= (ncrn
+ 1) & -2;
1143 add_param_plan(plan
, CORE_CLASS
, ncrn
, ncrn
+ is_long
, &vtop
[-i
]);
1144 ncrn
+= 1 + is_long
;
1148 nsaa
= (nsaa
+ (align
- 1)) & ~(align
- 1);
1149 add_param_plan(plan
, STACK_CLASS
, nsaa
, nsaa
+ size
, &vtop
[-i
]);
1150 nsaa
+= size
; /* size already rounded up before */
1155 /* Copy parameters to their final destination (core reg, VFP reg or stack) for
1158 nb_args: number of parameters the function take
1159 plan: the overall assignment plan for parameters
1160 todo: a bitmap indicating what core reg will hold a parameter
1162 Returns the number of SValue added by this function on the value stack */
1163 static int copy_params(int nb_args
, struct plan
*plan
, int todo
)
1165 int size
, align
, r
, i
, nb_extra_sval
= 0;
1166 struct param_plan
*pplan
;
1169 /* Several constraints require parameters to be copied in a specific order:
1170 - structures are copied to the stack before being loaded in a reg;
1171 - floats loaded to an odd numbered VFP reg are first copied to the
1172 preceding even numbered VFP reg and then moved to the next VFP reg.
1174 It is thus important that:
1175 - structures assigned to core regs must be copied after parameters
1176 assigned to the stack but before structures assigned to VFP regs because
1177 a structure can lie partly in core registers and partly on the stack;
1178 - parameters assigned to the stack and all structures be copied before
1179 parameters assigned to a core reg since copying a parameter to the stack
1180 require using a core reg;
1181 - parameters assigned to VFP regs be copied before structures assigned to
1182 VFP regs as the copy might use an even numbered VFP reg that already
1183 holds part of a structure. */
1185 for(i
= 0; i
< NB_CLASSES
; i
++) {
1186 for(pplan
= plan
->clsplans
[i
]; pplan
; pplan
= pplan
->prev
) {
1189 && (i
!= CORE_CLASS
|| pplan
->sval
->r
< VT_CONST
))
1192 vpushv(pplan
->sval
);
1193 pplan
->sval
->r
= pplan
->sval
->r2
= VT_CONST
; /* disable entry */
1196 case CORE_STRUCT_CLASS
:
1197 case VFP_STRUCT_CLASS
:
1198 if ((pplan
->sval
->type
.t
& VT_BTYPE
) == VT_STRUCT
) {
1200 size
= type_size(&pplan
->sval
->type
, &align
);
1201 /* align to stack align size */
1202 size
= (size
+ 3) & ~3;
1203 if (i
== STACK_CLASS
&& pplan
->prev
)
1204 padding
= pplan
->start
- pplan
->prev
->end
;
1205 size
+= padding
; /* Add padding if any */
1206 /* allocate the necessary size on stack */
1208 /* generate structure store */
1209 r
= get_reg(RC_INT
);
1210 o(0xE28D0000|(intr(r
)<<12)|padding
); /* add r, sp, padding */
1211 vset(&vtop
->type
, r
| VT_LVAL
, 0);
1213 /* XXX: optimize. Save all register because memcpy can use them */
1214 o(0xED2D0A00|(0&1)<<22|(0>>1)<<12|16); /* vpush {s0-s15} */
1215 vstore(); /* memcpy to current sp + potential padding */
1216 o(0xECBD0A00|(0&1)<<22|(0>>1)<<12|16); /* vpop {s0-s15} */
1218 /* Homogeneous float aggregate are loaded to VFP registers
1219 immediately since there is no way of loading data in multiple
1220 non consecutive VFP registers as what is done for other
1221 structures (see the use of todo). */
1222 if (i
== VFP_STRUCT_CLASS
) {
1223 int first
= pplan
->start
, nb
= pplan
->end
- first
+ 1;
1224 /* vpop.32 {pplan->start, ..., pplan->end} */
1225 o(0xECBD0A00|(first
&1)<<22|(first
>>1)<<12|nb
);
1226 /* No need to write the register used to a SValue since VFP regs
1227 cannot be used for gcall_or_jmp */
1230 if (is_float(pplan
->sval
->type
.t
)) {
1232 r
= vfpr(gv(RC_FLOAT
)) << 12;
1233 if ((pplan
->sval
->type
.t
& VT_BTYPE
) == VT_FLOAT
)
1237 r
|= 0x101; /* vpush.32 -> vpush.64 */
1239 o(0xED2D0A01 + r
); /* vpush */
1241 r
= fpr(gv(RC_FLOAT
)) << 12;
1242 if ((pplan
->sval
->type
.t
& VT_BTYPE
) == VT_FLOAT
)
1244 else if ((pplan
->sval
->type
.t
& VT_BTYPE
) == VT_DOUBLE
)
1247 size
= LDOUBLE_SIZE
;
1254 o(0xED2D0100|r
|(size
>>2)); /* some kind of vpush for FPA */
1257 /* simple type (currently always same size) */
1258 /* XXX: implicit cast ? */
1260 if ((pplan
->sval
->type
.t
& VT_BTYPE
) == VT_LLONG
) {
1264 o(0xE52D0004|(intr(r
)<<12)); /* push r */
1268 o(0xE52D0004|(intr(r
)<<12)); /* push r */
1270 if (i
== STACK_CLASS
&& pplan
->prev
)
1271 gadd_sp(pplan
->prev
->end
- pplan
->start
); /* Add padding if any */
1276 gv(regmask(TREG_F0
+ (pplan
->start
>> 1)));
1277 if (pplan
->start
& 1) { /* Must be in upper part of double register */
1278 o(0xEEF00A40|((pplan
->start
>>1)<<12)|(pplan
->start
>>1)); /* vmov.f32 s(n+1), sn */
1279 vtop
->r
= VT_CONST
; /* avoid being saved on stack by gv for next float */
1284 if ((pplan
->sval
->type
.t
& VT_BTYPE
) == VT_LLONG
) {
1286 gv(regmask(pplan
->end
));
1287 pplan
->sval
->r2
= vtop
->r
;
1290 gv(regmask(pplan
->start
));
1291 /* Mark register as used so that gcall_or_jmp use another one
1292 (regs >=4 are free as never used to pass parameters) */
1293 pplan
->sval
->r
= vtop
->r
;
1300 /* second pass to restore registers that were saved on stack by accident.
1301 Maybe redundant after the "lvalue_save" patch in tccgen.c:gv() */
1305 /* Manually free remaining registers since next parameters are loaded
1306 * manually, without the help of gv(int). */
1310 o(0xE8BD0000|todo
); /* pop {todo} */
1311 for(pplan
= plan
->clsplans
[CORE_STRUCT_CLASS
]; pplan
; pplan
= pplan
->prev
) {
1313 pplan
->sval
->r
= pplan
->start
;
1314 /* An SValue can only pin 2 registers at best (r and r2) but a structure
1315 can occupy more than 2 registers. Thus, we need to push on the value
1316 stack some fake parameter to have on SValue for each registers used
1317 by a structure (r2 is not used). */
1318 for (r
= pplan
->start
+ 1; r
<= pplan
->end
; r
++) {
1319 if (todo
& (1 << r
)) {
1327 return nb_extra_sval
;
1330 /* Generate function call. The function address is pushed first, then
1331 all the parameters in call order. This functions pops all the
1332 parameters and the function address. */
1333 void gfunc_call(int nb_args
)
1336 int def_float_abi
= float_abi
;
1343 #ifdef CONFIG_TCC_BCHECK
1344 if (tcc_state
->do_bounds_check
)
1345 gbound_args(nb_args
);
1349 if (float_abi
== ARM_HARD_FLOAT
) {
1350 variadic
= (vtop
[-nb_args
].type
.ref
->f
.func_type
== FUNC_ELLIPSIS
);
1351 if (variadic
|| floats_in_core_regs(&vtop
[-nb_args
]))
1352 float_abi
= ARM_SOFTFP_FLOAT
;
1355 /* cannot let cpu flags if other instruction are generated. Also avoid leaving
1356 VT_JMP anywhere except on the top of the stack because it would complicate
1357 the code generator. */
1358 r
= vtop
->r
& VT_VALMASK
;
1359 if (r
== VT_CMP
|| (r
& ~1) == VT_JMP
)
1362 memset(&plan
, 0, sizeof plan
);
1364 plan
.pplans
= tcc_malloc(nb_args
* sizeof(*plan
.pplans
));
1366 args_size
= assign_regs(nb_args
, float_abi
, &plan
, &todo
);
1369 if (args_size
& 7) { /* Stack must be 8 byte aligned at fct call for EABI */
1370 args_size
= (args_size
+ 7) & ~7;
1371 o(0xE24DD004); /* sub sp, sp, #4 */
1375 nb_args
+= copy_params(nb_args
, &plan
, todo
);
1376 tcc_free(plan
.pplans
);
1378 /* Move fct SValue on top as required by gcall_or_jmp */
1382 gadd_sp(args_size
); /* pop all parameters passed on the stack */
1383 #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
1384 if(float_abi
== ARM_SOFTFP_FLOAT
&& is_float(vtop
->type
.ref
->type
.t
)) {
1385 if((vtop
->type
.ref
->type
.t
& VT_BTYPE
) == VT_FLOAT
) {
1386 o(0xEE000A10); /*vmov s0, r0 */
1388 o(0xEE000B10); /* vmov.32 d0[0], r0 */
1389 o(0xEE201B10); /* vmov.32 d0[1], r1 */
1393 vtop
-= nb_args
+ 1; /* Pop all params and fct address from value stack */
1394 leaffunc
= 0; /* we are calling a function, so we aren't in a leaf function */
1395 float_abi
= def_float_abi
;
1398 /* generate function prolog of type 't' */
1399 void gfunc_prolog(Sym
*func_sym
)
1401 CType
*func_type
= &func_sym
->type
;
1403 int n
, nf
, size
, align
, rs
, struct_ret
= 0;
1404 int addr
, pn
, sn
; /* pn=core, sn=stack */
1408 struct avail_regs avregs
= {{0}};
1411 sym
= func_type
->ref
;
1414 if ((func_vt
.t
& VT_BTYPE
) == VT_STRUCT
&&
1415 !gfunc_sret(&func_vt
, func_var
, &ret_type
, &align
, &rs
))
1419 func_vc
= 12; /* Offset from fp of the place to store the result */
1421 for(sym2
= sym
->next
; sym2
&& (n
< 4 || nf
< 16); sym2
= sym2
->next
) {
1422 size
= type_size(&sym2
->type
, &align
);
1424 if (float_abi
== ARM_HARD_FLOAT
&& !func_var
&&
1425 (is_float(sym2
->type
.t
) || is_hgen_float_aggr(&sym2
->type
))) {
1426 int tmpnf
= assign_vfpreg(&avregs
, align
, size
);
1427 tmpnf
+= (size
+ 3) / 4;
1428 nf
= (tmpnf
> nf
) ? tmpnf
: nf
;
1432 n
+= (size
+ 3) / 4;
1434 o(0xE1A0C00D); /* mov ip,sp */
1443 o(0xE92D0000|((1<<n
)-1)); /* save r0-r4 on stack if needed */
1448 nf
=(nf
+1)&-2; /* nf => HARDFLOAT => EABI */
1449 o(0xED2D0A00|nf
); /* save s0-s15 on stack if needed */
1451 o(0xE92D5800); /* save fp, ip, lr */
1452 o(0xE1A0B00D); /* mov fp, sp */
1453 func_sub_sp_offset
= ind
;
1454 o(0xE1A00000); /* nop, leave space for stack adjustment in epilog */
1457 if (float_abi
== ARM_HARD_FLOAT
) {
1459 memset(&avregs
, 0, sizeof avregs
);
1462 pn
= struct_ret
, sn
= 0;
1463 while ((sym
= sym
->next
)) {
1466 size
= type_size(type
, &align
);
1467 size
= (size
+ 3) >> 2;
1468 align
= (align
+ 3) & ~3;
1470 if (float_abi
== ARM_HARD_FLOAT
&& !func_var
&& (is_float(sym
->type
.t
)
1471 || is_hgen_float_aggr(&sym
->type
))) {
1472 int fpn
= assign_vfpreg(&avregs
, align
, size
<< 2);
1481 pn
= (pn
+ (align
-1)/4) & -(align
/4);
1483 addr
= (nf
+ pn
) * 4;
1490 sn
= (sn
+ (align
-1)/4) & -(align
/4);
1492 addr
= (n
+ nf
+ sn
) * 4;
1495 sym_push(sym
->v
& ~SYM_FIELD
, type
, VT_LOCAL
| VT_LVAL
,
1501 #ifdef CONFIG_TCC_BCHECK
1502 if (tcc_state
->do_bounds_check
)
1503 gen_bounds_prolog();
1507 /* generate function epilog */
1508 void gfunc_epilog(void)
1513 #ifdef CONFIG_TCC_BCHECK
1514 if (tcc_state
->do_bounds_check
)
1515 gen_bounds_epilog();
1517 /* Copy float return value to core register if base standard is used and
1518 float computation is made with VFP */
1519 #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
1520 if ((float_abi
== ARM_SOFTFP_FLOAT
|| func_var
) && is_float(func_vt
.t
)) {
1521 if((func_vt
.t
& VT_BTYPE
) == VT_FLOAT
)
1522 o(0xEE100A10); /* fmrs r0, s0 */
1524 o(0xEE100B10); /* fmrdl r0, d0 */
1525 o(0xEE301B10); /* fmrdh r1, d0 */
1529 o(0xE89BA800); /* restore fp, sp, pc */
1530 diff
= (-loc
+ 3) & -4;
1533 diff
= ((diff
+ 11) & -8) - 4;
1536 x
=stuff_const(0xE24BD000, diff
); /* sub sp,fp,# */
1538 *(uint32_t *)(cur_text_section
->data
+ func_sub_sp_offset
) = x
;
1542 o(0xE59FC004); /* ldr ip,[pc+4] */
1543 o(0xE04BD00C); /* sub sp,fp,ip */
1544 o(0xE1A0F00E); /* mov pc,lr */
1546 *(uint32_t *)(cur_text_section
->data
+ func_sub_sp_offset
) = 0xE1000000|encbranch(func_sub_sp_offset
,addr
,1);
1551 ST_FUNC
void gen_fill_nops(int bytes
)
1554 tcc_error("alignment of code section not multiple of 4");
1561 /* generate a jump to a label */
1562 ST_FUNC
int gjmp(int t
)
1568 o(0xE0000000|encbranch(r
,t
,1));
1572 /* generate a jump to a fixed address */
1573 ST_FUNC
void gjmp_addr(int a
)
1578 ST_FUNC
int gjmp_cond(int op
, int t
)
1585 op
|=encbranch(r
,t
,1);
1590 ST_FUNC
int gjmp_append(int n
, int t
)
1597 p
= decbranch(lp
=p
);
1599 x
= (uint32_t *)(cur_text_section
->data
+ lp
);
1601 *x
|= encbranch(lp
,t
,1);
1607 /* generate an integer binary operation */
1608 void gen_opi(int op
)
1611 uint32_t opc
= 0, r
, fr
;
1612 unsigned short retreg
= REG_IRET
;
1620 case TOK_ADDC1
: /* add with carry generation */
1628 case TOK_SUBC1
: /* sub with carry generation */
1632 case TOK_ADDC2
: /* add with carry use */
1636 case TOK_SUBC2
: /* sub with carry use */
1653 gv2(RC_INT
, RC_INT
);
1657 o(0xE0000090|(intr(r
)<<16)|(intr(r
)<<8)|intr(fr
));
1682 func
=TOK___aeabi_idivmod
;
1691 func
=TOK___aeabi_uidivmod
;
1699 gv2(RC_INT
, RC_INT
);
1700 r
=intr(vtop
[-1].r2
=get_reg(RC_INT
));
1702 vtop
[-1].r
=get_reg_ex(RC_INT
,regmask(c
));
1704 o(0xE0800090|(r
<<16)|(intr(vtop
->r
)<<12)|(intr(c
)<<8)|intr(vtop
[1].r
));
1713 if((vtop
[-1].r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1714 if(opc
== 4 || opc
== 5 || opc
== 0xc) {
1716 opc
|=2; // sub -> rsb
1719 if ((vtop
->r
& VT_VALMASK
) == VT_CMP
||
1720 (vtop
->r
& (VT_VALMASK
& ~1)) == VT_JMP
)
1725 opc
=0xE0000000|(opc
<<20);
1726 if((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1728 x
=stuff_const(opc
|0x2000000|(c
<<16),vtop
->c
.i
);
1730 if ((x
& 0xfff00000) == 0xe3500000) // cmp rx,#c
1733 r
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,regmask(vtop
[-1].r
)));
1739 fr
=intr(gv(RC_INT
));
1740 #ifdef CONFIG_TCC_BCHECK
1741 if ((vtop
[-1].r
& VT_VALMASK
) >= VT_CONST
) {
1747 if ((opc
& 0xfff00000) == 0xe1500000) // cmp rx,ry
1750 r
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,two2mask(vtop
->r
,vtop
[-1].r
)));
1751 o(opc
|(c
<<16)|(r
<<12)|fr
);
1755 if (op
>= TOK_ULT
&& op
<= TOK_GT
)
1759 opc
=0xE1A00000|(opc
<<5);
1760 if ((vtop
->r
& VT_VALMASK
) == VT_CMP
||
1761 (vtop
->r
& (VT_VALMASK
& ~1)) == VT_JMP
)
1766 if ((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1767 fr
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,regmask(vtop
[-1].r
)));
1768 c
= vtop
->c
.i
& 0x1f;
1769 o(opc
|r
|(c
<<7)|(fr
<<12));
1771 fr
=intr(gv(RC_INT
));
1772 #ifdef CONFIG_TCC_BCHECK
1773 if ((vtop
[-1].r
& VT_VALMASK
) >= VT_CONST
) {
1779 c
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,two2mask(vtop
->r
,vtop
[-1].r
)));
1780 o(opc
|r
|(c
<<12)|(fr
<<8)|0x10);
1785 vpush_helper_func(func
);
1792 tcc_error("gen_opi %i unimplemented!",op
);
1797 static int is_zero(int i
)
1799 if((vtop
[i
].r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) != VT_CONST
)
1801 if (vtop
[i
].type
.t
== VT_FLOAT
)
1802 return (vtop
[i
].c
.f
== 0.f
);
1803 else if (vtop
[i
].type
.t
== VT_DOUBLE
)
1804 return (vtop
[i
].c
.d
== 0.0);
1805 return (vtop
[i
].c
.ld
== 0.l
);
1808 /* generate a floating point operation 'v = t1 op t2' instruction. The
1809 * two operands are guaranteed to have the same floating point type */
1810 void gen_opf(int op
)
1814 x
=0xEE000A00|T2CPR(vtop
->type
.t
);
1832 x
|=0x810000; /* fsubX -> fnegX */
1845 if(op
< TOK_ULT
|| op
> TOK_GT
) {
1846 tcc_error("unknown fp op %x!",op
);
1852 case TOK_LT
: op
=TOK_GT
; break;
1853 case TOK_GE
: op
=TOK_ULE
; break;
1854 case TOK_LE
: op
=TOK_GE
; break;
1855 case TOK_GT
: op
=TOK_ULT
; break;
1858 x
|=0xB40040; /* fcmpX */
1859 if(op
!=TOK_EQ
&& op
!=TOK_NE
)
1860 x
|=0x80; /* fcmpX -> fcmpeX */
1863 o(x
|0x10000|(vfpr(gv(RC_FLOAT
))<<12)); /* fcmp(e)X -> fcmp(e)zX */
1865 gv2(RC_FLOAT
,RC_FLOAT
);
1867 o(x
|(vfpr(vtop
[-1].r
) << 12));
1870 o(0xEEF1FA10); /* fmstat */
1873 case TOK_LE
: op
=TOK_ULE
; break;
1874 case TOK_LT
: op
=TOK_ULT
; break;
1875 case TOK_UGE
: op
=TOK_GE
; break;
1876 case TOK_UGT
: op
=TOK_GT
; break;
1890 #ifdef CONFIG_TCC_BCHECK
1891 if ((vtop
[-1].r
& VT_VALMASK
) >= VT_CONST
) {
1899 vtop
->r
=get_reg_ex(RC_FLOAT
,r
);
1902 o(x
|(vfpr(vtop
->r
)<<12));
1906 static uint32_t is_fconst()
1910 if((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) != VT_CONST
)
1912 if (vtop
->type
.t
== VT_FLOAT
)
1914 else if (vtop
->type
.t
== VT_DOUBLE
)
1944 /* generate a floating point operation 'v = t1 op t2' instruction. The
1945 two operands are guaranteed to have the same floating point type */
1946 void gen_opf(int op
)
1948 uint32_t x
, r
, r2
, c1
, c2
;
1949 //fputs("gen_opf\n",stderr);
1955 #if LDOUBLE_SIZE == 8
1956 if ((vtop
->type
.t
& VT_BTYPE
) != VT_FLOAT
)
1959 if ((vtop
->type
.t
& VT_BTYPE
) == VT_DOUBLE
)
1961 else if ((vtop
->type
.t
& VT_BTYPE
) == VT_LDOUBLE
)
1972 r
=fpr(gv(RC_FLOAT
));
1979 r2
=fpr(gv(RC_FLOAT
));
1980 #ifdef CONFIG_TCC_BCHECK
1981 if ((vtop
[-1].r
& VT_VALMASK
) >= VT_CONST
) {
1983 r
=fpr(gv(RC_FLOAT
));
1995 r
=fpr(gv(RC_FLOAT
));
1997 } else if(c1
&& c1
<=0xf) {
2000 r
=fpr(gv(RC_FLOAT
));
2005 r
=fpr(gv(RC_FLOAT
));
2007 r2
=fpr(gv(RC_FLOAT
));
2008 #ifdef CONFIG_TCC_BCHECK
2009 if ((vtop
[-1].r
& VT_VALMASK
) >= VT_CONST
) {
2011 r
=fpr(gv(RC_FLOAT
));
2023 r
=fpr(gv(RC_FLOAT
));
2028 r2
=fpr(gv(RC_FLOAT
));
2029 #ifdef CONFIG_TCC_BCHECK
2030 if ((vtop
[-1].r
& VT_VALMASK
) >= VT_CONST
) {
2032 r
=fpr(gv(RC_FLOAT
));
2044 r
=fpr(gv(RC_FLOAT
));
2046 } else if(c1
&& c1
<=0xf) {
2049 r
=fpr(gv(RC_FLOAT
));
2054 r
=fpr(gv(RC_FLOAT
));
2056 r2
=fpr(gv(RC_FLOAT
));
2057 #ifdef CONFIG_TCC_BCHECK
2058 if ((vtop
[-1].r
& VT_VALMASK
) >= VT_CONST
) {
2060 r
=fpr(gv(RC_FLOAT
));
2067 if(op
>= TOK_ULT
&& op
<= TOK_GT
) {
2068 x
|=0xd0f110; // cmfe
2069 /* bug (intention?) in Linux FPU emulator
2070 doesn't set carry if equal */
2076 tcc_error("unsigned comparison on floats?");
2082 op
=TOK_ULE
; /* correct in unordered case only if AC bit in FPSR set */
2086 x
&=~0x400000; // cmfe -> cmf
2108 r
=fpr(gv(RC_FLOAT
));
2115 r2
=fpr(gv(RC_FLOAT
));
2116 #ifdef CONFIG_TCC_BCHECK
2117 if ((vtop
[-1].r
& VT_VALMASK
) >= VT_CONST
) {
2119 r
=fpr(gv(RC_FLOAT
));
2128 tcc_error("unknown fp op %x!",op
);
2132 if(vtop
[-1].r
== VT_CMP
)
2138 vtop
[-1].r
=get_reg_ex(RC_FLOAT
,two2mask(vtop
[-1].r
,c1
));
2142 o(x
|(r
<<16)|(c1
<<12)|r2
);
2146 /* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
2147 and 'long long' cases. */
2148 ST_FUNC
void gen_cvt_itof(int t
)
2152 bt
=vtop
->type
.t
& VT_BTYPE
;
2153 if(bt
== VT_INT
|| bt
== VT_SHORT
|| bt
== VT_BYTE
) {
2159 r2
=vfpr(vtop
->r
=get_reg(RC_FLOAT
));
2160 o(0xEE000A10|(r
<<12)|(r2
<<16)); /* fmsr */
2162 if(!(vtop
->type
.t
& VT_UNSIGNED
))
2163 r2
|=0x80; /* fuitoX -> fsituX */
2164 o(0xEEB80A40|r2
|T2CPR(t
)); /* fYitoX*/
2166 r2
=fpr(vtop
->r
=get_reg(RC_FLOAT
));
2167 if((t
& VT_BTYPE
) != VT_FLOAT
)
2168 dsize
=0x80; /* flts -> fltd */
2169 o(0xEE000110|dsize
|(r2
<<16)|(r
<<12)); /* flts */
2170 if((vtop
->type
.t
& (VT_UNSIGNED
|VT_BTYPE
)) == (VT_UNSIGNED
|VT_INT
)) {
2172 o(0xE3500000|(r
<<12)); /* cmp */
2173 r
=fpr(get_reg(RC_FLOAT
));
2174 if(last_itod_magic
) {
2175 off
=ind
+8-last_itod_magic
;
2180 o(0xBD1F0100|(r
<<12)|off
); /* ldflts */
2182 o(0xEA000000); /* b */
2183 last_itod_magic
=ind
;
2184 o(0x4F800000); /* 4294967296.0f */
2186 o(0xBE000100|dsize
|(r2
<<16)|(r2
<<12)|r
); /* adflt */
2190 } else if(bt
== VT_LLONG
) {
2192 CType
*func_type
= 0;
2193 if((t
& VT_BTYPE
) == VT_FLOAT
) {
2194 func_type
= &func_float_type
;
2195 if(vtop
->type
.t
& VT_UNSIGNED
)
2196 func
=TOK___floatundisf
;
2198 func
=TOK___floatdisf
;
2199 #if LDOUBLE_SIZE != 8
2200 } else if((t
& VT_BTYPE
) == VT_LDOUBLE
) {
2201 func_type
= &func_ldouble_type
;
2202 if(vtop
->type
.t
& VT_UNSIGNED
)
2203 func
=TOK___floatundixf
;
2205 func
=TOK___floatdixf
;
2206 } else if((t
& VT_BTYPE
) == VT_DOUBLE
) {
2208 } else if((t
& VT_BTYPE
) == VT_DOUBLE
|| (t
& VT_BTYPE
) == VT_LDOUBLE
) {
2210 func_type
= &func_double_type
;
2211 if(vtop
->type
.t
& VT_UNSIGNED
)
2212 func
=TOK___floatundidf
;
2214 func
=TOK___floatdidf
;
2217 vpushsym(func_type
, external_helper_sym(func
));
2225 tcc_error("unimplemented gen_cvt_itof %x!",vtop
->type
.t
);
2228 /* convert fp to int 't' type */
2229 void gen_cvt_ftoi(int t
)
2235 r2
=vtop
->type
.t
& VT_BTYPE
;
2238 r
=vfpr(gv(RC_FLOAT
));
2240 o(0xEEBC0AC0|(r
<<12)|r
|T2CPR(r2
)|u
); /* ftoXizY */
2241 r2
=intr(vtop
->r
=get_reg(RC_INT
));
2242 o(0xEE100A10|(r
<<16)|(r2
<<12));
2247 func
=TOK___fixunssfsi
;
2248 #if LDOUBLE_SIZE != 8
2249 else if(r2
== VT_LDOUBLE
)
2250 func
=TOK___fixunsxfsi
;
2251 else if(r2
== VT_DOUBLE
)
2253 else if(r2
== VT_LDOUBLE
|| r2
== VT_DOUBLE
)
2255 func
=TOK___fixunsdfsi
;
2257 r
=fpr(gv(RC_FLOAT
));
2258 r2
=intr(vtop
->r
=get_reg(RC_INT
));
2259 o(0xEE100170|(r2
<<12)|r
);
2263 } else if(t
== VT_LLONG
) { // unsigned handled in gen_cvt_ftoi1
2266 #if LDOUBLE_SIZE != 8
2267 else if(r2
== VT_LDOUBLE
)
2269 else if(r2
== VT_DOUBLE
)
2271 else if(r2
== VT_LDOUBLE
|| r2
== VT_DOUBLE
)
2276 vpush_helper_func(func
);
2281 vtop
->r2
= REG_IRE2
;
2285 tcc_error("unimplemented gen_cvt_ftoi!");
2288 /* convert from one floating point type to another */
2289 void gen_cvt_ftof(int t
)
2292 if(((vtop
->type
.t
& VT_BTYPE
) == VT_FLOAT
) != ((t
& VT_BTYPE
) == VT_FLOAT
)) {
2293 uint32_t r
= vfpr(gv(RC_FLOAT
));
2294 o(0xEEB70AC0|(r
<<12)|r
|T2CPR(vtop
->type
.t
));
2297 /* all we have to do on i386 and FPA ARM is to put the float in a register */
2302 /* increment tcov counter */
2303 ST_FUNC
void gen_increment_tcov (SValue
*sv
)
2308 vtop
->r
= r1
= get_reg(RC_INT
);
2309 r2
= get_reg(RC_INT
);
2310 o(0xE59F0000 | (intr(r1
)<<12)); // ldr r1,[pc]
2311 o(0xEA000000); // b $+4
2312 greloc(cur_text_section
, sv
->sym
, ind
, R_ARM_REL32
);
2314 o(0xe080000f | (intr(r1
)<<16) | (intr(r1
)<<12)); // add r1,r1,pc
2315 o(0xe5900000 | (intr(r1
)<<16) | (intr(r2
)<<12)); // ldr r2, [r1]
2316 o(0xe2900001 | (intr(r2
)<<16) | (intr(r2
)<<12)); // adds r2, r2, #1
2317 o(0xe5800000 | (intr(r1
)<<16) | (intr(r2
)<<12)); // str r2, [r1]
2318 o(0xe2800004 | (intr(r1
)<<16) | (intr(r1
)<<12)); // add r1, r1, #4
2319 o(0xe5900000 | (intr(r1
)<<16) | (intr(r2
)<<12)); // ldr r2, [r1]
2320 o(0xe2a00000 | (intr(r2
)<<16) | (intr(r2
)<<12)); // adc r2, r2, #0
2321 o(0xe5800000 | (intr(r1
)<<16) | (intr(r2
)<<12)); // str r2, [r1]
2325 /* computed goto support */
2332 /* Save the stack pointer onto the stack and return the location of its address */
2333 ST_FUNC
void gen_vla_sp_save(int addr
) {
2336 v
.r
= VT_LOCAL
| VT_LVAL
;
2341 /* Restore the SP from a location on the stack */
2342 ST_FUNC
void gen_vla_sp_restore(int addr
) {
2345 v
.r
= VT_LOCAL
| VT_LVAL
;
2350 /* Subtract from the stack pointer, and push the resulting value onto the stack */
2351 ST_FUNC
void gen_vla_alloc(CType
*type
, int align
) {
2353 #if defined(CONFIG_TCC_BCHECK)
2354 if (tcc_state
->do_bounds_check
)
2357 r
= intr(gv(RC_INT
));
2358 #if defined(CONFIG_TCC_BCHECK)
2359 if (tcc_state
->do_bounds_check
)
2360 o(0xe2800001 | (r
<<16)|(r
<<12)); /* add r,r,#1 */
2362 o(0xE04D0000|(r
<<12)|r
); /* sub r, sp, r */
2370 if (align
& (align
- 1))
2371 tcc_error("alignment is not a power of 2: %i", align
);
2372 o(stuff_const(0xE3C0D000|(r
<<16), align
- 1)); /* bic sp, r, #align-1 */
2374 #if defined(CONFIG_TCC_BCHECK)
2375 if (tcc_state
->do_bounds_check
) {
2378 o(0xe1a0000d | (vtop
->r
<< 12)); // mov r0,sp
2380 vpush_helper_func(TOK___bound_new_region
);
2383 func_bound_add_epilog
= 1;
2388 /* end of ARM code generator */
2389 /*************************************************************/
2391 /*************************************************************/