void peep(void) { Reg *r, *r1, *r2; Prog *p, *p1; int t; /* * complete R structure */ t = 0; for(r=firstr; r!=R; r=r1) { r1 = r->link; if(r1 == R) break; p = r->prog->link; while(p != r1->prog) switch(p->as) { default: r2 = rega(); r->link = r2; r2->link = r1; r2->prog = p; p->reg = r2; r2->p1 = r; r->s1 = r2; r2->s1 = r1; r1->p1 = r2; r = r2; t++; case ADATA: case AGLOBL: case ANAME: case ASIGNAME: case ALOCALS: case ATYPE: p = p->link; } } // byte, word arithmetic elimination. elimshortmov(r); // constant propagation // find MOV $con,R followed by // another MOV $con,R without // setting R in the interim for(r=firstr; r!=R; r=r->link) { p = r->prog; switch(p->as) { case ALEAL: case ALEAQ: if(regtyp(&p->to)) if(p->from.sym != S) if(p->from.index == D_NONE || p->from.index == D_CONST) conprop(r); break; case AMOVB: case AMOVW: case AMOVL: case AMOVQ: case AMOVSS: case AMOVSD: if(regtyp(&p->to)) if(p->from.type == D_CONST) conprop(r); break; } } loop1: if(debug['P'] && debug['v']) dumpit("loop1", firstr); t = 0; for(r=firstr; r!=R; r=r->link) { p = r->prog; switch(p->as) { case AMOVL: case AMOVQ: case AMOVSS: case AMOVSD: if(regtyp(&p->to)) if(regtyp(&p->from)) { if(copyprop(r)) { excise(r); t++; } else if(subprop(r) && copyprop(r)) { excise(r); t++; } } break; case AMOVBLZX: case AMOVWLZX: case AMOVBLSX: case AMOVWLSX: if(regtyp(&p->to)) { r1 = rnops(uniqs(r)); if(r1 != R) { p1 = r1->prog; if(p->as == p1->as && p->to.type == p1->from.type){ p1->as = AMOVL; t++; } } } break; case AMOVBQSX: case AMOVBQZX: case AMOVWQSX: case AMOVWQZX: case AMOVLQSX: case AMOVLQZX: case AMOVQL: if(regtyp(&p->to)) { r1 = rnops(uniqs(r)); if(r1 != R) { p1 = r1->prog; if(p->as == p1->as && p->to.type == p1->from.type){ p1->as = AMOVQ; t++; } } } break; case AADDL: case AADDQ: case AADDW: if(p->from.type != D_CONST || needc(p->link)) break; if(p->from.offset == -1){ if(p->as == AADDQ) p->as = ADECQ; else if(p->as == AADDL) p->as = ADECL; else p->as = ADECW; p->from = zprog.from; break; } if(p->from.offset == 1){ if(p->as == AADDQ) p->as = AINCQ; else if(p->as == AADDL) p->as = AINCL; else p->as = AINCW; p->from = zprog.from; break; } break; case ASUBL: case ASUBQ: case ASUBW: if(p->from.type != D_CONST || needc(p->link)) break; if(p->from.offset == -1) { if(p->as == ASUBQ) p->as = AINCQ; else if(p->as == ASUBL) p->as = AINCL; else p->as = AINCW; p->from = zprog.from; break; } if(p->from.offset == 1){ if(p->as == ASUBQ) p->as = ADECQ; else if(p->as == ASUBL) p->as = ADECL; else p->as = ADECW; p->from = zprog.from; break; } break; } } if(t) goto loop1; // MOVLQZX removal. // The MOVLQZX exists to avoid being confused for a // MOVL that is just copying 32-bit data around during // copyprop. Now that copyprop is done, remov MOVLQZX R1, R2 // if it is dominated by an earlier ADDL/MOVL/etc into R1 that // will have already cleared the high bits. // // MOVSD removal. // We never use packed registers, so a MOVSD between registers // can be replaced by MOVAPD, which moves the pair of float64s // instead of just the lower one. We only use the lower one, but // the processor can do better if we do moves using both. for(r=firstr; r!=R; r=r->link) { p = r->prog; if(p->as == AMOVLQZX) if(regtyp(&p->from)) if(p->from.type == p->to.type) if(prevl(r, p->from.type)) excise(r); if(p->as == AMOVSD) if(regtyp(&p->from)) if(regtyp(&p->to)) p->as = AMOVAPD; } // load pipelining // push any load from memory as early as possible // to give it time to complete before use. for(r=firstr; r!=R; r=r->link) { p = r->prog; switch(p->as) { case AMOVB: case AMOVW: case AMOVL: case AMOVQ: case AMOVLQZX: if(regtyp(&p->to) && !regconsttyp(&p->from)) pushback(r); } } }
void peep(Prog *firstp) { Flow *r, *r1; Graph *g; Prog *p, *p1; int t; g = flowstart(firstp, sizeof(Flow)); if(g == nil) return; for(r=g->start, t=0; r!=nil; r=r->link, t++) r->active = t; // byte, word arithmetic elimination. elimshortmov(g); // constant propagation // find MOV $con,R followed by // another MOV $con,R without // setting R in the interim for(r=g->start; r!=nil; r=r->link) { p = r->prog; switch(p->as) { case ALEAL: case ALEAQ: if(regtyp(&p->to)) if(p->from.sym != S) if(p->from.index == D_NONE || p->from.index == D_CONST) conprop(r); break; case AMOVB: case AMOVW: case AMOVL: case AMOVQ: case AMOVSS: case AMOVSD: if(regtyp(&p->to)) if(p->from.type == D_CONST) conprop(r); break; } } loop1: if(debug['P'] && debug['v']) dumpit("loop1", g->start, 0); t = 0; for(r=g->start; r!=nil; r=r->link) { p = r->prog; switch(p->as) { case AMOVL: case AMOVQ: case AMOVSS: case AMOVSD: if(regtyp(&p->to)) if(regtyp(&p->from)) { if(copyprop(g, r)) { excise(r); t++; } else if(subprop(r) && copyprop(g, r)) { excise(r); t++; } } break; case AMOVBLZX: case AMOVWLZX: case AMOVBLSX: case AMOVWLSX: if(regtyp(&p->to)) { r1 = rnops(uniqs(r)); if(r1 != nil) { p1 = r1->prog; if(p->as == p1->as && p->to.type == p1->from.type){ p1->as = AMOVL; t++; } } } break; case AMOVBQSX: case AMOVBQZX: case AMOVWQSX: case AMOVWQZX: case AMOVLQSX: case AMOVLQZX: case AMOVQL: if(regtyp(&p->to)) { r1 = rnops(uniqs(r)); if(r1 != nil) { p1 = r1->prog; if(p->as == p1->as && p->to.type == p1->from.type){ p1->as = AMOVQ; t++; } } } break; case AADDL: case AADDQ: case AADDW: if(p->from.type != D_CONST || needc(p->link)) break; if(p->from.offset == -1){ if(p->as == AADDQ) p->as = ADECQ; else if(p->as == AADDL) p->as = ADECL; else p->as = ADECW; p->from = zprog.from; break; } if(p->from.offset == 1){ if(p->as == AADDQ) p->as = AINCQ; else if(p->as == AADDL) p->as = AINCL; else p->as = AINCW; p->from = zprog.from; break; } break; case ASUBL: case ASUBQ: case ASUBW: if(p->from.type != D_CONST || needc(p->link)) break; if(p->from.offset == -1) { if(p->as == ASUBQ) p->as = AINCQ; else if(p->as == ASUBL) p->as = AINCL; else p->as = AINCW; p->from = zprog.from; break; } if(p->from.offset == 1){ if(p->as == ASUBQ) p->as = ADECQ; else if(p->as == ASUBL) p->as = ADECL; else p->as = ADECW; p->from = zprog.from; break; } break; } } if(t) goto loop1; // MOVLQZX removal. // The MOVLQZX exists to avoid being confused for a // MOVL that is just copying 32-bit data around during // copyprop. Now that copyprop is done, remov MOVLQZX R1, R2 // if it is dominated by an earlier ADDL/MOVL/etc into R1 that // will have already cleared the high bits. // // MOVSD removal. // We never use packed registers, so a MOVSD between registers // can be replaced by MOVAPD, which moves the pair of float64s // instead of just the lower one. We only use the lower one, but // the processor can do better if we do moves using both. for(r=g->start; r!=nil; r=r->link) { p = r->prog; if(p->as == AMOVLQZX) if(regtyp(&p->from)) if(p->from.type == p->to.type) if(prevl(r, p->from.type)) excise(r); if(p->as == AMOVSD) if(regtyp(&p->from)) if(regtyp(&p->to)) p->as = AMOVAPD; } // load pipelining // push any load from memory as early as possible // to give it time to complete before use. for(r=g->start; r!=nil; r=r->link) { p = r->prog; switch(p->as) { case AMOVB: case AMOVW: case AMOVL: case AMOVQ: case AMOVLQZX: if(regtyp(&p->to) && !regconsttyp(&p->from)) pushback(r); } } flowend(g); }
void optfunc() { #if !HTOD block *b; int iter; // iteration count clock_t starttime; cmes ("optfunc()\n"); dbg_optprint("optfunc\n"); #ifdef DEBUG if (debugb) { dbg_printf("................Before optimization.........\n"); WRfunc(); } #endif iter = 0; if (localgot) { // Initialize with: // localgot = OPgot; elem *e = el_long(TYnptr, 0); e->Eoper = OPgot; e = el_bin(OPeq, TYnptr, el_var(localgot), e); startblock->Belem = el_combine(e, startblock->Belem); } // Each pass through the loop can reduce only one level of comma expression. // The infinite loop check needs to take this into account. int iterationLimit = 0; for (b = startblock; b; b = b->Bnext) { if (!b->Belem) continue; int d = el_countCommas(b->Belem); if (d > iterationLimit) iterationLimit = d; } // Some functions can take enormous amounts of time to optimize. // We try to put a lid on it. starttime = clock(); do { //printf("iter = %d\n", iter); #if TX86 if (++iter > 200) { assert(iter < iterationLimit); // infinite loop check break; } #else L1: #endif #if MARS util_progress(); #else file_progress(); #endif //printf("optelem\n"); /* canonicalize the trees */ for (b = startblock; b; b = b->Bnext) if (b->Belem) { #if DEBUG if(debuge) { dbg_printf("before\n"); elem_print(b->Belem); //el_check(b->Belem); } #endif b->Belem = doptelem(b->Belem,bc_goal[b->BC] | GOALagain); #if DEBUG if(0 && debugf) { dbg_printf("after\n"); elem_print(b->Belem); } #endif } //printf("blockopt\n"); #if TX86 if (mfoptim & MFdc) blockopt(0); // do block optimization out_regcand(&globsym); // recompute register candidates changes = 0; /* no changes yet */ if (mfoptim & MFcnp) constprop(); /* make relationals unsigned */ if (mfoptim & (MFli | MFliv)) #else if (config.optimized && (mfoptim & MFdc)) blockopt(0); // do block optimization dbg_optprint("blockopt\n"); out_regcand(); // recompute register candidates changes = 0; /* no changes yet */ dbg_optprint("constprop\n"); if (config.optimized && (mfoptim & MFcnp)) constprop(); /* make relationals unsigned */ dbg_optprint("loopopt\n"); if (config.optimized && (mfoptim & (MFli | MFliv))) #endif loopopt(); /* remove loop invariants and */ /* induction vars */ /* do loop rotation */ else for (b = startblock; b; b = b->Bnext) b->Bweight = 1; dbg_optprint("boolopt\n"); #if TX86 if (mfoptim & MFcnp) boolopt(); // optimize boolean values if (changes && mfoptim & MFloop && (clock() - starttime) < 30 * CLOCKS_PER_SEC) continue; if (mfoptim & MFcnp) constprop(); /* constant propagation */ if (mfoptim & MFcp) copyprop(); /* do copy propagation */ /* Floating point constants and string literals need to be * replaced with loads from variables in read-only data. * This can result in localgot getting needed. */ symbol *localgotsave = localgot; for (b = startblock; b; b = b->Bnext) { if (b->Belem) { b->Belem = doptelem(b->Belem,bc_goal[b->BC] | GOALstruct); if (b->Belem) b->Belem = el_convert(b->Belem); } } if (localgot != localgotsave) { /* Looks like we did need localgot, initialize with: * localgot = OPgot; */ elem *e = el_long(TYnptr, 0); e->Eoper = OPgot; e = el_bin(OPeq, TYnptr, el_var(localgot), e); startblock->Belem = el_combine(e, startblock->Belem); } /* localize() is after localgot, otherwise we wind up with * more than one OPgot in a function, which mucks up OSX * code generation which assumes at most one (localgotoffset). */ if (mfoptim & MFlocal) localize(); // improve expression locality if (mfoptim & MFda) rmdeadass(); /* remove dead assignments */ cmes2 ("changes = %d\n", changes); if (!(changes && mfoptim & MFloop && (clock() - starttime) < 30 * CLOCKS_PER_SEC)) break; } while (1); cmes2("%d iterations\n",iter); if (mfoptim & MFdc) blockopt(1); // do block optimization #else if (config.optimized && (mfoptim & MFcnp)) boolopt(); // optimize boolean values util_progress(); if (changes) goto L1; dbg_optprint("constprop\n"); if (config.optimized && (mfoptim & MFcnp)) constprop(); /* constant propagation */ dbg_optprint("copyprop\n"); if (config.optimized && (mfoptim & MFcp)) copyprop(); /* do copy propagation */ dbg_optprint("localize\n"); if (config.optimized && (mfoptim & MFlocal)) localize(); // improve expression locality dbg_optprint("rmdeadass\n"); if (config.optimized && (mfoptim & MFda)) rmdeadass(); /* remove dead assignments */ cmes2 ("changes = %d\n", changes); iter++; assert (iter < 80); /* infinite loop check */ } while (changes && (config.optimized) && (mfoptim & MFloop));
void peep(void) { Reg *r, *r1, *r2; Prog *p, *p1; int t; /* * complete R structure */ t = 0; for(r=firstr; r!=R; r=r1) { r1 = r->link; if(r1 == R) break; p = r->prog->link; while(p != r1->prog) switch(p->as) { default: r2 = rega(); r->link = r2; r2->link = r1; r2->prog = p; r2->p1 = r; r->s1 = r2; r2->s1 = r1; r1->p1 = r2; r = r2; t++; case ADATA: case AGLOBL: case ANAME: case ASIGNAME: p = p->link; } } loop1: t = 0; for(r=firstr; r!=R; r=r->link) { p = r->prog; if(p->as == ASLL || p->as == ASRL || p->as == ASRA) { /* * elide shift into D_SHIFT operand of subsequent instruction */ if(shiftprop(r)) { excise(r); t++; } } if(p->as == AMOVW || p->as == AMOVF || p->as == AMOVD) if(regtyp(&p->to)) { if(p->from.type == D_CONST) constprop(&p->from, &p->to, r->s1); else if(regtyp(&p->from)) if(p->from.type == p->to.type) { if(copyprop(r)) { excise(r); t++; } else if(subprop(r) && copyprop(r)) { excise(r); t++; } } } } if(t) goto loop1; /* * look for MOVB x,R; MOVB R,R */ for(r=firstr; r!=R; r=r->link) { p = r->prog; switch(p->as) { default: continue; case AEOR: /* * EOR -1,x,y => MVN x,y */ if(p->from.type == D_CONST && p->from.offset == -1) { p->as = AMVN; p->from.type = D_REG; if(p->reg != NREG) p->from.reg = p->reg; else p->from.reg = p->to.reg; p->reg = NREG; } continue; case AMOVH: case AMOVHU: case AMOVB: case AMOVBU: if(p->to.type != D_REG) continue; break; } r1 = r->link; if(r1 == R) continue; p1 = r1->prog; if(p1->as != p->as) continue; if(p1->from.type != D_REG || p1->from.reg != p->to.reg) continue; if(p1->to.type != D_REG || p1->to.reg != p->to.reg) continue; excise(r1); } for(r=firstr; r!=R; r=r->link) { p = r->prog; switch(p->as) { case AMOVW: case AMOVB: case AMOVBU: if(p->from.type == D_OREG && p->from.offset == 0) xtramodes(r, &p->from); else if(p->to.type == D_OREG && p->to.offset == 0) xtramodes(r, &p->to); else continue; break; case ACMP: /* * elide CMP $0,x if calculation of x can set condition codes */ if(p->from.type != D_CONST || p->from.offset != 0) continue; r2 = r->s1; if(r2 == R) continue; t = r2->prog->as; switch(t) { default: continue; case ABEQ: case ABNE: case ABMI: case ABPL: break; case ABGE: t = ABPL; break; case ABLT: t = ABMI; break; case ABHI: t = ABNE; break; case ABLS: t = ABEQ; break; } r1 = r; do r1 = uniqp(r1); while (r1 != R && r1->prog->as == ANOP); if(r1 == R) continue; p1 = r1->prog; if(p1->to.type != D_REG) continue; if(p1->to.reg != p->reg) if(!(p1->as == AMOVW && p1->from.type == D_REG && p1->from.reg == p->reg)) continue; switch(p1->as) { default: continue; case AMOVW: if(p1->from.type != D_REG) continue; case AAND: case AEOR: case AORR: case ABIC: case AMVN: case ASUB: case ARSB: case AADD: case AADC: case ASBC: case ARSC: break; } p1->scond |= C_SBIT; r2->prog->as = t; excise(r); continue; } } predicate(); }
void peep(void) { Reg *r, *r1, *r2; Prog *p, *p1; int t; /* * complete R structure */ t = 0; for(r=firstr; r!=R; r=r1) { r1 = r->link; if(r1 == R) break; p = r->prog->link; while(p != r1->prog) switch(p->as) { default: r2 = rega(); r->link = r2; r2->link = r1; r2->prog = p; r2->p1 = r; r->s1 = r2; r2->s1 = r1; r1->p1 = r2; r = r2; t++; case ADATA: case AGLOBL: case ANAME: case ASIGNAME: p = p->link; } } loop1: t = 0; for(r=firstr; r!=R; r=r->link) { p = r->prog; if(p->as == AMOVW || p->as == AFMOVF || p->as == AFMOVD) if(regtyp(&p->to)) { if(regtyp(&p->from)) if(p->from.type == p->to.type) { if(copyprop(r)) { excise(r); t++; } else if(subprop(r) && copyprop(r)) { excise(r); t++; } } if(regzer(&p->from)) if(p->to.type == D_REG) { p->from.type = D_REG; p->from.reg = 0; if(copyprop(r)) { excise(r); t++; } else if(subprop(r) && copyprop(r)) { excise(r); t++; } } } } if(t) goto loop1; /* * look for MOVB x,R; MOVB R,R */ for(r=firstr; r!=R; r=r->link) { p = r->prog; switch(p->as) { default: continue; case AMOVH: case AMOVHU: case AMOVB: case AMOVBU: if(p->to.type != D_REG) continue; break; } r1 = r->link; if(r1 == R) continue; p1 = r1->prog; if(p1->as != p->as) continue; if(p1->from.type != D_REG || p1->from.reg != p->to.reg) continue; if(p1->to.type != D_REG || p1->to.reg != p->to.reg) continue; excise(r1); } }
void peep(void) { Reg *r, *r1, *r2; Prog *p, *p1; int t; /* * complete R structure */ t = 0; for(r=firstr; r!=R; r=r1) { r1 = r->link; if(r1 == R) break; p = r->prog->link; while(p != r1->prog) switch(p->as) { default: r2 = rega(); r->link = r2; r2->link = r1; r2->prog = p; r2->p1 = r; r->s1 = r2; r2->s1 = r1; r1->p1 = r2; r = r2; t++; case ADATA: case AGLOBL: case ANAME: case ASIGNAME: p = p->link; } } pc = 0; /* speculating it won't kill */ loop1: t = 0; for(r=firstr; r!=R; r=r->link) { p = r->prog; switch(p->as) { case AMOVL: if(regtyp(&p->to)) if(regtyp(&p->from)) { if(copyprop(r)) { excise(r); t++; } if(subprop(r) && copyprop(r)) { excise(r); t++; } } break; case AMOVBLSX: case AMOVBLZX: case AMOVWLSX: case AMOVWLZX: if(regtyp(&p->to)) { r1 = uniqs(r); if(r1 != R) { p1 = r1->prog; if(p->as == p1->as && p->to.type == p1->from.type) p1->as = AMOVL; } } break; case AADDL: case AADDW: if(p->from.type != D_CONST || needc(p->link)) break; if(p->from.offset == -1) { if(p->as == AADDL) p->as = ADECL; else p->as = ADECW; p->from = zprog.from; } else if(p->from.offset == 1) { if(p->as == AADDL) p->as = AINCL; else p->as = AINCW; p->from = zprog.from; } break; case ASUBL: case ASUBW: if(p->from.type != D_CONST || needc(p->link)) break; if(p->from.offset == -1) { if(p->as == ASUBL) p->as = AINCL; else p->as = AINCW; p->from = zprog.from; } else if(p->from.offset == 1) { if(p->as == ASUBL) p->as = ADECL; else p->as = ADECW; p->from = zprog.from; } break; } } if(t) goto loop1; }
void peep(void) { Reg *r, *r1, *r2; Prog *p, *p1; int t; /* * complete R structure */ t = 0; for(r=firstr; r!=R; r=r1) { r1 = r->link; if(r1 == R) break; p = r->prog->link; while(p != r1->prog) switch(p->as) { default: r2 = rega(); r->link = r2; r2->link = r1; r2->prog = p; p->reg = r2; r2->p1 = r; r->s1 = r2; r2->s1 = r1; r1->p1 = r2; r = r2; t++; case ADATA: case AGLOBL: case ANAME: case ASIGNAME: p = p->link; } } // constant propagation // find MOV $con,R followed by // another MOV $con,R without // setting R in the interim for(r=firstr; r!=R; r=r->link) { p = r->prog; switch(p->as) { case ALEAL: case ALEAQ: if(regtyp(&p->to)) if(p->from.sym != S) conprop(r); break; case AMOVB: case AMOVW: case AMOVL: case AMOVQ: case AMOVSS: case AMOVSD: if(regtyp(&p->to)) if(p->from.type == D_CONST) conprop(r); break; } } loop1: if(debug['P'] && debug['v']) dumpit("loop1", firstr); t = 0; for(r=firstr; r!=R; r=r->link) { p = r->prog; switch(p->as) { case AMOVL: case AMOVQ: case AMOVSS: case AMOVSD: if(regtyp(&p->to)) if(regtyp(&p->from)) { if(copyprop(r)) { excise(r); t++; } else if(subprop(r) && copyprop(r)) { excise(r); t++; } } break; case AMOVBLZX: case AMOVWLZX: case AMOVBLSX: case AMOVWLSX: if(regtyp(&p->to)) { r1 = rnops(uniqs(r)); if(r1 != R) { p1 = r1->prog; if(p->as == p1->as && p->to.type == p1->from.type){ p1->as = AMOVL; t++; } } } break; case AMOVBQSX: case AMOVBQZX: case AMOVWQSX: case AMOVWQZX: case AMOVLQSX: case AMOVLQZX: if(regtyp(&p->to)) { r1 = rnops(uniqs(r)); if(r1 != R) { p1 = r1->prog; if(p->as == p1->as && p->to.type == p1->from.type){ p1->as = AMOVQ; t++; } } } break; case AADDL: case AADDQ: case AADDW: if(p->from.type != D_CONST || needc(p->link)) break; if(p->from.offset == -1){ if(p->as == AADDQ) p->as = ADECQ; else if(p->as == AADDL) p->as = ADECL; else p->as = ADECW; p->from = zprog.from; break; } if(p->from.offset == 1){ if(p->as == AADDQ) p->as = AINCQ; else if(p->as == AADDL) p->as = AINCL; else p->as = AINCW; p->from = zprog.from; break; } break; case ASUBL: case ASUBQ: case ASUBW: if(p->from.type != D_CONST || needc(p->link)) break; if(p->from.offset == -1) { if(p->as == ASUBQ) p->as = AINCQ; else if(p->as == ASUBL) p->as = AINCL; else p->as = AINCW; p->from = zprog.from; break; } if(p->from.offset == 1){ if(p->as == ASUBQ) p->as = ADECQ; else if(p->as == ASUBL) p->as = ADECL; else p->as = ADECW; p->from = zprog.from; break; } break; } } if(t) goto loop1; }
void peep(Prog *firstp) { Flow *r, *r1; Graph *g; Prog *p, *p1; int t; g = flowstart(firstp, sizeof(Flow)); if(g == nil) return; for(r=g->start, t=0; r!=nil; r=r->link, t++) r->active = t; // byte, word arithmetic elimination. elimshortmov(g); // constant propagation // find MOV $con,R followed by // another MOV $con,R without // setting R in the interim for(r=g->start; r!=nil; r=r->link) { p = r->prog; switch(p->as) { case ALEAL: if(regtyp(&p->to)) if(p->from.sym != S) if(p->from.index == D_NONE || p->from.index == D_CONST) conprop(r); break; case AMOVB: case AMOVW: case AMOVL: case AMOVSS: case AMOVSD: if(regtyp(&p->to)) if(p->from.type == D_CONST) conprop(r); break; } } loop1: if(debug['P'] && debug['v']) dumpit("loop1", g->start, 0); t = 0; for(r=g->start; r!=nil; r=r->link) { p = r->prog; switch(p->as) { case AMOVL: case AMOVSS: case AMOVSD: if(regtyp(&p->to)) if(regtyp(&p->from)) { if(copyprop(g, r)) { excise(r); t++; } else if(subprop(r) && copyprop(g, r)) { excise(r); t++; } } break; case AMOVBLZX: case AMOVWLZX: case AMOVBLSX: case AMOVWLSX: if(regtyp(&p->to)) { r1 = rnops(uniqs(r)); if(r1 != nil) { p1 = r1->prog; if(p->as == p1->as && p->to.type == p1->from.type){ p1->as = AMOVL; t++; } } } break; case AADDL: case AADDW: if(p->from.type != D_CONST || needc(p->link)) break; if(p->from.offset == -1){ if(p->as == AADDL) p->as = ADECL; else p->as = ADECW; p->from = zprog.from; break; } if(p->from.offset == 1){ if(p->as == AADDL) p->as = AINCL; else p->as = AINCW; p->from = zprog.from; break; } break; case ASUBL: case ASUBW: if(p->from.type != D_CONST || needc(p->link)) break; if(p->from.offset == -1) { if(p->as == ASUBL) p->as = AINCL; else p->as = AINCW; p->from = zprog.from; break; } if(p->from.offset == 1){ if(p->as == ASUBL) p->as = ADECL; else p->as = ADECW; p->from = zprog.from; break; } break; } } if(t) goto loop1; // MOVSD removal. // We never use packed registers, so a MOVSD between registers // can be replaced by MOVAPD, which moves the pair of float64s // instead of just the lower one. We only use the lower one, but // the processor can do better if we do moves using both. for(r=g->start; r!=nil; r=r->link) { p = r->prog; if(p->as == AMOVSD) if(regtyp(&p->from)) if(regtyp(&p->to)) p->as = AMOVAPD; } flowend(g); }
void peep(void) { Reg *r, *r1, *r2; Prog *p, *p1; int t; /* * complete R structure */ t = 0; for(r=firstr; r!=R; r=r1) { r1 = r->link; if(r1 == R) break; p = r->prog->link; while(p != r1->prog) switch(p->as) { default: r2 = rega(); r->link = r2; r2->link = r1; r2->prog = p; r2->p1 = r; r->s1 = r2; r2->s1 = r1; r1->p1 = r2; r = r2; t++; case ADATA: case AGLOBL: case ANAME: case ASIGNAME: p = p->link; } } loop1: t = 0; for(r=firstr; r!=R; r=r->link) { p = r->prog; if(p->as == AMOVW || p->as == AFMOVS || p->as == AFMOVD) if(regtyp(&p->to)) { if(regtyp(&p->from)) if(p->from.type == p->to.type) { if(copyprop(r)) { excise(r); t++; } else if(subprop(r) && copyprop(r)) { excise(r); t++; } } if(regzer(&p->from)) if(p->to.type == D_REG) { p->from.type = D_REG; p->from.reg = REGZERO; if(copyprop(r)) { excise(r); t++; } else if(subprop(r) && copyprop(r)) { excise(r); t++; } } } } if(t) goto loop1; /* * look for MOVB x,R; MOVB R,R */ for(r=firstr; r!=R; r=r->link) { p = r->prog; switch(p->as) { default: continue; case AMOVH: case AMOVHZ: case AMOVB: case AMOVBZ: if(p->to.type != D_REG) continue; break; } r1 = r->link; if(r1 == R) continue; p1 = r1->prog; if(p1->as != p->as) continue; if(p1->from.type != D_REG || p1->from.reg != p->to.reg) continue; if(p1->to.type != D_REG || p1->to.reg != p->to.reg) continue; excise(r1); } if(debug['Q'] > 1) return; /* allow following code improvement to be suppressed */ /* * look for OP x,y,R; CMP R, $0 -> OPCC x,y,R * when OP can set condition codes correctly */ for(r=firstr; r!=R; r=r->link) { p = r->prog; switch(p->as) { case ACMP: if(!regzer(&p->to)) continue; r1 = r->s1; if(r1 == R) continue; switch(r1->prog->as) { default: continue; case ABCL: case ABC: /* the conditions can be complex and these are currently little used */ continue; case ABEQ: case ABGE: case ABGT: case ABLE: case ABLT: case ABNE: case ABVC: case ABVS: break; } r1 = r; do r1 = uniqp(r1); while (r1 != R && r1->prog->as == ANOP); if(r1 == R) continue; p1 = r1->prog; if(p1->to.type != D_REG || p1->to.reg != p->from.reg) continue; switch(p1->as) { case ASUB: case AADD: case AXOR: case AOR: /* irregular instructions */ if(p1->from.type == D_CONST) continue; break; } switch(p1->as) { default: continue; case AMOVW: if(p1->from.type != D_REG) continue; continue; case AANDCC: case AANDNCC: case AORCC: case AORNCC: case AXORCC: case ASUBCC: case AADDCC: t = p1->as; break; /* don't deal with floating point instructions for now */ /* case AFABS: t = AFABSCC; break; case AFADD: t = AFADDCC; break; case AFADDS: t = AFADDSCC; break; case AFCTIW: t = AFCTIWCC; break; case AFCTIWZ: t = AFCTIWZCC; break; case AFDIV: t = AFDIVCC; break; case AFDIVS: t = AFDIVSCC; break; case AFMADD: t = AFMADDCC; break; case AFMADDS: t = AFMADDSCC; break; case AFMOVD: t = AFMOVDCC; break; case AFMSUB: t = AFMSUBCC; break; case AFMSUBS: t = AFMSUBSCC; break; case AFMUL: t = AFMULCC; break; case AFMULS: t = AFMULSCC; break; case AFNABS: t = AFNABSCC; break; case AFNEG: t = AFNEGCC; break; case AFNMADD: t = AFNMADDCC; break; case AFNMADDS: t = AFNMADDSCC; break; case AFNMSUB: t = AFNMSUBCC; break; case AFNMSUBS: t = AFNMSUBSCC; break; case AFRSP: t = AFRSPCC; break; case AFSUB: t = AFSUBCC; break; case AFSUBS: t = AFSUBSCC; break; case ACNTLZW: t = ACNTLZWCC; break; case AMTFSB0: t = AMTFSB0CC; break; case AMTFSB1: t = AMTFSB1CC; break; */ case AADD: t = AADDCC; break; case AADDV: t = AADDVCC; break; case AADDC: t = AADDCCC; break; case AADDCV: t = AADDCVCC; break; case AADDME: t = AADDMECC; break; case AADDMEV: t = AADDMEVCC; break; case AADDE: t = AADDECC; break; case AADDEV: t = AADDEVCC; break; case AADDZE: t = AADDZECC; break; case AADDZEV: t = AADDZEVCC; break; case AAND: t = AANDCC; break; case AANDN: t = AANDNCC; break; case ADIVW: t = ADIVWCC; break; case ADIVWV: t = ADIVWVCC; break; case ADIVWU: t = ADIVWUCC; break; case ADIVWUV: t = ADIVWUVCC; break; case AEQV: t = AEQVCC; break; case AEXTSB: t = AEXTSBCC; break; case AEXTSH: t = AEXTSHCC; break; case AMULHW: t = AMULHWCC; break; case AMULHWU: t = AMULHWUCC; break; case AMULLW: t = AMULLWCC; break; case AMULLWV: t = AMULLWVCC; break; case ANAND: t = ANANDCC; break; case ANEG: t = ANEGCC; break; case ANEGV: t = ANEGVCC; break; case ANOR: t = ANORCC; break; case AOR: t = AORCC; break; case AORN: t = AORNCC; break; case AREM: t = AREMCC; break; case AREMV: t = AREMVCC; break; case AREMU: t = AREMUCC; break; case AREMUV: t = AREMUVCC; break; case ARLWMI: t = ARLWMICC; break; case ARLWNM: t = ARLWNMCC; break; case ASLW: t = ASLWCC; break; case ASRAW: t = ASRAWCC; break; case ASRW: t = ASRWCC; break; case ASUB: t = ASUBCC; break; case ASUBV: t = ASUBVCC; break; case ASUBC: t = ASUBCCC; break; case ASUBCV: t = ASUBCVCC; break; case ASUBME: t = ASUBMECC; break; case ASUBMEV: t = ASUBMEVCC; break; case ASUBE: t = ASUBECC; break; case ASUBEV: t = ASUBEVCC; break; case ASUBZE: t = ASUBZECC; break; case ASUBZEV: t = ASUBZEVCC; break; case AXOR: t = AXORCC; break; break; } if(debug['Q']) print("cmp %P; %P -> ", p1, p); p1->as = t; if(debug['Q']) print("%P\n", p1); excise(r); continue; } } }
void peep(Prog *firstp) { Flow *r; Graph *g; Prog *p; int t; g = flowstart(firstp, sizeof(Flow)); if(g == nil) return; for(r=g->start, t=0; r!=nil; r=r->link, t++) r->active = t; loop1: if(debug['P'] && debug['v']) dumpit("loop1", g->start, 0); t = 0; for(r=g->start; r!=nil; r=r->link) { p = r->prog; switch(p->as) { case ASLL: case ASRL: case ASRA: /* * elide shift into D_SHIFT operand of subsequent instruction */ // if(shiftprop(r)) { // excise(r); // t++; // break; // } break; case AMOVB: case AMOVH: case AMOVW: case AMOVF: case AMOVD: if(regtyp(&p->from)) if(p->from.type == p->to.type) if(p->scond == C_SCOND_NONE) { if(copyprop(g, r)) { excise(r); t++; break; } if(subprop(r) && copyprop(g, r)) { excise(r); t++; break; } } break; case AMOVHS: case AMOVHU: case AMOVBS: case AMOVBU: if(p->from.type == D_REG) { if(shortprop(r)) t++; } break; #ifdef NOTDEF if(p->scond == C_SCOND_NONE) if(regtyp(&p->to)) if(isdconst(&p->from)) { constprop(&p->from, &p->to, r->s1); } break; #endif } } if(t) goto loop1; for(r=g->start; r!=nil; r=r->link) { p = r->prog; switch(p->as) { case AEOR: /* * EOR -1,x,y => MVN x,y */ if(isdconst(&p->from) && p->from.offset == -1) { p->as = AMVN; p->from.type = D_REG; if(p->reg != NREG) p->from.reg = p->reg; else p->from.reg = p->to.reg; p->reg = NREG; } break; } } for(r=g->start; r!=nil; r=r->link) { p = r->prog; switch(p->as) { case AMOVW: case AMOVB: case AMOVBS: case AMOVBU: if(p->from.type == D_OREG && p->from.offset == 0) xtramodes(g, r, &p->from); else if(p->to.type == D_OREG && p->to.offset == 0) xtramodes(g, r, &p->to); else continue; break; // case ACMP: // /* // * elide CMP $0,x if calculation of x can set condition codes // */ // if(isdconst(&p->from) || p->from.offset != 0) // continue; // r2 = r->s1; // if(r2 == nil) // continue; // t = r2->prog->as; // switch(t) { // default: // continue; // case ABEQ: // case ABNE: // case ABMI: // case ABPL: // break; // case ABGE: // t = ABPL; // break; // case ABLT: // t = ABMI; // break; // case ABHI: // t = ABNE; // break; // case ABLS: // t = ABEQ; // break; // } // r1 = r; // do // r1 = uniqp(r1); // while (r1 != nil && r1->prog->as == ANOP); // if(r1 == nil) // continue; // p1 = r1->prog; // if(p1->to.type != D_REG) // continue; // if(p1->to.reg != p->reg) // if(!(p1->as == AMOVW && p1->from.type == D_REG && p1->from.reg == p->reg)) // continue; // // switch(p1->as) { // default: // continue; // case AMOVW: // if(p1->from.type != D_REG) // continue; // case AAND: // case AEOR: // case AORR: // case ABIC: // case AMVN: // case ASUB: // case ARSB: // case AADD: // case AADC: // case ASBC: // case ARSC: // break; // } // p1->scond |= C_SBIT; // r2->prog->as = t; // excise(r); // continue; } } // predicate(g); flowend(g); }
void peep(void) { Reg *r, *r1, *r2; Prog *p, *p1; int t; p1 = nil; USED(p1); // ... in unreachable code... /* * complete R structure */ for(r=firstr; r!=R; r=r1) { r1 = r->link; if(r1 == R) break; p = r->prog->link; while(p != r1->prog) switch(p->as) { default: r2 = rega(); r->link = r2; r2->link = r1; r2->prog = p; r2->p1 = r; r->s1 = r2; r2->s1 = r1; r1->p1 = r2; r = r2; case ADATA: case AGLOBL: case ANAME: case ASIGNAME: p = p->link; } } //dumpit("begin", firstr); loop1: t = 0; for(r=firstr; r!=R; r=r->link) { p = r->prog; switch(p->as) { case ASLL: case ASRL: case ASRA: /* * elide shift into D_SHIFT operand of subsequent instruction */ // if(shiftprop(r)) { // excise(r); // t++; // break; // } break; case AMOVW: case AMOVF: case AMOVD: if(regtyp(&p->from)) if(p->from.type == p->to.type) if(p->scond == C_SCOND_NONE) { if(copyprop(r)) { excise(r); t++; break; } if(subprop(r) && copyprop(r)) { excise(r); t++; break; } } break; #ifdef NOTDEF if(p->scond == C_SCOND_NONE) if(regtyp(&p->to)) if(isdconst(&p->from)) { constprop(&p->from, &p->to, r->s1); } break; #endif } } if(t) goto loop1; return; #ifdef NOTDEF for(r=firstr; r!=R; r=r->link) { p = r->prog; switch(p->as) { // case AEOR: // /* // * EOR -1,x,y => MVN x,y // */ // if(isdconst(&p->from) && p->from.offset == -1) { // p->as = AMVN; // p->from.type = D_REG; // if(p->reg != NREG) // p->from.reg = p->reg; // else // p->from.reg = p->to.reg; // p->reg = NREG; // } // break; case AMOVH: case AMOVHU: case AMOVB: case AMOVBU: /* * look for MOVB x,R; MOVB R,R */ if(p->to.type != D_REG) break; if(r1 == R) break; p1 = r1->prog; if(p1->as != p->as) break; if(p1->from.type != D_REG || p1->from.reg != p->to.reg) break; if(p1->to.type != D_REG || p1->to.reg != p->to.reg) break; excise(r1); break; } r1 = r->link; } // for(r=firstr; r!=R; r=r->link) { // p = r->prog; // switch(p->as) { // case AMOVW: // case AMOVB: // case AMOVBU: // if(p->from.type == D_OREG && p->from.offset == 0) // xtramodes(r, &p->from); // else // if(p->to.type == D_OREG && p->to.offset == 0) // xtramodes(r, &p->to); // else // continue; // break; // case ACMP: // /* // * elide CMP $0,x if calculation of x can set condition codes // */ // if(isdconst(&p->from) || p->from.offset != 0) // continue; // r2 = r->s1; // if(r2 == R) // continue; // t = r2->prog->as; // switch(t) { // default: // continue; // case ABEQ: // case ABNE: // case ABMI: // case ABPL: // break; // case ABGE: // t = ABPL; // break; // case ABLT: // t = ABMI; // break; // case ABHI: // t = ABNE; // break; // case ABLS: // t = ABEQ; // break; // } // r1 = r; // do // r1 = uniqp(r1); // while (r1 != R && r1->prog->as == ANOP); // if(r1 == R) // continue; // p1 = r1->prog; // if(p1->to.type != D_REG) // continue; // if(p1->to.reg != p->reg) // if(!(p1->as == AMOVW && p1->from.type == D_REG && p1->from.reg == p->reg)) // continue; // // switch(p1->as) { // default: // continue; // case AMOVW: // if(p1->from.type != D_REG) // continue; // case AAND: // case AEOR: // case AORR: // case ABIC: // case AMVN: // case ASUB: // case ARSB: // case AADD: // case AADC: // case ASBC: // case ARSC: // break; // } // p1->scond |= C_SBIT; // r2->prog->as = t; // excise(r); // continue; // } // } predicate(); #endif }
void peep(void) { Reg *r, *r1, *r2; Prog *p, *p1; int t; /* * complete R structure */ t = 0; for(r=firstr; r!=R; r=r1) { r1 = r->link; if(r1 == R) break; p = r->prog->link; while(p != r1->prog) switch(p->as) { default: r2 = rega(); r->link = r2; r2->link = r1; r2->prog = p; p->reg = r2; r2->p1 = r; r->s1 = r2; r2->s1 = r1; r1->p1 = r2; r = r2; t++; case ADATA: case AGLOBL: case ANAME: case ASIGNAME: p = p->link; } } // byte, word arithmetic elimination. elimshortmov(r); // constant propagation // find MOV $con,R followed by // another MOV $con,R without // setting R in the interim for(r=firstr; r!=R; r=r->link) { p = r->prog; switch(p->as) { case ALEAL: if(regtyp(&p->to)) if(p->from.sym != S) conprop(r); break; case AMOVB: case AMOVW: case AMOVL: case AMOVSS: case AMOVSD: if(regtyp(&p->to)) if(p->from.type == D_CONST) conprop(r); break; } } loop1: if(debug['P'] && debug['v']) dumpit("loop1", firstr); t = 0; for(r=firstr; r!=R; r=r->link) { p = r->prog; switch(p->as) { case AMOVL: case AMOVSS: case AMOVSD: if(regtyp(&p->to)) if(regtyp(&p->from)) { if(copyprop(r)) { excise(r); t++; } else if(subprop(r) && copyprop(r)) { excise(r); t++; } } break; case AMOVBLZX: case AMOVWLZX: case AMOVBLSX: case AMOVWLSX: if(regtyp(&p->to)) { r1 = rnops(uniqs(r)); if(r1 != R) { p1 = r1->prog; if(p->as == p1->as && p->to.type == p1->from.type){ p1->as = AMOVL; t++; } } } break; case AADDL: case AADDW: if(p->from.type != D_CONST || needc(p->link)) break; if(p->from.offset == -1){ if(p->as == AADDL) p->as = ADECL; else p->as = ADECW; p->from = zprog.from; break; } if(p->from.offset == 1){ if(p->as == AADDL) p->as = AINCL; else p->as = AINCW; p->from = zprog.from; break; } break; case ASUBL: case ASUBW: if(p->from.type != D_CONST || needc(p->link)) break; if(p->from.offset == -1) { if(p->as == ASUBL) p->as = AINCL; else p->as = AINCW; p->from = zprog.from; break; } if(p->from.offset == 1){ if(p->as == ASUBL) p->as = ADECL; else p->as = ADECW; p->from = zprog.from; break; } break; } } if(t) goto loop1; // MOVSD removal. // We never use packed registers, so a MOVSD between registers // can be replaced by MOVAPD, which moves the pair of float64s // instead of just the lower one. We only use the lower one, but // the processor can do better if we do moves using both. for(r=firstr; r!=R; r=r->link) { p = r->prog; if(p->as == AMOVSD) if(regtyp(&p->from)) if(regtyp(&p->to)) p->as = AMOVAPD; } }