From 6e5b1cc43a308e1154090349f6452d6a03bacb00 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 4 Oct 2004 22:19:21 +0000 Subject: [PATCH] ARM fixes (Daniel Glockner) --- Makefile | 3 + arm-gen.c | 262 +++++++++++++++++++++++++++++++++++++++++--------------------- tcc.c | 50 +++++++++++- tcctok.h | 7 ++ 4 files changed, 232 insertions(+), 90 deletions(-) diff --git a/Makefile b/Makefile index 068db07c..85578278 100644 --- a/Makefile +++ b/Makefile @@ -117,6 +117,9 @@ tcc: tcc_g Makefile c67-tcc: tcc.c c67-gen.c tccelf.c tccasm.c tcctok.h libtcc.h Makefile $(CC) $(CFLAGS) -DTCC_TARGET_C67 -o $@ $< $(LIBS) +arm-tcc: tcc.c arm-gen.c tccelf.c tccasm.c tcctok.h libtcc.h Makefile + $(CC) $(CFLAGS) -DTCC_TARGET_ARM -o $@ $< $(LIBS) + # TinyCC runtime libraries libtcc1.o: libtcc1.c $(CC) -O2 -Wall -c -o $@ $< diff --git a/arm-gen.c b/arm-gen.c index 1498e4ef..07662229 100644 --- a/arm-gen.c +++ b/arm-gen.c @@ -119,6 +119,9 @@ void o(unsigned long i) int ind1; ind1 = ind + 4; + if (!cur_text_section) + error("compiler error! This happens f.ex. if the compiler\n" + "can't evaluate constant expressions outside of a function."); if (ind1 > cur_text_section->data_allocated) section_realloc(cur_text_section, ind1); cur_text_section->data[ind++] = i&255; @@ -285,12 +288,18 @@ void gsym(int t) static unsigned long fpr(int r) { + if(rTREG_F3) + error("compiler error! register %i is no fp register\n",r); return r-5; } static unsigned long intr(int r) { - return r==4?12:r; + if(r==4) + return 12; + if((r<0 || r>4) && r!=14) + error("compiler error! register %i is no int register\n",r); + return r; } static void calcaddr(unsigned long *base,int *off,int *sgn,int maxoff,unsigned shift) @@ -425,8 +434,15 @@ void load(int r, SValue *sv) op=0xED100100; if(!sign) op|=0x800000; +#if LDOUBLE_SIZE == 8 if ((ft & VT_BTYPE) != VT_FLOAT) op|=0x8000; +#else + if ((ft & VT_BTYPE) == VT_DOUBLE) + op|=0x8000; + else if ((ft & VT_BTYPE) == VT_LDOUBLE) + op|=0x400000; +#endif o(op|(fpr(r)<<12)|(fc>>2)|(base<<16)); } else if((ft & VT_TYPE) == VT_BYTE || (ft & VT_BTYPE) == VT_SHORT) { calcaddr(&base,&fc,&sign,255,0); @@ -536,8 +552,15 @@ void store(int r, SValue *sv) op=0xED000100; if(!sign) op|=0x800000; +#if LDOUBLE_SIZE == 8 if ((ft & VT_BTYPE) != VT_FLOAT) op|=0x8000; +#else + if ((ft & VT_BTYPE) == VT_DOUBLE) + op|=0x8000; + if ((ft & VT_BTYPE) == VT_LDOUBLE) + op|=0x400000; +#endif o(op|(fpr(r)<<12)|(fc>>2)|(base<<16)); return; } else if((ft & VT_BTYPE) == VT_SHORT) { @@ -605,9 +628,36 @@ void gfunc_call(int nb_args) { int size, align, r, args_size, i; Sym *func_sym; + signed char plan[4][2]={{-1,-1},{-1,-1},{-1,-1},{-1,-1}}; + int todo=0xf, keep, plan2[4]={0,0,0,0}; + r = vtop->r & VT_VALMASK; + if (r == VT_CMP || (r & ~1) == VT_JMP) + gv(RC_INT); args_size = 0; + for(i = nb_args ; i-- && args_size < 16 ;) { + if ((vtop[-i].type.t & VT_BTYPE) == VT_STRUCT) { + size = type_size(&vtop[-i].type, &align); + size = (size + 3) & ~3; + args_size += size; + } else if ((vtop[-i].type.t & VT_BTYPE) == VT_FLOAT) + args_size += 4; + else if ((vtop[-i].type.t & VT_BTYPE) == VT_DOUBLE) + args_size += 8; + else if ((vtop[-i].type.t & VT_BTYPE) == VT_LDOUBLE) + args_size += LDOUBLE_SIZE; + else { + plan[nb_args-1-i][0]=args_size/4; + args_size += 4; + if ((vtop[-i].type.t & VT_BTYPE) == VT_LLONG && args_size < 16) { + plan[nb_args-1-i][1]=args_size/4; + args_size += 4; + } + } + } + args_size = keep = 0; for(i = 0;i < nb_args; i++) { + vnrott(keep+1); if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) { size = type_size(&vtop->type, &align); /* align to stack align size */ @@ -620,6 +670,7 @@ void gfunc_call(int nb_args) vset(&vtop->type, r | VT_LVAL, 0); vswap(); vstore(); + vtop--; args_size += size; } else if (is_float(vtop->type.t)) { r=fpr(gv(RC_FLOAT))<<12; @@ -635,37 +686,78 @@ void gfunc_call(int nb_args) else if(size == 8) r|=0x8000; - o(0xED2D0100|r); + o(0xED2D0100|r|(size>>2)); + vtop--; args_size += size; } else { + int s; /* simple type (currently always same size) */ /* XXX: implicit cast ? */ - r = gv(RC_INT); + size=4; if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { + lexpand_nr(); + s=RC_INT; + if(nb_args-i<5 && plan[nb_args-i-1][1]!=-1) { + s=regmask(plan[nb_args-i-1][1]); + todo&=~(1<r2)<<12)); /* str r2,[sp,#-4]! */ + } + s=RC_INT; + if(nb_args-i<5 && plan[nb_args-i-1][0]!=-1) { + s=regmask(plan[nb_args-i-1][0]); + todo&=~(1<r)<<12)); /* str r,[sp,#-4]! */ args_size += size; } - vtop--; } - save_regs(0); /* save used temporary registers */ + for(i=keep;i--;) { + gv(plan2[i]); + vrott(keep); + } + save_regs(keep); /* save used temporary registers */ + keep++; if(args_size) { int n; n=args_size/4; if(n>4) n=4; - o(0xE8BD0000|((1<r=i; + keep++; + } + } args_size-=n*4; } + vnrott(keep); func_sym = vtop->type.ref; gcall_or_jmp(0); if (args_size) gadd_sp(args_size); - vtop--; + vtop-=keep; } /* generate function prolog of type 't' */ @@ -906,6 +998,9 @@ void gen_opi(int op) opc|=2; // sub -> rsb } } + if ((vtop->r & VT_VALMASK) == VT_CMP || + (vtop->r & (VT_VALMASK & ~1)) == VT_JMP) + gv(RC_INT); vswap(); c=intr(gv(RC_INT)); vswap(); @@ -931,6 +1026,9 @@ done: break; case 2: opc=0xE1A00000|(opc<<5); + if ((vtop->r & VT_VALMASK) == VT_CMP || + (vtop->r & (VT_VALMASK & ~1)) == VT_JMP) + gv(RC_INT); vswap(); r=intr(gv(RC_INT)); vswap(); @@ -1007,7 +1105,16 @@ void gen_opf(int op) c1 = is_fconst(); vswap(); c2 = is_fconst(); - x=0xEE000180; + x=0xEE000100; +#if LDOUBLE_SIZE == 8 + if ((vtop->type.t & VT_BTYPE) != VT_FLOAT) + x|=0x80; +#else + if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) + x|=0x80; + else if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) + x|=0x80000; +#endif switch(op) { case '+': @@ -1083,6 +1190,7 @@ void gen_opf(int op) break; default: if(op >= TOK_ULT && op <= TOK_GT) { + x|=0xd0f110; // cmfe switch(op) { case TOK_ULT: case TOK_UGE: @@ -1102,8 +1210,11 @@ void gen_opf(int op) case TOK_GT: op=TOK_UGT; break; + case TOK_EQ: + case TOK_NE: + x&=~0x400000; // cmfe -> cmf + break; } - x|=0x90f110; if(c1 && !c2) { c2=c1; vswap(); @@ -1122,6 +1233,12 @@ void gen_opf(int op) break; } } +// bug (intention?) in Linux FPU emulator +// doesn't set carry if equal + if(op==TOK_ULT) + op=TOK_LT; + else if(op==TOK_UGE) + op=TOK_GE; vswap(); r=fpr(gv(RC_FLOAT)); vswap(); @@ -1157,10 +1274,10 @@ void gen_opf(int op) void gen_cvt_itof(int t) { int r,r2,bt; - r=intr(gv(RC_INT)); - r2=fpr(vtop->r=get_reg(RC_FLOAT)); bt=vtop->type.t & VT_BTYPE; if(bt == VT_INT || bt == VT_SHORT || bt == VT_BYTE) { + r=intr(gv(RC_INT)); + r2=fpr(vtop->r=get_reg(RC_FLOAT)); o(0xEE000190|(r2<<16)|(r<<12)); if((vtop->type.t & (VT_UNSIGNED|VT_BTYPE)) == (VT_UNSIGNED|VT_INT)) { unsigned int off=0; @@ -1183,26 +1300,16 @@ void gen_cvt_itof(int t) } return; } else if(bt == VT_LLONG) { - int r3; - unsigned long x=0; - r3=intr(vtop->r2); - o(0xe52d0004|(r<<12)); //str r0, [sp, -#4]! - o(0xe3500000|(r3<<16)); //cmp r1, #0 - o(0xa3800102|(r3<<16)|(r3<<12)); //orrge r1, r1, #0x80000000 - o(0xe59f0014|(r<<12)); //ldr r0, [pc, #20] - o(0xe52d0004|(r3<<12)); //str r1, [sp, -#4]! - o(0xe52d0004|(r<<12)); //str r0, [sp, -#4]! - o(0xecfd0103|(r2<<12)); //ldfe f0, [sp], #12 - r=fpr(get_reg(RC_FLOAT)); - if((vtop->type.t & VT_UNSIGNED) != VT_UNSIGNED) - x=0xE0000000; - o(0xaddf0101|(r<<12)|x); //ldf(ge)e f1, [pc, #4] - o(0xae280100|(r2<<16)|(r2<<12)|r|x); //suf(ge)e f0, f0, f1 - o(0xea000002); //b pc+8 - o(0x403e);o(0x80000000);o(0); - if(x) - o(0xbe280100|(r2<<16)|(r2<<12)|r); //suflte f0, f0, f1 - vtop->r2=VT_CONST; + int func; + if(vtop->type.t & VT_UNSIGNED) + func=TOK___ulltold; + else + func=TOK___slltold; + vpush_global_sym(&func_old_type, func); + vswap(); + gfunc_call(1); + vpushi(0); + vtop->r=TREG_F0; return; } error("unimplemented gen_cvt_itof %x!",vtop->type.t); @@ -1211,65 +1318,48 @@ void gen_cvt_itof(int t) /* convert fp to int 't' type */ void gen_cvt_ftoi(int t) { - int r,r2,u; + int r,r2,u,func=0; u=t&VT_UNSIGNED; t&=VT_BTYPE; - r=fpr(gv(RC_FLOAT)); - r2=intr(vtop->r=get_reg(RC_INT)); + r2=vtop->type.t & VT_BTYPE; if(t==VT_INT) { if(u) { - u=fpr(get_reg(RC_FLOAT)); - o(0xed9f0100|(u<<12)); - o(0xea000000); - o(0x4f000000); - o(0xee90f110|(r<<12)|u); - o(0x2e200180|(r<<16)|(r<<12)|u); - o(0x2e200180|(r<<16)|(r<<12)|u); - o(0xee100150|(r2<<12)|u); - } else - o(0xEE100170|(r<<12)|r); + if(r2 == VT_FLOAT) + func=TOK___fixunssfsi; + else if(r2 == VT_DOUBLE) + func=TOK___fixunsdfsi; + else if(r2 == VT_LDOUBLE) +#if LDOUBLE_SIZE == 8 + func=TOK___fixunsdfsi; +#else + func=TOK___fixunsxfsi; +#endif + } else { + r=fpr(gv(RC_FLOAT)); + r2=intr(vtop->r=get_reg(RC_INT)); + o(0xEE100170|(r2<<12)|r); return; - } else if(t==VT_LLONG) { - int Q,R; - Q=r2; - R=intr(vtop->r2=get_reg(RC_INT)); - if(Qr; - vtop->r=vtop->r2; - vtop->r2=r2; } - if(!u) - r2=intr(get_reg(RC_INT)); - o(0xed6d0103|(r<<12)); - o(0xe0dde0b4); - o(0xe8bd0000|(1<r2 = REG_LRET; + vtop->r = REG_IRET; return; } error("unimplemented gen_cvt_ftoi!"); diff --git a/tcc.c b/tcc.c index 3b7c58a7..066391dc 100644 --- a/tcc.c +++ b/tcc.c @@ -728,6 +728,8 @@ int ieee_finite(double d); void error(const char *fmt, ...); void vpushi(int v); void vrott(int n); +void vnrott(int n); +void lexpand_nr(void); static void vpush_global_sym(CType *type, int v); void vset(CType *type, int r, int v); void type_to_str(char *buf, int buf_size, @@ -4685,6 +4687,34 @@ void lexpand(void) vtop[-1].type.t = VT_INT | u; } +#ifdef TCC_TARGET_ARM +/* expand long long on stack */ +void lexpand_nr(void) +{ + int u,v; + + u = vtop->type.t & VT_UNSIGNED; + vdup(); + vtop->r2 = VT_CONST; + vtop->type.t = VT_INT | u; + v=vtop[-1].r & (VT_VALMASK | VT_LVAL); + if (v == VT_CONST) { + vtop[-1].c.ui = vtop->c.ull; + vtop->c.ui = vtop->c.ull >> 32; + vtop->r = VT_CONST; + } else if (v == (VT_LVAL|VT_CONST) || v == (VT_LVAL|VT_LOCAL)) { + vtop->c.ui += 4; + vtop->r = vtop[-1].r; + } else if (v > VT_CONST) { + vtop--; + lexpand(); + } else + vtop->r = vtop[-1].r2; + vtop[-1].r2 = VT_CONST; + vtop[-1].type.t = VT_INT | u; +} +#endif + /* build a long long from two ints */ void lbuild(int t) { @@ -4722,6 +4752,22 @@ void vrott(int n) vtop[-n + 1] = tmp; } +#ifdef TCC_TARGET_ARM +/* like vrott but in other direction + In ... I1 -> I(n-1) ... I1 In [top is right] + */ +void vnrott(int n) +{ + int i; + SValue tmp; + + tmp = vtop[-n + 1]; + for(i = n - 1; i > 0; i--) + vtop[-i] = vtop[-i + 1]; + vtop[0] = tmp; +} +#endif + /* pop stack value */ void vpop(void) { @@ -5531,11 +5577,7 @@ static void gen_cast(CType *type) } } else { do_itof: -#if !defined(TCC_TARGET_ARM) - gen_cvt_itof1(dbt); -#else gen_cvt_itof(dbt); -#endif } } else if (sf) { /* convert fp to int */ diff --git a/tcctok.h b/tcctok.h index 4f90fc9e..1f802367 100644 --- a/tcctok.h +++ b/tcctok.h @@ -119,6 +119,13 @@ DEF(TOK___sardi3, "__ashrdi3") DEF(TOK___shrdi3, "__lshrdi3") DEF(TOK___shldi3, "__ashldi3") + DEF(TOK___slltold, "__slltold") + DEF(TOK___fixunssfsi, "__fixunssfsi") + DEF(TOK___fixunsdfsi, "__fixunsdfsi") + DEF(TOK___fixunsxfsi, "__fixunsxfsi") + DEF(TOK___fixsfdi, "__fixsfdi") + DEF(TOK___fixdfdi, "__fixdfdi") + DEF(TOK___fixxfdi, "__fixxfdi") #else /* XXX: same names on i386 ? */ DEF(TOK___sardi3, "__sardi3") -- 2.11.4.GIT