diff --git a/src/backend/cod3.c b/src/backend/cod3.c index a8a0dd2a3e87..c04fb12b9041 100644 --- a/src/backend/cod3.c +++ b/src/backend/cod3.c @@ -2697,93 +2697,25 @@ code *prolog() c = cat(c,nteh_setsp(0x89)); // MOV __context[EBP].esp,ESP #endif - // Load register parameters off of the stack. Do not use - // assignaddr(), as it will replace the stack reference with - // the register! + // Keep track of used registers. + unsigned usedregs = 0; for (si = 0; si < globsym.top; si++) { symbol *s = globsym.tab[si]; - code *c2; - unsigned sz = type_size(s->Stype); + if (s->Sclass == SCfastpar) + usedregs |= mask[s->Spreg]; + } + namedargs = usedregs; - if ((s->Sclass == SCregpar || s->Sclass == SCparameter) && - s->Sfl == FLreg && - (refparam -#if MARS - // This variable has been reference by a nested function - || s->Stype->Tty & mTYvolatile -#endif - )) + // Do register argument to stack moves. + for (si = 0; si < globsym.top; si++) + { symbol *s = globsym.tab[si]; + if (s->Sclass == SCfastpar && s->Sfl != FLreg) { - /* MOV reg,param[BP] */ - //assert(refparam); - if (mask[s->Sreglsw] & XMMREGS) - { - unsigned op = (sz == 4) ? 0xF30F10 : 0xF20F10; // MOVSS/D xreg,mem - unsigned xreg = s->Sreglsw - XMM0; - code *c2 = genc1(CNIL,op,modregxrm(2,xreg,BPRM),FLconst,Poff + s->Soffset); - if (!hasframe) - { // Convert to ESP relative address rather than EBP - c2->Irm = modregxrm(2,xreg,4); - c2->Isib = modregrm(0,4,SP); - c2->IEVpointer1 += EBPtoESP; - } - c = cat(c,c2); - } - else - { - code *c2 = genc1(CNIL,0x8B ^ (sz == 1), - modregxrm(2,s->Sreglsw,BPRM),FLconst,Poff + s->Soffset); - if (!I16 && sz == SHORTSIZE) - c2->Iflags |= CFopsize; // operand size - if (I64 && sz == REGSIZE) - c2->Irex |= REX_W; - if (!hasframe) - { /* Convert to ESP relative address rather than EBP */ - assert(!I16); - c2->Irm = modregxrm(2,s->Sreglsw,4); - c2->Isib = modregrm(0,4,SP); - c2->IEVpointer1 += EBPtoESP; - } - if (sz > REGSIZE) - { - code *c3 = genc1(CNIL,0x8B, - modregxrm(2,s->Sregmsw,BPRM),FLconst,Poff + s->Soffset + REGSIZE); - if (I64) - c3->Irex |= REX_W; - if (!hasframe) - { /* Convert to ESP relative address rather than EBP */ - assert(!I16); - c3->Irm = modregxrm(2,s->Sregmsw,4); - c3->Isib = modregrm(0,4,SP); - c3->IEVpointer1 += EBPtoESP; - } - c2 = cat(c2,c3); - } - c = cat(c,c2); - } - } - else if (s->Sclass == SCfastpar) - { // Argument is passed in a register unsigned preg = s->Spreg; + assert(usedregs & mask[preg]); // bug 6189 + usedregs &= ~mask[preg]; - namedargs |= mask[preg]; - - if (s->Sfl == FLreg) - { // MOV reg,preg - if (mask[preg] & XMMREGS) - { - unsigned op = (sz == 4) ? 0xF30F10 : 0xF20F10; // MOVSS/D xreg,preg - unsigned xreg = s->Sreglsw - XMM0; - c = gen2(c,op,modregxrmx(3,xreg,preg - XMM0)); - } - else - { - c = genmovreg(c,s->Sreglsw,preg); - if (I64 && sz == 8) - code_orrex(c, REX_W); - } - } - else if (s->Sflags & SFLdead || + if (s->Sflags & SFLdead || (!anyiasm && !(s->Sflags & SFLread) && s->Sflags & SFLunambig && #if MARS // This variable has been reference by a nested function @@ -2796,6 +2728,7 @@ code *prolog() } else { + unsigned sz = type_size(s->Stype); targ_size_t offset = Aoff + BPoff + s->Soffset; int op = 0x89; // MOV x[EBP],preg if (preg >= XMM0 && preg <= XMM15) @@ -2813,7 +2746,7 @@ code *prolog() if (!(pushalloc && preg == pushallocreg)) { // MOV x[EBP],preg - c2 = genc1(CNIL,op, + code *c2 = genc1(CNIL,op, modregxrm(2,preg,BPRM),FLconst, offset); if (preg >= XMM0 && preg <= XMM15) { @@ -2836,7 +2769,7 @@ code *prolog() { // MOV offset[ESP],preg // BUG: byte size? - c2 = genc1(CNIL,op, + code *c2 = genc1(CNIL,op, (modregrm(0,4,SP) << 8) | modregxrm(2,preg,4),FLconst,offset); if (preg >= XMM0 && preg <= XMM15) @@ -2856,6 +2789,132 @@ code *prolog() } } +#ifdef DEBUG + // check that SFLmark flag is not used + for (si = 0; si < globsym.top; si++) + { symbol *s = globsym.tab[si]; + assert(!(s->Sflags & SFLmark)); + } +#endif + + // Do register argument to register variable moves. + while (1) + { + size_t cnt=0, defer=0; + for (si = 0; si < globsym.top; si++) + { symbol *s = globsym.tab[si]; + if (s->Sclass != SCfastpar || s->Sfl != FLreg || + s->Spreg == s->Sreglsw || s->Sflags & SFLmark) + continue; + + ++cnt; + if (usedregs & mask[s->Sreglsw]) + { + ++defer; + continue; + } + + s->Sflags |= SFLmark; + + // MOV reg,preg + unsigned preg = s->Spreg; + assert(usedregs & mask[preg]); // bug 6189 + usedregs &= ~mask[preg]; + usedregs |= mask[s->Sreglsw]; + + unsigned sz = type_size(s->Stype); + if (mask[preg] & XMMREGS) + { + unsigned op = (sz == 4) ? 0xF30F10 : 0xF20F10; // MOVSS/D xreg,preg + unsigned xreg = s->Sreglsw - XMM0; + c = gen2(c,op,modregxrmx(3,xreg,preg - XMM0)); + } + else + { + c = genmovreg(c,s->Sreglsw,preg); + if (I64 && sz == 8) + code_orrex(c, REX_W); + } + } + if (defer) + assert(defer < cnt); // no cyclic register moves + else + break; + } + + for (si = 0; si < globsym.top; si++) + { symbol *s = globsym.tab[si]; + s->Sflags &= ~SFLmark; + } + + + // Do stack argument to register variable moves. + for (si = 0; si < globsym.top; si++) + { symbol *s = globsym.tab[si]; + unsigned sz = type_size(s->Stype); + if ((s->Sclass == SCregpar || s->Sclass == SCparameter) && + s->Sfl == FLreg && + (refparam +#if MARS + // This variable has been reference by a nested function + || s->Stype->Tty & mTYvolatile +#endif + )) + { + /* MOV reg,param[BP] */ + //assert(refparam); + assert(!(usedregs & mask[s->Sreglsw])); // bug 6189 + usedregs |= mask[s->Sreglsw]; + if (mask[s->Sreglsw] & XMMREGS) + { + unsigned op = (sz == 4) ? 0xF30F10 : 0xF20F10; // MOVSS/D xreg,mem + unsigned xreg = s->Sreglsw - XMM0; + code *c2 = genc1(CNIL,op,modregxrm(2,xreg,BPRM),FLconst,Poff + s->Soffset); + if (!hasframe) + { // Convert to ESP relative address rather than EBP + c2->Irm = modregxrm(2,xreg,4); + c2->Isib = modregrm(0,4,SP); + c2->IEVpointer1 += EBPtoESP; + } + c = cat(c,c2); + } + else + { + code *c2 = genc1(CNIL,0x8B ^ (sz == 1), + modregxrm(2,s->Sreglsw,BPRM),FLconst,Poff + s->Soffset); + if (!I16 && sz == SHORTSIZE) + c2->Iflags |= CFopsize; // operand size + if (I64 && sz == REGSIZE) + c2->Irex |= REX_W; + if (!hasframe) + { /* Convert to ESP relative address rather than EBP */ + assert(!I16); + c2->Irm = modregxrm(2,s->Sreglsw,4); + c2->Isib = modregrm(0,4,SP); + c2->IEVpointer1 += EBPtoESP; + } + if (sz > REGSIZE) + { + assert(!(usedregs & mask[s->Sregmsw])); // bug 6189 + usedregs |= mask[s->Sregmsw]; + code *c3 = genc1(CNIL,0x8B, + modregxrm(2,s->Sregmsw,BPRM),FLconst,Poff + s->Soffset + REGSIZE); + if (I64) + c3->Irex |= REX_W; + if (!hasframe) + { /* Convert to ESP relative address rather than EBP */ + assert(!I16); + c3->Irm = modregxrm(2,s->Sregmsw,4); + c3->Isib = modregrm(0,4,SP); + c3->IEVpointer1 += EBPtoESP; + } + c2 = cat(c2,c3); + } + c = cat(c,c2); + } + } + } + /* Load arguments passed in registers into the varargs save area * so they can be accessed by va_arg(). */