?? arm-gen.c
字號(hào):
/* simple type (currently always same size) */ /* XXX: implicit cast ? */ 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<<plan[nb_args-i-1][1]); } if(s==RC_INT) { r = gv(s); o(0xE52D0004|(intr(r)<<12)); /* str r,[sp,#-4]! */ vtop--; } else { plan2[keep]=s; keep++; vswap(); } size = 8; } 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<<plan[nb_args-i-1][0]); } if(s==RC_INT) { r = gv(s); o(0xE52D0004|(intr(r)<<12)); /* str r,[sp,#-4]! */ vtop--; } else { plan2[keep]=s; keep++; } args_size += size; } } 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; todo&=((1<<n)-1); if(todo) { int i; o(0xE8BD0000|todo); for(i=0;i<4;i++) if(todo&(1<<i)) { vpushi(0); vtop->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-=keep;}/* generate function prolog of type 't' */void gfunc_prolog(CType *func_type){ Sym *sym,*sym2; int n,addr,size,align; sym = func_type->ref; func_vt = sym->type; n=0; addr=12; if((func_vt.t & VT_BTYPE) == VT_STRUCT) { func_vc = addr; addr += 4; n++; } for(sym2=sym->next;sym2 && n<4;sym2=sym2->next) { size = type_size(&sym2->type, &align); size = (size + 3) & ~3; n+=size/4; } o(0xE1A0C00D); /* mov ip,sp */ if(func_type->ref->c == FUNC_ELLIPSIS) n=4; if(n) { if(n>4) n=4; o(0xE92D0000|((1<<n)-1)); /* save r0-r4 on stack if needed */ } o(0xE92D5800); /* save fp, ip, lr*/ o(0xE1A0B00D); /* mov fp,sp */ func_sub_sp_offset = ind; o(0xE1A00000); /* nop, leave space for stack adjustment */ while ((sym = sym->next)) { CType *type; type = &sym->type; sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr); size = type_size(type, &align); size = (size + 3) & ~3; addr += size; } last_itod_magic=0; loc = 0;}/* generate function epilog */void gfunc_epilog(void){ unsigned long x; o(0xE89BA800); /* restore fp, sp, pc */ if(loc) { x=stuff_const(0xE24DD000, (-loc + 3) & -4); /* sub sp,sp,# */ if(x) *(unsigned long *)(cur_text_section->data + func_sub_sp_offset) = x; else { unsigned long addr; addr=ind; o(0xE59FC004); /* ldr ip,[pc+4] */ o(0xE04DD00C); /* sub sp,sp,ip */ o(0xE1A0F00E); /* mov pc,lr */ o((-loc + 3) & -4); *(unsigned long *)(cur_text_section->data + func_sub_sp_offset) = 0xE1000000|encbranch(func_sub_sp_offset,addr,1); } }}/* generate a jump to a label */int gjmp(int t){ int r; r=ind; o(0xE0000000|encbranch(r,t,1)); return r;}/* generate a jump to a fixed address */void gjmp_addr(int a){ gjmp(a);}/* generate a test. set 'inv' to invert test. Stack entry is popped */int gtst(int inv, int t){ int v, r; unsigned long op; v = vtop->r & VT_VALMASK; r=ind; if (v == VT_CMP) { op=mapcc(inv?negcc(vtop->c.i):vtop->c.i); op|=encbranch(r,t,1); o(op); t=r; } else if (v == VT_JMP || v == VT_JMPI) { if ((v & 1) == inv) { if(!vtop->c.i) vtop->c.i=t; else { unsigned long *x; int p,lp; if(t) { p = vtop->c.i; do { p = decbranch(lp=p); } while(p); x = (unsigned long *)(cur_text_section->data + lp); *x &= 0xff000000; *x |= encbranch(lp,t,1); } t = vtop->c.i; } } else { t = gjmp(t); gsym(vtop->c.i); } } else { if (is_float(vtop->type.t)) { r=gv(RC_FLOAT); o(0xEE90F118|fpr(r)<<16); vtop->r = VT_CMP; vtop->c.i = TOK_NE; return gtst(inv, t); } else if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { /* constant jmp optimization */ if ((vtop->c.i != 0) != inv) t = gjmp(t); } else { v = gv(RC_INT); o(0xE3300000|(intr(v)<<16)); vtop->r = VT_CMP; vtop->c.i = TOK_NE; return gtst(inv, t); } } vtop--; return t;}/* generate an integer binary operation */void gen_opi(int op){ int c, func = 0; unsigned long opc = 0,r,fr; c=0; switch(op) { case '+': opc = 0x8; c=1; break; case TOK_ADDC1: /* add with carry generation */ opc = 0x9; c=1; break; case '-': opc = 0x4; c=1; break; case TOK_SUBC1: /* sub with carry generation */ opc = 0x5; c=1; break; case TOK_ADDC2: /* add with carry use */ opc = 0xA; c=1; break; case TOK_SUBC2: /* sub with carry use */ opc = 0xC; c=1; break; case '&': opc = 0x0; c=1; break; case '^': opc = 0x2; c=1; break; case '|': opc = 0x18; c=1; break; case '*': gv2(RC_INT, RC_INT); r = vtop[-1].r; fr = vtop[0].r; vtop--; o(0xE0000090|(intr(r)<<16)|(intr(r)<<8)|intr(fr)); return; case TOK_SHL: opc = 0; c=2; break; case TOK_SHR: opc = 1; c=2; break; case TOK_SAR: opc = 2; c=2; break; case '/': case TOK_PDIV: func=TOK___divsi3; c=3; break; case TOK_UDIV: func=TOK___udivsi3; c=3; break; case '%': func=TOK___modsi3; c=3; break; case TOK_UMOD: func=TOK___umodsi3; c=3; break; case TOK_UMULL: gv2(RC_INT, RC_INT); r=intr(vtop[-1].r2=get_reg(RC_INT)); c=vtop[-1].r; vtop[-1].r=get_reg_ex(RC_INT,regmask(c)); vtop--; o(0xE0800090|(r<<16)|(intr(vtop->r)<<12)|(intr(c)<<8)|intr(vtop[1].r)); return; default: opc = 0x15; c=1; break; } switch(c) { case 1: if((vtop[-1].r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { if(opc == 4 || opc == 5 || opc == 0xc) { vswap(); 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(); opc=0xE0000000|(opc<<20)|(c<<16); if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { unsigned long x; x=stuff_const(opc|0x2000000,vtop->c.i); if(x) { r=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r))); o(x|(r<<12)); goto done; } } fr=intr(gv(RC_INT)); r=intr(vtop[-1].r=get_reg_ex(RC_INT,two2mask(vtop->r,vtop[-1].r))); o(opc|(r<<12)|fr);done: vtop--; if (op >= TOK_ULT && op <= TOK_GT) { vtop->r = VT_CMP; vtop->c.i = op; } 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(); opc|=r; if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { fr=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r))); c = vtop->c.i & 0x1f; o(opc|(c<<7)|(fr<<12)); } else { fr=intr(gv(RC_INT)); c=intr(vtop[-1].r=get_reg_ex(RC_INT,two2mask(vtop->r,vtop[-1].r))); o(opc|(c<<12)|(fr<<8)|0x10); } vtop--; break; case 3: vpush_global_sym(&func_old_type, func); vrott(3); gfunc_call(2); vpushi(0); vtop->r = REG_IRET; break; default: error("gen_opi %i unimplemented!",op); }}static int is_fconst(){ long double f; int r; if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) return 0; if (vtop->type.t == VT_FLOAT) f = vtop->c.f; else if (vtop->type.t == VT_DOUBLE) f = vtop->c.d; else f = vtop->c.ld; if(!ieee_finite(f)) return 0; r=0x8; if(f<0.0) { r=0x18; f=-f; } if(f==0.0) return r; if(f==1.0) return r|1; if(f==2.0) return r|2; if(f==3.0) return r|3; if(f==4.0) return r|4; if(f==5.0) return r|5; if(f==0.5) return r|6; if(f==10.0) return r|7; return 0;}/* generate a floating point operation 'v = t1 op t2' instruction. The two operands are guaranted to have the same floating point type */void gen_opf(int op){ unsigned long x; int r,r2,c1,c2; //fputs("gen_opf\n",stderr); vswap(); c1 = is_fconst(); vswap(); c2 = is_fconst(); 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 '+': if(!c2) { vswap(); c2=c1; } vswap(); r=fpr(gv(RC_FLOAT)); vswap(); if(c2) { if(c2>0xf) x|=0x200000; // suf r2=c2&0xf; } else { r2=fpr(gv(RC_FLOAT)); } break; case '-': if(c2) { if(c2<=0xf) x|=0x200000; // suf r2=c2&0xf; vswap(); r=fpr(gv(RC_FLOAT)); vswap(); } else if(c1 && c1<=0xf) { x|=0x300000; // rsf r2=c1; r=fpr(gv(RC_FLOAT)); vswap(); } else { x|=0x200000; // suf vswap(); r=fpr(gv(RC_FLOAT)); vswap(); r2=fpr(gv(RC_FLOAT)); } break; case '*': if(!c2 || c2>0xf) { vswap(); c2=c1; } vswap(); r=fpr(gv(RC_FLOAT)); vswap(); if(c2 && c2<=0xf) r2=c2; else r2=fpr(gv(RC_FLOAT)); x|=0x100000; // muf break; case '/': if(c2 && c2<=0xf) { x|=0x400000; // dvf r2=c2; vswap(); r=fpr(gv(RC_FLOAT)); vswap(); } else if(c1 && c1<=0xf) { x|=0x500000; // rdf r2=c1; r=fpr(gv(RC_FLOAT)); vswap(); } else { x|=0x400000; // dvf vswap(); r=fpr(gv(RC_FLOAT)); vswap(); r2=fpr(gv(RC_FLOAT)); } break; default: if(op >= TOK_ULT && op <= TOK_GT) { x|=0xd0f110; // cmfe switch(op) { case TOK_ULT: case TOK_UGE: case TOK_ULE: case TOK_UGT: fputs("unsigned comparision on floats?\n",stderr); break; case TOK_LT: op=TOK_ULT; break; case TOK_GE: op=TOK_UGE; break; case TOK_LE: op=TOK_ULE; break; case TOK_GT: op=TOK_UGT; break; case TOK_EQ: case TOK_NE: x&=~0x400000; // cmfe -> cmf break; } if(c1 && !c2) { c2=c1; vswap(); switch(op) { case TOK_ULT: op=TOK_UGT; break; case TOK_UGE: op=TOK_ULE; break; case TOK_ULE: op=TOK_UGE; break; case TOK_UGT: op=TOK_ULT; 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(); if(c2) { if(c2>0xf) x|=0x200000; r2=c2&0xf; } else { r2=fpr(gv(RC_FLOAT)); } vtop[-1].r = VT_CMP; vtop[-1].c.i = op; } else { error("unknown fp op %x!\n",op); return; } } if(vtop[-1].r == VT_CMP) c1=15; else { c1=vtop->r; if(r2&0x8) c1=vtop[-1].r; vtop[-1].r=get_reg_ex(RC_FLOAT,two2mask(vtop[-1].r,c1)); c1=fpr(vtop[-1].r); } vtop--; o(x|(r<<16)|(c1<<12)|r2);}/* convert integers to fp 't' type. Must handle 'int', 'unsigned int' and 'long long' cases. */void gen_cvt_itof(int t){ int r,r2,bt; 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; o(0xE3500000|(r<<12)); r=fpr(get_reg(RC_FLOAT)); if(last_itod_magic) { off=ind+8-last_itod_magic; off/=4; if(off>255) off=0; } o(0xBD1F8100|(r<<12)|off); if(!off) { o(0xEA000001); last_itod_magic=ind; o(0x41F00000); o(0); } o(0xBE000180|(r2<<16)|(r2<<12)|r); } return; } else if(bt == VT_LLONG) { 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);}/* convert fp to int 't' type */void gen_cvt_ftoi(int t){ int r,r2,u,func=0; u=t&VT_UNSIGNED; t&=VT_BTYPE; r2=vtop->type.t & VT_BTYPE; if(t==VT_INT) { if(u) { 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) { // unsigned handled in gen_cvt_ftoi1 if(r2 == VT_FLOAT) func=TOK___fixsfdi; else if(r2 == VT_DOUBLE) func=TOK___fixdfdi; else if(r2 == VT_LDOUBLE)#if LDOUBLE_SIZE == 8 func=TOK___fixdfdi;#else func=TOK___fixxfdi;#endif } if(func) { vpush_global_sym(&func_old_type, func); vswap(); gfunc_call(1); vpushi(0); if(t == VT_LLONG) vtop->r2 = REG_LRET; vtop->r = REG_IRET; return; } error("unimplemented gen_cvt_ftoi!");}/* convert from one floating point type to another */void gen_cvt_ftof(int t){ /* all we have to do on i386 and ARM is to put the float in a register */ gv(RC_FLOAT);}/* computed goto support */void ggoto(void){ gcall_or_jmp(1); vtop--;}/* end of ARM code generator *//*************************************************************/
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -