void ivars(void) { char *temp=NULL; env_overr(&Spice_Exec_Dir, "SPICE_EXEC_DIR"); env_overr(&Spice_Lib_Dir, "SPICE_LIB_DIR"); mkvar(&News_File, Spice_Lib_Dir, "news", "SPICE_NEWS"); mkvar(&Default_MFB_Cap, Spice_Lib_Dir, "mfbcap", "SPICE_MFBCAP"); mkvar(&Help_Path, Spice_Lib_Dir, "helpdir", "SPICE_HELP_DIR"); mkvar(&Lib_Path, Spice_Lib_Dir, "scripts", "SPICE_SCRIPTS"); mkvar(&Spice_Path, Spice_Exec_Dir, "ngspice", "SPICE_PATH"); env_overr(&Spice_Host, "SPICE_HOST"); env_overr(&Bug_Addr, "SPICE_BUGADDR"); env_overr(&Def_Editor, "SPICE_EDITOR"); env_overr(&temp, "SPICE_ASCIIRAWFILE"); if(temp) AsciiRawFile = atoi(temp); }
extern void varpop(Push *push) { Var *var; assert(pushlist == push); assert(rootlist == &push->defnroot); assert(rootlist->next == &push->nameroot); if (isexported(push->name)) isdirty = TRUE; push->defn = callsettor(push->name, push->defn); var = dictget(vars, push->name); if (var != NULL) if (push->defn != NULL) { var->defn = push->defn; var->flags = push->flags; var->env = NULL; } else vars = dictput(vars, push->name, NULL); else if (push->defn != NULL) { var = mkvar(NULL); var->defn = push->defn; var->flags = push->flags; vars = dictput(vars, push->name, var); } pushlist = pushlist->next; rootlist = rootlist->next->next; }
extern void vardef(char *name, Binding *binding, List *defn) { Var *var; validatevar(name); for (; binding != NULL; binding = binding->next) if (streq(name, binding->name)) { binding->defn = defn; rebound = TRUE; return; } RefAdd(name); defn = callsettor(name, defn); if (isexported(name)) isdirty = TRUE; var = dictget(vars, name); if (var != NULL) if (defn != NULL) { var->defn = defn; var->env = NULL; var->flags = hasbindings(defn) ? var_hasbindings : 0; } else vars = dictput(vars, name, NULL); else if (defn != NULL) { var = mkvar(defn); vars = dictput(vars, name, var); } RefRemove(name); }
extern void varpush(Push *push, char *name, List *defn) { Var *var; validatevar(name); push->name = name; push->nameroot.next = rootlist; push->nameroot.p = (void **) &push->name; rootlist = &push->nameroot; if (isexported(name)) isdirty = TRUE; defn = callsettor(name, defn); var = dictget(vars, push->name); if (var == NULL) { push->defn = NULL; push->flags = 0; var = mkvar(defn); vars = dictput(vars, push->name, var); } else { push->defn = var->defn; push->flags = var->flags; var->defn = defn; var->env = NULL; var->flags = hasbindings(defn) ? var_hasbindings : 0; } push->next = pushlist; pushlist = push; push->defnroot.next = rootlist; push->defnroot.p = (void **) &push->defn; rootlist = &push->defnroot; }
/* determine whether we should determine the next value of a variable. also decide which variables to registerize. */ static void trackneed(void) { SemVar *v; int ch, i, j, o; for(j = 0; j < nvars; j++) { v = vars[j]; if(v->idx == 0 && v->prime) { if(v->sym->semc[0]->def != 0 && v->sym->semc[1]->def != 0) { error(v->sym, "'%s' both primed and unprimed defined", v->sym->name); continue; } if((v->sym->opt & OPTREG) != 0 && v->sym->semc[0]->def != 0) { if((v->sym->semc[0]->flags & SVCANNX) == 0) { error(v->sym, "'%s' cannot be register", v->sym->name); v->sym->opt &= ~OPTREG; } else v->sym->semc[0]->flags |= SVNEEDNX | SVDELDEF | SVREG; } if((v->sym->opt & (OPTOUT|OPTWIRE)) == OPTOUT && v->sym->semc[0]->def != 0 && (v->sym->semc[0]->flags & SVCANNX) != 0) v->sym->semc[0]->flags |= SVNEEDNX | SVDELDEF | SVREG; if(v->sym->semc[1]->def != 0) { if((v->sym->opt & OPTWIRE) != 0) { error(v->sym, "'%s' cannot be wire", v->sym->name); v->sym->opt &= ~OPTWIRE; } else v->sym->semc[0]->flags |= SVREG; } } } /* propagate SVNEEDNX to all variables we are dependent on */ do { ch = 0; for(j = 0; j < nvars; j++) { v = vars[j]; if((v->flags & SVNEEDNX) == 0) continue; if(v->deps == nil) continue; for(i = 0; i < v->deps->n; i++) { o = v->deps->p[i]->flags & SVNEEDNX; v->deps->p[i]->flags |= SVNEEDNX; ch += o == 0; } } } while(ch > 0); for(j = 0; j < nvars; j++) { v = vars[j]; if((v->flags & SVREG) != 0) v->tnext = v->sym->semc[1]; else if((v->flags & SVNEEDNX) != 0) v->tnext = mkvar(v->sym, 1); } }
/* add initialization statements to blocks as needed */ static void sinitbuild(SemBlock *b) { SemBlock *yes, *no, *then; SemInit *si; ASTNode *p; SemVar *nv, *v; SemTrigger *t; for(t = sinits; t != nil; t = t->next) { yes = newblock(); no = newblock(); then = newblock(); yes->cont = node(ASTBLOCK, nil); then->phi = node(ASTBLOCK, nil); b->jump = node(ASTIF, t->trigger, node(ASTSEMGOTO, yes), node(ASTSEMGOTO, no)); yes->jump = node(ASTSEMGOTO, then); no->jump = node(ASTSEMGOTO, then); mkftlist(b, 1, yes, no, nil); mkftlist(yes, 0, b, nil); mkftlist(yes, 1, then, nil); mkftlist(no, 0, b, nil); mkftlist(no, 1, then, nil); mkftlist(then, 0, yes, no, nil); for(si = t->first; si != nil; si = si->tnext) { v = mkvar(si->var->sym, 1); if(--si->var->nsinits > 0) nv = mkvar(si->var->sym, 1); else nv = si->var->sym->semc[1]; yes->cont->nl = nlcat(yes->cont->nl, nl(node(ASTASS, OPNOP, node(ASTSSA, v), si->val))); p = node(ASTPHI); p->nl = nls(node(ASTSSA, v), node(ASTSSA, ssaget(sinitvars, v->sym, 1)), nil); then->phi->nl = nlcat(then->phi->nl, nl(node(ASTASS, OPNOP, node(ASTSSA, nv), p))); defsadd(sinitvars, nv, 1); } b = then; } }
/* find all variables in a statement that we would like to initialize */ static Nodes * sinitblock(ASTNode *n) { SemVar *v, *nv; SemInit *s; if(n->t != ASTASS || n->n1->t != ASTSSA) return nl(n); v = n->n1->semv; if(v != v->sym->semc[1]) return nl(n); for(s = v->sym->semc[0]->init; s != nil; s = s->vnext) if(s->type == SISYNC) break; if(s == nil) return nl(n); nv = mkvar(v->sym, v->prime); n->n1 = node(ASTSSA, nv); defsadd(sinitvars, nv, 1); return nl(n); }
static void setoutvar(void) { Type *t; Node *n; Addr a; Iter save; Bits bit; int z; t = structfirst(&save, getoutarg(curfn->type)); while(t != T) { n = nodarg(t, 1); a = zprog.from; naddr(n, &a, 0); bit = mkvar(R, &a); for(z=0; z<BITS; z++) ovar.b[z] |= bit.b[z]; t = structnext(&save); } //if(bany(&ovar)) //print("ovars = %Q\n", ovar); }
Bits mkvar(Reg *r, Addr *a) { Var *v; int i, t, n, et, z; int32 o; Bits bit; LSym *s; /* * mark registers used */ t = a->type; r->regu |= doregbits(t); r->regu |= doregbits(a->index); switch(t) { default: goto none; case D_ADDR: a->type = a->index; bit = mkvar(r, a); for(z=0; z<BITS; z++) addrs.b[z] |= bit.b[z]; a->type = t; goto none; case D_EXTERN: case D_STATIC: case D_PARAM: case D_AUTO: n = t; break; } s = a->sym; if(s == nil) goto none; if(s->name[0] == '.') goto none; et = a->etype; o = a->offset; v = var; for(i=0; i<nvar; i++) { if(s == v->sym) if(n == v->name) if(o == v->offset) goto out; v++; } if(nvar >= NVAR) fatal(Z, "variable not optimized: %s", s->name); i = nvar; nvar++; v = &var[i]; v->sym = s; v->offset = o; v->name = n; v->etype = et; if(debug['R']) print("bit=%2d et=%2d %D\n", i, et, a); out: bit = blsh(i); if(n == D_EXTERN || n == D_STATIC) for(z=0; z<BITS; z++) externs.b[z] |= bit.b[z]; if(n == D_PARAM) for(z=0; z<BITS; z++) params.b[z] |= bit.b[z]; if(v->etype != et || !(typechlpfd[et] || typev[et])) /* funny punning */ for(z=0; z<BITS; z++) addrs.b[z] |= bit.b[z]; return bit; none: return zbits; }
/* scan: parse the contents of fp, expecting the input side (phase) of a rule if ph=='i', or the output side if ph=='o' */ List scan (FILE *fp, int ph) { int c = 0; /* Current char on fp */ int nb = 0, nw = 0; /* Position in rule (bit/word) */ Symbol csym = 0L; /* Current variable being scanned */ T f_msk=(T)0, f_val=(T)0; /* Current constant mask and value */ List pats = 0L; /* All the patterns (words) for this phase */ List vars = 0L; /* All the vars for a given pattern */ while ((c=getc(fp)) != EOF) { if (debugp) fprintf(stdout, "/* bit: %c msk: 0x%x val: 0x%x */\n", c, (unsigned)f_msk, (unsigned)f_val); /* Inputs end with '=', outputs with '+' */ if ((c == '=' && ph == 'i') || (c == '+' && ph == 'o')) break; switch(c) { case ' ': case '\f': case '\n': case '\r': case '\t': case '\v': continue; case '#': /* Comment character */ while ((c=getc(fp)) != EOF && c != '\n'); if (c == EOF && (nb > 0 || (ph == 'i' && nw > 0))) error(stringf("Unexpected end of file reading patterns at " "rule %d, word %c%d, bit %d", nr,ph,nw,nb)); continue; case '-': /* Denotes body of a variable */ if (!csym) /* We must be defining a variable */ error(stringf("'-' appears with no leading symbol " "at rule %d, word %c%d, bit %d", nr, ph, nw, nb)); else { /* Extend the variable's right boundary */ ++csym->r; assert(csym->r == nb); } break; case '0': case '1': /* Constant characters */ if (csym) { /* End any variable definition */ vars = mkvar(csym, vars); csym = 0L; } f_msk |= 1; f_val |= (c-'0'); break; default: c = tolower(c); /* Variables named by a-z, case insensitive */ if (c >= 'a' && c <= 'z') { char *s = stringf("%c", c); if (csym) vars = mkvar(csym, vars); if (!lookup(s, stab) && ph == 'o') error(stringf("Symbol '%c' used with no prior " "definition at rule %d, word o%d", c, nr, nw)); csym = install(s, stab); csym->l = csym->r = nb; } else error(stringf("Illegal character in rule file at rule %d, " "word %c%d, bit %d", nr, ph, nw, nb)); } if (nb == SZ-1) { /* End of a pattern (word): append this info */ pat_t *pat; /* to list of patterns, and reset current */ if (csym) { /* pattern state (masks, vars, bit count) */ vars = mkvar(csym, vars); csym = 0L; } NEW(pat, 1, ARENA0); pat->f_msk = f_msk; f_msk = (T)0; pat->f_val = f_val; f_val = (T)0; pat->nv = l_length(vars); if (debugp) fprintf(stdout, "/* msk: 0x%x, val: 0x%x, nv: 0x%x */\n", (unsigned)pat->f_msk, (unsigned)pat->f_val, pat->nv); l_ltov(pat->v, var_t *, vars, ARENA0); pats = l_append(pat, pats, ARENA0); ++nw; nb = 0; vars = 0L; } else { /* Still more to go: move on to next bit */ ++nb; f_msk <<= 1; f_val <<= 1;
void regopt(Prog *firstp) { Reg *r, *r1; Prog *p; int i, z, nr; uint32 vreg; Bits bit; if(first == 0) { fmtinstall('Q', Qconv); } fixjmp(firstp); first++; if(debug['K']) { if(first != 13) return; // debug['R'] = 2; // debug['P'] = 2; print("optimizing %S\n", curfn->nname->sym); } // count instructions nr = 0; for(p=firstp; p!=P; p=p->link) nr++; // if too big dont bother if(nr >= 10000) { // print("********** %S is too big (%d)\n", curfn->nname->sym, nr); return; } r1 = R; firstr = R; lastr = R; /* * control flow is more complicated in generated go code * than in generated c code. define pseudo-variables for * registers, so we have complete register usage information. */ nvar = NREGVAR; memset(var, 0, NREGVAR*sizeof var[0]); for(i=0; i<NREGVAR; i++) var[i].node = newname(lookup(regname[i])); regbits = RtoB(REGSP)|RtoB(REGLINK)|RtoB(REGPC); for(z=0; z<BITS; z++) { externs.b[z] = 0; params.b[z] = 0; consts.b[z] = 0; addrs.b[z] = 0; ovar.b[z] = 0; } // build list of return variables setoutvar(); /* * pass 1 * build aux data structure * allocate pcs * find use and set of variables */ nr = 0; for(p=firstp; p != P; p = p->link) { switch(p->as) { case ADATA: case AGLOBL: case ANAME: case ASIGNAME: continue; } r = rega(); nr++; if(firstr == R) { firstr = r; lastr = r; } else { lastr->link = r; r->p1 = lastr; lastr->s1 = r; lastr = r; } r->prog = p; p->regp = r; r1 = r->p1; if(r1 != R) { switch(r1->prog->as) { case ARET: case AB: case ARFE: r->p1 = R; r1->s1 = R; } } /* * left side always read */ bit = mkvar(r, &p->from); for(z=0; z<BITS; z++) r->use1.b[z] |= bit.b[z]; /* * middle always read when present */ if(p->reg != NREG) { if(p->from.type != D_FREG) r->use1.b[0] |= RtoB(p->reg); else r->use1.b[0] |= FtoB(p->reg); } /* * right side depends on opcode */ bit = mkvar(r, &p->to); if(bany(&bit)) switch(p->as) { default: yyerror("reg: unknown op: %A", p->as); break; /* * right side read */ case ATST: case ATEQ: case ACMP: case ACMN: case ACMPD: case ACMPF: rightread: for(z=0; z<BITS; z++) r->use2.b[z] |= bit.b[z]; break; /* * right side read or read+write, depending on middle * ADD x, z => z += x * ADD x, y, z => z = x + y */ case AADD: case AAND: case AEOR: case ASUB: case ARSB: case AADC: case ASBC: case ARSC: case AORR: case ABIC: case ASLL: case ASRL: case ASRA: case AMUL: case AMULU: case ADIV: case AMOD: case AMODU: case ADIVU: if(p->reg != NREG) goto rightread; // fall through /* * right side read+write */ case AADDF: case AADDD: case ASUBF: case ASUBD: case AMULF: case AMULD: case ADIVF: case ADIVD: case AMULA: case AMULAL: case AMULALU: for(z=0; z<BITS; z++) { r->use2.b[z] |= bit.b[z]; r->set.b[z] |= bit.b[z]; } break; /* * right side write */ case ANOP: case AMOVB: case AMOVBU: case AMOVD: case AMOVDF: case AMOVDW: case AMOVF: case AMOVFW: case AMOVH: case AMOVHU: case AMOVW: case AMOVWD: case AMOVWF: case AMVN: case AMULL: case AMULLU: if((p->scond & C_SCOND) != C_SCOND_NONE) for(z=0; z<BITS; z++) r->use2.b[z] |= bit.b[z]; for(z=0; z<BITS; z++) r->set.b[z] |= bit.b[z]; break; /* * funny */ case ABL: setaddrs(bit); break; } if(p->as == AMOVM) { z = p->to.offset; if(p->from.type == D_CONST) z = p->from.offset; for(i=0; z; i++) { if(z&1) regbits |= RtoB(i); z >>= 1; } } }
void regopt(Prog *firstp) { Reg *r, *r1; Prog *p; int i, z, nr; uint32 vreg; Bits bit; if(first == 0) { fmtinstall('Q', Qconv); } first++; if(debug['K']) { if(first != 13) return; // debug['R'] = 2; // debug['P'] = 2; print("optimizing %S\n", curfn->nname->sym); } // count instructions nr = 0; for(p=firstp; p!=P; p=p->link) nr++; // if too big dont bother if(nr >= 10000) { // print("********** %S is too big (%d)\n", curfn->nname->sym, nr); return; } r1 = R; firstr = R; lastr = R; nvar = 0; regbits = RtoB(REGSP)|RtoB(REGLINK)|RtoB(REGPC); for(z=0; z<BITS; z++) { externs.b[z] = 0; params.b[z] = 0; consts.b[z] = 0; addrs.b[z] = 0; ovar.b[z] = 0; } // build list of return variables setoutvar(); /* * pass 1 * build aux data structure * allocate pcs * find use and set of variables */ nr = 0; for(p=firstp; p != P; p = p->link) { switch(p->as) { case ADATA: case AGLOBL: case ANAME: case ASIGNAME: continue; } r = rega(); nr++; if(firstr == R) { firstr = r; lastr = r; } else { lastr->link = r; r->p1 = lastr; lastr->s1 = r; lastr = r; } r->prog = p; p->regp = r; r1 = r->p1; if(r1 != R) { switch(r1->prog->as) { case ARET: case AB: case ARFE: r->p1 = R; r1->s1 = R; } } /* * left side always read */ bit = mkvar(r, &p->from); for(z=0; z<BITS; z++) r->use1.b[z] |= bit.b[z]; /* * right side depends on opcode */ bit = mkvar(r, &p->to); if(bany(&bit)) switch(p->as) { default: yyerror("reg: unknown op: %A", p->as); break; /* * right side write */ case ANOP: case AMOVB: case AMOVBU: case AMOVH: case AMOVHU: case AMOVW: case AMOVF: case AMOVD: for(z=0; z<BITS; z++) r->set.b[z] |= bit.b[z]; break; /* * funny */ case ABL: setaddrs(bit); break; } if(p->as == AMOVM) { z = p->to.offset; if(p->from.type == D_CONST) z = p->from.offset; for(i=0; z; i++) { if(z&1) regbits |= RtoB(i); z >>= 1; } } }
Bits mkvar(Reg *r, Adr *a, int isro) { Var *v; int i, t, n, et, z; int32_t o; Bits bit; Sym *s; /* * mark registers used */ t = a->type; r->regu |= doregbits(t); r->regu |= doregbits(a->index); et = a->etype; switch(t) { default: goto none; case D_INDIR+D_GS: if(!isro || 1) goto none; n = t; {static Sym er; a->sym = &er;} a->sym->name = "$extreg"; break; case D_ADDR: a->type = a->index; bit = mkvar(r, a, 0); for(z=0; z<BITS; z++) addrs.b[z] |= bit.b[z]; a->type = t; goto none; case D_EXTERN: case D_STATIC: case D_PARAM: case D_AUTO: n = t; break; } s = a->sym; if(s == S) goto none; if(s->name[0] == '.') goto none; o = a->offset; v = var; for(i=0; i<nvar; i++) { if(s == v->sym) if(n == v->name) if(o == v->offset) goto out; v++; } if(nvar >= NVAR) { if(debug['w'] > 1 && s) warn(Z, "variable not optimized: %s", s->name); goto none; } i = nvar; nvar++; v = &var[i]; v->sym = s; v->offset = o; v->name = n; v->etype = et; if(debug['R']) print("bit=%2d et=%2d %D\n", i, et, a); out: bit = blsh(i); if(n == D_EXTERN || n == D_STATIC) for(z=0; z<BITS; z++) externs.b[z] |= bit.b[z]; if(n == D_PARAM) for(z=0; z<BITS; z++) params.b[z] |= bit.b[z]; if(v->etype != et || !typechlpfd[et]) /* funny punning */ for(z=0; z<BITS; z++) addrs.b[z] |= bit.b[z]; return bit; none: return zbits; }
Bits mkvar(Reg *r, Adr *a) { Var *v; int i, t, n, et, z, w, flag; int32 o; Bits bit; Sym *s; /* * mark registers used */ t = a->type; if(r != R) { r->regu |= doregbits(t); r->regu |= doregbits(a->index); } switch(t) { default: goto none; case D_ADDR: a->type = a->index; bit = mkvar(r, a); for(z=0; z<BITS; z++) addrs.b[z] |= bit.b[z]; a->type = t; ostats.naddr++; goto none; case D_EXTERN: case D_STATIC: case D_PARAM: case D_AUTO: n = t; break; } s = a->sym; if(s == S) goto none; if(s->name[0] == '.') goto none; et = a->etype; o = a->offset; w = a->width; v = var; flag = 0; for(i=0; i<nvar; i++) { if(s == v->sym) if(n == v->name) { // if it is the same, use it if(v->etype == et) if(v->width == w) if(v->offset == o) goto out; // if it overlaps, set max // width and dont registerize if(overlap(v, o, w)) flag = 1; } v++; } if(flag) goto none; switch(et) { case 0: case TFUNC: case TARRAY: goto none; } if(nvar >= NVAR) { if(debug['w'] > 1 && s) fatal("variable not optimized: %D", a); goto none; } i = nvar; nvar++; v = &var[i]; v->sym = s; v->offset = o; v->name = n; v->gotype = a->gotype; v->etype = et; v->width = w; if(debug['R']) print("bit=%2d et=%2d w=%d %D\n", i, et, w, a); ostats.nvar++; out: bit = blsh(i); // funny punning if(v->etype != et) { if(debug['R']) print("pun et=%d/%d w=%d/%d o=%d/%d %D\n", v->etype, et, v->width, w, v->offset, o, a); for(z=0; z<BITS; z++) addrs.b[z] |= bit.b[z]; goto none; } if(n == D_EXTERN || n == D_STATIC) for(z=0; z<BITS; z++) externs.b[z] |= bit.b[z]; if(n == D_PARAM) for(z=0; z<BITS; z++) params.b[z] |= bit.b[z]; return bit; none: return zbits; }
void readtext(char *s) { Dir *d; Lsym *l; Value *v; Symbol sym; ulong length; extern Machdata mipsmach; if(mtype != 0){ symmap = newmap(0, 1); if(symmap == 0) print("%s: (error) loadmap: cannot make symbol map\n", argv0); length = 1<<24; d = dirfstat(text); if(d != nil) { length = d->length; free(d); } setmap(symmap, text, 0, length, 0, "binary"); free(d); return; } machdata = &mipsmach; if(!crackhdr(text, &fhdr)) { print("can't decode file header\n"); return; } symmap = loadmap(0, text, &fhdr); if(symmap == 0) print("%s: (error) loadmap: cannot make symbol map\n", argv0); if(syminit(text, &fhdr) < 0) { print("%s: (error) syminit: %r\n", argv0); return; } print("%s:%s\n\n", s, fhdr.name); if(mach->sbreg && lookup(0, mach->sbreg, &sym)) { mach->sb = sym.value; l = enter("SB", Tid); l->v->vstore.fmt = 'X'; l->v->vstore.u0.sival = mach->sb; l->v->type = TINT; l->v->set = 1; } l = mkvar("objtype"); v = l->v; v->vstore.fmt = 's'; v->set = 1; v->vstore.u0.sstring = strnode(mach->name); v->type = TSTRING; l = mkvar("textfile"); v = l->v; v->vstore.fmt = 's'; v->set = 1; v->vstore.u0.sstring = strnode(s); v->type = TSTRING; machbytype(fhdr.type); varreg(); }
void regopt(Prog *firstp) { Reg *r, *r1; Prog *p; Graph *g; int i, z; uint32 vreg; Bits bit; ProgInfo info; if(first) { fmtinstall('Q', Qconv); first = 0; } fixjmp(firstp); mergetemp(firstp); /* * control flow is more complicated in generated go code * than in generated c code. define pseudo-variables for * registers, so we have complete register usage information. */ nvar = NREGVAR; memset(var, 0, NREGVAR*sizeof var[0]); for(i=0; i<NREGVAR; i++) { if(regnodes[i] == N) regnodes[i] = newname(lookup(regname[i])); var[i].node = regnodes[i]; } regbits = RtoB(REGSP)|RtoB(REGLINK)|RtoB(REGPC); for(z=0; z<BITS; z++) { externs.b[z] = 0; params.b[z] = 0; consts.b[z] = 0; addrs.b[z] = 0; ovar.b[z] = 0; } // build list of return variables setoutvar(); /* * pass 1 * build aux data structure * allocate pcs * find use and set of variables */ g = flowstart(firstp, sizeof(Reg)); if(g == nil) return; firstr = (Reg*)g->start; for(r = firstr; r != R; r = (Reg*)r->f.link) { p = r->f.prog; proginfo(&info, p); // Avoid making variables for direct-called functions. if(p->as == ABL && p->to.type == D_EXTERN) continue; bit = mkvar(r, &p->from); if(info.flags & LeftRead) for(z=0; z<BITS; z++) r->use1.b[z] |= bit.b[z]; if(info.flags & LeftAddr) setaddrs(bit); if(info.flags & RegRead) { if(p->from.type != D_FREG) r->use1.b[0] |= RtoB(p->reg); else r->use1.b[0] |= FtoB(p->reg); } if(info.flags & (RightAddr | RightRead | RightWrite)) { bit = mkvar(r, &p->to); if(info.flags & RightAddr) setaddrs(bit); if(info.flags & RightRead) for(z=0; z<BITS; z++) r->use2.b[z] |= bit.b[z]; if(info.flags & RightWrite) for(z=0; z<BITS; z++) r->set.b[z] |= bit.b[z]; } } if(firstr == R) return; for(i=0; i<nvar; i++) { Var *v = var+i; if(v->addr) { bit = blsh(i); for(z=0; z<BITS; z++) addrs.b[z] |= bit.b[z]; } if(debug['R'] && debug['v']) print("bit=%2d addr=%d et=%-6E w=%-2d s=%N + %lld\n", i, v->addr, v->etype, v->width, v->node, v->offset); } if(debug['R'] && debug['v']) dumpit("pass1", &firstr->f, 1); /* * pass 2 * find looping structure */ flowrpo(g); if(debug['R'] && debug['v']) dumpit("pass2", &firstr->f, 1); /* * pass 3 * iterate propagating usage * back until flow graph is complete */ loop1: change = 0; for(r = firstr; r != R; r = (Reg*)r->f.link) r->f.active = 0; for(r = firstr; r != R; r = (Reg*)r->f.link) if(r->f.prog->as == ARET) prop(r, zbits, zbits); loop11: /* pick up unreachable code */ i = 0; for(r = firstr; r != R; r = r1) { r1 = (Reg*)r->f.link; if(r1 && r1->f.active && !r->f.active) { prop(r, zbits, zbits); i = 1; } } if(i) goto loop11; if(change) goto loop1; if(debug['R'] && debug['v']) dumpit("pass3", &firstr->f, 1); /* * pass 4 * iterate propagating register/variable synchrony * forward until graph is complete */ loop2: change = 0; for(r = firstr; r != R; r = (Reg*)r->f.link) r->f.active = 0; synch(firstr, zbits); if(change) goto loop2; addsplits(); if(debug['R'] && debug['v']) dumpit("pass4", &firstr->f, 1); if(debug['R'] > 1) { print("\nprop structure:\n"); for(r = firstr; r != R; r = (Reg*)r->f.link) { print("%d:%P", r->f.loop, r->f.prog); for(z=0; z<BITS; z++) { bit.b[z] = r->set.b[z] | r->refahead.b[z] | r->calahead.b[z] | r->refbehind.b[z] | r->calbehind.b[z] | r->use1.b[z] | r->use2.b[z]; bit.b[z] &= ~addrs.b[z]; } if(bany(&bit)) { print("\t"); if(bany(&r->use1)) print(" u1=%Q", r->use1); if(bany(&r->use2)) print(" u2=%Q", r->use2); if(bany(&r->set)) print(" st=%Q", r->set); if(bany(&r->refahead)) print(" ra=%Q", r->refahead); if(bany(&r->calahead)) print(" ca=%Q", r->calahead); if(bany(&r->refbehind)) print(" rb=%Q", r->refbehind); if(bany(&r->calbehind)) print(" cb=%Q", r->calbehind); } print("\n"); } } /* * pass 4.5 * move register pseudo-variables into regu. */ for(r = firstr; r != R; r = (Reg*)r->f.link) { r->regu = (r->refbehind.b[0] | r->set.b[0]) & REGBITS; r->set.b[0] &= ~REGBITS; r->use1.b[0] &= ~REGBITS; r->use2.b[0] &= ~REGBITS; r->refbehind.b[0] &= ~REGBITS; r->refahead.b[0] &= ~REGBITS; r->calbehind.b[0] &= ~REGBITS; r->calahead.b[0] &= ~REGBITS; r->regdiff.b[0] &= ~REGBITS; r->act.b[0] &= ~REGBITS; } if(debug['R'] && debug['v']) dumpit("pass4.5", &firstr->f, 1); /* * pass 5 * isolate regions * calculate costs (paint1) */ r = firstr; if(r) { for(z=0; z<BITS; z++) bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) & ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]); if(bany(&bit) & !r->f.refset) { // should never happen - all variables are preset if(debug['w']) print("%L: used and not set: %Q\n", r->f.prog->lineno, bit); r->f.refset = 1; } } for(r = firstr; r != R; r = (Reg*)r->f.link) r->act = zbits; rgp = region; nregion = 0; for(r = firstr; r != R; r = (Reg*)r->f.link) { for(z=0; z<BITS; z++) bit.b[z] = r->set.b[z] & ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]); if(bany(&bit) && !r->f.refset) { if(debug['w']) print("%L: set and not used: %Q\n", r->f.prog->lineno, bit); r->f.refset = 1; excise(&r->f); } for(z=0; z<BITS; z++) bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]); while(bany(&bit)) { i = bnum(bit); rgp->enter = r; rgp->varno = i; change = 0; if(debug['R'] > 1) print("\n"); paint1(r, i); bit.b[i/32] &= ~(1L<<(i%32)); if(change <= 0) { if(debug['R']) print("%L $%d: %Q\n", r->f.prog->lineno, change, blsh(i)); continue; } rgp->cost = change; nregion++; if(nregion >= NRGN) { if(debug['R'] > 1) print("too many regions\n"); goto brk; } rgp++; } } brk: qsort(region, nregion, sizeof(region[0]), rcmp); if(debug['R'] && debug['v']) dumpit("pass5", &firstr->f, 1); /* * pass 6 * determine used registers (paint2) * replace code (paint3) */ rgp = region; for(i=0; i<nregion; i++) { bit = blsh(rgp->varno); vreg = paint2(rgp->enter, rgp->varno); vreg = allreg(vreg, rgp); if(debug['R']) { if(rgp->regno >= NREG) print("%L $%d F%d: %Q\n", rgp->enter->f.prog->lineno, rgp->cost, rgp->regno-NREG, bit); else print("%L $%d R%d: %Q\n", rgp->enter->f.prog->lineno, rgp->cost, rgp->regno, bit); } if(rgp->regno != 0) paint3(rgp->enter, rgp->varno, vreg, rgp->regno); rgp++; } if(debug['R'] && debug['v']) dumpit("pass6", &firstr->f, 1); /* * pass 7 * peep-hole on basic block */ if(!debug['R'] || debug['P']) { peep(firstp); } if(debug['R'] && debug['v']) dumpit("pass7", &firstr->f, 1); /* * last pass * eliminate nops * free aux structures * adjust the stack pointer * MOVW.W R1,-12(R13) <<- start * MOVW R0,R1 * MOVW R1,8(R13) * MOVW $0,R1 * MOVW R1,4(R13) * BL ,runtime.newproc+0(SB) * MOVW &ft+-32(SP),R7 <<- adjust * MOVW &j+-40(SP),R6 <<- adjust * MOVW autotmp_0003+-24(SP),R5 <<- adjust * MOVW $12(R13),R13 <<- finish */ vreg = 0; for(p = firstp; p != P; p = p->link) { while(p->link != P && p->link->as == ANOP) p->link = p->link->link; if(p->to.type == D_BRANCH) while(p->to.u.branch != P && p->to.u.branch->as == ANOP) p->to.u.branch = p->to.u.branch->link; if(p->as == AMOVW && p->to.reg == 13) { if(p->scond & C_WBIT) { vreg = -p->to.offset; // in adjust region // print("%P adjusting %d\n", p, vreg); continue; } if(p->from.type == D_CONST && p->to.type == D_REG) { if(p->from.offset != vreg) print("in and out different\n"); // print("%P finish %d\n", p, vreg); vreg = 0; // done adjust region continue; } // print("%P %d %d from type\n", p, p->from.type, D_CONST); // print("%P %d %d to type\n\n", p, p->to.type, D_REG); } if(p->as == AMOVW && vreg != 0) { if(p->from.sym != S) if(p->from.name == D_AUTO || p->from.name == D_PARAM) { p->from.offset += vreg; // print("%P adjusting from %d %d\n", p, vreg, p->from.type); } if(p->to.sym != S) if(p->to.name == D_AUTO || p->to.name == D_PARAM) { p->to.offset += vreg; // print("%P adjusting to %d %d\n", p, vreg, p->from.type); } } } flowend(g); }
void regopt(Prog *p) { Reg *r, *r1, *r2; Prog *p1; int i, z; long initpc, val, npc; ulong vreg; Bits bit; struct { long m; long c; Reg* p; } log5[6], *lp; firstr = R; lastr = R; nvar = 0; regbits = 0; for(z=0; z<BITS; z++) { externs.b[z] = 0; params.b[z] = 0; consts.b[z] = 0; addrs.b[z] = 0; } /* * pass 1 * build aux data structure * allocate pcs * find use and set of variables */ val = 5L * 5L * 5L * 5L * 5L; lp = log5; for(i=0; i<5; i++) { lp->m = val; lp->c = 0; lp->p = R; val /= 5L; lp++; } val = 0; for(; p != P; p = p->link) { switch(p->as) { case ADATA: case AGLOBL: case ANAME: case ASIGNAME: continue; } r = rega(); if(firstr == R) { firstr = r; lastr = r; } else { lastr->link = r; r->p1 = lastr; lastr->s1 = r; lastr = r; } r->prog = p; r->pc = val; val++; lp = log5; for(i=0; i<5; i++) { lp->c--; if(lp->c <= 0) { lp->c = lp->m; if(lp->p != R) lp->p->log5 = r; lp->p = r; (lp+1)->c = 0; break; } lp++; } r1 = r->p1; if(r1 != R) switch(r1->prog->as) { case ARETURN: case ABR: case ARFI: case ARFCI: case ARFID: r->p1 = R; r1->s1 = R; } /* * left side always read */ bit = mkvar(&p->from, p->as==AMOVW || p->as == AMOVWZ || p->as == AMOVD); for(z=0; z<BITS; z++) r->use1.b[z] |= bit.b[z]; /* * right side depends on opcode */ bit = mkvar(&p->to, 0); if(bany(&bit)) switch(p->as) { default: diag(Z, "reg: unknown asop: %A", p->as); break; /* * right side write */ case ANOP: case AMOVB: case AMOVBU: case AMOVBZ: case AMOVBZU: case AMOVH: case AMOVHBR: case AMOVWBR: case AMOVHU: case AMOVHZ: case AMOVHZU: case AMOVW: case AMOVWU: case AMOVWZ: case AMOVWZU: case AMOVD: case AMOVDU: case AFMOVD: case AFMOVDCC: case AFMOVDU: case AFMOVS: case AFMOVSU: case AFRSP: for(z=0; z<BITS; z++) r->set.b[z] |= bit.b[z]; break; /* * funny */ case ABL: for(z=0; z<BITS; z++) addrs.b[z] |= bit.b[z]; break; } } if(firstr == R) return; initpc = pc - val; npc = val; /* * pass 2 * turn branch references to pointers * build back pointers */ for(r = firstr; r != R; r = r->link) { p = r->prog; if(p->to.type == D_BRANCH) { val = p->to.offset - initpc; r1 = firstr; while(r1 != R) { r2 = r1->log5; if(r2 != R && val >= r2->pc) { r1 = r2; continue; } if(r1->pc == val) break; r1 = r1->link; } if(r1 == R) { nearln = p->lineno; diag(Z, "ref not found\n%P", p); continue; } if(r1 == r) { nearln = p->lineno; diag(Z, "ref to self\n%P", p); continue; } r->s2 = r1; r->p2link = r1->p2; r1->p2 = r; } } if(debug['R']) { p = firstr->prog; print("\n%L %D\n", p->lineno, &p->from); } /* * pass 2.5 * find looping structure */ for(r = firstr; r != R; r = r->link) r->active = 0; change = 0; loopit(firstr, npc); if(debug['R'] && debug['v']) { print("\nlooping structure:\n"); for(r = firstr; r != R; r = r->link) { print("%ld:%P", r->loop, r->prog); for(z=0; z<BITS; z++) bit.b[z] = r->use1.b[z] | r->use2.b[z] | r->set.b[z]; if(bany(&bit)) { print("\t"); if(bany(&r->use1)) print(" u1=%B", r->use1); if(bany(&r->use2)) print(" u2=%B", r->use2); if(bany(&r->set)) print(" st=%B", r->set); } print("\n"); } } /* * pass 3 * iterate propagating usage * back until flow graph is complete */ loop1: change = 0; for(r = firstr; r != R; r = r->link) r->active = 0; for(r = firstr; r != R; r = r->link) if(r->prog->as == ARETURN) prop(r, zbits, zbits); loop11: /* pick up unreachable code */ i = 0; for(r = firstr; r != R; r = r1) { r1 = r->link; if(r1 && r1->active && !r->active) { prop(r, zbits, zbits); i = 1; } } if(i) goto loop11; if(change) goto loop1; /* * pass 4 * iterate propagating register/variable synchrony * forward until graph is complete */ loop2: change = 0; for(r = firstr; r != R; r = r->link) r->active = 0; synch(firstr, zbits); if(change) goto loop2; /* * pass 5 * isolate regions * calculate costs (paint1) */ r = firstr; if(r) { for(z=0; z<BITS; z++) bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) & ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]); if(bany(&bit)) { nearln = r->prog->lineno; warn(Z, "used and not set: %B", bit); if(debug['R'] && !debug['w']) print("used and not set: %B\n", bit); } } if(debug['R'] && debug['v']) print("\nprop structure:\n"); for(r = firstr; r != R; r = r->link) r->act = zbits; rgp = region; nregion = 0; for(r = firstr; r != R; r = r->link) { if(debug['R'] && debug['v']) print("%P\n set = %B; rah = %B; cal = %B\n", r->prog, r->set, r->refahead, r->calahead); for(z=0; z<BITS; z++) bit.b[z] = r->set.b[z] & ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]); if(bany(&bit)) { nearln = r->prog->lineno; warn(Z, "set and not used: %B", bit); if(debug['R']) print("set an not used: %B\n", bit); excise(r); } for(z=0; z<BITS; z++) bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]); while(bany(&bit)) { i = bnum(bit); rgp->enter = r; rgp->varno = i; change = 0; if(debug['R'] && debug['v']) print("\n"); paint1(r, i); bit.b[i/32] &= ~(1L<<(i%32)); if(change <= 0) { if(debug['R']) print("%L$%d: %B\n", r->prog->lineno, change, blsh(i)); continue; } rgp->cost = change; nregion++; if(nregion >= NRGN) { warn(Z, "too many regions"); goto brk; } rgp++; } } brk: qsort(region, nregion, sizeof(region[0]), rcmp); /* * pass 6 * determine used registers (paint2) * replace code (paint3) */ rgp = region; for(i=0; i<nregion; i++) { bit = blsh(rgp->varno); vreg = paint2(rgp->enter, rgp->varno); vreg = allreg(vreg, rgp); if(debug['R']) { if(rgp->regno >= NREG) print("%L$%d F%d: %B\n", rgp->enter->prog->lineno, rgp->cost, rgp->regno-NREG, bit); else print("%L$%d R%d: %B\n", rgp->enter->prog->lineno, rgp->cost, rgp->regno, bit); } if(rgp->regno != 0) paint3(rgp->enter, rgp->varno, vreg, rgp->regno); rgp++; } /* * pass 7 * peep-hole on basic block */ if(!debug['R'] || debug['P']) peep(); /* * pass 8 * recalculate pc */ val = initpc; for(r = firstr; r != R; r = r1) { r->pc = val; p = r->prog; p1 = P; r1 = r->link; if(r1 != R) p1 = r1->prog; for(; p != p1; p = p->link) { switch(p->as) { default: val++; break; case ANOP: case ADATA: case AGLOBL: case ANAME: case ASIGNAME: break; } } } pc = val; /* * fix up branches */ if(debug['R']) if(bany(&addrs)) print("addrs: %B\n", addrs); r1 = 0; /* set */ for(r = firstr; r != R; r = r->link) { p = r->prog; if(p->to.type == D_BRANCH) p->to.offset = r->s2->pc; r1 = r; } /* * last pass * eliminate nops * free aux structures */ for(p = firstr->prog; p != P; p = p->link){ while(p->link && p->link->as == ANOP) p->link = p->link->link; } if(r1 != R) { r1->link = freer; freer = firstr; } }
void regopt(Prog *p) { Reg *r, *r1, *r2; Prog *p1; int i, z; int32_t initpc, val, npc; uint32_t vreg; Bits bit; struct { int32_t m; int32_t c; Reg* p; } log5[6], *lp; firstr = R; lastr = R; nvar = 0; regbits = RtoB(D_SP) | RtoB(D_AX); for(z=0; z<BITS; z++) { externs.b[z] = 0; params.b[z] = 0; consts.b[z] = 0; addrs.b[z] = 0; } /* * pass 1 * build aux data structure * allocate pcs * find use and set of variables */ val = 5L * 5L * 5L * 5L * 5L; lp = log5; for(i=0; i<5; i++) { lp->m = val; lp->c = 0; lp->p = R; val /= 5L; lp++; } val = 0; for(; p != P; p = p->link) { switch(p->as) { case ADATA: case AGLOBL: case ANAME: case ASIGNAME: continue; } r = rega(); if(firstr == R) { firstr = r; lastr = r; } else { lastr->link = r; r->p1 = lastr; lastr->s1 = r; lastr = r; } r->prog = p; r->pc = val; val++; lp = log5; for(i=0; i<5; i++) { lp->c--; if(lp->c <= 0) { lp->c = lp->m; if(lp->p != R) lp->p->log5 = r; lp->p = r; (lp+1)->c = 0; break; } lp++; } r1 = r->p1; if(r1 != R) switch(r1->prog->as) { case ARET: case AJMP: case AIRETL: r->p1 = R; r1->s1 = R; } bit = mkvar(r, &p->from, p->as==AMOVL); if(bany(&bit)) switch(p->as) { /* * funny */ case ALEAL: for(z=0; z<BITS; z++) addrs.b[z] |= bit.b[z]; break; /* * left side read */ default: for(z=0; z<BITS; z++) r->use1.b[z] |= bit.b[z]; break; } bit = mkvar(r, &p->to, 0); if(bany(&bit)) switch(p->as) { default: diag(Z, "reg: unknown op: %A", p->as); break; /* * right side read */ case ACMPB: case ACMPL: case ACMPW: for(z=0; z<BITS; z++) r->use2.b[z] |= bit.b[z]; break; /* * right side write */ case ANOP: case AMOVL: case AMOVB: case AMOVW: case AMOVBLSX: case AMOVBLZX: case AMOVWLSX: case AMOVWLZX: for(z=0; z<BITS; z++) r->set.b[z] |= bit.b[z]; break; /* * right side read+write */ case AADDB: case AADDL: case AADDW: case AANDB: case AANDL: case AANDW: case ASUBB: case ASUBL: case ASUBW: case AORB: case AORL: case AORW: case AXORB: case AXORL: case AXORW: case ASALB: case ASALL: case ASALW: case ASARB: case ASARL: case ASARW: case AROLB: case AROLL: case AROLW: case ARORB: case ARORL: case ARORW: case ASHLB: case ASHLL: case ASHLW: case ASHRB: case ASHRL: case ASHRW: case AIMULL: case AIMULW: case ANEGL: case ANOTL: case AADCL: case ASBBL: for(z=0; z<BITS; z++) { r->set.b[z] |= bit.b[z]; r->use2.b[z] |= bit.b[z]; } break; /* * funny */ case AFMOVDP: case AFMOVFP: case AFMOVLP: case AFMOVVP: case AFMOVWP: case ACALL: for(z=0; z<BITS; z++) addrs.b[z] |= bit.b[z]; break; } switch(p->as) { case AIMULL: case AIMULW: if(p->to.type != D_NONE) break; case AIDIVB: case AIDIVL: case AIDIVW: case AIMULB: case ADIVB: case ADIVL: case ADIVW: case AMULB: case AMULL: case AMULW: case ACWD: case ACDQ: r->regu |= RtoB(D_AX) | RtoB(D_DX); break; case AREP: case AREPN: case ALOOP: case ALOOPEQ: case ALOOPNE: r->regu |= RtoB(D_CX); break; case AMOVSB: case AMOVSL: case AMOVSW: case ACMPSB: case ACMPSL: case ACMPSW: r->regu |= RtoB(D_SI) | RtoB(D_DI); break; case ASTOSB: case ASTOSL: case ASTOSW: case ASCASB: case ASCASL: case ASCASW: r->regu |= RtoB(D_AX) | RtoB(D_DI); break; case AINSB: case AINSL: case AINSW: case AOUTSB: case AOUTSL: case AOUTSW: r->regu |= RtoB(D_DI) | RtoB(D_DX); break; case AFSTSW: case ASAHF: r->regu |= RtoB(D_AX); break; } } if(firstr == R) return; initpc = pc - val; npc = val; /* * pass 2 * turn branch references to pointers * build back pointers */ for(r = firstr; r != R; r = r->link) { p = r->prog; if(p->to.type == D_BRANCH) { val = p->to.offset - initpc; r1 = firstr; while(r1 != R) { r2 = r1->log5; if(r2 != R && val >= r2->pc) { r1 = r2; continue; } if(r1->pc == val) break; r1 = r1->link; } if(r1 == R) { nearln = p->lineno; diag(Z, "ref not found\n%P", p); continue; } if(r1 == r) { nearln = p->lineno; diag(Z, "ref to self\n%P", p); continue; } r->s2 = r1; r->p2link = r1->p2; r1->p2 = r; } } if(debug['R']) { p = firstr->prog; print("\n%L %D\n", p->lineno, &p->from); } /* * pass 2.5 * find looping structure */ for(r = firstr; r != R; r = r->link) r->active = 0; change = 0; loopit(firstr, npc); if(debug['R'] && debug['v']) { print("\nlooping structure:\n"); for(r = firstr; r != R; r = r->link) { print("%ld:%P", r->loop, r->prog); for(z=0; z<BITS; z++) bit.b[z] = r->use1.b[z] | r->use2.b[z] | r->set.b[z]; if(bany(&bit)) { print("\t"); if(bany(&r->use1)) print(" u1=%B", r->use1); if(bany(&r->use2)) print(" u2=%B", r->use2); if(bany(&r->set)) print(" st=%B", r->set); } print("\n"); } } /* * pass 3 * iterate propagating usage * back until flow graph is complete */ loop1: change = 0; for(r = firstr; r != R; r = r->link) r->active = 0; for(r = firstr; r != R; r = r->link) if(r->prog->as == ARET) prop(r, zbits, zbits); loop11: /* pick up unreachable code */ i = 0; for(r = firstr; r != R; r = r1) { r1 = r->link; if(r1 && r1->active && !r->active) { prop(r, zbits, zbits); i = 1; } } if(i) goto loop11; if(change) goto loop1; /* * pass 4 * iterate propagating register/variable synchrony * forward until graph is complete */ loop2: change = 0; for(r = firstr; r != R; r = r->link) r->active = 0; synch(firstr, zbits); if(change) goto loop2; /* * pass 5 * isolate regions * calculate costs (paint1) */ r = firstr; if(r) { for(z=0; z<BITS; z++) bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) & ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]); if(bany(&bit)) { nearln = r->prog->lineno; warn(Z, "used and not set: %B", bit); if(debug['R'] && !debug['w']) print("used and not set: %B\n", bit); } } if(debug['R'] && debug['v']) print("\nprop structure:\n"); for(r = firstr; r != R; r = r->link) r->act = zbits; rgp = region; nregion = 0; for(r = firstr; r != R; r = r->link) { if(debug['R'] && debug['v']) { print("%P\t", r->prog); if(bany(&r->set)) print("s:%B ", r->set); if(bany(&r->refahead)) print("ra:%B ", r->refahead); if(bany(&r->calahead)) print("ca:%B ", r->calahead); print("\n"); } for(z=0; z<BITS; z++) bit.b[z] = r->set.b[z] & ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]); if(bany(&bit)) { nearln = r->prog->lineno; warn(Z, "set and not used: %B", bit); if(debug['R']) print("set and not used: %B\n", bit); excise(r); } for(z=0; z<BITS; z++) bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]); while(bany(&bit)) { i = bnum(bit); rgp->enter = r; rgp->varno = i; change = 0; if(debug['R'] && debug['v']) print("\n"); paint1(r, i); bit.b[i/32] &= ~(1L<<(i%32)); if(change <= 0) { if(debug['R']) print("%L$%d: %B\n", r->prog->lineno, change, blsh(i)); continue; } rgp->cost = change; nregion++; if(nregion >= NRGN) { warn(Z, "too many regions"); goto brk; } rgp++; } } brk: qsort(region, nregion, sizeof(region[0]), rcmp); /* * pass 6 * determine used registers (paint2) * replace code (paint3) */ rgp = region; for(i=0; i<nregion; i++) { bit = blsh(rgp->varno); vreg = paint2(rgp->enter, rgp->varno); vreg = allreg(vreg, rgp); if(debug['R']) { print("%L$%d %R: %B\n", rgp->enter->prog->lineno, rgp->cost, rgp->regno, bit); } if(rgp->regno != 0) paint3(rgp->enter, rgp->varno, vreg, rgp->regno); rgp++; } /* * pass 7 * peep-hole on basic block */ if(!debug['R'] || debug['P']) peep(); /* * pass 8 * recalculate pc */ val = initpc; for(r = firstr; r != R; r = r1) { r->pc = val; p = r->prog; p1 = P; r1 = r->link; if(r1 != R) p1 = r1->prog; for(; p != p1; p = p->link) { switch(p->as) { default: val++; break; case ANOP: case ADATA: case AGLOBL: case ANAME: case ASIGNAME: break; } } } pc = val; /* * fix up branches */ if(debug['R']) if(bany(&addrs)) print("addrs: %B\n", addrs); r1 = 0; /* set */ for(r = firstr; r != R; r = r->link) { p = r->prog; if(p->to.type == D_BRANCH) p->to.offset = r->s2->pc; r1 = r; } /* * last pass * eliminate nops * free aux structures */ for(p = firstr->prog; p != P; p = p->link){ while(p->link && p->link->as == ANOP) p->link = p->link->link; } if(r1 != R) { r1->link = freer; freer = firstr; } }
Bits mkvar(Reg *r, Adr *a) { Var *v; int i, t, n, et, z, w, flag; uint32 regu; int32 o; Bits bit; Sym *s; /* * mark registers used */ t = a->type; if(t == D_NONE) goto none; if(r != R) r->use1.b[0] |= doregbits(a->index); switch(t) { default: regu = doregbits(t); if(regu == 0) goto none; bit = zbits; bit.b[0] = regu; return bit; case D_ADDR: a->type = a->index; bit = mkvar(r, a); setaddrs(bit); a->type = t; ostats.naddr++; goto none; case D_EXTERN: case D_STATIC: case D_PARAM: case D_AUTO: n = t; break; } s = a->sym; if(s == S) goto none; if(s->name[0] == '.') goto none; et = a->etype; o = a->offset; w = a->width; flag = 0; for(i=0; i<nvar; i++) { v = var+i; if(v->sym == s && v->name == n) { if(v->offset == o) if(v->etype == et) if(v->width == w) return blsh(i); // if they overlaps, disable both if(overlap(v->offset, v->width, o, w)) { // print("disable overlap %s %d %d %d %d, %E != %E\n", s->name, v->offset, v->width, o, w, v->etype, et); v->addr = 1; flag = 1; } } } if(a->pun) { // print("disable pun %s\n", s->name); flag = 1; } switch(et) { case 0: case TFUNC: goto none; } if(nvar >= NVAR) { if(debug['w'] > 1 && s) fatal("variable not optimized: %D", a); goto none; } i = nvar; nvar++; v = var+i; v->sym = s; v->offset = o; v->name = n; v->gotype = a->gotype; v->etype = et; v->width = w; v->addr = flag; // funny punning if(debug['R']) print("bit=%2d et=%2d w=%d %S %D\n", i, et, w, s, a); ostats.nvar++; bit = blsh(i); if(n == D_EXTERN || n == D_STATIC) for(z=0; z<BITS; z++) externs.b[z] |= bit.b[z]; if(n == D_PARAM) for(z=0; z<BITS; z++) params.b[z] |= bit.b[z]; return bit; none: return zbits; }
void regopt(Prog *firstp) { Reg *r, *r1; Prog *p; Graph *g; ProgInfo info; int i, z; uint32 vreg; Bits bit; if(first) { fmtinstall('Q', Qconv); exregoffset = D_R15; first = 0; } mergetemp(firstp); /* * control flow is more complicated in generated go code * than in generated c code. define pseudo-variables for * registers, so we have complete register usage information. */ nvar = NREGVAR; memset(var, 0, NREGVAR*sizeof var[0]); for(i=0; i<NREGVAR; i++) { if(regnodes[i] == N) regnodes[i] = newname(lookup(regname[i])); var[i].node = regnodes[i]; } regbits = RtoB(D_SP); for(z=0; z<BITS; z++) { externs.b[z] = 0; params.b[z] = 0; consts.b[z] = 0; addrs.b[z] = 0; ovar.b[z] = 0; } // build list of return variables setoutvar(); /* * pass 1 * build aux data structure * allocate pcs * find use and set of variables */ g = flowstart(firstp, sizeof(Reg)); if(g == nil) return; firstr = (Reg*)g->start; for(r = firstr; r != R; r = (Reg*)r->f.link) { p = r->f.prog; if(p->as == AVARDEF) continue; proginfo(&info, p); // Avoid making variables for direct-called functions. if(p->as == ACALL && p->to.type == D_EXTERN) continue; r->use1.b[0] |= info.reguse | info.regindex; r->set.b[0] |= info.regset; bit = mkvar(r, &p->from); if(bany(&bit)) { if(info.flags & LeftAddr) setaddrs(bit); if(info.flags & LeftRead) for(z=0; z<BITS; z++) r->use1.b[z] |= bit.b[z]; if(info.flags & LeftWrite) for(z=0; z<BITS; z++) r->set.b[z] |= bit.b[z]; } bit = mkvar(r, &p->to); if(bany(&bit)) { if(info.flags & RightAddr) setaddrs(bit); if(info.flags & RightRead) for(z=0; z<BITS; z++) r->use2.b[z] |= bit.b[z]; if(info.flags & RightWrite) for(z=0; z<BITS; z++) r->set.b[z] |= bit.b[z]; } } for(i=0; i<nvar; i++) { Var *v = var+i; if(v->addr) { bit = blsh(i); for(z=0; z<BITS; z++) addrs.b[z] |= bit.b[z]; } if(debug['R'] && debug['v']) print("bit=%2d addr=%d et=%-6E w=%-2d s=%N + %lld\n", i, v->addr, v->etype, v->width, v->node, v->offset); } if(debug['R'] && debug['v']) dumpit("pass1", &firstr->f, 1); /* * pass 2 * find looping structure */ flowrpo(g); if(debug['R'] && debug['v']) dumpit("pass2", &firstr->f, 1); /* * pass 3 * iterate propagating usage * back until flow graph is complete */ loop1: change = 0; for(r = firstr; r != R; r = (Reg*)r->f.link) r->f.active = 0; for(r = firstr; r != R; r = (Reg*)r->f.link) if(r->f.prog->as == ARET) prop(r, zbits, zbits); loop11: /* pick up unreachable code */ i = 0; for(r = firstr; r != R; r = r1) { r1 = (Reg*)r->f.link; if(r1 && r1->f.active && !r->f.active) { prop(r, zbits, zbits); i = 1; } } if(i) goto loop11; if(change) goto loop1; if(debug['R'] && debug['v']) dumpit("pass3", &firstr->f, 1); /* * pass 4 * iterate propagating register/variable synchrony * forward until graph is complete */ loop2: change = 0; for(r = firstr; r != R; r = (Reg*)r->f.link) r->f.active = 0; synch(firstr, zbits); if(change) goto loop2; if(debug['R'] && debug['v']) dumpit("pass4", &firstr->f, 1); /* * pass 4.5 * move register pseudo-variables into regu. */ for(r = firstr; r != R; r = (Reg*)r->f.link) { r->regu = (r->refbehind.b[0] | r->set.b[0]) & REGBITS; r->set.b[0] &= ~REGBITS; r->use1.b[0] &= ~REGBITS; r->use2.b[0] &= ~REGBITS; r->refbehind.b[0] &= ~REGBITS; r->refahead.b[0] &= ~REGBITS; r->calbehind.b[0] &= ~REGBITS; r->calahead.b[0] &= ~REGBITS; r->regdiff.b[0] &= ~REGBITS; r->act.b[0] &= ~REGBITS; } /* * pass 5 * isolate regions * calculate costs (paint1) */ r = firstr; if(r) { for(z=0; z<BITS; z++) bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) & ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]); if(bany(&bit) && !r->f.refset) { // should never happen - all variables are preset if(debug['w']) print("%L: used and not set: %Q\n", r->f.prog->lineno, bit); r->f.refset = 1; } } for(r = firstr; r != R; r = (Reg*)r->f.link) r->act = zbits; rgp = region; nregion = 0; for(r = firstr; r != R; r = (Reg*)r->f.link) { for(z=0; z<BITS; z++) bit.b[z] = r->set.b[z] & ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]); if(bany(&bit) && !r->f.refset) { if(debug['w']) print("%L: set and not used: %Q\n", r->f.prog->lineno, bit); r->f.refset = 1; excise(&r->f); } for(z=0; z<BITS; z++) bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]); while(bany(&bit)) { i = bnum(bit); rgp->enter = r; rgp->varno = i; change = 0; paint1(r, i); bit.b[i/32] &= ~(1L<<(i%32)); if(change <= 0) continue; rgp->cost = change; nregion++; if(nregion >= NRGN) { if(debug['R'] && debug['v']) print("too many regions\n"); goto brk; } rgp++; } } brk: qsort(region, nregion, sizeof(region[0]), rcmp); if(debug['R'] && debug['v']) dumpit("pass5", &firstr->f, 1); /* * pass 6 * determine used registers (paint2) * replace code (paint3) */ rgp = region; for(i=0; i<nregion; i++) { bit = blsh(rgp->varno); vreg = paint2(rgp->enter, rgp->varno); vreg = allreg(vreg, rgp); if(rgp->regno != 0) { if(debug['R'] && debug['v']) { Var *v; v = var + rgp->varno; print("registerize %N+%lld (bit=%2d et=%2E) in %R\n", v->node, v->offset, rgp->varno, v->etype, rgp->regno); } paint3(rgp->enter, rgp->varno, vreg, rgp->regno); } rgp++; } if(debug['R'] && debug['v']) dumpit("pass6", &firstr->f, 1); /* * free aux structures. peep allocates new ones. */ flowend(g); firstr = R; /* * pass 7 * peep-hole on basic block */ if(!debug['R'] || debug['P']) peep(firstp); /* * eliminate nops */ for(p=firstp; p!=P; p=p->link) { while(p->link != P && p->link->as == ANOP) p->link = p->link->link; if(p->to.type == D_BRANCH) while(p->to.u.branch != P && p->to.u.branch->as == ANOP) p->to.u.branch = p->to.u.branch->link; } if(debug['R']) { if(ostats.ncvtreg || ostats.nspill || ostats.nreload || ostats.ndelmov || ostats.nvar || ostats.naddr || 0) print("\nstats\n"); if(ostats.ncvtreg) print(" %4d cvtreg\n", ostats.ncvtreg); if(ostats.nspill) print(" %4d spill\n", ostats.nspill); if(ostats.nreload) print(" %4d reload\n", ostats.nreload); if(ostats.ndelmov) print(" %4d delmov\n", ostats.ndelmov); if(ostats.nvar) print(" %4d var\n", ostats.nvar); if(ostats.naddr) print(" %4d addr\n", ostats.naddr); memset(&ostats, 0, sizeof(ostats)); } }
void regopt(Prog *firstp) { Reg *r, *r1; Prog *p; int i, z, nr; uint32 vreg; Bits bit; if(first) { fmtinstall('Q', Qconv); exregoffset = D_DI; // no externals first = 0; } fixjmp(firstp); // count instructions nr = 0; for(p=firstp; p!=P; p=p->link) nr++; // if too big dont bother if(nr >= 10000) { // print("********** %S is too big (%d)\n", curfn->nname->sym, nr); return; } r1 = R; firstr = R; lastr = R; /* * control flow is more complicated in generated go code * than in generated c code. define pseudo-variables for * registers, so we have complete register usage information. */ nvar = NREGVAR; memset(var, 0, NREGVAR*sizeof var[0]); for(i=0; i<NREGVAR; i++) var[i].node = newname(lookup(regname[i])); regbits = RtoB(D_SP); for(z=0; z<BITS; z++) { externs.b[z] = 0; params.b[z] = 0; consts.b[z] = 0; addrs.b[z] = 0; ovar.b[z] = 0; } // build list of return variables setoutvar(); /* * pass 1 * build aux data structure * allocate pcs * find use and set of variables */ nr = 0; for(p=firstp; p!=P; p=p->link) { switch(p->as) { case ADATA: case AGLOBL: case ANAME: case ASIGNAME: continue; } r = rega(); nr++; if(firstr == R) { firstr = r; lastr = r; } else { lastr->link = r; r->p1 = lastr; lastr->s1 = r; lastr = r; } r->prog = p; p->reg = r; r1 = r->p1; if(r1 != R) { switch(r1->prog->as) { case ARET: case AJMP: case AIRETL: r->p1 = R; r1->s1 = R; } } bit = mkvar(r, &p->from); if(bany(&bit)) switch(p->as) { /* * funny */ case ALEAL: case AFMOVL: case AFMOVW: case AFMOVV: setaddrs(bit); break; /* * left side read */ default: for(z=0; z<BITS; z++) r->use1.b[z] |= bit.b[z]; break; /* * left side read+write */ case AXCHGB: case AXCHGW: case AXCHGL: for(z=0; z<BITS; z++) { r->use1.b[z] |= bit.b[z]; r->set.b[z] |= bit.b[z]; } break; } bit = mkvar(r, &p->to); if(bany(&bit)) switch(p->as) { default: yyerror("reg: unknown op: %A", p->as); break; /* * right side read */ case ACMPB: case ACMPL: case ACMPW: case ATESTB: case ATESTL: case ATESTW: for(z=0; z<BITS; z++) r->use2.b[z] |= bit.b[z]; break; /* * right side write */ case AFSTSW: case ALEAL: case ANOP: case AMOVL: case AMOVB: case AMOVW: case AMOVBLSX: case AMOVBLZX: case AMOVBWSX: case AMOVBWZX: case AMOVWLSX: case AMOVWLZX: case APOPL: for(z=0; z<BITS; z++) r->set.b[z] |= bit.b[z]; break; /* * right side read+write */ case AINCB: case AINCL: case AINCW: case ADECB: case ADECL: case ADECW: case AADDB: case AADDL: case AADDW: case AANDB: case AANDL: case AANDW: case ASUBB: case ASUBL: case ASUBW: case AORB: case AORL: case AORW: case AXORB: case AXORL: case AXORW: case ASALB: case ASALL: case ASALW: case ASARB: case ASARL: case ASARW: case ARCLB: case ARCLL: case ARCLW: case ARCRB: case ARCRL: case ARCRW: case AROLB: case AROLL: case AROLW: case ARORB: case ARORL: case ARORW: case ASHLB: case ASHLL: case ASHLW: case ASHRB: case ASHRL: case ASHRW: case AIMULL: case AIMULW: case ANEGB: case ANEGL: case ANEGW: case ANOTB: case ANOTL: case ANOTW: case AADCL: case ASBBL: case ASETCC: case ASETCS: case ASETEQ: case ASETGE: case ASETGT: case ASETHI: case ASETLE: case ASETLS: case ASETLT: case ASETMI: case ASETNE: case ASETOC: case ASETOS: case ASETPC: case ASETPL: case ASETPS: case AXCHGB: case AXCHGW: case AXCHGL: for(z=0; z<BITS; z++) { r->set.b[z] |= bit.b[z]; r->use2.b[z] |= bit.b[z]; } break; /* * funny */ case AFMOVDP: case AFMOVFP: case AFMOVLP: case AFMOVVP: case AFMOVWP: case ACALL: setaddrs(bit); break; } switch(p->as) { case AIMULL: case AIMULW: if(p->to.type != D_NONE) break; case AIDIVL: case AIDIVW: case ADIVL: case ADIVW: case AMULL: case AMULW: r->set.b[0] |= RtoB(D_AX) | RtoB(D_DX); r->use1.b[0] |= RtoB(D_AX) | RtoB(D_DX); break; case AIDIVB: case AIMULB: case ADIVB: case AMULB: r->set.b[0] |= RtoB(D_AX); r->use1.b[0] |= RtoB(D_AX); break; case ACWD: r->set.b[0] |= RtoB(D_AX) | RtoB(D_DX); r->use1.b[0] |= RtoB(D_AX); break; case ACDQ: r->set.b[0] |= RtoB(D_DX); r->use1.b[0] |= RtoB(D_AX); break; case AREP: case AREPN: case ALOOP: case ALOOPEQ: case ALOOPNE: r->set.b[0] |= RtoB(D_CX); r->use1.b[0] |= RtoB(D_CX); break; case AMOVSB: case AMOVSL: case AMOVSW: case ACMPSB: case ACMPSL: case ACMPSW: r->set.b[0] |= RtoB(D_SI) | RtoB(D_DI); r->use1.b[0] |= RtoB(D_SI) | RtoB(D_DI); break; case ASTOSB: case ASTOSL: case ASTOSW: case ASCASB: case ASCASL: case ASCASW: r->set.b[0] |= RtoB(D_DI); r->use1.b[0] |= RtoB(D_AX) | RtoB(D_DI); break; case AINSB: case AINSL: case AINSW: r->set.b[0] |= RtoB(D_DX) | RtoB(D_DI); r->use1.b[0] |= RtoB(D_DI); break; case AOUTSB: case AOUTSL: case AOUTSW: r->set.b[0] |= RtoB(D_DI); r->use1.b[0] |= RtoB(D_DX) | RtoB(D_DI); break; } } if(firstr == R) return; for(i=0; i<nvar; i++) { Var *v = var+i; if(v->addr) { bit = blsh(i); for(z=0; z<BITS; z++) addrs.b[z] |= bit.b[z]; } // print("bit=%2d addr=%d et=%-6E w=%-2d s=%S + %lld\n", // i, v->addr, v->etype, v->width, v->sym, v->offset); } if(debug['R'] && debug['v']) dumpit("pass1", firstr); /* * pass 2 * turn branch references to pointers * build back pointers */ for(r=firstr; r!=R; r=r->link) { p = r->prog; if(p->to.type == D_BRANCH) { if(p->to.branch == P) fatal("pnil %P", p); r1 = p->to.branch->reg; if(r1 == R) fatal("rnil %P", p); if(r1 == r) { //fatal("ref to self %P", p); continue; } r->s2 = r1; r->p2link = r1->p2; r1->p2 = r; } } if(debug['R'] && debug['v']) dumpit("pass2", firstr); /* * pass 2.5 * find looping structure */ for(r = firstr; r != R; r = r->link) r->active = 0; change = 0; loopit(firstr, nr); if(debug['R'] && debug['v']) dumpit("pass2.5", firstr); /* * pass 3 * iterate propagating usage * back until flow graph is complete */ loop1: change = 0; for(r = firstr; r != R; r = r->link) r->active = 0; for(r = firstr; r != R; r = r->link) if(r->prog->as == ARET) prop(r, zbits, zbits); loop11: /* pick up unreachable code */ i = 0; for(r = firstr; r != R; r = r1) { r1 = r->link; if(r1 && r1->active && !r->active) { prop(r, zbits, zbits); i = 1; } } if(i) goto loop11; if(change) goto loop1; if(debug['R'] && debug['v']) dumpit("pass3", firstr); /* * pass 4 * iterate propagating register/variable synchrony * forward until graph is complete */ loop2: change = 0; for(r = firstr; r != R; r = r->link) r->active = 0; synch(firstr, zbits); if(change) goto loop2; if(debug['R'] && debug['v']) dumpit("pass4", firstr); /* * pass 4.5 * move register pseudo-variables into regu. */ for(r = firstr; r != R; r = r->link) { r->regu = (r->refbehind.b[0] | r->set.b[0]) & REGBITS; r->set.b[0] &= ~REGBITS; r->use1.b[0] &= ~REGBITS; r->use2.b[0] &= ~REGBITS; r->refbehind.b[0] &= ~REGBITS; r->refahead.b[0] &= ~REGBITS; r->calbehind.b[0] &= ~REGBITS; r->calahead.b[0] &= ~REGBITS; r->regdiff.b[0] &= ~REGBITS; r->act.b[0] &= ~REGBITS; } /* * pass 5 * isolate regions * calculate costs (paint1) */ r = firstr; if(r) { for(z=0; z<BITS; z++) bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) & ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]); if(bany(&bit) && !r->refset) { // should never happen - all variables are preset if(debug['w']) print("%L: used and not set: %Q\n", r->prog->lineno, bit); r->refset = 1; } } for(r = firstr; r != R; r = r->link) r->act = zbits; rgp = region; nregion = 0; for(r = firstr; r != R; r = r->link) { for(z=0; z<BITS; z++) bit.b[z] = r->set.b[z] & ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]); if(bany(&bit) && !r->refset) { if(debug['w']) print("%L: set and not used: %Q\n", r->prog->lineno, bit); r->refset = 1; excise(r); } for(z=0; z<BITS; z++) bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]); while(bany(&bit)) { i = bnum(bit); rgp->enter = r; rgp->varno = i; change = 0; paint1(r, i); bit.b[i/32] &= ~(1L<<(i%32)); if(change <= 0) continue; rgp->cost = change; nregion++; if(nregion >= NRGN) { if(debug['R'] && debug['v']) print("too many regions\n"); goto brk; } rgp++; } } brk: qsort(region, nregion, sizeof(region[0]), rcmp); /* * pass 6 * determine used registers (paint2) * replace code (paint3) */ rgp = region; for(i=0; i<nregion; i++) { bit = blsh(rgp->varno); vreg = paint2(rgp->enter, rgp->varno); vreg = allreg(vreg, rgp); if(rgp->regno != 0) paint3(rgp->enter, rgp->varno, vreg, rgp->regno); rgp++; } if(debug['R'] && debug['v']) dumpit("pass6", firstr); /* * pass 7 * peep-hole on basic block */ if(!debug['R'] || debug['P']) { peep(); } /* * eliminate nops * free aux structures */ for(p=firstp; p!=P; p=p->link) { while(p->link != P && p->link->as == ANOP) p->link = p->link->link; if(p->to.type == D_BRANCH) while(p->to.branch != P && p->to.branch->as == ANOP) p->to.branch = p->to.branch->link; } if(r1 != R) { r1->link = freer; freer = firstr; } if(debug['R']) { if(ostats.ncvtreg || ostats.nspill || ostats.nreload || ostats.ndelmov || ostats.nvar || ostats.naddr || 0) print("\nstats\n"); if(ostats.ncvtreg) print(" %4d cvtreg\n", ostats.ncvtreg); if(ostats.nspill) print(" %4d spill\n", ostats.nspill); if(ostats.nreload) print(" %4d reload\n", ostats.nreload); if(ostats.ndelmov) print(" %4d delmov\n", ostats.ndelmov); if(ostats.nvar) print(" %4d var\n", ostats.nvar); if(ostats.naddr) print(" %4d addr\n", ostats.naddr); memset(&ostats, 0, sizeof(ostats)); } }
Bits mkvar(Reg *r, Adr *a) { Var *v; int i, t, n, et, z, flag; int64 w; uint32 regu; int64 o; Bits bit; Node *node; /* * mark registers used */ t = a->type; if(t == D_NONE) goto none; if(r != R) r->use1.b[0] |= doregbits(a->index); switch(t) { default: regu = doregbits(t); if(regu == 0) goto none; bit = zbits; bit.b[0] = regu; return bit; case D_ADDR: a->type = a->index; bit = mkvar(r, a); setaddrs(bit); a->type = t; ostats.naddr++; goto none; case D_EXTERN: case D_STATIC: case D_PARAM: case D_AUTO: n = t; break; } node = a->node; if(node == N || node->op != ONAME || node->orig == N) goto none; node = node->orig; if(node->orig != node) fatal("%D: bad node", a); if(node->sym == S || node->sym->name[0] == '.') goto none; et = a->etype; o = a->offset; w = a->width; if(w < 0) fatal("bad width %lld for %D", w, a); flag = 0; for(i=0; i<nvar; i++) { v = var+i; if(v->node == node && v->name == n) { if(v->offset == o) if(v->etype == et) if(v->width == w) return blsh(i); // if they overlaps, disable both if(overlap(v->offset, v->width, o, w)) { // print("disable overlap %s %d %d %d %d, %E != %E\n", s->name, v->offset, v->width, o, w, v->etype, et); v->addr = 1; flag = 1; } } } switch(et) { case 0: case TFUNC: goto none; } if(nvar >= NVAR) { if(debug['w'] > 1 && node != N) fatal("variable not optimized: %#N", node); goto none; } i = nvar; nvar++; v = var+i; v->offset = o; v->name = n; v->etype = et; v->width = w; v->addr = flag; // funny punning v->node = node; if(debug['R']) print("bit=%2d et=%2E w=%lld+%lld %#N %D flag=%d\n", i, et, o, w, node, a, v->addr); ostats.nvar++; bit = blsh(i); if(n == D_EXTERN || n == D_STATIC) for(z=0; z<BITS; z++) externs.b[z] |= bit.b[z]; if(n == D_PARAM) for(z=0; z<BITS; z++) params.b[z] |= bit.b[z]; return bit; none: return zbits; }
int main(int argc, const char *argv[]) { /** * Test 1 */ struct exp *e1, *e2; struct explist *l; l = NULL; l = cons(mkconstant(5), l); l = cons(mkconstant(3), l); l = cons(mkconstant(2), l); e1 = mkopapp(isplus, l); l = NULL; l = cons(mkvar("x"), l); l = cons(mkvar("x"), l); l = cons(mkvar("x"), l); e2 = mkopapp(ismult, l); e1 = mklet("x", e1, e2); printf("%d\n", evalexp(e1)); // should print 1000 /** * Test 2 */ struct exp *e3, *e4, *e5; l = NULL; l = cons(mkconstant(5), l); l = cons(mkconstant(3), l); l = cons(mkconstant(2), l); e1 = mkopapp(isplus, l); l = NULL; l = cons(mkvar("y"), l); l = cons(mkvar("x"), l); l = cons(mkvar("z"), l); e2 = mkopapp(ismult, l); e3 = mklet("x", e1, e2); e4 = mklet("y", mkconstant(5), e3); e5 = mklet("z", mkconstant(40), e4); printf("%d\n", evalexp(e5)); // should print 2000 /** * Test 3 */ l = NULL; l = cons(mkconstant(3), l); l = cons(mkvar("x"), l); e2 = mkopapp(isplus, l); l = NULL; l = cons(mkconstant(9), l); l = cons(mkvar("x"), l); e5 = mkopapp(isplus, l); e4 = mklet("x", mkconstant(4), e5); l = NULL; l = cons(e4, l); l = cons(mkvar("x"), l); e3 = mkopapp(isplus, l); e1 = mklet("x", mklet("x", mkconstant(2), e2), e3); printf("%d\n", evalexp(e1)); // should print 18 return 0; }