/* * substitute s for v in a * return failure to substitute */ int copysub(Adr *a, Adr *v, Adr *s, int f) { int t; if(copyas(a, v)) { t = s->type; if(t >= D_AX && t <= D_R15 || t >= D_X0 && t <= D_X0+15) { if(f) a->type = t; } return 0; } if(regtyp(v)) { t = v->type; if(a->type == t+D_INDIR) { if((s->type == D_BP || s->type == D_R13) && a->index != D_NONE) return 1; /* can't use BP-base with index */ if(f) a->type = s->type+D_INDIR; // return 0; } if(a->index == t) { if(f) a->index = s->type; return 0; } return 0; } return 0; }
int smallindir(Addr *a, Addr *reg) { return regtyp(reg) && a->type == D_INDIR + reg->type && a->index == D_NONE && 0 <= a->offset && a->offset < 4096; }
/* * direct reference, * could be set/use depending on * semantics */ int copyas(Adr *a, Adr *v) { if(regtyp(v)) if(a->type == v->type) if(a->reg == v->reg) return 1; return 0; }
void nilopt(Prog *firstp) { NilFlow *r; Prog *p; Graph *g; int ncheck, nkill; g = flowstart(firstp, sizeof(NilFlow)); if(g == nil) return; if(debug_checknil > 1 /* || strcmp(curfn->nname->sym->name, "f1") == 0 */) dumpit("nilopt", g->start, 0); ncheck = 0; nkill = 0; for(r = (NilFlow*)g->start; r != nil; r = (NilFlow*)r->f.link) { p = r->f.prog; if(p->as != ACHECKNIL || !regtyp(&p->from)) continue; ncheck++; if(stackaddr(&p->from)) { if(debug_checknil && p->lineno > 1) warnl(p->lineno, "removed nil check of SP address"); r->kill = 1; continue; } nilwalkfwd(r); if(r->kill) { if(debug_checknil && p->lineno > 1) warnl(p->lineno, "removed nil check before indirect"); continue; } nilwalkback(r); if(r->kill) { if(debug_checknil && p->lineno > 1) warnl(p->lineno, "removed repeated nil check"); continue; } } for(r = (NilFlow*)g->start; r != nil; r = (NilFlow*)r->f.link) { if(r->kill) { nkill++; excise(&r->f); } } flowend(g); if(debug_checknil > 1) print("%S: removed %d of %d nil checks\n", curfn->nname->sym, nkill, ncheck); }
/* * direct reference, * could be set/use depending on * semantics */ int copyas(Adr *a, Adr *v) { if(a->type != v->type) return 0; if(regtyp(v)) return 1; if(v->type == D_AUTO || v->type == D_PARAM) if(v->offset == a->offset) return 1; return 0; }
int copyau1(Prog *p, Adr *v) { if(regtyp(v)) if(p->from.type == v->type || p->to.type == v->type) if(p->reg == v->reg) { if(a2type(p) != v->type) print("botch a2type %P\n", p); return 1; } return 0; }
/* * either direct or indirect */ int copyau(Adr *a, Adr *v) { if(copyas(a, v)) return 1; if(regtyp(v)) { if(a->type-D_INDIR == v->type) return 1; if(a->index == v->type) return 1; } return 0; }
static int regconsttyp(Adr *a) { if(regtyp(a)) return 1; switch(a->type) { case D_CONST: case D_FCONST: case D_SCONST: case D_ADDR: return 1; } return 0; }
/* * direct reference, * could be set/use depending on * semantics */ static int copyas(Adr *a, Adr *v) { if(D_AL <= a->type && a->type <= D_BL) fatal("use of byte register"); if(D_AL <= v->type && v->type <= D_BL) fatal("use of byte register"); if(a->type != v->type) return 0; if(regtyp(v)) return 1; if(v->type == D_AUTO || v->type == D_PARAM) if(v->offset == a->offset) return 1; return 0; }
/* * direct reference, * could be set/use depending on * semantics */ int copyas(Adr *a, Adr *v) { if(regtyp(v)) { if(a->type == v->type) if(a->reg == v->reg) return 1; } else if(v->type == D_CONST) { /* for constprop */ if(a->type == v->type) if(a->name == v->name) if(a->sym == v->sym) if(a->reg == v->reg) if(a->offset == v->offset) return 1; } return 0; }
/* * compare v to the center * register in p (p->reg) * the trick is that this * register might be D_REG * D_FREG. there are basically * two cases, * ADD r,r,r * CMP r,r, */ static int copyau1(Prog *p, Adr *v) { if(regtyp(v)) if(p->reg == v->reg) { if(p->to.type != D_NONE) { if(v->type == p->to.type) return 1; return 0; } if(p->from.type != D_NONE) { if(v->type == p->from.type) return 1; return 0; } print("copyau1: can't tell %P\n", p); } return 0; }
static void nilwalkfwd(NilFlow *rcheck) { NilFlow *r; Prog *p; ProgInfo info; // If the path down from rcheck dereferences the address // (possibly with a small offset) before writing to memory // and before any subsequent checks, it's okay to wait for // that implicit check. Only consider this basic block to // avoid problems like: // _ = *x // should panic // for {} // no writes but infinite loop may be considered visible for(r = (NilFlow*)uniqs(&rcheck->f); r != nil; r = (NilFlow*)uniqs(&r->f)) { p = r->f.prog; proginfo(&info, p); if((info.flags & LeftRead) && smallindir(&p->from, &rcheck->f.prog->from)) { rcheck->kill = 1; return; } if((info.flags & (RightRead|RightWrite)) && smallindir(&p->to, &rcheck->f.prog->from)) { rcheck->kill = 1; return; } // Stop if another nil check happens. if(p->as == ACHECKNIL) return; // Stop if value is lost. if((info.flags & RightWrite) && sameaddr(&p->to, &rcheck->f.prog->from)) return; // Stop if memory write. if((info.flags & RightWrite) && !regtyp(&p->to)) return; } }
/* * either direct or indirect */ int copyau(Adr *a, Adr *v) { if(copyas(a, v)) { if(debug['P'] && debug['v']) print("\tcopyau: copyas returned 1\n"); return 1; } if(regtyp(v)) { if(a->type-D_INDIR == v->type) { if(debug['P'] && debug['v']) print("\tcopyau: found indir use - return 1\n"); return 1; } if(a->index == v->type) { if(debug['P'] && debug['v']) print("\tcopyau: found index use - return 1\n"); return 1; } } return 0; }
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, *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); }
/* * the idea is to substitute * one register for another * from one MOV to another * MOV a, R0 * ADD b, R0 / no use of R1 * MOV R0, R1 * would be converted to * MOV a, R1 * ADD b, R1 * MOV R1, R0 * hopefully, then the former or latter MOV * will be eliminated by copy propagation. */ static int subprop(Flow *r0) { Prog *p; ProgInfo info; Adr *v1, *v2; Flow *r; int t; if(debug['P'] && debug['v']) print("subprop %P\n", r0->prog); p = r0->prog; v1 = &p->from; if(!regtyp(v1)) { if(debug['P'] && debug['v']) print("\tnot regtype %D; return 0\n", v1); return 0; } v2 = &p->to; if(!regtyp(v2)) { if(debug['P'] && debug['v']) print("\tnot regtype %D; return 0\n", v2); return 0; } for(r=uniqp(r0); r!=nil; r=uniqp(r)) { if(debug['P'] && debug['v']) print("\t? %P\n", r->prog); if(uniqs(r) == nil) { if(debug['P'] && debug['v']) print("\tno unique successor\n"); break; } p = r->prog; proginfo(&info, p); if(info.flags & Call) { if(debug['P'] && debug['v']) print("\tfound %P; return 0\n", p); return 0; } if(info.reguse | info.regset) { if(debug['P'] && debug['v']) print("\tfound %P; return 0\n", p); return 0; } if((info.flags & Move) && (info.flags & (SizeL|SizeQ|SizeF|SizeD)) && p->to.type == v1->type) goto gotit; if(copyau(&p->from, v2) || copyau(&p->to, v2)) { if(debug['P'] && debug['v']) print("\tcopyau %D failed\n", v2); break; } if(copysub(&p->from, v1, v2, 0) || copysub(&p->to, v1, v2, 0)) { if(debug['P'] && debug['v']) print("\tcopysub failed\n"); break; } } if(debug['P'] && debug['v']) print("\tran off end; return 0\n"); return 0; gotit: copysub(&p->to, v1, v2, 1); if(debug['P']) { print("gotit: %D->%D\n%P", v1, v2, r->prog); if(p->from.type == v2->type) print(" excise"); print("\n"); } for(r=uniqs(r); r!=r0; r=uniqs(r)) { p = r->prog; copysub(&p->from, v1, v2, 1); copysub(&p->to, v1, v2, 1); if(debug['P']) print("%P\n", r->prog); } t = v1->type; v1->type = v2->type; v2->type = t; if(debug['P']) print("%P last\n", r->prog); return 1; }
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; }
// movb elimination. // movb is simulated by the linker // when a register other than ax, bx, cx, dx // is used, so rewrite to other instructions // when possible. a movb into a register // can smash the entire 32-bit register without // causing any trouble. static void elimshortmov(Reg *r) { Prog *p; USED(r); for(r=firstr; r!=R; r=r->link) { p = r->prog; if(regtyp(&p->to)) { switch(p->as) { case AINCB: case AINCW: p->as = AINCQ; break; case ADECB: case ADECW: p->as = ADECQ; break; case ANEGB: case ANEGW: p->as = ANEGQ; break; case ANOTB: case ANOTW: p->as = ANOTQ; break; } if(regtyp(&p->from) || p->from.type == D_CONST) { // move or artihmetic into partial register. // from another register or constant can be movl. // we don't switch to 64-bit arithmetic if it can // change how the carry bit is set (and the carry bit is needed). switch(p->as) { case AMOVB: case AMOVW: p->as = AMOVQ; break; case AADDB: case AADDW: if(!needc(p->link)) p->as = AADDQ; break; case ASUBB: case ASUBW: if(!needc(p->link)) p->as = ASUBQ; break; case AMULB: case AMULW: p->as = AMULQ; break; case AIMULB: case AIMULW: p->as = AIMULQ; break; case AANDB: case AANDW: p->as = AANDQ; break; case AORB: case AORW: p->as = AORQ; break; case AXORB: case AXORW: p->as = AXORQ; break; case ASHLB: case ASHLW: p->as = ASHLQ; break; } } else if(p->from.type >= D_NONE) { // explicit zero extension, but don't // do that if source is a byte register // (only AH can occur and it's forbidden). switch(p->as) { case AMOVB: p->as = AMOVBQZX; break; case AMOVW: p->as = AMOVWQZX; break; } } } } }
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); } }
/* * the idea is to substitute * one register for another * from one MOV to another * MOV a, R0 * ADD b, R0 / no use of R1 * MOV R0, R1 * would be converted to * MOV a, R1 * ADD b, R1 * MOV R1, R0 * hopefully, then the former or latter MOV * will be eliminated by copy propagation. */ int subprop(Reg *r0) { Prog *p; Adr *v1, *v2; Reg *r; int t; if(debug['P'] && debug['v']) print("subprop %P\n", r0->prog); p = r0->prog; v1 = &p->from; if(!regtyp(v1)) { if(debug['P'] && debug['v']) print("\tnot regtype %D; return 0\n", v1); return 0; } v2 = &p->to; if(!regtyp(v2)) { if(debug['P'] && debug['v']) print("\tnot regtype %D; return 0\n", v2); return 0; } for(r=uniqp(r0); r!=R; r=uniqp(r)) { if(debug['P'] && debug['v']) print("\t? %P\n", r->prog); if(uniqs(r) == R) { if(debug['P'] && debug['v']) print("\tno unique successor\n"); break; } p = r->prog; switch(p->as) { case ACALL: if(debug['P'] && debug['v']) print("\tfound %P; return 0\n", p); return 0; case AIMULL: case AIMULQ: case AIMULW: if(p->to.type != D_NONE) break; goto giveup; case ARCLB: case ARCLL: case ARCLQ: case ARCLW: case ARCRB: case ARCRL: case ARCRQ: case ARCRW: case AROLB: case AROLL: case AROLQ: case AROLW: case ARORB: case ARORL: case ARORQ: case ARORW: case ASALB: case ASALL: case ASALQ: case ASALW: case ASARB: case ASARL: case ASARQ: case ASARW: case ASHLB: case ASHLL: case ASHLQ: case ASHLW: case ASHRB: case ASHRL: case ASHRQ: case ASHRW: if(p->from.type == D_CONST) break; goto giveup; case ADIVB: case ADIVL: case ADIVQ: case ADIVW: case AIDIVB: case AIDIVL: case AIDIVQ: case AIDIVW: case AIMULB: case AMULB: case AMULL: case AMULQ: case AMULW: case AREP: case AREPN: case ACWD: case ACDQ: case ACQO: case ASTOSB: case ASTOSL: case ASTOSQ: case AMOVSB: case AMOVSL: case AMOVSQ: giveup: if(debug['P'] && debug['v']) print("\tfound %P; return 0\n", p); return 0; case AMOVL: case AMOVQ: case AMOVSS: case AMOVSD: if(p->to.type == v1->type) goto gotit; break; } if(copyau(&p->from, v2) || copyau(&p->to, v2)) { if(debug['P'] && debug['v']) print("\tcopyau %D failed\n", v2); break; } if(copysub(&p->from, v1, v2, 0) || copysub(&p->to, v1, v2, 0)) { if(debug['P'] && debug['v']) print("\tcopysub failed\n"); break; } } if(debug['P'] && debug['v']) print("\tran off end; return 0\n"); return 0; gotit: copysub(&p->to, v1, v2, 1); if(debug['P']) { print("gotit: %D->%D\n%P", v1, v2, r->prog); if(p->from.type == v2->type) print(" excise"); print("\n"); } for(r=uniqs(r); r!=r0; r=uniqs(r)) { p = r->prog; copysub(&p->from, v1, v2, 1); copysub(&p->to, v1, v2, 1); if(debug['P']) print("%P\n", r->prog); } t = v1->type; v1->type = v2->type; v2->type = t; if(debug['P']) print("%P last\n", r->prog); return 1; }
/* * the idea is to substitute * one register for another * from one MOV to another * MOV a, R0 * ADD b, R0 / no use of R1 * MOV R0, R1 * would be converted to * MOV a, R1 * ADD b, R1 * MOV R1, R0 * hopefully, then the former or latter MOV * will be eliminated by copy propagation. */ static int subprop(Flow *r0) { Prog *p; Adr *v1, *v2; Flow *r; int t; ProgInfo info; p = r0->prog; v1 = &p->from; if(!regtyp(v1)) return 0; v2 = &p->to; if(!regtyp(v2)) return 0; for(r=uniqp(r0); r!=nil; r=uniqp(r)) { if(debug['P'] && debug['v']) print("\t? %P\n", r->prog); if(uniqs(r) == nil) break; p = r->prog; proginfo(&info, p); if(info.flags & Call) return 0; if(info.reguse | info.regset) return 0; if((info.flags & Move) && (info.flags & (SizeL|SizeQ|SizeF|SizeD)) && p->to.type == v1->type) goto gotit; if(copyau(&p->from, v2) || copyau(&p->to, v2)) break; if(copysub(&p->from, v1, v2, 0) || copysub(&p->to, v1, v2, 0)) break; } return 0; gotit: copysub(&p->to, v1, v2, 1); if(debug['P']) { print("gotit: %D->%D\n%P", v1, v2, r->prog); if(p->from.type == v2->type) print(" excise"); print("\n"); } for(r=uniqs(r); r!=r0; r=uniqs(r)) { p = r->prog; copysub(&p->from, v1, v2, 1); copysub(&p->to, v1, v2, 1); if(debug['P']) print("%P\n", r->prog); } t = v1->type; v1->type = v2->type; v2->type = t; if(debug['P']) print("%P last\n", r->prog); return 1; }
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; }
/* * the idea is to substitute * one register for another * from one MOV to another * MOV a, R0 * ADD b, R0 / no use of R1 * MOV R0, R1 * would be converted to * MOV a, R1 * ADD b, R1 * MOV R1, R0 * hopefully, then the former or latter MOV * will be eliminated by copy propagation. */ int subprop(Reg *r0) { Prog *p; Adr *v1, *v2; Reg *r; int t; p = r0->prog; v1 = &p->from; if(!regtyp(v1)) return 0; v2 = &p->to; if(!regtyp(v2)) return 0; for(r=uniqp(r0); r!=R; r=uniqp(r)) { if(uniqs(r) == R) break; p = r->prog; switch(p->as) { case ACALL: return 0; case AIMULL: case AIMULQ: case AIMULW: if(p->to.type != D_NONE) break; case ADIVB: case ADIVL: case ADIVQ: case ADIVW: case AIDIVB: case AIDIVL: case AIDIVQ: case AIDIVW: case AIMULB: case AMULB: case AMULL: case AMULQ: case AMULW: case ARCLB: case ARCLL: case ARCLQ: case ARCLW: case ARCRB: case ARCRL: case ARCRQ: case ARCRW: case AROLB: case AROLL: case AROLQ: case AROLW: case ARORB: case ARORL: case ARORQ: case ARORW: case ASALB: case ASALL: case ASALQ: case ASALW: case ASARB: case ASARL: case ASARQ: case ASARW: case ASHLB: case ASHLL: case ASHLQ: case ASHLW: case ASHRB: case ASHRL: case ASHRQ: case ASHRW: case AREP: case AREPN: case ACWD: case ACDQ: case ACQO: case ASTOSB: case ASTOSL: case ASTOSQ: case AMOVSB: case AMOVSL: case AMOVSQ: return 0; case AMOVL: case AMOVQ: if(p->to.type == v1->type) goto gotit; break; } if(copyau(&p->from, v2) || copyau(&p->to, v2)) break; if(copysub(&p->from, v1, v2, 0) || copysub(&p->to, v1, v2, 0)) break; } return 0; gotit: copysub(&p->to, v1, v2, 1); if(debug['P']) { print("gotit: %D->%D\n%P", v1, v2, r->prog); if(p->from.type == v2->type) print(" excise"); print("\n"); } for(r=uniqs(r); r!=r0; r=uniqs(r)) { p = r->prog; copysub(&p->from, v1, v2, 1); copysub(&p->to, v1, v2, 1); if(debug['P']) print("%P\n", r->prog); } t = v1->type; v1->type = v2->type; v2->type = t; if(debug['P']) print("%P last\n", r->prog); return 1; }
int stackaddr(Addr *a) { return regtyp(a) && a->type == D_SP; }
static void pushback(Reg *r0) { Reg *r, *b; Prog *p0, *p, t; b = R; p0 = r0->prog; for(r=uniqp(r0); r!=R && uniqs(r)!=R; r=uniqp(r)) { p = r->prog; if(p->as != ANOP) { if(!regconsttyp(&p->from) || !regtyp(&p->to)) break; if(copyu(p, &p0->to, A) || copyu(p0, &p->to, A)) break; } if(p->as == ACALL) break; b = r; } if(b == R) { if(debug['v']) { print("no pushback: %P\n", r0->prog); if(r) print("\t%P [%d]\n", r->prog, uniqs(r)!=R); } return; } if(debug['v']) { print("pushback\n"); for(r=b;; r=r->link) { print("\t%P\n", r->prog); if(r == r0) break; } } t = *r0->prog; for(r=uniqp(r0);; r=uniqp(r)) { p0 = r->link->prog; p = r->prog; p0->as = p->as; p0->lineno = p->lineno; p0->from = p->from; p0->to = p->to; if(r == b) break; } p0 = r->prog; p0->as = t.as; p0->lineno = t.lineno; p0->from = t.from; p0->to = t.to; if(debug['v']) { print("\tafter\n"); for(r=b;; r=r->link) { print("\t%P\n", r->prog); if(r == r0) break; } } }
/* * the idea is to substitute * one register for another * from one MOV to another * MOV a, R0 * ADD b, R0 / no use of R1 * MOV R0, R1 * would be converted to * MOV a, R1 * ADD b, R1 * MOV R1, R0 * hopefully, then the former or latter MOV * will be eliminated by copy propagation. */ int subprop(Reg *r0) { Prog *p; Adr *v1, *v2; Reg *r; int t; p = r0->prog; v1 = &p->from; if(!regtyp(v1)) return 0; v2 = &p->to; if(!regtyp(v2)) return 0; for(r=uniqp(r0); r!=R; r=uniqp(r)) { if(uniqs(r) == R) break; p = r->prog; switch(p->as) { case AJMPL: return 0; case AADD: case ASUB: case ASLL: case ASRL: case ASRA: case AOR: case AAND: case AXOR: case AMUL: case ADIV: case ADIVL: case AMOD: case AMODL: case AFADDD: case AFADDF: case AFSUBD: case AFSUBF: case AFMULD: case AFMULF: case AFDIVD: case AFDIVF: if(p->to.type == v1->type) if(p->to.reg == v1->reg) { if(p->reg == NREG) p->reg = p->to.reg; goto gotit; } break; case AFMOVF: case AFMOVD: case AMOVW: if(p->to.type == v1->type) if(p->to.reg == v1->reg) goto gotit; break; } if(copyau(&p->from, v2) || copyau1(p, v2) || copyau(&p->to, v2)) break; if(copysub(&p->from, v1, v2, 0) || copysub1(p, v1, v2, 0) || copysub(&p->to, v1, v2, 0)) break; } return 0; gotit: copysub(&p->to, v1, v2, 1); if(debug['P']) { print("gotit: %D->%D\n%P", v1, v2, r->prog); if(p->from.type == v2->type) print(" excise"); print("\n"); } for(r=uniqs(r); r!=r0; r=uniqs(r)) { p = r->prog; copysub(&p->from, v1, v2, 1); copysub1(p, v1, v2, 1); copysub(&p->to, v1, v2, 1); if(debug['P']) print("%P\n", r->prog); } t = v1->reg; v1->reg = v2->reg; v2->reg = t; if(debug['P']) print("%P last\n", r->prog); return 1; }
// movb elimination. // movb is simulated by the linker // when a register other than ax, bx, cx, dx // is used, so rewrite to other instructions // when possible. a movb into a register // can smash the entire 64-bit register without // causing any trouble. static void elimshortmov(Graph *g) { Prog *p; Flow *r; for(r=g->start; r!=nil; r=r->link) { p = r->prog; if(regtyp(&p->to)) { switch(p->as) { case AINCB: case AINCW: p->as = AINCL; break; case ADECB: case ADECW: p->as = ADECL; break; case ANEGB: case ANEGW: p->as = ANEGL; break; case ANOTB: case ANOTW: p->as = ANOTL; break; } if(regtyp(&p->from) || p->from.type == D_CONST) { // move or artihmetic into partial register. // from another register or constant can be movl. // we don't switch to 32-bit arithmetic if it can // change how the carry bit is set (and the carry bit is needed). switch(p->as) { case AMOVB: case AMOVW: p->as = AMOVL; break; case AADDB: case AADDW: if(!needc(p->link)) p->as = AADDL; break; case ASUBB: case ASUBW: if(!needc(p->link)) p->as = ASUBL; break; case AMULB: case AMULW: p->as = AMULL; break; case AIMULB: case AIMULW: p->as = AIMULL; break; case AANDB: case AANDW: p->as = AANDL; break; case AORB: case AORW: p->as = AORL; break; case AXORB: case AXORW: p->as = AXORL; break; case ASHLB: case ASHLW: p->as = ASHLL; break; } } else { // explicit zero extension switch(p->as) { case AMOVB: p->as = AMOVBLZX; break; case AMOVW: p->as = AMOVWLZX; break; } } } } }
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; 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(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(); }