summaryrefslogtreecommitdiff
path: root/src/cmd/5g/reg.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/5g/reg.c')
-rw-r--r--src/cmd/5g/reg.c1606
1 files changed, 0 insertions, 1606 deletions
diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c
deleted file mode 100644
index 77d0a87eb..000000000
--- a/src/cmd/5g/reg.c
+++ /dev/null
@@ -1,1606 +0,0 @@
-// Inferno utils/5c/reg.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5g/reg.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-
-#include "gg.h"
-#include "opt.h"
-
-#define NREGVAR 24
-#define REGBITS ((uint32)0xffffff)
-#define P2R(p) (Reg*)(p->reg)
-
- void addsplits(void);
- int noreturn(Prog *p);
-static int first = 0;
-
-Reg*
-rega(void)
-{
- Reg *r;
-
- r = freer;
- if(r == R) {
- r = mal(sizeof(*r));
- } else
- freer = r->link;
-
- *r = zreg;
- return r;
-}
-
-int
-rcmp(const void *a1, const void *a2)
-{
- Rgn *p1, *p2;
- int c1, c2;
-
- p1 = (Rgn*)a1;
- p2 = (Rgn*)a2;
- c1 = p2->cost;
- c2 = p1->cost;
- if(c1 -= c2)
- return c1;
- return p2->varno - p1->varno;
-}
-
-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(b))
-//print("ovars = %Q\n", &ovar);
-}
-
-void
-excise(Reg *r)
-{
- Prog *p;
-
- p = r->prog;
- p->as = ANOP;
- p->scond = zprog.scond;
- p->from = zprog.from;
- p->to = zprog.to;
- p->reg = zprog.reg;
-}
-
-static void
-setaddrs(Bits bit)
-{
- int i, n;
- Var *v;
- Sym *s;
-
- while(bany(&bit)) {
- // convert each bit to a variable
- i = bnum(bit);
- s = var[i].sym;
- n = var[i].name;
- bit.b[i/32] &= ~(1L<<(i%32));
-
- // disable all pieces of that variable
- for(i=0; i<nvar; i++) {
- v = var+i;
- if(v->sym == s && v->name == n)
- v->addr = 2;
- }
- }
-}
-
-static char* regname[] = {
- ".R0",
- ".R1",
- ".R2",
- ".R3",
- ".R4",
- ".R5",
- ".R6",
- ".R7",
- ".R8",
- ".R9",
- ".R10",
- ".R11",
- ".R12",
- ".R13",
- ".R14",
- ".R15",
- ".F0",
- ".F1",
- ".F2",
- ".F3",
- ".F4",
- ".F5",
- ".F6",
- ".F7",
-};
-
-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;
-
- /*
- * 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].sym = 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 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;
- }
- }
- }
- 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);
- }
-
- /*
- * 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->regp;
- 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']) {
- p = firstr->prog;
- print("\n%L %D\n", p->lineno, &p->from);
- print(" addr = %Q\n", addrs);
- }
-
- /*
- * pass 2.5
- * find looping structure
- */
- for(r = firstr; r != R; r = r->link)
- r->active = 0;
- change = 0;
- loopit(firstr, nr);
-
- /*
- * 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;
-
- addsplits();
-
- if(debug['R'] > 1) {
- print("\nprop structure:\n");
- for(r = firstr; r != R; r = r->link) {
- print("%d:%P", r->loop, r->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 = 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;
- 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->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);
-
- /*
- * 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->prog->lineno,
- rgp->cost,
- rgp->regno-NREG,
- bit);
- else
- print("%L $%d R%d: %Q\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();
- }
-
- /*
- * 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.branch != P && p->to.branch->as == ANOP)
- p->to.branch = p->to.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);
- }
- }
- }
- if(r1 != R) {
- r1->link = freer;
- freer = firstr;
- }
-
-}
-
-void
-addsplits(void)
-{
- Reg *r, *r1;
- int z, i;
- Bits bit;
-
- for(r = firstr; r != R; r = r->link) {
- if(r->loop > 1)
- continue;
- if(r->prog->as == ABL)
- continue;
- for(r1 = r->p2; r1 != R; r1 = r1->p2link) {
- if(r1->loop <= 1)
- continue;
- for(z=0; z<BITS; z++)
- bit.b[z] = r1->calbehind.b[z] &
- (r->refahead.b[z] | r->use1.b[z] | r->use2.b[z]) &
- ~(r->calahead.b[z] & addrs.b[z]);
- while(bany(&bit)) {
- i = bnum(bit);
- bit.b[i/32] &= ~(1L << (i%32));
- }
- }
- }
-}
-
-/*
- * add mov b,rn
- * just after r
- */
-void
-addmove(Reg *r, int bn, int rn, int f)
-{
- Prog *p, *p1;
- Adr *a;
- Var *v;
-
- p1 = mal(sizeof(*p1));
- *p1 = zprog;
- p = r->prog;
-
- p1->link = p->link;
- p->link = p1;
- p1->lineno = p->lineno;
-
- v = var + bn;
-
- a = &p1->to;
- a->sym = v->sym;
- a->name = v->name;
- a->node = v->node;
- a->offset = v->offset;
- a->etype = v->etype;
- a->type = D_OREG;
- if(a->etype == TARRAY || a->sym == S)
- a->type = D_CONST;
-
- if(v->addr)
- fatal("addmove: shouldnt be doing this %A\n", a);
-
- switch(v->etype) {
- default:
- print("What is this %E\n", v->etype);
-
- case TINT8:
- p1->as = AMOVB;
- break;
- case TBOOL:
- case TUINT8:
- p1->as = AMOVBU;
- break;
- case TINT16:
- p1->as = AMOVH;
- break;
- case TUINT16:
- p1->as = AMOVHU;
- break;
- case TINT32:
- case TUINT32:
- case TPTR32:
- p1->as = AMOVW;
- break;
- case TFLOAT32:
- p1->as = AMOVF;
- break;
- case TFLOAT64:
- p1->as = AMOVD;
- break;
- }
-
- p1->from.type = D_REG;
- p1->from.reg = rn;
- if(rn >= NREG) {
- p1->from.type = D_FREG;
- p1->from.reg = rn-NREG;
- }
- if(!f) {
- p1->from = *a;
- *a = zprog.from;
- a->type = D_REG;
- a->reg = rn;
- if(rn >= NREG) {
- a->type = D_FREG;
- a->reg = rn-NREG;
- }
- if(v->etype == TUINT8 || v->etype == TBOOL)
- p1->as = AMOVBU;
- if(v->etype == TUINT16)
- p1->as = AMOVHU;
- }
- if(debug['R'])
- print("%P\t.a%P\n", p, p1);
-}
-
-static int
-overlap(int32 o1, int w1, int32 o2, int w2)
-{
- int32 t1, t2;
-
- t1 = o1+w1;
- t2 = o2+w2;
-
- if(!(t1 > o2 && t2 > o1))
- return 0;
-
- return 1;
-}
-
-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;
- n = D_NONE;
-
- flag = 0;
- if(a->pun)
- flag = 1;
-
- switch(t) {
- default:
- print("type %d %d %D\n", t, a->name, a);
- goto none;
-
- case D_NONE:
- case D_FCONST:
- case D_BRANCH:
- break;
-
- case D_CONST:
- flag = 1;
- goto onereg;
-
- case D_REGREG:
- bit = zbits;
- if(a->offset != NREG)
- bit.b[0] |= RtoB(a->offset);
- if(a->reg != NREG)
- bit.b[0] |= RtoB(a->reg);
- return bit;
-
- case D_REG:
- case D_SHIFT:
- onereg:
- if(a->reg != NREG) {
- bit = zbits;
- bit.b[0] = RtoB(a->reg);
- return bit;
- }
- break;
-
- case D_OREG:
- if(a->reg != NREG) {
- if(a == &r->prog->from)
- r->use1.b[0] |= RtoB(a->reg);
- else
- r->use2.b[0] |= RtoB(a->reg);
- if(r->prog->scond & (C_PBIT|C_WBIT))
- r->set.b[0] |= RtoB(a->reg);
- }
- break;
-
- case D_FREG:
- if(a->reg != NREG) {
- bit = zbits;
- bit.b[0] = FtoB(a->reg);
- return bit;
- }
- break;
- }
-
- switch(a->name) {
- default:
- goto none;
-
- case D_EXTERN:
- case D_STATIC:
- case D_AUTO:
- case D_PARAM:
- n = a->name;
- break;
- }
-
- s = a->sym;
- if(s == S)
- goto none;
- if(s->name[0] == '.')
- goto none;
- et = a->etype;
- o = a->offset;
- w = a->width;
-
- 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)
- if(!flag)
- return blsh(i);
-
- // if they overlaps, disable both
- if(overlap(v->offset, v->width, o, w)) {
- v->addr = 1;
- flag = 1;
- }
- }
- }
-
- switch(et) {
- case 0:
- case TFUNC:
- case TARRAY:
- case TSTRING:
- 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
- v->node = a->node;
-
- if(debug['R'])
- print("bit=%2d et=%E pun=%d %D\n", i, et, flag, a);
-
- 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
-prop(Reg *r, Bits ref, Bits cal)
-{
- Reg *r1, *r2;
- int z;
-
- for(r1 = r; r1 != R; r1 = r1->p1) {
- for(z=0; z<BITS; z++) {
- ref.b[z] |= r1->refahead.b[z];
- if(ref.b[z] != r1->refahead.b[z]) {
- r1->refahead.b[z] = ref.b[z];
- change++;
- }
- cal.b[z] |= r1->calahead.b[z];
- if(cal.b[z] != r1->calahead.b[z]) {
- r1->calahead.b[z] = cal.b[z];
- change++;
- }
- }
- switch(r1->prog->as) {
- case ABL:
- if(noreturn(r1->prog))
- break;
- for(z=0; z<BITS; z++) {
- cal.b[z] |= ref.b[z] | externs.b[z];
- ref.b[z] = 0;
- }
- break;
-
- case ATEXT:
- for(z=0; z<BITS; z++) {
- cal.b[z] = 0;
- ref.b[z] = 0;
- }
- break;
-
- case ARET:
- for(z=0; z<BITS; z++) {
- cal.b[z] = externs.b[z] | ovar.b[z];
- ref.b[z] = 0;
- }
- break;
- }
- for(z=0; z<BITS; z++) {
- ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
- r1->use1.b[z] | r1->use2.b[z];
- cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
- r1->refbehind.b[z] = ref.b[z];
- r1->calbehind.b[z] = cal.b[z];
- }
- if(r1->active)
- break;
- r1->active = 1;
- }
- for(; r != r1; r = r->p1)
- for(r2 = r->p2; r2 != R; r2 = r2->p2link)
- prop(r2, r->refbehind, r->calbehind);
-}
-
-/*
- * find looping structure
- *
- * 1) find reverse postordering
- * 2) find approximate dominators,
- * the actual dominators if the flow graph is reducible
- * otherwise, dominators plus some other non-dominators.
- * See Matthew S. Hecht and Jeffrey D. Ullman,
- * "Analysis of a Simple Algorithm for Global Data Flow Problems",
- * Conf. Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
- * Oct. 1-3, 1973, pp. 207-217.
- * 3) find all nodes with a predecessor dominated by the current node.
- * such a node is a loop head.
- * recursively, all preds with a greater rpo number are in the loop
- */
-int32
-postorder(Reg *r, Reg **rpo2r, int32 n)
-{
- Reg *r1;
-
- r->rpo = 1;
- r1 = r->s1;
- if(r1 && !r1->rpo)
- n = postorder(r1, rpo2r, n);
- r1 = r->s2;
- if(r1 && !r1->rpo)
- n = postorder(r1, rpo2r, n);
- rpo2r[n] = r;
- n++;
- return n;
-}
-
-int32
-rpolca(int32 *idom, int32 rpo1, int32 rpo2)
-{
- int32 t;
-
- if(rpo1 == -1)
- return rpo2;
- while(rpo1 != rpo2){
- if(rpo1 > rpo2){
- t = rpo2;
- rpo2 = rpo1;
- rpo1 = t;
- }
- while(rpo1 < rpo2){
- t = idom[rpo2];
- if(t >= rpo2)
- fatal("bad idom");
- rpo2 = t;
- }
- }
- return rpo1;
-}
-
-int
-doms(int32 *idom, int32 r, int32 s)
-{
- while(s > r)
- s = idom[s];
- return s == r;
-}
-
-int
-loophead(int32 *idom, Reg *r)
-{
- int32 src;
-
- src = r->rpo;
- if(r->p1 != R && doms(idom, src, r->p1->rpo))
- return 1;
- for(r = r->p2; r != R; r = r->p2link)
- if(doms(idom, src, r->rpo))
- return 1;
- return 0;
-}
-
-void
-loopmark(Reg **rpo2r, int32 head, Reg *r)
-{
- if(r->rpo < head || r->active == head)
- return;
- r->active = head;
- r->loop += LOOP;
- if(r->p1 != R)
- loopmark(rpo2r, head, r->p1);
- for(r = r->p2; r != R; r = r->p2link)
- loopmark(rpo2r, head, r);
-}
-
-void
-loopit(Reg *r, int32 nr)
-{
- Reg *r1;
- int32 i, d, me;
-
- if(nr > maxnr) {
- rpo2r = mal(nr * sizeof(Reg*));
- idom = mal(nr * sizeof(int32));
- maxnr = nr;
- }
- d = postorder(r, rpo2r, 0);
- if(d > nr)
- fatal("too many reg nodes");
- nr = d;
- for(i = 0; i < nr / 2; i++){
- r1 = rpo2r[i];
- rpo2r[i] = rpo2r[nr - 1 - i];
- rpo2r[nr - 1 - i] = r1;
- }
- for(i = 0; i < nr; i++)
- rpo2r[i]->rpo = i;
-
- idom[0] = 0;
- for(i = 0; i < nr; i++){
- r1 = rpo2r[i];
- me = r1->rpo;
- d = -1;
- if(r1->p1 != R && r1->p1->rpo < me)
- d = r1->p1->rpo;
- for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
- if(r1->rpo < me)
- d = rpolca(idom, d, r1->rpo);
- idom[i] = d;
- }
-
- for(i = 0; i < nr; i++){
- r1 = rpo2r[i];
- r1->loop++;
- if(r1->p2 != R && loophead(idom, r1))
- loopmark(rpo2r, i, r1);
- }
-}
-
-void
-synch(Reg *r, Bits dif)
-{
- Reg *r1;
- int z;
-
- for(r1 = r; r1 != R; r1 = r1->s1) {
- for(z=0; z<BITS; z++) {
- dif.b[z] = (dif.b[z] &
- ~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
- r1->set.b[z] | r1->regdiff.b[z];
- if(dif.b[z] != r1->regdiff.b[z]) {
- r1->regdiff.b[z] = dif.b[z];
- change++;
- }
- }
- if(r1->active)
- break;
- r1->active = 1;
- for(z=0; z<BITS; z++)
- dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
- if(r1->s2 != R)
- synch(r1->s2, dif);
- }
-}
-
-uint32
-allreg(uint32 b, Rgn *r)
-{
- Var *v;
- int i;
-
- v = var + r->varno;
- r->regno = 0;
- switch(v->etype) {
-
- default:
- fatal("unknown etype %d/%E", bitno(b), v->etype);
- break;
-
- case TINT8:
- case TUINT8:
- case TINT16:
- case TUINT16:
- case TINT32:
- case TUINT32:
- case TINT:
- case TUINT:
- case TUINTPTR:
- case TBOOL:
- case TPTR32:
- i = BtoR(~b);
- if(i && r->cost >= 0) {
- r->regno = i;
- return RtoB(i);
- }
- break;
-
- case TFLOAT32:
- case TFLOAT64:
- i = BtoF(~b);
- if(i && r->cost >= 0) {
- r->regno = i+NREG;
- return FtoB(i);
- }
- break;
-
- case TINT64:
- case TUINT64:
- case TPTR64:
- case TINTER:
- case TSTRUCT:
- case TARRAY:
- break;
- }
- return 0;
-}
-
-void
-paint1(Reg *r, int bn)
-{
- Reg *r1;
- Prog *p;
- int z;
- uint32 bb;
-
- z = bn/32;
- bb = 1L<<(bn%32);
- if(r->act.b[z] & bb)
- return;
- for(;;) {
- if(!(r->refbehind.b[z] & bb))
- break;
- r1 = r->p1;
- if(r1 == R)
- break;
- if(!(r1->refahead.b[z] & bb))
- break;
- if(r1->act.b[z] & bb)
- break;
- r = r1;
- }
-
- if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb) {
- change -= CLOAD * r->loop;
- if(debug['R'] > 1)
- print("%d%P\td %Q $%d\n", r->loop,
- r->prog, blsh(bn), change);
- }
- for(;;) {
- r->act.b[z] |= bb;
- p = r->prog;
-
- if(r->use1.b[z] & bb) {
- change += CREF * r->loop;
- if(debug['R'] > 1)
- print("%d%P\tu1 %Q $%d\n", r->loop,
- p, blsh(bn), change);
- }
-
- if((r->use2.b[z]|r->set.b[z]) & bb) {
- change += CREF * r->loop;
- if(debug['R'] > 1)
- print("%d%P\tu2 %Q $%d\n", r->loop,
- p, blsh(bn), change);
- }
-
- if(STORE(r) & r->regdiff.b[z] & bb) {
- change -= CLOAD * r->loop;
- if(debug['R'] > 1)
- print("%d%P\tst %Q $%d\n", r->loop,
- p, blsh(bn), change);
- }
-
- if(r->refbehind.b[z] & bb)
- for(r1 = r->p2; r1 != R; r1 = r1->p2link)
- if(r1->refahead.b[z] & bb)
- paint1(r1, bn);
-
- if(!(r->refahead.b[z] & bb))
- break;
- r1 = r->s2;
- if(r1 != R)
- if(r1->refbehind.b[z] & bb)
- paint1(r1, bn);
- r = r->s1;
- if(r == R)
- break;
- if(r->act.b[z] & bb)
- break;
- if(!(r->refbehind.b[z] & bb))
- break;
- }
-}
-
-uint32
-paint2(Reg *r, int bn)
-{
- Reg *r1;
- int z;
- uint32 bb, vreg;
-
- z = bn/32;
- bb = 1L << (bn%32);
- vreg = regbits;
- if(!(r->act.b[z] & bb))
- return vreg;
- for(;;) {
- if(!(r->refbehind.b[z] & bb))
- break;
- r1 = r->p1;
- if(r1 == R)
- break;
- if(!(r1->refahead.b[z] & bb))
- break;
- if(!(r1->act.b[z] & bb))
- break;
- r = r1;
- }
- for(;;) {
- r->act.b[z] &= ~bb;
-
- vreg |= r->regu;
-
- if(r->refbehind.b[z] & bb)
- for(r1 = r->p2; r1 != R; r1 = r1->p2link)
- if(r1->refahead.b[z] & bb)
- vreg |= paint2(r1, bn);
-
- if(!(r->refahead.b[z] & bb))
- break;
- r1 = r->s2;
- if(r1 != R)
- if(r1->refbehind.b[z] & bb)
- vreg |= paint2(r1, bn);
- r = r->s1;
- if(r == R)
- break;
- if(!(r->act.b[z] & bb))
- break;
- if(!(r->refbehind.b[z] & bb))
- break;
- }
- return vreg;
-}
-
-void
-paint3(Reg *r, int bn, int32 rb, int rn)
-{
- Reg *r1;
- Prog *p;
- int z;
- uint32 bb;
-
- z = bn/32;
- bb = 1L << (bn%32);
- if(r->act.b[z] & bb)
- return;
- for(;;) {
- if(!(r->refbehind.b[z] & bb))
- break;
- r1 = r->p1;
- if(r1 == R)
- break;
- if(!(r1->refahead.b[z] & bb))
- break;
- if(r1->act.b[z] & bb)
- break;
- r = r1;
- }
-
- if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
- addmove(r, bn, rn, 0);
-
- for(;;) {
- r->act.b[z] |= bb;
- p = r->prog;
-
- if(r->use1.b[z] & bb) {
- if(debug['R'])
- print("%P", p);
- addreg(&p->from, rn);
- if(debug['R'])
- print("\t.c%P\n", p);
- }
- if((r->use2.b[z]|r->set.b[z]) & bb) {
- if(debug['R'])
- print("%P", p);
- addreg(&p->to, rn);
- if(debug['R'])
- print("\t.c%P\n", p);
- }
-
- if(STORE(r) & r->regdiff.b[z] & bb)
- addmove(r, bn, rn, 1);
- r->regu |= rb;
-
- if(r->refbehind.b[z] & bb)
- for(r1 = r->p2; r1 != R; r1 = r1->p2link)
- if(r1->refahead.b[z] & bb)
- paint3(r1, bn, rb, rn);
-
- if(!(r->refahead.b[z] & bb))
- break;
- r1 = r->s2;
- if(r1 != R)
- if(r1->refbehind.b[z] & bb)
- paint3(r1, bn, rb, rn);
- r = r->s1;
- if(r == R)
- break;
- if(r->act.b[z] & bb)
- break;
- if(!(r->refbehind.b[z] & bb))
- break;
- }
-}
-
-void
-addreg(Adr *a, int rn)
-{
-
- if(a->type == D_CONST)
- fatal("addreg: cant do this %D %d\n", a, rn);
-
- a->sym = 0;
- a->name = D_NONE;
- a->type = D_REG;
- a->reg = rn;
- if(rn >= NREG) {
- a->type = D_FREG;
- a->reg = rn-NREG;
- }
-}
-
-/*
- * bit reg
- * 0 R0
- * 1 R1
- * ... ...
- * 10 R10
- */
-int32
-RtoB(int r)
-{
-
- if(r < 2 || r >= REGTMP-2) // excluded R9 and R10 for m and g
- return 0;
- return 1L << r;
-}
-
-int
-BtoR(int32 b)
-{
- b &= 0x01fcL; // excluded R9 and R10 for m and g
- if(b == 0)
- return 0;
- return bitno(b);
-}
-
-/*
- * bit reg
- * 18 F2
- * 19 F3
- * ... ...
- * 23 F7
- */
-int32
-FtoB(int f)
-{
-
- if(f < 2 || f > NFREG-1)
- return 0;
- return 1L << (f + 16);
-}
-
-int
-BtoF(int32 b)
-{
-
- b &= 0xfc0000L;
- if(b == 0)
- return 0;
- return bitno(b) - 16;
-}
-
-static Sym* symlist[10];
-
-int
-noreturn(Prog *p)
-{
- Sym *s;
- int i;
-
- if(symlist[0] == S) {
- symlist[0] = pkglookup("panicindex", runtimepkg);
- symlist[1] = pkglookup("panicslice", runtimepkg);
- symlist[2] = pkglookup("throwinit", runtimepkg);
- symlist[3] = pkglookup("panic", runtimepkg);
- symlist[4] = pkglookup("panicwrap", runtimepkg);
- }
-
- s = p->to.sym;
- if(s == S)
- return 0;
- for(i=0; symlist[i]!=S; i++)
- if(s == symlist[i])
- return 1;
- return 0;
-}
-
-void
-dumpone(Reg *r)
-{
- int z;
- Bits bit;
-
- print("%d:%P", r->loop, r->prog);
- for(z=0; z<BITS; z++)
- bit.b[z] =
- r->set.b[z] |
- r->use1.b[z] |
- r->use2.b[z] |
- r->refbehind.b[z] |
- r->refahead.b[z] |
- r->calbehind.b[z] |
- r->calahead.b[z] |
- r->regdiff.b[z] |
- r->act.b[z] |
- 0;
- if(bany(&bit)) {
- print("\t");
- if(bany(&r->set))
- print(" s:%Q", r->set);
- if(bany(&r->use1))
- print(" u1:%Q", r->use1);
- if(bany(&r->use2))
- print(" u2:%Q", r->use2);
- if(bany(&r->refbehind))
- print(" rb:%Q ", r->refbehind);
- if(bany(&r->refahead))
- print(" ra:%Q ", r->refahead);
- if(bany(&r->calbehind))
- print("cb:%Q ", r->calbehind);
- if(bany(&r->calahead))
- print(" ca:%Q ", r->calahead);
- if(bany(&r->regdiff))
- print(" d:%Q ", r->regdiff);
- if(bany(&r->act))
- print(" a:%Q ", r->act);
- }
- print("\n");
-}
-
-void
-dumpit(char *str, Reg *r0)
-{
- Reg *r, *r1;
-
- print("\n%s\n", str);
- for(r = r0; r != R; r = r->link) {
- dumpone(r);
- r1 = r->p2;
- if(r1 != R) {
- print(" pred:");
- for(; r1 != R; r1 = r1->p2link)
- print(" %.4ud", r1->prog->loc);
- print("\n");
- }
-// r1 = r->s1;
-// if(r1 != R) {
-// print(" succ:");
-// for(; r1 != R; r1 = r1->s1)
-// print(" %.4ud", r1->prog->loc);
-// print("\n");
-// }
- }
-}