diff --git a/i386-gen.c b/i386-gen.c index b9811f5..018307a 100644 --- a/i386-gen.c +++ b/i386-gen.c @@ -33,17 +33,25 @@ #define RC_ST0 0x0008 #define RC_ECX 0x0010 #define RC_EDX 0x0020 +#define RC_EBX 0x0040 +#define RC_ESI 0x0080 +#define RC_EDI 0x0100 +#define RC_INT2 0x0200 #define RC_IRET RC_EAX /* function return: integer register */ #define RC_LRET RC_EDX /* function return: second integer register */ #define RC_FRET RC_ST0 /* function return: float register */ +#define RC_MASK (RC_INT|RC_INT2|RC_FLOAT) /* pretty names for the registers */ enum { TREG_EAX = 0, TREG_ECX, TREG_EDX, + TREG_EBX, + TREG_ESP, TREG_ST0, - TREG_ESP = 4 + TREG_ESI, + TREG_EDI, }; /* return registers for function */ @@ -90,10 +98,14 @@ enum { #include "tcc.h" ST_DATA const int reg_classes[NB_REGS] = { - /* eax */ RC_INT | RC_EAX, - /* ecx */ RC_INT | RC_ECX, + /* eax */ RC_INT | RC_EAX | RC_INT2, + /* ecx */ RC_INT | RC_ECX | RC_INT2, /* edx */ RC_INT | RC_EDX, + RC_INT|RC_INT2|RC_EBX, + 0, /* st0 */ RC_FLOAT | RC_ST0, + RC_RSI|RC_INT2, + RC_RDI|RC_INT2, }; static unsigned long func_sub_sp_offset; @@ -226,6 +238,14 @@ ST_FUNC void load(int r, SValue *sv) v = fr & VT_VALMASK; if (fr & VT_LVAL) { + if(fr & VT_TMP){ + int size, align; + if((ft & VT_BTYPE) == VT_FUNC) + size = 4; + else + size = type_size(&sv->type, &align); + loc_stack(size, 0); + } if (v == VT_LLOCAL) { v1.type.t = VT_INT; v1.r = VT_LOCAL | VT_LVAL; @@ -715,40 +735,48 @@ ST_FUNC int gtst(int inv, int t) /* generate an integer binary operation */ ST_FUNC void gen_opi(int op) { - int r, fr, opc, c; + int r, fr, opc, fc, c; + int cc, uu, tt2; + + fr = vtop[0].r; + fc = vtop->c.ul; + cc = (fr & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; + tt2 = (fr & (VT_LVAL | VT_LVAL_TYPE)) == VT_LVAL; switch(op) { case '+': case TOK_ADDC1: /* add with carry generation */ opc = 0; gen_op8: - if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { + vswap(); + r = gv(RC_INT); + vswap(); + if (cc) { /* constant case */ - vswap(); - r = gv(RC_INT); - vswap(); c = vtop->c.i; if (c == (char)c) { /* generate inc and dec for smaller code */ - if (c==1 && opc==0) { + if (c == 1 && opc == 0) { o (0x40 | r); // inc - } else if (c==1 && opc==5) { + } else if (c == 1 && opc == 5) { o (0x48 | r); // dec } else { o(0x83); - o(0xc0 | (opc << 3) | r); + o(0xc0 + r + opc*8); g(c); } } else { o(0x81); - oad(0xc0 | (opc << 3) | r, c); + oad(0xc0 + r+ opc*8, c); } } else { - gv2(RC_INT, RC_INT); - r = vtop[-1].r; - fr = vtop[0].r; - o((opc << 3) | 0x01); - o(0xc0 + r + fr * 8); + if(!tt2) + fr = gv(RC_INT); + o(0x03 + opc*8); + if(fr >= VT_CONST) + gen_modrm(r, fr, vtop->sym, fc); + else + o(0xc0 + fr + r*8); } vtop--; if (op >= TOK_ULT && op <= TOK_GT) { @@ -776,12 +804,28 @@ ST_FUNC void gen_opi(int op) opc = 1; goto gen_op8; case '*': - gv2(RC_INT, RC_INT); - r = vtop[-1].r; - fr = vtop[0].r; + opc = 5; + vswap(); + r = gv(RC_INT); + vswap(); + if(!tt2) + fr = gv(RC_INT); + if(r == TREG_EAX){ + if(fr != TREG_EDX) + save_reg(TREG_EDX); + o(0xf7); + if(fr >= VT_CONST) + gen_modrm(opc, fr, vtop->sym, fc); + else + o(0xc0 + fr + opc*8); + }else{ + o(0xaf0f); /* imul fr, r */ + if(fr >= VT_CONST) + gen_modrm(r, fr, vtop->sym, fc); + else + o(0xc0 + fr + r*8); + } vtop--; - o(0xaf0f); /* imul fr, r */ - o(0xc0 + fr + r * 8); break; case TOK_SHL: opc = 4; @@ -792,56 +836,71 @@ ST_FUNC void gen_opi(int op) case TOK_SAR: opc = 7; gen_shift: - opc = 0xc0 | (opc << 3); - if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { + if (cc) { /* constant case */ vswap(); r = gv(RC_INT); vswap(); - c = vtop->c.i & 0x1f; - o(0xc1); /* shl/shr/sar $xxx, r */ - o(opc | r); - g(c); + c = vtop->c.i; + if(c == 1){ + o(0xd1); + o(0xc0 + r + opc*8); + }else{ + o(0xc1); /* shl/shr/sar $xxx, r */ + o(0xc0 + r + opc*8); + g(c & 0x1f); + } } else { /* we generate the shift in ecx */ gv2(RC_INT, RC_ECX); r = vtop[-1].r; o(0xd3); /* shl/shr/sar %cl, r */ - o(opc | r); + o(0xc0 + r + opc*8); } vtop--; break; - case '/': - case TOK_UDIV: - case TOK_PDIV: - case '%': case TOK_UMOD: + opc = 4; + uu = 1; + goto divmod; + case TOK_UDIV: case TOK_UMULL: + opc = 6; + uu = 1; + goto divmod; + case '/': + case '%': + case TOK_PDIV: + opc = 7; + uu = 0; + divmod: /* first operand must be in eax */ /* XXX: need better constraint for second operand */ - gv2(RC_EAX, RC_ECX); - r = vtop[-1].r; - fr = vtop[0].r; - vtop--; - save_reg(TREG_EDX); - if (op == TOK_UMULL) { + if(!tt2){ + gv2(RC_EAX, RC_INT2); + fr = vtop[0].r; + }else{ + vswap(); + gv(RC_EAX); + vswap(); + } + save_reg(TREG_EDX); + if (op == TOK_UMULL) { o(0xf7); /* mul fr */ - o(0xe0 + fr); - vtop->r2 = TREG_EDX; + vtop->r2 = TREG_EDX; + }else{ + o(uu ? 0xd231 : 0x99); /* xor %edx,%edx : cdq RDX:RAX <- sign-extend of RAX. */ + o(0xf7); /* div fr, %eax */ + } + if(fr >= VT_CONST) + gen_modrm(opc, fr, vtop->sym, fc); + else + o(0xc0 + fr + opc*8); + if (op == '%' || op == TOK_UMOD) + r = TREG_EDX; + else r = TREG_EAX; - } else { - if (op == TOK_UDIV || op == TOK_UMOD) { - o(0xf7d231); /* xor %edx, %edx, div fr, %eax */ - o(0xf0 + fr); - } else { - o(0xf799); /* cltd, idiv fr, %eax */ - o(0xf8 + fr); - } - if (op == '%' || op == TOK_UMOD) - r = TREG_EDX; - else - r = TREG_EAX; - } + vtop--; vtop->r = r; break; default: