2 * ARMv4 code generator for TCC
4 * Copyright (c) 2003 Daniel Glöckner
6 * Based on i386-gen.c by Fabrice Bellard
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #ifdef TARGET_DEFS_ONLY
26 #ifndef TCC_ARM_VFP // Avoid useless warning
31 /* number of available registers */
38 /* a register can belong to several classes. The classes must be
39 sorted from more general to more precise (see gv2() code which does
40 assumptions on it). */
41 #define RC_INT 0x0001 /* generic integer register */
42 #define RC_FLOAT 0x0002 /* generic float register */
58 #define RC_IRET RC_R0 /* function return: integer register */
59 #define RC_LRET RC_R1 /* function return: second integer register */
60 #define RC_FRET RC_F0 /* function return: float register */
62 /* pretty names for the registers */
82 #define T2CPR(t) (((t) & VT_BTYPE) != VT_FLOAT ? 0x100 : 0)
85 /* return registers for function */
86 #define REG_IRET TREG_R0 /* single word int return register */
87 #define REG_LRET TREG_R1 /* second word return register (for long long) */
88 #define REG_FRET TREG_F0 /* float return register */
91 #define TOK___divdi3 TOK___aeabi_ldivmod
92 #define TOK___moddi3 TOK___aeabi_ldivmod
93 #define TOK___udivdi3 TOK___aeabi_uldivmod
94 #define TOK___umoddi3 TOK___aeabi_uldivmod
97 /* defined if function parameters must be evaluated in reverse order */
98 #define INVERT_FUNC_PARAMS
100 /* defined if structures are passed as pointers. Otherwise structures
101 are directly pushed on stack. */
102 //#define FUNC_STRUCT_PARAM_AS_PTR
104 #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
105 ST_DATA CType float_type
, double_type
, func_float_type
, func_double_type
;
106 #define func_ldouble_type func_double_type
108 #define func_float_type func_old_type
109 #define func_double_type func_old_type
110 #define func_ldouble_type func_old_type
113 /* pointer size, in bytes */
116 /* long double size and alignment, in bytes */
118 #define LDOUBLE_SIZE 8
122 #define LDOUBLE_SIZE 8
126 #define LDOUBLE_ALIGN 8
128 #define LDOUBLE_ALIGN 4
131 /* maximum alignment (for aligned attribute support) */
134 #define CHAR_IS_UNSIGNED
136 /******************************************************/
139 #define EM_TCC_TARGET EM_ARM
141 /* relocation type for 32 bit data relocation */
142 #define R_DATA_32 R_ARM_ABS32
143 #define R_DATA_PTR R_ARM_ABS32
144 #define R_JMP_SLOT R_ARM_JUMP_SLOT
145 #define R_COPY R_ARM_COPY
147 #define ELF_START_ADDR 0x00008000
148 #define ELF_PAGE_SIZE 0x1000
150 /******************************************************/
151 #else /* ! TARGET_DEFS_ONLY */
152 /******************************************************/
155 ST_DATA
const int reg_classes
[NB_REGS
] = {
156 /* r0 */ RC_INT
| RC_R0
,
157 /* r1 */ RC_INT
| RC_R1
,
158 /* r2 */ RC_INT
| RC_R2
,
159 /* r3 */ RC_INT
| RC_R3
,
160 /* r12 */ RC_INT
| RC_R12
,
161 /* f0 */ RC_FLOAT
| RC_F0
,
162 /* f1 */ RC_FLOAT
| RC_F1
,
163 /* f2 */ RC_FLOAT
| RC_F2
,
164 /* f3 */ RC_FLOAT
| RC_F3
,
166 /* d4/s8 */ RC_FLOAT
| RC_F4
,
167 /* d5/s10 */ RC_FLOAT
| RC_F5
,
168 /* d6/s12 */ RC_FLOAT
| RC_F6
,
169 /* d7/s14 */ RC_FLOAT
| RC_F7
,
173 /* keep in sync with line 104 above */
174 #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
175 ST_DATA CType float_type
, double_type
, func_float_type
, func_double_type
;
178 static int func_sub_sp_offset
, last_itod_magic
;
181 static int two2mask(int a
,int b
) {
182 return (reg_classes
[a
]|reg_classes
[b
])&~(RC_INT
|RC_FLOAT
);
185 static int regmask(int r
) {
186 return reg_classes
[r
]&~(RC_INT
|RC_FLOAT
);
189 /******************************************************/
193 /* this is a good place to start adding big-endian support*/
197 if (!cur_text_section
)
198 tcc_error("compiler error! This happens f.ex. if the compiler\n"
199 "can't evaluate constant expressions outside of a function.");
200 if (ind1
> cur_text_section
->data_allocated
)
201 section_realloc(cur_text_section
, ind1
);
202 cur_text_section
->data
[ind
++] = i
&255;
204 cur_text_section
->data
[ind
++] = i
&255;
206 cur_text_section
->data
[ind
++] = i
&255;
208 cur_text_section
->data
[ind
++] = i
;
211 static uint32_t stuff_const(uint32_t op
, uint32_t c
)
214 uint32_t nc
= 0, negop
= 0;
224 case 0x1A00000: //mov
225 case 0x1E00000: //mvn
232 return (op
&0xF010F000)|((op
>>16)&0xF)|0x1E00000;
236 return (op
&0xF010F000)|((op
>>16)&0xF)|0x1A00000;
237 case 0x1C00000: //bic
242 case 0x1800000: //orr
244 return (op
&0xFFF0FFFF)|0x1E00000;
250 if(c
<256) /* catch undefined <<32 */
253 m
=(0xff>>i
)|(0xff<<(32-i
));
255 return op
|(i
<<7)|(c
<<i
)|(c
>>(32-i
));
265 void stuff_const_harder(uint32_t op
, uint32_t v
) {
271 uint32_t a
[16], nv
, no
, o2
, n2
;
274 o2
=(op
&0xfff0ffff)|((op
&0xf000)<<4);;
276 a
[i
]=(a
[i
-1]>>2)|(a
[i
-1]<<30);
278 for(j
=i
<4?i
+12:15;j
>=i
+4;j
--)
279 if((v
&(a
[i
]|a
[j
]))==v
) {
280 o(stuff_const(op
,v
&a
[i
]));
281 o(stuff_const(o2
,v
&a
[j
]));
288 for(j
=i
<4?i
+12:15;j
>=i
+4;j
--)
289 if((nv
&(a
[i
]|a
[j
]))==nv
) {
290 o(stuff_const(no
,nv
&a
[i
]));
291 o(stuff_const(n2
,nv
&a
[j
]));
296 for(k
=i
<4?i
+12:15;k
>=j
+4;k
--)
297 if((v
&(a
[i
]|a
[j
]|a
[k
]))==v
) {
298 o(stuff_const(op
,v
&a
[i
]));
299 o(stuff_const(o2
,v
&a
[j
]));
300 o(stuff_const(o2
,v
&a
[k
]));
307 for(k
=i
<4?i
+12:15;k
>=j
+4;k
--)
308 if((nv
&(a
[i
]|a
[j
]|a
[k
]))==nv
) {
309 o(stuff_const(no
,nv
&a
[i
]));
310 o(stuff_const(n2
,nv
&a
[j
]));
311 o(stuff_const(n2
,nv
&a
[k
]));
314 o(stuff_const(op
,v
&a
[0]));
315 o(stuff_const(o2
,v
&a
[4]));
316 o(stuff_const(o2
,v
&a
[8]));
317 o(stuff_const(o2
,v
&a
[12]));
321 ST_FUNC
uint32_t encbranch(int pos
, int addr
, int fail
)
325 if(addr
>=0x1000000 || addr
<-0x1000000) {
327 tcc_error("FIXME: function bigger than 32MB");
330 return 0x0A000000|(addr
&0xffffff);
333 int decbranch(int pos
)
336 x
=*(uint32_t *)(cur_text_section
->data
+ pos
);
343 /* output a symbol and patch all calls to it */
344 void gsym_addr(int t
, int a
)
349 x
=(uint32_t *)(cur_text_section
->data
+ t
);
352 *x
=0xE1A00000; // nop
355 *x
|= encbranch(lt
,a
,1);
366 static uint32_t vfpr(int r
)
368 if(r
<TREG_F0
|| r
>TREG_F7
)
369 tcc_error("compiler error! register %i is no vfp register",r
);
373 static uint32_t fpr(int r
)
375 if(r
<TREG_F0
|| r
>TREG_F3
)
376 tcc_error("compiler error! register %i is no fpa register",r
);
381 static uint32_t intr(int r
)
385 if((r
<0 || r
>4) && r
!=14)
386 tcc_error("compiler error! register %i is no int register",r
);
390 static void calcaddr(uint32_t *base
, int *off
, int *sgn
, int maxoff
, unsigned shift
)
392 if(*off
>maxoff
|| *off
&((1<<shift
)-1)) {
399 y
=stuff_const(x
,*off
&~maxoff
);
405 y
=stuff_const(x
,(*off
+maxoff
)&~maxoff
);
409 *off
=((*off
+maxoff
)&~maxoff
)-*off
;
412 stuff_const_harder(x
,*off
&~maxoff
);
417 static uint32_t mapcc(int cc
)
422 return 0x30000000; /* CC/LO */
424 return 0x20000000; /* CS/HS */
426 return 0x00000000; /* EQ */
428 return 0x10000000; /* NE */
430 return 0x90000000; /* LS */
432 return 0x80000000; /* HI */
434 return 0x40000000; /* MI */
436 return 0x50000000; /* PL */
438 return 0xB0000000; /* LT */
440 return 0xA0000000; /* GE */
442 return 0xD0000000; /* LE */
444 return 0xC0000000; /* GT */
446 tcc_error("unexpected condition code");
447 return 0xE0000000; /* AL */
450 static int negcc(int cc
)
479 tcc_error("unexpected condition code");
483 /* load 'r' from value 'sv' */
484 void load(int r
, SValue
*sv
)
486 int v
, ft
, fc
, fr
, sign
;
503 uint32_t base
= 0xB; // fp
506 v1
.r
= VT_LOCAL
| VT_LVAL
;
508 load(base
=14 /* lr */, &v1
);
511 } else if(v
== VT_CONST
) {
519 } else if(v
< VT_CONST
) {
526 calcaddr(&base
,&fc
,&sign
,1020,2);
528 op
=0xED100A00; /* flds */
531 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
532 op
|=0x100; /* flds -> fldd */
533 o(op
|(vfpr(r
)<<12)|(fc
>>2)|(base
<<16));
538 #if LDOUBLE_SIZE == 8
539 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
542 if ((ft
& VT_BTYPE
) == VT_DOUBLE
)
544 else if ((ft
& VT_BTYPE
) == VT_LDOUBLE
)
547 o(op
|(fpr(r
)<<12)|(fc
>>2)|(base
<<16));
549 } else if((ft
& (VT_BTYPE
|VT_UNSIGNED
)) == VT_BYTE
550 || (ft
& VT_BTYPE
) == VT_SHORT
) {
551 calcaddr(&base
,&fc
,&sign
,255,0);
553 if ((ft
& VT_BTYPE
) == VT_SHORT
)
555 if ((ft
& VT_UNSIGNED
) == 0)
559 o(op
|(intr(r
)<<12)|(base
<<16)|((fc
&0xf0)<<4)|(fc
&0xf));
561 calcaddr(&base
,&fc
,&sign
,4095,0);
565 if ((ft
& VT_BTYPE
) == VT_BYTE
)
567 o(op
|(intr(r
)<<12)|fc
|(base
<<16));
573 op
=stuff_const(0xE3A00000|(intr(r
)<<12),sv
->c
.ul
);
574 if (fr
& VT_SYM
|| !op
) {
575 o(0xE59F0000|(intr(r
)<<12));
578 greloc(cur_text_section
, sv
->sym
, ind
, R_ARM_ABS32
);
583 } else if (v
== VT_LOCAL
) {
584 op
=stuff_const(0xE28B0000|(intr(r
)<<12),sv
->c
.ul
);
585 if (fr
& VT_SYM
|| !op
) {
586 o(0xE59F0000|(intr(r
)<<12));
588 if(fr
& VT_SYM
) // needed ?
589 greloc(cur_text_section
, sv
->sym
, ind
, R_ARM_ABS32
);
591 o(0xE08B0000|(intr(r
)<<12)|intr(r
));
595 } else if(v
== VT_CMP
) {
596 o(mapcc(sv
->c
.ul
)|0x3A00001|(intr(r
)<<12));
597 o(mapcc(negcc(sv
->c
.ul
))|0x3A00000|(intr(r
)<<12));
599 } else if (v
== VT_JMP
|| v
== VT_JMPI
) {
602 o(0xE3A00000|(intr(r
)<<12)|t
);
605 o(0xE3A00000|(intr(r
)<<12)|(t
^1));
607 } else if (v
< VT_CONST
) {
610 o(0xEEB00A40|(vfpr(r
)<<12)|vfpr(v
)|T2CPR(ft
)); /* fcpyX */
612 o(0xEE008180|(fpr(r
)<<12)|fpr(v
));
615 o(0xE1A00000|(intr(r
)<<12)|intr(v
));
619 tcc_error("load unimplemented!");
622 /* store register 'r' in lvalue 'v' */
623 void store(int r
, SValue
*sv
)
626 int v
, ft
, fc
, fr
, sign
;
641 if (fr
& VT_LVAL
|| fr
== VT_LOCAL
) {
647 } else if(v
== VT_CONST
) {
658 calcaddr(&base
,&fc
,&sign
,1020,2);
660 op
=0xED000A00; /* fsts */
663 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
664 op
|=0x100; /* fsts -> fstd */
665 o(op
|(vfpr(r
)<<12)|(fc
>>2)|(base
<<16));
670 #if LDOUBLE_SIZE == 8
671 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
674 if ((ft
& VT_BTYPE
) == VT_DOUBLE
)
676 if ((ft
& VT_BTYPE
) == VT_LDOUBLE
)
679 o(op
|(fpr(r
)<<12)|(fc
>>2)|(base
<<16));
682 } else if((ft
& VT_BTYPE
) == VT_SHORT
) {
683 calcaddr(&base
,&fc
,&sign
,255,0);
687 o(op
|(intr(r
)<<12)|(base
<<16)|((fc
&0xf0)<<4)|(fc
&0xf));
689 calcaddr(&base
,&fc
,&sign
,4095,0);
693 if ((ft
& VT_BTYPE
) == VT_BYTE
)
695 o(op
|(intr(r
)<<12)|fc
|(base
<<16));
700 tcc_error("store unimplemented");
703 static void gadd_sp(int val
)
705 stuff_const_harder(0xE28DD000,val
);
708 /* 'is_jmp' is '1' if it is a jump */
709 static void gcall_or_jmp(int is_jmp
)
712 if ((vtop
->r
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
) {
715 x
=encbranch(ind
,ind
+vtop
->c
.ul
,0);
717 if (vtop
->r
& VT_SYM
) {
718 /* relocation case */
719 greloc(cur_text_section
, vtop
->sym
, ind
, R_ARM_PC24
);
721 put_elf_reloc(symtab_section
, cur_text_section
, ind
, R_ARM_PC24
, 0);
722 o(x
|(is_jmp
?0xE0000000:0xE1000000));
725 o(0xE28FE004); // add lr,pc,#4
726 o(0xE51FF004); // ldr pc,[pc,#-4]
727 if (vtop
->r
& VT_SYM
)
728 greloc(cur_text_section
, vtop
->sym
, ind
, R_ARM_ABS32
);
732 /* otherwise, indirect call */
735 o(0xE1A0E00F); // mov lr,pc
736 o(0xE1A0F000|intr(r
)); // mov pc,r
740 /* Generate function call. The function address is pushed first, then
741 all the parameters in call order. This functions pops all the
742 parameters and the function address. */
743 void gfunc_call(int nb_args
)
745 int size
, align
, r
, args_size
, i
;
747 signed char plan
[4][2]={{-1,-1},{-1,-1},{-1,-1},{-1,-1}};
748 int todo
=0xf, keep
, plan2
[4]={0,0,0,0};
750 r
= vtop
->r
& VT_VALMASK
;
751 if (r
== VT_CMP
|| (r
& ~1) == VT_JMP
)
754 if((vtop
[-nb_args
].type
.ref
->type
.t
& VT_BTYPE
) == VT_STRUCT
755 && type_size(&vtop
[-nb_args
].type
.ref
->type
, &align
) <= 4) {
758 vtop
[-nb_args
]=vtop
[-nb_args
+1];
759 vtop
[-nb_args
+1]=tmp
;
764 vtop
->type
.t
= VT_LLONG
;
766 for(i
= nb_args
+ 1 ; i
-- ;) {
767 size
= type_size(&vtop
[-i
].type
, &align
);
768 if(args_size
& (align
-1)) {
770 vtop
->type
.t
= VT_VOID
; /* padding */
775 args_size
+= (size
+ 3) & -4;
780 for(i
= nb_args
; i
-- && args_size
< 16 ;) {
781 switch(vtop
[-i
].type
.t
& VT_BTYPE
) {
786 size
= type_size(&vtop
[-i
].type
, &align
);
787 size
= (size
+ 3) & -4;
791 plan
[nb_args
-1-i
][0]=args_size
/4;
793 if ((vtop
[-i
].type
.t
& VT_BTYPE
) == VT_LLONG
&& args_size
< 16) {
794 plan
[nb_args
-1-i
][1]=args_size
/4;
799 args_size
= keep
= 0;
800 for(i
= 0;i
< nb_args
; i
++) {
802 if ((vtop
->type
.t
& VT_BTYPE
) == VT_STRUCT
) {
803 size
= type_size(&vtop
->type
, &align
);
804 /* align to stack align size */
805 size
= (size
+ 3) & -4;
806 /* allocate the necessary size on stack */
808 /* generate structure store */
810 o(0xE1A0000D|(intr(r
)<<12));
811 vset(&vtop
->type
, r
| VT_LVAL
, 0);
816 } else if (is_float(vtop
->type
.t
)) {
818 r
=vfpr(gv(RC_FLOAT
))<<12;
820 if ((vtop
->type
.t
& VT_BTYPE
) != VT_FLOAT
)
823 r
|=0x101; /* fstms -> fstmd */
827 r
=fpr(gv(RC_FLOAT
))<<12;
828 if ((vtop
->type
.t
& VT_BTYPE
) == VT_FLOAT
)
830 else if ((vtop
->type
.t
& VT_BTYPE
) == VT_DOUBLE
)
840 o(0xED2D0100|r
|(size
>>2));
846 /* simple type (currently always same size) */
847 /* XXX: implicit cast ? */
849 if ((vtop
->type
.t
& VT_BTYPE
) == VT_LLONG
) {
852 if(nb_args
-i
<5 && plan
[nb_args
-i
-1][1]!=-1) {
853 s
=regmask(plan
[nb_args
-i
-1][1]);
854 todo
&=~(1<<plan
[nb_args
-i
-1][1]);
858 o(0xE52D0004|(intr(r
)<<12)); /* str r,[sp,#-4]! */
868 if(nb_args
-i
<5 && plan
[nb_args
-i
-1][0]!=-1) {
869 s
=regmask(plan
[nb_args
-i
-1][0]);
870 todo
&=~(1<<plan
[nb_args
-i
-1][0]);
873 if(vtop
->type
.t
== VT_VOID
) {
875 o(0xE24DD004); /* sub sp,sp,#4 */
881 o(0xE52D0004|(intr(r
)<<12)); /* str r,[sp,#-4]! */
894 save_regs(keep
); /* save used temporary registers */
915 func_sym
= vtop
->type
.ref
;
920 if((vtop
->type
.ref
->type
.t
& VT_BTYPE
) == VT_STRUCT
921 && type_size(&vtop
->type
.ref
->type
, &align
) <= 4)
923 store(REG_IRET
,vtop
-keep
);
927 else if(is_float(vtop
->type
.ref
->type
.t
)) {
928 if((vtop
->type
.ref
->type
.t
& VT_BTYPE
) == VT_FLOAT
) {
929 o(0xEE000A10); /* fmsr s0,r0 */
931 o(0xEE000B10); /* fmdlr d0,r0 */
932 o(0xEE201B10); /* fmdhr d0,r1 */
941 /* generate function prolog of type 't' */
942 void gfunc_prolog(CType
*func_type
)
945 int n
,addr
,size
,align
;
947 sym
= func_type
->ref
;
952 if((func_vt
.t
& VT_BTYPE
) == VT_STRUCT
953 && type_size(&func_vt
,&align
) > 4)
959 for(sym2
=sym
->next
;sym2
&& n
<4;sym2
=sym2
->next
) {
960 size
= type_size(&sym2
->type
, &align
);
963 o(0xE1A0C00D); /* mov ip,sp */
964 if(func_type
->ref
->c
== FUNC_ELLIPSIS
)
972 o(0xE92D0000|((1<<n
)-1)); /* save r0-r4 on stack if needed */
974 o(0xE92D5800); /* save fp, ip, lr */
975 o(0xE28DB00C); /* add fp, sp, #12 */
976 func_sub_sp_offset
= ind
;
977 o(0xE1A00000); /* nop, leave space for stack adjustment */
978 while ((sym
= sym
->next
)) {
981 size
= type_size(type
, &align
);
982 size
= (size
+ 3) & -4;
984 addr
= (addr
+ align
- 1) & -align
;
986 sym_push(sym
->v
& ~SYM_FIELD
, type
, VT_LOCAL
| lvalue_type(type
->t
), addr
);
994 /* generate function epilog */
995 void gfunc_epilog(void)
1000 if(is_float(func_vt
.t
)) {
1001 if((func_vt
.t
& VT_BTYPE
) == VT_FLOAT
)
1002 o(0xEE100A10); /* fmrs r0, s0 */
1004 o(0xEE100B10); /* fmrdl r0, d0 */
1005 o(0xEE301B10); /* fmrdh r1, d0 */
1009 o(0xE91BA800); /* restore fp, sp, pc */
1010 diff
= (-loc
+ 3) & -4;
1013 diff
= (diff
+ 7) & -8;
1016 x
=stuff_const(0xE24BD000, diff
); /* sub sp,fp,# */
1018 *(uint32_t *)(cur_text_section
->data
+ func_sub_sp_offset
) = x
;
1022 o(0xE59FC004); /* ldr ip,[pc+4] */
1023 o(0xE04BD00C); /* sub sp,fp,ip */
1024 o(0xE1A0F00E); /* mov pc,lr */
1026 *(uint32_t *)(cur_text_section
->data
+ func_sub_sp_offset
) = 0xE1000000|encbranch(func_sub_sp_offset
,addr
,1);
1031 /* generate a jump to a label */
1036 o(0xE0000000|encbranch(r
,t
,1));
1040 /* generate a jump to a fixed address */
1041 void gjmp_addr(int a
)
1046 /* generate a test. set 'inv' to invert test. Stack entry is popped */
1047 int gtst(int inv
, int t
)
1051 v
= vtop
->r
& VT_VALMASK
;
1054 op
=mapcc(inv
?negcc(vtop
->c
.i
):vtop
->c
.i
);
1055 op
|=encbranch(r
,t
,1);
1058 } else if (v
== VT_JMP
|| v
== VT_JMPI
) {
1059 if ((v
& 1) == inv
) {
1068 p
= decbranch(lp
=p
);
1070 x
= (uint32_t *)(cur_text_section
->data
+ lp
);
1072 *x
|= encbranch(lp
,t
,1);
1081 if (is_float(vtop
->type
.t
)) {
1084 o(0xEEB50A40|(vfpr(r
)<<12)|T2CPR(vtop
->type
.t
)); /* fcmpzX */
1085 o(0xEEF1FA10); /* fmstat */
1087 o(0xEE90F118|(fpr(r
)<<16));
1091 return gtst(inv
, t
);
1092 } else if ((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1093 /* constant jmp optimization */
1094 if ((vtop
->c
.i
!= 0) != inv
)
1098 o(0xE3300000|(intr(v
)<<16));
1101 return gtst(inv
, t
);
1108 /* generate an integer binary operation */
1109 void gen_opi(int op
)
1112 uint32_t opc
= 0, r
, fr
;
1113 unsigned short retreg
= REG_IRET
;
1121 case TOK_ADDC1
: /* add with carry generation */
1129 case TOK_SUBC1
: /* sub with carry generation */
1133 case TOK_ADDC2
: /* add with carry use */
1137 case TOK_SUBC2
: /* sub with carry use */
1154 gv2(RC_INT
, RC_INT
);
1158 o(0xE0000090|(intr(r
)<<16)|(intr(r
)<<8)|intr(fr
));
1183 func
=TOK___aeabi_idivmod
;
1192 func
=TOK___aeabi_uidivmod
;
1200 gv2(RC_INT
, RC_INT
);
1201 r
=intr(vtop
[-1].r2
=get_reg(RC_INT
));
1203 vtop
[-1].r
=get_reg_ex(RC_INT
,regmask(c
));
1205 o(0xE0800090|(r
<<16)|(intr(vtop
->r
)<<12)|(intr(c
)<<8)|intr(vtop
[1].r
));
1214 if((vtop
[-1].r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1215 if(opc
== 4 || opc
== 5 || opc
== 0xc) {
1217 opc
|=2; // sub -> rsb
1220 if ((vtop
->r
& VT_VALMASK
) == VT_CMP
||
1221 (vtop
->r
& (VT_VALMASK
& ~1)) == VT_JMP
)
1226 opc
=0xE0000000|(opc
<<20)|(c
<<16);
1227 if((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1229 x
=stuff_const(opc
|0x2000000,vtop
->c
.i
);
1231 r
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,regmask(vtop
[-1].r
)));
1236 fr
=intr(gv(RC_INT
));
1237 r
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,two2mask(vtop
->r
,vtop
[-1].r
)));
1241 if (op
>= TOK_ULT
&& op
<= TOK_GT
) {
1247 opc
=0xE1A00000|(opc
<<5);
1248 if ((vtop
->r
& VT_VALMASK
) == VT_CMP
||
1249 (vtop
->r
& (VT_VALMASK
& ~1)) == VT_JMP
)
1255 if ((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1256 fr
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,regmask(vtop
[-1].r
)));
1257 c
= vtop
->c
.i
& 0x1f;
1258 o(opc
|(c
<<7)|(fr
<<12));
1260 fr
=intr(gv(RC_INT
));
1261 c
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,two2mask(vtop
->r
,vtop
[-1].r
)));
1262 o(opc
|(c
<<12)|(fr
<<8)|0x10);
1267 vpush_global_sym(&func_old_type
, func
);
1274 tcc_error("gen_opi %i unimplemented!",op
);
1279 static int is_zero(int i
)
1281 if((vtop
[i
].r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) != VT_CONST
)
1283 if (vtop
[i
].type
.t
== VT_FLOAT
)
1284 return (vtop
[i
].c
.f
== 0.f
);
1285 else if (vtop
[i
].type
.t
== VT_DOUBLE
)
1286 return (vtop
[i
].c
.d
== 0.0);
1287 return (vtop
[i
].c
.ld
== 0.l
);
1290 /* generate a floating point operation 'v = t1 op t2' instruction. The
1291 * two operands are guaranted to have the same floating point type */
1292 void gen_opf(int op
)
1296 x
=0xEE000A00|T2CPR(vtop
->type
.t
);
1314 x
|=0x810000; /* fsubX -> fnegX */
1327 if(op
< TOK_ULT
&& op
> TOK_GT
) {
1328 tcc_error("unknown fp op %x!",op
);
1334 case TOK_LT
: op
=TOK_GT
; break;
1335 case TOK_GE
: op
=TOK_ULE
; break;
1336 case TOK_LE
: op
=TOK_GE
; break;
1337 case TOK_GT
: op
=TOK_ULT
; break;
1340 x
|=0xB40040; /* fcmpX */
1341 if(op
!=TOK_EQ
&& op
!=TOK_NE
)
1342 x
|=0x80; /* fcmpX -> fcmpeX */
1345 o(x
|0x10000|(vfpr(gv(RC_FLOAT
))<<12)); /* fcmp(e)X -> fcmp(e)zX */
1347 x
|=vfpr(gv(RC_FLOAT
));
1349 o(x
|(vfpr(gv(RC_FLOAT
))<<12));
1352 o(0xEEF1FA10); /* fmstat */
1355 case TOK_LE
: op
=TOK_ULE
; break;
1356 case TOK_LT
: op
=TOK_ULT
; break;
1357 case TOK_UGE
: op
=TOK_GE
; break;
1358 case TOK_UGT
: op
=TOK_GT
; break;
1375 vtop
->r
=get_reg_ex(RC_FLOAT
,r
);
1378 o(x
|(vfpr(vtop
->r
)<<12));
1382 static uint32_t is_fconst()
1386 if((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) != VT_CONST
)
1388 if (vtop
->type
.t
== VT_FLOAT
)
1390 else if (vtop
->type
.t
== VT_DOUBLE
)
1420 /* generate a floating point operation 'v = t1 op t2' instruction. The
1421 two operands are guaranted to have the same floating point type */
1422 void gen_opf(int op
)
1424 uint32_t x
, r
, r2
, c1
, c2
;
1425 //fputs("gen_opf\n",stderr);
1431 #if LDOUBLE_SIZE == 8
1432 if ((vtop
->type
.t
& VT_BTYPE
) != VT_FLOAT
)
1435 if ((vtop
->type
.t
& VT_BTYPE
) == VT_DOUBLE
)
1437 else if ((vtop
->type
.t
& VT_BTYPE
) == VT_LDOUBLE
)
1448 r
=fpr(gv(RC_FLOAT
));
1455 r2
=fpr(gv(RC_FLOAT
));
1464 r
=fpr(gv(RC_FLOAT
));
1466 } else if(c1
&& c1
<=0xf) {
1469 r
=fpr(gv(RC_FLOAT
));
1474 r
=fpr(gv(RC_FLOAT
));
1476 r2
=fpr(gv(RC_FLOAT
));
1485 r
=fpr(gv(RC_FLOAT
));
1490 r2
=fpr(gv(RC_FLOAT
));
1498 r
=fpr(gv(RC_FLOAT
));
1500 } else if(c1
&& c1
<=0xf) {
1503 r
=fpr(gv(RC_FLOAT
));
1508 r
=fpr(gv(RC_FLOAT
));
1510 r2
=fpr(gv(RC_FLOAT
));
1514 if(op
>= TOK_ULT
&& op
<= TOK_GT
) {
1515 x
|=0xd0f110; // cmfe
1516 /* bug (intention?) in Linux FPU emulator
1517 doesn't set carry if equal */
1523 tcc_error("unsigned comparision on floats?");
1529 op
=TOK_ULE
; /* correct in unordered case only if AC bit in FPSR set */
1533 x
&=~0x400000; // cmfe -> cmf
1555 r
=fpr(gv(RC_FLOAT
));
1562 r2
=fpr(gv(RC_FLOAT
));
1564 vtop
[-1].r
= VT_CMP
;
1567 tcc_error("unknown fp op %x!",op
);
1571 if(vtop
[-1].r
== VT_CMP
)
1577 vtop
[-1].r
=get_reg_ex(RC_FLOAT
,two2mask(vtop
[-1].r
,c1
));
1581 o(x
|(r
<<16)|(c1
<<12)|r2
);
1585 /* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
1586 and 'long long' cases. */
1587 ST_FUNC
void gen_cvt_itof1(int t
)
1591 bt
=vtop
->type
.t
& VT_BTYPE
;
1592 if(bt
== VT_INT
|| bt
== VT_SHORT
|| bt
== VT_BYTE
) {
1598 r2
=vfpr(vtop
->r
=get_reg(RC_FLOAT
));
1599 o(0xEE000A10|(r
<<12)|(r2
<<16)); /* fmsr */
1601 if(!(vtop
->type
.t
& VT_UNSIGNED
))
1602 r2
|=0x80; /* fuitoX -> fsituX */
1603 o(0xEEB80A40|r2
|T2CPR(t
)); /* fYitoX*/
1605 r2
=fpr(vtop
->r
=get_reg(RC_FLOAT
));
1606 if((t
& VT_BTYPE
) != VT_FLOAT
)
1607 dsize
=0x80; /* flts -> fltd */
1608 o(0xEE000110|dsize
|(r2
<<16)|(r
<<12)); /* flts */
1609 if((vtop
->type
.t
& (VT_UNSIGNED
|VT_BTYPE
)) == (VT_UNSIGNED
|VT_INT
)) {
1611 o(0xE3500000|(r
<<12)); /* cmp */
1612 r
=fpr(get_reg(RC_FLOAT
));
1613 if(last_itod_magic
) {
1614 off
=ind
+8-last_itod_magic
;
1619 o(0xBD1F0100|(r
<<12)|off
); /* ldflts */
1621 o(0xEA000000); /* b */
1622 last_itod_magic
=ind
;
1623 o(0x4F800000); /* 4294967296.0f */
1625 o(0xBE000100|dsize
|(r2
<<16)|(r2
<<12)|r
); /* adflt */
1629 } else if(bt
== VT_LLONG
) {
1631 CType
*func_type
= 0;
1632 if((t
& VT_BTYPE
) == VT_FLOAT
) {
1633 func_type
= &func_float_type
;
1634 if(vtop
->type
.t
& VT_UNSIGNED
)
1635 func
=TOK___floatundisf
;
1637 func
=TOK___floatdisf
;
1638 #if LDOUBLE_SIZE != 8
1639 } else if((t
& VT_BTYPE
) == VT_LDOUBLE
) {
1640 func_type
= &func_ldouble_type
;
1641 if(vtop
->type
.t
& VT_UNSIGNED
)
1642 func
=TOK___floatundixf
;
1644 func
=TOK___floatdixf
;
1645 } else if((t
& VT_BTYPE
) == VT_DOUBLE
) {
1647 } else if((t
& VT_BTYPE
) == VT_DOUBLE
|| (t
& VT_BTYPE
) == VT_LDOUBLE
) {
1649 func_type
= &func_double_type
;
1650 if(vtop
->type
.t
& VT_UNSIGNED
)
1651 func
=TOK___floatundidf
;
1653 func
=TOK___floatdidf
;
1656 vpush_global_sym(func_type
, func
);
1664 tcc_error("unimplemented gen_cvt_itof %x!",vtop
->type
.t
);
1667 /* convert fp to int 't' type */
1668 void gen_cvt_ftoi(int t
)
1674 r2
=vtop
->type
.t
& VT_BTYPE
;
1677 r
=vfpr(gv(RC_FLOAT
));
1679 o(0xEEBC0A40|(r
<<12)|r
|T2CPR(r2
)); /* ftoXiY */
1680 r2
=intr(vtop
->r
=get_reg(RC_INT
));
1681 o(0xEE100A10|(r
<<16)|(r2
<<12));
1686 func
=TOK___fixunssfsi
;
1687 #if LDOUBLE_SIZE != 8
1688 else if(r2
== VT_LDOUBLE
)
1689 func
=TOK___fixunsxfsi
;
1690 else if(r2
== VT_DOUBLE
)
1692 else if(r2
== VT_LDOUBLE
|| r2
== VT_DOUBLE
)
1694 func
=TOK___fixunsdfsi
;
1696 r
=fpr(gv(RC_FLOAT
));
1697 r2
=intr(vtop
->r
=get_reg(RC_INT
));
1698 o(0xEE100170|(r2
<<12)|r
);
1702 } else if(t
== VT_LLONG
) { // unsigned handled in gen_cvt_ftoi1
1705 #if LDOUBLE_SIZE != 8
1706 else if(r2
== VT_LDOUBLE
)
1708 else if(r2
== VT_DOUBLE
)
1710 else if(r2
== VT_LDOUBLE
|| r2
== VT_DOUBLE
)
1715 vpush_global_sym(&func_old_type
, func
);
1720 vtop
->r2
= REG_LRET
;
1724 tcc_error("unimplemented gen_cvt_ftoi!");
1727 /* convert from one floating point type to another */
1728 void gen_cvt_ftof(int t
)
1731 if(((vtop
->type
.t
& VT_BTYPE
) == VT_FLOAT
) != ((t
& VT_BTYPE
) == VT_FLOAT
)) {
1732 uint32_t r
= vfpr(gv(RC_FLOAT
));
1733 o(0xEEB70AC0|(r
<<12)|r
|T2CPR(vtop
->type
.t
));
1736 /* all we have to do on i386 and FPA ARM is to put the float in a register */
1741 /* computed goto support */
1748 /* end of ARM code generator */
1749 /*************************************************************/
1751 /*************************************************************/