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 /* number of available registers */
26 /* a register can belong to several classes. The classes must be
27 sorted from more general to more precise (see gv2() code which does
28 assumptions on it). */
29 #define RC_INT 0x0001 /* generic integer register */
30 #define RC_FLOAT 0x0002 /* generic float register */
40 #define RC_IRET RC_R0 /* function return: integer register */
41 #define RC_LRET RC_R1 /* function return: second integer register */
42 #define RC_FRET RC_F0 /* function return: float register */
44 /* pretty names for the registers */
57 int reg_classes
[NB_REGS
] = {
58 /* r0 */ RC_INT
| RC_R0
,
59 /* r1 */ RC_INT
| RC_R1
,
60 /* r2 */ RC_INT
| RC_R2
,
61 /* r3 */ RC_INT
| RC_R3
,
62 /* r12 */ RC_INT
| RC_R12
,
63 /* f0 */ RC_FLOAT
| RC_F0
,
64 /* f1 */ RC_FLOAT
| RC_F1
,
65 /* f2 */ RC_FLOAT
| RC_F2
,
66 /* f3 */ RC_FLOAT
| RC_F3
,
69 static int two2mask(int a
,int b
) {
70 return (reg_classes
[a
]|reg_classes
[b
])&~(RC_INT
|RC_FLOAT
);
73 static int regmask(int r
) {
74 return reg_classes
[r
]&~(RC_INT
|RC_FLOAT
);
77 /* return registers for function */
78 #define REG_IRET TREG_R0 /* single word int return register */
79 #define REG_LRET TREG_R1 /* second word return register (for long long) */
80 #define REG_FRET TREG_F0 /* float return register */
82 /* defined if function parameters must be evaluated in reverse order */
83 #define INVERT_FUNC_PARAMS
85 /* defined if structures are passed as pointers. Otherwise structures
86 are directly pushed on stack. */
87 //#define FUNC_STRUCT_PARAM_AS_PTR
89 /* pointer size, in bytes */
92 /* long double size and alignment, in bytes */
93 #define LDOUBLE_SIZE 8
94 #define LDOUBLE_ALIGN 4
95 /* maximum alignment (for aligned attribute support) */
98 #define CHAR_IS_UNSIGNED
100 /******************************************************/
103 #define EM_TCC_TARGET EM_ARM
105 /* relocation type for 32 bit data relocation */
106 #define R_DATA_32 R_ARM_ABS32
107 #define R_JMP_SLOT R_ARM_JUMP_SLOT
108 #define R_COPY R_ARM_COPY
110 #define ELF_START_ADDR 0x00008000
111 #define ELF_PAGE_SIZE 0x1000
113 /******************************************************/
114 static unsigned long func_sub_sp_offset
,last_itod_magic
;
116 void o(unsigned long i
)
118 /* this is a good place to start adding big-endian support*/
122 if (!cur_text_section
)
123 error("compiler error! This happens f.ex. if the compiler\n"
124 "can't evaluate constant expressions outside of a function.");
125 if (ind1
> cur_text_section
->data_allocated
)
126 section_realloc(cur_text_section
, ind1
);
127 cur_text_section
->data
[ind
++] = i
&255;
129 cur_text_section
->data
[ind
++] = i
&255;
131 cur_text_section
->data
[ind
++] = i
&255;
133 cur_text_section
->data
[ind
++] = i
;
136 static unsigned long stuff_const(unsigned long op
,unsigned long c
)
139 unsigned long nc
= 0,negop
= 0;
149 case 0x1A00000: //mov
150 case 0x1E00000: //mvn
157 return (op
&0xF010F000)|((op
>>16)&0xF)|0x1E00000;
161 return (op
&0xF010F000)|((op
>>16)&0xF)|0x1A00000;
162 case 0x1C00000: //bic
167 case 0x1800000: //orr
169 return (op
&0xFFF0FFFF)|0x1E00000;
175 if(c
<256) /* catch undefined <<32 */
178 m
=(0xff>>i
)|(0xff<<(32-i
));
180 return op
|(i
<<7)|(c
<<i
)|(c
>>(32-i
));
190 void stuff_const_harder(unsigned long op
,unsigned long v
) {
196 unsigned long a
[16],nv
,no
,o2
,n2
;
199 o2
=(op
&0xfff0ffff)|((op
&0xf000)<<4);;
201 a
[i
]=(a
[i
-1]>>2)|(a
[i
-1]<<30);
203 for(j
=i
+4;i
<13+i
;i
++)
204 if((v
&(a
[i
]|a
[j
]))==v
) {
205 o(stuff_const(op
,v
&a
[i
]));
206 o(stuff_const(o2
,v
&a
[j
]));
213 for(j
=i
+4;i
<13+i
;i
++)
214 if((nv
&(a
[i
]|a
[j
]))==nv
) {
215 o(stuff_const(no
,nv
&a
[i
]));
216 o(stuff_const(n2
,nv
&a
[j
]));
221 for(k
=j
+4;k
<13+i
;i
++)
222 if((v
&(a
[i
]|a
[j
]|a
[k
]))==v
) {
223 o(stuff_const(op
,v
&a
[i
]));
224 o(stuff_const(o2
,v
&a
[j
]));
225 o(stuff_const(o2
,v
&a
[k
]));
232 for(k
=j
+4;k
<13+i
;i
++)
233 if((nv
&(a
[i
]|a
[j
]|a
[k
]))==nv
) {
234 o(stuff_const(no
,nv
&a
[i
]));
235 o(stuff_const(n2
,nv
&a
[j
]));
236 o(stuff_const(n2
,nv
&a
[k
]));
239 o(stuff_const(op
,v
&a
[0]));
240 o(stuff_const(o2
,v
&a
[4]));
241 o(stuff_const(o2
,v
&a
[8]));
242 o(stuff_const(o2
,v
&a
[12]));
246 unsigned long encbranch(int pos
,int addr
,int fail
)
250 if(addr
>=0x1000000 || addr
<-0x1000000) {
252 error("FIXME: function bigger than 32MB");
255 return 0x0A000000|(addr
&0xffffff);
258 int decbranch(int pos
)
261 x
=*(int *)(cur_text_section
->data
+ pos
);
268 /* output a symbol and patch all calls to it */
269 void gsym_addr(int t
, int a
)
274 x
=(unsigned long *)(cur_text_section
->data
+ t
);
277 *x
=0xE1A00000; // nop
280 *x
|= encbranch(lt
,a
,1);
290 static unsigned long fpr(int r
)
292 if(r
<TREG_F0
|| r
>TREG_F3
)
293 error("compiler error! register %i is no fp register\n",r
);
297 static unsigned long intr(int r
)
301 if((r
<0 || r
>4) && r
!=14)
302 error("compiler error! register %i is no int register\n",r
);
306 static void calcaddr(unsigned long *base
,int *off
,int *sgn
,int maxoff
,unsigned shift
)
308 if(*off
>maxoff
|| *off
&((1<<shift
)-1)) {
315 y
=stuff_const(x
,*off
&~maxoff
);
321 y
=stuff_const(x
,(*off
+maxoff
)&~maxoff
);
325 *off
=((*off
+maxoff
)&~maxoff
)-*off
;
328 stuff_const_harder(x
,*off
&~maxoff
);
333 static unsigned long mapcc(int cc
)
358 error("unexpected condition code");
362 static int negcc(int cc
)
387 error("unexpected condition code");
391 /* load 'r' from value 'sv' */
392 void load(int r
, SValue
*sv
)
394 int v
, ft
, fc
, fr
, sign
;
411 unsigned long base
=0xB; // fp
414 v1
.r
= VT_LOCAL
| VT_LVAL
;
416 load(base
=14 /* lr */, &v1
);
419 } else if(v
== VT_CONST
) {
427 } else if(v
< VT_CONST
) {
434 calcaddr(&base
,&fc
,&sign
,1020,2);
438 #if LDOUBLE_SIZE == 8
439 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
442 if ((ft
& VT_BTYPE
) == VT_DOUBLE
)
444 else if ((ft
& VT_BTYPE
) == VT_LDOUBLE
)
447 o(op
|(fpr(r
)<<12)|(fc
>>2)|(base
<<16));
448 } else if((ft
& VT_TYPE
) == VT_BYTE
|| (ft
& VT_BTYPE
) == VT_SHORT
) {
449 calcaddr(&base
,&fc
,&sign
,255,0);
451 if ((ft
& VT_BTYPE
) == VT_SHORT
)
453 if ((ft
& VT_UNSIGNED
) == 0)
457 o(op
|(intr(r
)<<12)|(base
<<16)|((fc
&0xf0)<<4)|(fc
&0xf));
459 calcaddr(&base
,&fc
,&sign
,4095,0);
463 if ((ft
& VT_BTYPE
) == VT_BYTE
)
465 o(op
|(intr(r
)<<12)|fc
|(base
<<16));
471 op
=stuff_const(0xE3A00000|(intr(r
)<<12),sv
->c
.ul
);
472 if (fr
& VT_SYM
|| !op
) {
473 o(0xE59F0000|(intr(r
)<<12));
476 greloc(cur_text_section
, sv
->sym
, ind
, R_ARM_ABS32
);
481 } else if (v
== VT_LOCAL
) {
482 op
=stuff_const(0xE28B0000|(intr(r
)<<12),sv
->c
.ul
);
483 if (fr
& VT_SYM
|| !op
) {
484 o(0xE59F0000|(intr(r
)<<12));
486 if(fr
& VT_SYM
) // needed ?
487 greloc(cur_text_section
, sv
->sym
, ind
, R_ARM_ABS32
);
489 o(0xE08B0000|(intr(r
)<<12)|intr(r
));
493 } else if(v
== VT_CMP
) {
494 o(mapcc(sv
->c
.ul
)|0x3A00001|(intr(r
)<<12));
495 o(mapcc(negcc(sv
->c
.ul
))|0x3A00000|(intr(r
)<<12));
497 } else if (v
== VT_JMP
|| v
== VT_JMPI
) {
500 o(0xE3A00000|(intr(r
)<<12)|t
);
503 o(0xE3A00000|(intr(r
)<<12)|(t
^1));
505 } else if (v
< VT_CONST
) {
507 o(0xEE008180|(fpr(r
)<<12)|fpr(v
));
509 o(0xE1A00000|(intr(r
)<<12)|intr(v
));
513 error("load unimplemented!");
516 /* store register 'r' in lvalue 'v' */
517 void store(int r
, SValue
*sv
)
520 int v
, ft
, fc
, fr
, sign
;
535 if (fr
& VT_LVAL
|| fr
== VT_LOCAL
) {
536 unsigned long base
=0xb;
541 } else if(v
== VT_CONST
) {
552 calcaddr(&base
,&fc
,&sign
,1020,2);
556 #if LDOUBLE_SIZE == 8
557 if ((ft
& VT_BTYPE
) != VT_FLOAT
)
560 if ((ft
& VT_BTYPE
) == VT_DOUBLE
)
562 if ((ft
& VT_BTYPE
) == VT_LDOUBLE
)
565 o(op
|(fpr(r
)<<12)|(fc
>>2)|(base
<<16));
567 } else if((ft
& VT_BTYPE
) == VT_SHORT
) {
568 calcaddr(&base
,&fc
,&sign
,255,0);
572 o(op
|(intr(r
)<<12)|(base
<<16)|((fc
&0xf0)<<4)|(fc
&0xf));
574 calcaddr(&base
,&fc
,&sign
,4095,0);
578 if ((ft
& VT_BTYPE
) == VT_BYTE
)
580 o(op
|(intr(r
)<<12)|fc
|(base
<<16));
585 error("store unimplemented");
588 static void gadd_sp(int val
)
590 stuff_const_harder(0xE28DD000,val
);
593 /* 'is_jmp' is '1' if it is a jump */
594 static void gcall_or_jmp(int is_jmp
)
597 if ((vtop
->r
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
) {
600 x
=encbranch(ind
,ind
+vtop
->c
.ul
,0);
602 if (vtop
->r
& VT_SYM
) {
603 /* relocation case */
604 greloc(cur_text_section
, vtop
->sym
, ind
, R_ARM_PC24
);
606 put_elf_reloc(symtab_section
, cur_text_section
, ind
, R_ARM_PC24
, 0);
607 o(x
|(is_jmp
?0xE0000000:0xE1000000));
610 o(0xE28FE004); // add lr,pc,#4
611 o(0xE51FF004); // ldr pc,[pc,#-4]
612 if (vtop
->r
& VT_SYM
)
613 greloc(cur_text_section
, vtop
->sym
, ind
, R_ARM_ABS32
);
617 /* otherwise, indirect call */
620 o(0xE1A0E00F); // mov lr,pc
621 o(0xE1A0F000|intr(r
)); // mov pc,r
625 /* Generate function call. The function address is pushed first, then
626 all the parameters in call order. This functions pops all the
627 parameters and the function address. */
628 void gfunc_call(int nb_args
)
630 int size
, align
, r
, args_size
, i
;
632 signed char plan
[4][2]={{-1,-1},{-1,-1},{-1,-1},{-1,-1}};
633 int todo
=0xf, keep
, plan2
[4]={0,0,0,0};
635 r
= vtop
->r
& VT_VALMASK
;
636 if (r
== VT_CMP
|| (r
& ~1) == VT_JMP
)
639 for(i
= nb_args
; i
-- && args_size
< 16 ;) {
640 if ((vtop
[-i
].type
.t
& VT_BTYPE
) == VT_STRUCT
) {
641 size
= type_size(&vtop
[-i
].type
, &align
);
642 size
= (size
+ 3) & ~3;
644 } else if ((vtop
[-i
].type
.t
& VT_BTYPE
) == VT_FLOAT
)
646 else if ((vtop
[-i
].type
.t
& VT_BTYPE
) == VT_DOUBLE
)
648 else if ((vtop
[-i
].type
.t
& VT_BTYPE
) == VT_LDOUBLE
)
649 args_size
+= LDOUBLE_SIZE
;
651 plan
[nb_args
-1-i
][0]=args_size
/4;
653 if ((vtop
[-i
].type
.t
& VT_BTYPE
) == VT_LLONG
&& args_size
< 16) {
654 plan
[nb_args
-1-i
][1]=args_size
/4;
659 args_size
= keep
= 0;
660 for(i
= 0;i
< nb_args
; i
++) {
662 if ((vtop
->type
.t
& VT_BTYPE
) == VT_STRUCT
) {
663 size
= type_size(&vtop
->type
, &align
);
664 /* align to stack align size */
665 size
= (size
+ 3) & ~3;
666 /* allocate the necessary size on stack */
668 /* generate structure store */
670 o(0xE1A0000D|(intr(r
)<<12));
671 vset(&vtop
->type
, r
| VT_LVAL
, 0);
676 } else if (is_float(vtop
->type
.t
)) {
677 r
=fpr(gv(RC_FLOAT
))<<12;
678 if ((vtop
->type
.t
& VT_BTYPE
) == VT_FLOAT
)
680 else if ((vtop
->type
.t
& VT_BTYPE
) == VT_DOUBLE
)
690 o(0xED2D0100|r
|(size
>>2));
695 /* simple type (currently always same size) */
696 /* XXX: implicit cast ? */
698 if ((vtop
->type
.t
& VT_BTYPE
) == VT_LLONG
) {
701 if(nb_args
-i
<5 && plan
[nb_args
-i
-1][1]!=-1) {
702 s
=regmask(plan
[nb_args
-i
-1][1]);
703 todo
&=~(1<<plan
[nb_args
-i
-1][1]);
707 o(0xE52D0004|(intr(r
)<<12)); /* str r,[sp,#-4]! */
717 if(nb_args
-i
<5 && plan
[nb_args
-i
-1][0]!=-1) {
718 s
=regmask(plan
[nb_args
-i
-1][0]);
719 todo
&=~(1<<plan
[nb_args
-i
-1][0]);
723 o(0xE52D0004|(intr(r
)<<12)); /* str r,[sp,#-4]! */
736 save_regs(keep
); /* save used temporary registers */
757 func_sym
= vtop
->type
.ref
;
764 /* generate function prolog of type 't' */
765 void gfunc_prolog(CType
*func_type
)
768 int n
,addr
,size
,align
;
770 sym
= func_type
->ref
;
775 if((func_vt
.t
& VT_BTYPE
) == VT_STRUCT
) {
780 for(sym2
=sym
->next
;sym2
&& n
<4;sym2
=sym2
->next
) {
781 size
= type_size(&sym2
->type
, &align
);
782 size
= (size
+ 3) & ~3;
785 o(0xE1A0C00D); /* mov ip,sp */
786 if(func_type
->ref
->c
== FUNC_ELLIPSIS
)
791 o(0xE92D0000|((1<<n
)-1)); /* save r0-r4 on stack if needed */
793 o(0xE92D5800); /* save fp, ip, lr*/
794 o(0xE1A0B00D); /* mov fp,sp */
795 func_sub_sp_offset
= ind
;
796 o(0xE1A00000); /* nop, leave space for stack adjustment */
797 while ((sym
= sym
->next
)) {
800 sym_push(sym
->v
& ~SYM_FIELD
, type
, VT_LOCAL
| VT_LVAL
, addr
);
801 size
= type_size(type
, &align
);
802 size
= (size
+ 3) & ~3;
809 /* generate function epilog */
810 void gfunc_epilog(void)
813 o(0xE89BA800); /* restore fp, sp, pc */
815 x
=stuff_const(0xE24DD000, (-loc
+ 3) & -4); /* sub sp,sp,# */
817 *(unsigned long *)(cur_text_section
->data
+ func_sub_sp_offset
) = x
;
821 o(0xE59FC004); /* ldr ip,[pc+4] */
822 o(0xE04DD00C); /* sub sp,sp,ip */
823 o(0xE1A0F00E); /* mov pc,lr */
825 *(unsigned long *)(cur_text_section
->data
+ func_sub_sp_offset
) = 0xE1000000|encbranch(func_sub_sp_offset
,addr
,1);
830 /* generate a jump to a label */
835 o(0xE0000000|encbranch(r
,t
,1));
839 /* generate a jump to a fixed address */
840 void gjmp_addr(int a
)
845 /* generate a test. set 'inv' to invert test. Stack entry is popped */
846 int gtst(int inv
, int t
)
850 v
= vtop
->r
& VT_VALMASK
;
853 op
=mapcc(inv
?negcc(vtop
->c
.i
):vtop
->c
.i
);
854 op
|=encbranch(r
,t
,1);
857 } else if (v
== VT_JMP
|| v
== VT_JMPI
) {
858 if ((v
& 1) == inv
) {
869 x
= (unsigned long *)(cur_text_section
->data
+ lp
);
871 *x
|= encbranch(lp
,t
,1);
880 if (is_float(vtop
->type
.t
)) {
882 o(0xEE90F118|fpr(r
)<<16);
886 } else if ((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
887 /* constant jmp optimization */
888 if ((vtop
->c
.i
!= 0) != inv
)
892 o(0xE3300000|(intr(v
)<<16));
902 /* generate an integer binary operation */
906 unsigned long opc
= 0,r
,fr
;
914 case TOK_ADDC1
: /* add with carry generation */
922 case TOK_SUBC1
: /* sub with carry generation */
926 case TOK_ADDC2
: /* add with carry use */
930 case TOK_SUBC2
: /* sub with carry use */
951 o(0xE0000090|(intr(r
)<<16)|(intr(r
)<<8)|intr(fr
));
984 r
=intr(vtop
[-1].r2
=get_reg(RC_INT
));
986 vtop
[-1].r
=get_reg_ex(RC_INT
,regmask(c
));
988 o(0xE0800090|(r
<<16)|(intr(vtop
->r
)<<12)|(intr(c
)<<8)|intr(vtop
[1].r
));
997 if((vtop
[-1].r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
998 if(opc
== 4 || opc
== 5 || opc
== 0xc) {
1000 opc
|=2; // sub -> rsb
1003 if ((vtop
->r
& VT_VALMASK
) == VT_CMP
||
1004 (vtop
->r
& (VT_VALMASK
& ~1)) == VT_JMP
)
1009 opc
=0xE0000000|(opc
<<20)|(c
<<16);
1010 if((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1012 x
=stuff_const(opc
|0x2000000,vtop
->c
.i
);
1014 r
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,regmask(vtop
[-1].r
)));
1019 fr
=intr(gv(RC_INT
));
1020 r
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,two2mask(vtop
->r
,vtop
[-1].r
)));
1024 if (op
>= TOK_ULT
&& op
<= TOK_GT
) {
1030 opc
=0xE1A00000|(opc
<<5);
1031 if ((vtop
->r
& VT_VALMASK
) == VT_CMP
||
1032 (vtop
->r
& (VT_VALMASK
& ~1)) == VT_JMP
)
1038 if ((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
) {
1039 fr
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,regmask(vtop
[-1].r
)));
1040 c
= vtop
->c
.i
& 0x1f;
1041 o(opc
|(c
<<7)|(fr
<<12));
1043 fr
=intr(gv(RC_INT
));
1044 c
=intr(vtop
[-1].r
=get_reg_ex(RC_INT
,two2mask(vtop
->r
,vtop
[-1].r
)));
1045 o(opc
|(c
<<12)|(fr
<<8)|0x10);
1050 vpush_global_sym(&func_old_type
, func
);
1057 error("gen_opi %i unimplemented!",op
);
1061 static int is_fconst()
1065 if((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) != VT_CONST
)
1067 if (vtop
->type
.t
== VT_FLOAT
)
1069 else if (vtop
->type
.t
== VT_DOUBLE
)
1099 /* generate a floating point operation 'v = t1 op t2' instruction. The
1100 two operands are guaranted to have the same floating point type */
1101 void gen_opf(int op
)
1105 //fputs("gen_opf\n",stderr);
1111 #if LDOUBLE_SIZE == 8
1112 if ((vtop
->type
.t
& VT_BTYPE
) != VT_FLOAT
)
1115 if ((vtop
->type
.t
& VT_BTYPE
) == VT_DOUBLE
)
1117 else if ((vtop
->type
.t
& VT_BTYPE
) == VT_LDOUBLE
)
1128 r
=fpr(gv(RC_FLOAT
));
1135 r2
=fpr(gv(RC_FLOAT
));
1144 r
=fpr(gv(RC_FLOAT
));
1146 } else if(c1
&& c1
<=0xf) {
1149 r
=fpr(gv(RC_FLOAT
));
1154 r
=fpr(gv(RC_FLOAT
));
1156 r2
=fpr(gv(RC_FLOAT
));
1165 r
=fpr(gv(RC_FLOAT
));
1170 r2
=fpr(gv(RC_FLOAT
));
1178 r
=fpr(gv(RC_FLOAT
));
1180 } else if(c1
&& c1
<=0xf) {
1183 r
=fpr(gv(RC_FLOAT
));
1188 r
=fpr(gv(RC_FLOAT
));
1190 r2
=fpr(gv(RC_FLOAT
));
1194 if(op
>= TOK_ULT
&& op
<= TOK_GT
) {
1195 x
|=0xd0f110; // cmfe
1201 fputs("unsigned comparision on floats?\n",stderr
);
1217 x
&=~0x400000; // cmfe -> cmf
1238 // bug (intention?) in Linux FPU emulator
1239 // doesn't set carry if equal
1242 else if(op
==TOK_UGE
)
1245 r
=fpr(gv(RC_FLOAT
));
1252 r2
=fpr(gv(RC_FLOAT
));
1254 vtop
[-1].r
= VT_CMP
;
1257 error("unknown fp op %x!\n",op
);
1261 if(vtop
[-1].r
== VT_CMP
)
1267 vtop
[-1].r
=get_reg_ex(RC_FLOAT
,two2mask(vtop
[-1].r
,c1
));
1271 o(x
|(r
<<16)|(c1
<<12)|r2
);
1274 /* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
1275 and 'long long' cases. */
1276 void gen_cvt_itof(int t
)
1279 bt
=vtop
->type
.t
& VT_BTYPE
;
1280 if(bt
== VT_INT
|| bt
== VT_SHORT
|| bt
== VT_BYTE
) {
1282 r2
=fpr(vtop
->r
=get_reg(RC_FLOAT
));
1283 o(0xEE000190|(r2
<<16)|(r
<<12));
1284 if((vtop
->type
.t
& (VT_UNSIGNED
|VT_BTYPE
)) == (VT_UNSIGNED
|VT_INT
)) {
1286 o(0xE3500000|(r
<<12));
1287 r
=fpr(get_reg(RC_FLOAT
));
1288 if(last_itod_magic
) {
1289 off
=ind
+8-last_itod_magic
;
1294 o(0xBD1F8100|(r
<<12)|off
);
1297 last_itod_magic
=ind
;
1301 o(0xBE000180|(r2
<<16)|(r2
<<12)|r
);
1304 } else if(bt
== VT_LLONG
) {
1306 if(vtop
->type
.t
& VT_UNSIGNED
)
1310 vpush_global_sym(&func_old_type
, func
);
1317 error("unimplemented gen_cvt_itof %x!",vtop
->type
.t
);
1320 /* convert fp to int 't' type */
1321 void gen_cvt_ftoi(int t
)
1326 r2
=vtop
->type
.t
& VT_BTYPE
;
1330 func
=TOK___fixunssfsi
;
1331 else if(r2
== VT_DOUBLE
)
1332 func
=TOK___fixunsdfsi
;
1333 else if(r2
== VT_LDOUBLE
)
1334 #if LDOUBLE_SIZE == 8
1335 func
=TOK___fixunsdfsi
;
1337 func
=TOK___fixunsxfsi
;
1340 r
=fpr(gv(RC_FLOAT
));
1341 r2
=intr(vtop
->r
=get_reg(RC_INT
));
1342 o(0xEE100170|(r2
<<12)|r
);
1345 } else if(t
== VT_LLONG
) { // unsigned handled in gen_cvt_ftoi1
1348 else if(r2
== VT_DOUBLE
)
1350 else if(r2
== VT_LDOUBLE
)
1351 #if LDOUBLE_SIZE == 8
1358 vpush_global_sym(&func_old_type
, func
);
1363 vtop
->r2
= REG_LRET
;
1367 error("unimplemented gen_cvt_ftoi!");
1370 /* convert from one floating point type to another */
1371 void gen_cvt_ftof(int t
)
1373 /* all we have to do on i386 and ARM is to put the float in a register */
1377 /* computed goto support */
1384 /* end of ARM code generator */
1385 /*************************************************************/