/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include "l.h" enum{ E_ICC = 1<<0, E_FCC = 1<<1, E_MEM = 1<<2, E_MEMSP = 1<<3, /* uses offset and size */ E_MEMSB = 1<<4, /* uses offset and size */ E_LR = 1<<5, E_CR = 1<<6, E_CTR = 1<<7, E_XER = 1<<8, E_CR0 = 0xF<<0, E_CR1 = 0xF<<4, ANYMEM = E_MEM|E_MEMSP|E_MEMSB, ALL = ~0,}; typedef struct Sch Sch;typedef struct Dep Dep; struct Dep{ ulong ireg; ulong freg; ulong cc; ulong cr;};struct Sch{ Prog p; Dep set; Dep used; long soffset; char size; char comp;}; void regused(Sch*, Prog*);int depend(Sch*, Sch*);int conflict(Sch*, Sch*);int offoverlap(Sch*, Sch*);void dumpbits(Sch*, Dep*); voidsched(Prog *p0, Prog *pe){ Prog *p, *q; Sch sch[NSCHED], *s, *t, *u, *se, stmp; if(!debug['Q']) return; /* * build side structure */ s = sch; for(p=p0;; p=p->link) { memset(s, 0, sizeof(*s)); s->p = *p; regused(s, p); if(debug['X']) { Bprint(&bso, "%P\tset", &s->p); dumpbits(s, &s->set); Bprint(&bso, "; used"); dumpbits(s, &s->used); if(s->comp) Bprint(&bso, "; compound"); if(s->p.mark & LOAD) Bprint(&bso, "; load"); if(s->p.mark & BRANCH) Bprint(&bso, "; branch"); if(s->p.mark & FCMP) Bprint(&bso, "; fcmp"); Bprint(&bso, "\n"); } s++; if(p == pe) break; } se = s; for(s=se-1; s>=sch; s--) { /* * load delay. interlocked. */ if(s->p.mark & LOAD) { if(s >= se-1) continue; if(!conflict(s, (s+1))) continue; /* * s is load, s+1 is immediate use of result * t is the trial instruction to insert between s and s+1 */ for(t=s-1; t>=sch; t--) { if(t->p.mark & BRANCH) goto no2; if(t->p.mark & FCMP) if((s+1)->p.mark & BRANCH) goto no2; if(t->p.mark & LOAD) if(conflict(t, (s+1))) goto no2; for(u=t+1; u<=s; u++) if(depend(u, t)) goto no2; goto out2; no2:; } if(debug['X']) Bprint(&bso, "?l%P\n", &s->p); continue; out2: if(debug['X']) { Bprint(&bso, "!l%P\n", &t->p); Bprint(&bso, "%P\n", &s->p); } stmp = *t; memmove(t, t+1, (uchar*)s - (uchar*)t); *s = stmp; s--; continue; } /* * fop2 delay. */ if(s->p.mark & FCMP) { if(s >= se-1) continue; if(!((s+1)->p.mark & BRANCH)) continue; /* t is the trial instruction to use */ for(t=s-1; t>=sch; t--) { for(u=t+1; u<=s; u++) if(depend(u, t)) goto no3; goto out3; no3:; } if(debug['X']) Bprint(&bso, "?f%P\n", &s->p); continue; out3: if(debug['X']) { Bprint(&bso, "!f%P\n", &t->p); Bprint(&bso, "%P\n", &s->p); } stmp = *t; memmove(t, t+1, (uchar*)s - (uchar*)t); *s = stmp; s--; continue; } } /* * put it all back */ for(s=sch, p=p0; s<se; s++, p=q) { q = p->link; if(q != s->p.link) { *p = s->p; p->link = q; } } if(debug['X']) Bprint(&bso, "\n");} voidregused(Sch *s, Prog *realp){ int c, ar, ad, ld, sz, nr, upd; ulong m; Prog *p; p = &s->p; s->comp = compound(p); if(s->comp) { s->set.ireg |= 1<<REGTMP; s->used.ireg |= 1<<REGTMP; } ar = 0; /* dest is really reference */ ad = 0; /* source/dest is really address */ ld = 0; /* opcode is load instruction */ sz = 32*4; /* size of load/store for overlap computation */ nr = 0; /* source/dest is not really reg */ upd = 0; /* move with update; changes reg */ /* * flags based on opcode */ switch(p->as) { case ATEXT: curtext = realp; autosize = p->to.offset + 4; ad = 1; break; case ABL: s->set.cc |= E_LR; ar = 1; ad = 1; break; case ABR: ar = 1; ad = 1; break; case ACMP: s->set.cc |= E_ICC; if(p->reg == 0) s->set.cr |= E_CR0; else s->set.cr |= (0xF<<((p->reg&7)*4)); ar = 1; break; case AFCMPO: case AFCMPU: s->set.cc |= E_FCC; if(p->reg == 0) s->set.cr |= E_CR0; else s->set.cr |= (0xF<<((p->reg&7)*4)); ar = 1; break; case ACRAND: case ACRANDN: case ACREQV: case ACRNAND: case ACRNOR: case ACROR: case ACRORN: case ACRXOR: s->used.cr |= 1<<p->from.reg; s->set.cr |= 1<<p->to.reg; nr = 1; break; case ABCL: /* tricky */ s->used.cc |= E_FCC|E_ICC; s->used.cr = ALL; s->set.cc |= E_LR; ar = 1; break; case ABC: /* tricky */ s->used.cc |= E_FCC|E_ICC; s->used.cr = ALL; ar = 1; break; case ABEQ: case ABGE: case ABGT: case ABLE: case ABLT: case ABNE: case ABVC: case ABVS: s->used.cc |= E_ICC; s->used.cr |= E_CR0; ar = 1; break; case ALSW: case AMOVMW: /* could do better */ sz = 32*4; ld = 1; break; case AMOVBU: case AMOVBZU: upd = 1; sz = 1; ld = 1; break; case AMOVB: case AMOVBZ: sz = 1; ld = 1; break; case AMOVHU: case AMOVHZU: upd = 1; sz = 2; ld = 1; break; case AMOVH: case AMOVHBR: case AMOVHZ: sz = 2; ld = 1; break; case AFMOVSU: case AMOVWU: upd = 1; sz = 4; ld = 1; break; case AFMOVS: case AMOVW: case AMOVWBR: case ALWAR: sz = 4; ld = 1; break; case AFMOVDU: upd = 1; sz = 8; ld = 1; break; case AFMOVD: sz = 8; ld = 1; break; case AFMOVDCC: sz = 8; ld = 1; s->set.cc |= E_FCC; s->set.cr |= E_CR1; break; case AMOVFL: case AMOVCRFS: case AMTFSB0: case AMTFSB0CC: case AMTFSB1: case AMTFSB1CC: s->set.ireg = ALL; s->set.freg = ALL; s->set.cc = ALL; s->set.cr = ALL; break; case AADDCC: case AADDVCC: case AADDCCC: case AADDCVCC: case AADDMECC: case AADDMEVCC: case AADDECC: case AADDEVCC: case AADDZECC: case AADDZEVCC: case AANDCC: case AANDNCC: case ACNTLZWCC: case ADIVWCC: case ADIVWVCC: case ADIVWUCC: case ADIVWUVCC: case AEQVCC: case AEXTSBCC: case AEXTSHCC: case AMULHWCC: case AMULHWUCC: case AMULLWCC: case AMULLWVCC: case ANANDCC: case ANEGCC: case ANEGVCC: case ANORCC: case AORCC: case AORNCC: case AREMCC: case AREMVCC: case AREMUCC: case AREMUVCC: case ARLWMICC: case ARLWNMCC: case ASLWCC: case ASRAWCC: case ASRWCC: case ASTWCCC: case ASUBCC: case ASUBVCC: case ASUBCCC: case ASUBCVCC: case ASUBMECC: case ASUBMEVCC: case ASUBECC: case ASUBEVCC: case ASUBZECC: case ASUBZEVCC: case AXORCC: s->set.cc |= E_ICC; s->set.cr |= E_CR0; break; case AFABSCC: case AFADDCC: case AFADDSCC: case AFCTIWCC: case AFCTIWZCC: case AFDIVCC: case AFDIVSCC: case AFMADDCC: case AFMADDSCC: case AFMSUBCC: case AFMSUBSCC: case AFMULCC: case AFMULSCC: case AFNABSCC: case AFNEGCC: case AFNMADDCC: case AFNMADDSCC: case AFNMSUBCC: case AFNMSUBSCC: case AFRSPCC: case AFSUBCC: case AFSUBSCC: s->set.cc |= E_FCC; s->set.cr |= E_CR1; break; } /* * flags based on 'to' field */ c = p->to.class; if(c == 0) { c = aclass(&p->to) + 1; p->to.class = c; } c--; switch(c) { default: print("unknown class %d %D\n", c, &p->to); case C_NONE: case C_ZCON: case C_SCON: case C_UCON: case C_LCON: case C_ADDCON: case C_ANDCON: case C_SBRA: case C_LBRA: break; case C_CREG: c = p->to.reg; if(c == NREG) s->set.cr = ALL; else s->set.cr |= (0xF << ((p->from.reg&7)*4)); s->set.cc = ALL; break; case C_SPR: case C_SREG: case C_FPSCR: case C_MSR: case C_XER: s->set.ireg = ALL; s->set.freg = ALL; s->set.cc = ALL; s->set.cr = ALL; break; case C_LR: s->set.cc |= E_LR; break; case C_CTR: s->set.cc |= E_CTR; break; case C_ZOREG: case C_SOREG: case C_LOREG: c = p->to.reg; s->used.ireg |= 1<<c; if(upd) s->set.ireg |= 1<<c; if(ad) break; s->size = sz; s->soffset = regoff(&p->to); m = ANYMEM; if(c == REGSB) m = E_MEMSB; if(c == REGSP) m = E_MEMSP; if(ar) s->used.cc |= m; else s->set.cc |= m; break; case C_SACON: case C_LACON: s->used.ireg |= 1<<REGSP; if(upd) s->set.ireg |= 1<<c; break; case C_SECON: case C_LECON:Lines 1–500 of 810. Load more
/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include "l.h" enum { E_ICC = 1<<0, E_FCC = 1<<1, E_MEM = 1<<2, E_MEMSP = 1<<3, /* uses offset and size */ E_MEMSB = 1<<4, /* uses offset and size */ E_LR = 1<<5, E_CR = 1<<6, E_CTR = 1<<7, E_XER = 1<<8, E_CR0 = 0xF<<0, E_CR1 = 0xF<<4, ANYMEM = E_MEM|E_MEMSP|E_MEMSB, ALL = ~0, }; typedef struct Sch Sch; typedef struct Dep Dep; struct Dep { ulong ireg; ulong freg; ulong cc; ulong cr; }; struct Sch { Prog p; Dep set; Dep used; long soffset; char size; char comp; }; void regused(Sch*, Prog*); int depend(Sch*, Sch*); int conflict(Sch*, Sch*); int offoverlap(Sch*, Sch*); void dumpbits(Sch*, Dep*); void sched(Prog *p0, Prog *pe) { Prog *p, *q; Sch sch[NSCHED], *s, *t, *u, *se, stmp; if(!debug['Q']) return; /* * build side structure */ s = sch; for(p=p0;; p=p->link) { memset(s, 0, sizeof(*s)); s->p = *p; regused(s, p); if(debug['X']) { Bprint(&bso, "%P\tset", &s->p); dumpbits(s, &s->set); Bprint(&bso, "; used"); dumpbits(s, &s->used); if(s->comp) Bprint(&bso, "; compound"); if(s->p.mark & LOAD) Bprint(&bso, "; load"); if(s->p.mark & BRANCH) Bprint(&bso, "; branch"); if(s->p.mark & FCMP) Bprint(&bso, "; fcmp"); Bprint(&bso, "\n"); } s++; if(p == pe) break; } se = s; for(s=se-1; s>=sch; s--) { /* * load delay. interlocked. */ if(s->p.mark & LOAD) { if(s >= se-1) continue; if(!conflict(s, (s+1))) continue; /* * s is load, s+1 is immediate use of result * t is the trial instruction to insert between s and s+1 */ for(t=s-1; t>=sch; t--) { if(t->p.mark & BRANCH) goto no2; if(t->p.mark & FCMP) if((s+1)->p.mark & BRANCH) goto no2; if(t->p.mark & LOAD) if(conflict(t, (s+1))) goto no2; for(u=t+1; u<=s; u++) if(depend(u, t)) goto no2; goto out2; no2:; } if(debug['X']) Bprint(&bso, "?l%P\n", &s->p); continue; out2: if(debug['X']) { Bprint(&bso, "!l%P\n", &t->p); Bprint(&bso, "%P\n", &s->p); } stmp = *t; memmove(t, t+1, (uchar*)s - (uchar*)t); *s = stmp; s--; continue; } /* * fop2 delay. */ if(s->p.mark & FCMP) { if(s >= se-1) continue; if(!((s+1)->p.mark & BRANCH)) continue; /* t is the trial instruction to use */ for(t=s-1; t>=sch; t--) { for(u=t+1; u<=s; u++) if(depend(u, t)) goto no3; goto out3; no3:; } if(debug['X']) Bprint(&bso, "?f%P\n", &s->p); continue; out3: if(debug['X']) { Bprint(&bso, "!f%P\n", &t->p); Bprint(&bso, "%P\n", &s->p); } stmp = *t; memmove(t, t+1, (uchar*)s - (uchar*)t); *s = stmp; s--; continue; } } /* * put it all back */ for(s=sch, p=p0; s<se; s++, p=q) { q = p->link; if(q != s->p.link) { *p = s->p; p->link = q; } } if(debug['X']) Bprint(&bso, "\n"); } void regused(Sch *s, Prog *realp) { int c, ar, ad, ld, sz, nr, upd; ulong m; Prog *p; p = &s->p; s->comp = compound(p); if(s->comp) { s->set.ireg |= 1<<REGTMP; s->used.ireg |= 1<<REGTMP; } ar = 0; /* dest is really reference */ ad = 0; /* source/dest is really address */ ld = 0; /* opcode is load instruction */ sz = 32*4; /* size of load/store for overlap computation */ nr = 0; /* source/dest is not really reg */ upd = 0; /* move with update; changes reg */ /* * flags based on opcode */ switch(p->as) { case ATEXT: curtext = realp; autosize = p->to.offset + 4; ad = 1; break; case ABL: s->set.cc |= E_LR; ar = 1; ad = 1; break; case ABR: ar = 1; ad = 1; break; case ACMP: s->set.cc |= E_ICC; if(p->reg == 0) s->set.cr |= E_CR0; else s->set.cr |= (0xF<<((p->reg&7)*4)); ar = 1; break; case AFCMPO: case AFCMPU: s->set.cc |= E_FCC; if(p->reg == 0) s->set.cr |= E_CR0; else s->set.cr |= (0xF<<((p->reg&7)*4)); ar = 1; break; case ACRAND: case ACRANDN: case ACREQV: case ACRNAND: case ACRNOR: case ACROR: case ACRORN: case ACRXOR: s->used.cr |= 1<<p->from.reg; s->set.cr |= 1<<p->to.reg; nr = 1; break; case ABCL: /* tricky */ s->used.cc |= E_FCC|E_ICC; s->used.cr = ALL; s->set.cc |= E_LR; ar = 1; break; case ABC: /* tricky */ s->used.cc |= E_FCC|E_ICC; s->used.cr = ALL; ar = 1; break; case ABEQ: case ABGE: case ABGT: case ABLE: case ABLT: case ABNE: case ABVC: case ABVS: s->used.cc |= E_ICC; s->used.cr |= E_CR0; ar = 1; break; case ALSW: case AMOVMW: /* could do better */ sz = 32*4; ld = 1; break; case AMOVBU: case AMOVBZU: upd = 1; sz = 1; ld = 1; break; case AMOVB: case AMOVBZ: sz = 1; ld = 1; break; case AMOVHU: case AMOVHZU: upd = 1; sz = 2; ld = 1; break; case AMOVH: case AMOVHBR: case AMOVHZ: sz = 2; ld = 1; break; case AFMOVSU: case AMOVWU: upd = 1; sz = 4; ld = 1; break; case AFMOVS: case AMOVW: case AMOVWBR: case ALWAR: sz = 4; ld = 1; break; case AFMOVDU: upd = 1; sz = 8; ld = 1; break; case AFMOVD: sz = 8; ld = 1; break; case AFMOVDCC: sz = 8; ld = 1; s->set.cc |= E_FCC; s->set.cr |= E_CR1; break; case AMOVFL: case AMOVCRFS: case AMTFSB0: case AMTFSB0CC: case AMTFSB1: case AMTFSB1CC: s->set.ireg = ALL; s->set.freg = ALL; s->set.cc = ALL; s->set.cr = ALL; break; case AADDCC: case AADDVCC: case AADDCCC: case AADDCVCC: case AADDMECC: case AADDMEVCC: case AADDECC: case AADDEVCC: case AADDZECC: case AADDZEVCC: case AANDCC: case AANDNCC: case ACNTLZWCC: case ADIVWCC: case ADIVWVCC: case ADIVWUCC: case ADIVWUVCC: case AEQVCC: case AEXTSBCC: case AEXTSHCC: case AMULHWCC: case AMULHWUCC: case AMULLWCC: case AMULLWVCC: case ANANDCC: case ANEGCC: case ANEGVCC: case ANORCC: case AORCC: case AORNCC: case AREMCC: case AREMVCC: case AREMUCC: case AREMUVCC: case ARLWMICC: case ARLWNMCC: case ASLWCC: case ASRAWCC: case ASRWCC: case ASTWCCC: case ASUBCC: case ASUBVCC: case ASUBCCC: case ASUBCVCC: case ASUBMECC: case ASUBMEVCC: case ASUBECC: case ASUBEVCC: case ASUBZECC: case ASUBZEVCC: case AXORCC: s->set.cc |= E_ICC; s->set.cr |= E_CR0; break; case AFABSCC: case AFADDCC: case AFADDSCC: case AFCTIWCC: case AFCTIWZCC: case AFDIVCC: case AFDIVSCC: case AFMADDCC: case AFMADDSCC: case AFMSUBCC: case AFMSUBSCC: case AFMULCC: case AFMULSCC: case AFNABSCC: case AFNEGCC: case AFNMADDCC: case AFNMADDSCC: case AFNMSUBCC: case AFNMSUBSCC: case AFRSPCC: case AFSUBCC: case AFSUBSCC: s->set.cc |= E_FCC; s->set.cr |= E_CR1; break; } /* * flags based on 'to' field */ c = p->to.class; if(c == 0) { c = aclass(&p->to) + 1; p->to.class = c; } c--; switch(c) { default: print("unknown class %d %D\n", c, &p->to); case C_NONE: case C_ZCON: case C_SCON: case C_UCON: case C_LCON: case C_ADDCON: case C_ANDCON: case C_SBRA: case C_LBRA: break; case C_CREG: c = p->to.reg; if(c == NREG) s->set.cr = ALL; else s->set.cr |= (0xF << ((p->from.reg&7)*4)); s->set.cc = ALL; break; case C_SPR: case C_SREG: case C_FPSCR: case C_MSR: case C_XER: s->set.ireg = ALL; s->set.freg = ALL; s->set.cc = ALL; s->set.cr = ALL; break; case C_LR: s->set.cc |= E_LR; break; case C_CTR: s->set.cc |= E_CTR; break; case C_ZOREG: case C_SOREG: case C_LOREG: c = p->to.reg; s->used.ireg |= 1<<c; if(upd) s->set.ireg |= 1<<c; if(ad) break; s->size = sz; s->soffset = regoff(&p->to); m = ANYMEM; if(c == REGSB) m = E_MEMSB; if(c == REGSP) m = E_MEMSP; if(ar) s->used.cc |= m; else s->set.cc |= m; break; case C_SACON: case C_LACON: s->used.ireg |= 1<<REGSP; if(upd) s->set.ireg |= 1<<c; break; case C_SECON: case C_LECON: