Commit 1250d2e3 authored by Russ Cox's avatar Russ Cox

cmd/gc: remove C subclassing trick from popt.c

It does not convert to Go well.

Being able to do this just once, instead of 4 times, was the primary
motivation for all the recent refactoring (not that it wasn't overdue).

Still bit-for-bit identical.

Change-Id: Ia01f17948441bf64fa78ec4226f0bb40af0bbaab
Reviewed-on: https://go-review.googlesource.com/3962Reviewed-by: default avatarAustin Clements <austin@google.com>
parent ad88fd1d
...@@ -65,7 +65,7 @@ peep(Prog *firstp) ...@@ -65,7 +65,7 @@ peep(Prog *firstp)
Prog *p; Prog *p;
int t; int t;
g = flowstart(firstp, sizeof(Flow)); g = flowstart(firstp, 0);
if(g == nil) if(g == nil)
return; return;
gactive = 0; gactive = 0;
......
...@@ -97,7 +97,7 @@ peep(Prog *firstp) ...@@ -97,7 +97,7 @@ peep(Prog *firstp)
Prog *p, *p1; Prog *p, *p1;
int t; int t;
g = flowstart(firstp, sizeof(Flow)); g = flowstart(firstp, 0);
if(g == nil) if(g == nil)
return; return;
gactive = 0; gactive = 0;
......
...@@ -94,7 +94,7 @@ peep(Prog *firstp) ...@@ -94,7 +94,7 @@ peep(Prog *firstp)
Prog *p, *p1; Prog *p, *p1;
int t; int t;
g = flowstart(firstp, sizeof(Flow)); g = flowstart(firstp, 0);
if(g == nil) if(g == nil)
return; return;
gactive = 0; gactive = 0;
......
...@@ -55,7 +55,7 @@ peep(Prog *firstp) ...@@ -55,7 +55,7 @@ peep(Prog *firstp)
Prog *p, *p1; Prog *p, *p1;
int t; int t;
g = flowstart(firstp, sizeof(Flow)); g = flowstart(firstp, 0);
if(g == nil) if(g == nil)
return; return;
gactive = 0; gactive = 0;
......
...@@ -1557,9 +1557,12 @@ struct Flow { ...@@ -1557,9 +1557,12 @@ struct Flow {
int32 active; // usable by client int32 active; // usable by client
int32 id; // sequence number in flow graph
int32 rpo; // reverse post ordering int32 rpo; // reverse post ordering
uint16 loop; // x5 for every loop uint16 loop; // x5 for every loop
uchar refset; // diagnostic generated uchar refset; // diagnostic generated
void* data; // for use by client
}; };
struct Graph struct Graph
......
...@@ -202,7 +202,7 @@ fixjmp(Prog *firstp) ...@@ -202,7 +202,7 @@ fixjmp(Prog *firstp)
// Control flow analysis. The Flow structures hold predecessor and successor // Control flow analysis. The Flow structures hold predecessor and successor
// information as well as basic loop analysis. // information as well as basic loop analysis.
// //
// graph = flowstart(firstp, sizeof(Flow)); // graph = flowstart(firstp, 0);
// ... use flow graph ... // ... use flow graph ...
// flowend(graph); // free graph // flowend(graph); // free graph
// //
...@@ -215,18 +215,19 @@ fixjmp(Prog *firstp) ...@@ -215,18 +215,19 @@ fixjmp(Prog *firstp)
// //
// for(f2 = f->p2; f2 != nil; f2 = f2->p2link) // for(f2 = f->p2; f2 != nil; f2 = f2->p2link)
// //
// Often the Flow struct is embedded as the first field inside a larger struct S. // The size argument to flowstart specifies an amount of zeroed memory
// In that case casts are needed to convert Flow* to S* in many places but the // to allocate in every f->data field, for use by the client.
// idea is the same. Pass sizeof(S) instead of sizeof(Flow) to flowstart. // If size == 0, f->data will be nil.
Graph* Graph*
flowstart(Prog *firstp, int size) flowstart(Prog *firstp, int size)
{ {
int nf; int id, nf;
Flow *f, *f1, *start, *last; Flow *f, *f1, *start, *last;
Graph *graph; Graph *graph;
Prog *p; Prog *p;
ProgInfo info; ProgInfo info;
char *data;
// Count and mark instructions to annotate. // Count and mark instructions to annotate.
nf = 0; nf = 0;
...@@ -248,12 +249,16 @@ flowstart(Prog *firstp, int size) ...@@ -248,12 +249,16 @@ flowstart(Prog *firstp, int size)
} }
// Allocate annotations and assign to instructions. // Allocate annotations and assign to instructions.
graph = calloc(sizeof *graph + size*nf, 1); graph = calloc(sizeof *graph + sizeof(Flow)*nf + size*nf, 1);
if(graph == nil) if(graph == nil)
fatal("out of memory"); fatal("out of memory");
start = (Flow*)(graph+1); start = (Flow*)(graph+1);
last = nil; last = nil;
f = start; f = start;
data = (char*)(f+nf);
if(size == 0)
data = nil;
id = 0;
for(p = firstp; p != P; p = p->link) { for(p = firstp; p != P; p = p->link) {
if(p->opt == nil) if(p->opt == nil)
continue; continue;
...@@ -262,8 +267,11 @@ flowstart(Prog *firstp, int size) ...@@ -262,8 +267,11 @@ flowstart(Prog *firstp, int size)
if(last) if(last)
last->link = f; last->link = f;
last = f; last = f;
f->data = data;
f = (Flow*)((uchar*)f + size); f->id = id;
f++;
id++;
data += size;
} }
// Fill in pred/succ information. // Fill in pred/succ information.
...@@ -498,13 +506,12 @@ uniqs(Flow *r) ...@@ -498,13 +506,12 @@ uniqs(Flow *r)
// ACM TOPLAS 1999. // ACM TOPLAS 1999.
typedef struct TempVar TempVar; typedef struct TempVar TempVar;
typedef struct TempFlow TempFlow;
struct TempVar struct TempVar
{ {
Node *node; Node *node;
TempFlow *def; // definition of temp var Flow *def; // definition of temp var
TempFlow *use; // use list, chained through TempFlow.uselink Flow *use; // use list, chained through Flow.data
TempVar *freelink; // next free temp in Type.opt list TempVar *freelink; // next free temp in Type.opt list
TempVar *merge; // merge var with this one TempVar *merge; // merge var with this one
vlong start; // smallest Prog.pc in live range vlong start; // smallest Prog.pc in live range
...@@ -513,12 +520,6 @@ struct TempVar ...@@ -513,12 +520,6 @@ struct TempVar
uchar removed; // removed from program uchar removed; // removed from program
}; };
struct TempFlow
{
Flow f;
TempFlow *uselink;
};
static int static int
startcmp(const void *va, const void *vb) startcmp(const void *va, const void *vb)
{ {
...@@ -541,15 +542,15 @@ canmerge(Node *n) ...@@ -541,15 +542,15 @@ canmerge(Node *n)
return n->class == PAUTO && strncmp(n->sym->name, "autotmp", 7) == 0; return n->class == PAUTO && strncmp(n->sym->name, "autotmp", 7) == 0;
} }
static void mergewalk(TempVar*, TempFlow*, uint32); static void mergewalk(TempVar*, Flow*, uint32);
static void varkillwalk(TempVar*, TempFlow*, uint32); static void varkillwalk(TempVar*, Flow*, uint32);
void void
mergetemp(Prog *firstp) mergetemp(Prog *firstp)
{ {
int i, j, nvar, ninuse, nfree, nkill; int i, j, nvar, ninuse, nfree, nkill;
TempVar *var, *v, *v1, **bystart, **inuse; TempVar *var, *v, *v1, **bystart, **inuse;
TempFlow *r; Flow *f;
NodeList *l, **lp; NodeList *l, **lp;
Node *n; Node *n;
Prog *p, *p1; Prog *p, *p1;
...@@ -560,7 +561,7 @@ mergetemp(Prog *firstp) ...@@ -560,7 +561,7 @@ mergetemp(Prog *firstp)
enum { Debug = 0 }; enum { Debug = 0 };
g = flowstart(firstp, sizeof(TempFlow)); g = flowstart(firstp, 0);
if(g == nil) if(g == nil)
return; return;
...@@ -585,8 +586,8 @@ mergetemp(Prog *firstp) ...@@ -585,8 +586,8 @@ mergetemp(Prog *firstp)
// We assume that the earliest reference to a temporary is its definition. // We assume that the earliest reference to a temporary is its definition.
// This is not true of variables in general but our temporaries are all // This is not true of variables in general but our temporaries are all
// single-use (that's why we have so many!). // single-use (that's why we have so many!).
for(r = (TempFlow*)g->start; r != nil; r = (TempFlow*)r->f.link) { for(f = g->start; f != nil; f = f->link) {
p = r->f.prog; p = f->prog;
arch.proginfo(&info, p); arch.proginfo(&info, p);
if(p->from.node != N && ((Node*)(p->from.node))->opt && p->to.node != N && ((Node*)(p->to.node))->opt) if(p->from.node != N && ((Node*)(p->from.node))->opt && p->to.node != N && ((Node*)(p->to.node))->opt)
...@@ -598,9 +599,9 @@ mergetemp(Prog *firstp) ...@@ -598,9 +599,9 @@ mergetemp(Prog *firstp)
v = n->opt; v = n->opt;
if(v != nil) { if(v != nil) {
if(v->def == nil) if(v->def == nil)
v->def = r; v->def = f;
r->uselink = v->use; f->data = v->use;
v->use = r; v->use = f;
if(n == p->from.node && (info.flags & LeftAddr)) if(n == p->from.node && (info.flags & LeftAddr))
v->addr = 1; v->addr = 1;
} }
...@@ -616,8 +617,8 @@ mergetemp(Prog *firstp) ...@@ -616,8 +617,8 @@ mergetemp(Prog *firstp)
if(v->addr) if(v->addr)
continue; continue;
// Used in only one instruction, which had better be a write. // Used in only one instruction, which had better be a write.
if((r = v->use) != nil && r->uselink == nil) { if((f = v->use) != nil && (Flow*)f->data == nil) {
p = r->f.prog; p = f->prog;
arch.proginfo(&info, p); arch.proginfo(&info, p);
if(p->to.node == v->node && (info.flags & RightWrite) && !(info.flags & RightRead)) { if(p->to.node == v->node && (info.flags & RightWrite) && !(info.flags & RightRead)) {
p->as = ANOP; p->as = ANOP;
...@@ -633,10 +634,10 @@ mergetemp(Prog *firstp) ...@@ -633,10 +634,10 @@ mergetemp(Prog *firstp)
// Written in one instruction, read in the next, otherwise unused, // Written in one instruction, read in the next, otherwise unused,
// no jumps to the next instruction. Happens mainly in 386 compiler. // no jumps to the next instruction. Happens mainly in 386 compiler.
if((r = v->use) != nil && r->f.link == &r->uselink->f && r->uselink->uselink == nil && uniqp(r->f.link) == &r->f) { if((f = v->use) != nil && f->link == (Flow*)f->data && (Flow*)((Flow*)f->data)->data == nil && uniqp(f->link) == f) {
p = r->f.prog; p = f->prog;
arch.proginfo(&info, p); arch.proginfo(&info, p);
p1 = r->f.link->prog; p1 = f->link->prog;
arch.proginfo(&info1, p1); arch.proginfo(&info1, p1);
enum { enum {
SizeAny = SizeB | SizeW | SizeL | SizeQ | SizeF | SizeD, SizeAny = SizeB | SizeW | SizeL | SizeQ | SizeF | SizeD,
...@@ -645,7 +646,7 @@ mergetemp(Prog *firstp) ...@@ -645,7 +646,7 @@ mergetemp(Prog *firstp)
!((info.flags|info1.flags) & (LeftAddr|RightAddr)) && !((info.flags|info1.flags) & (LeftAddr|RightAddr)) &&
(info.flags & SizeAny) == (info1.flags & SizeAny)) { (info.flags & SizeAny) == (info1.flags & SizeAny)) {
p1->from = p->from; p1->from = p->from;
arch.excise(&r->f); arch.excise(f);
v->removed = 1; v->removed = 1;
if(Debug) if(Debug)
print("drop immediate-use %S\n", v->node->sym); print("drop immediate-use %S\n", v->node->sym);
...@@ -657,16 +658,16 @@ mergetemp(Prog *firstp) ...@@ -657,16 +658,16 @@ mergetemp(Prog *firstp)
// Traverse live range of each variable to set start, end. // Traverse live range of each variable to set start, end.
// Each flood uses a new value of gen so that we don't have // Each flood uses a new value of gen so that we don't have
// to clear all the r->f.active words after each variable. // to clear all the r->active words after each variable.
gen = 0; gen = 0;
for(v = var; v < var+nvar; v++) { for(v = var; v < var+nvar; v++) {
gen++; gen++;
for(r = v->use; r != nil; r = r->uselink) for(f = v->use; f != nil; f = (Flow*)f->data)
mergewalk(v, r, gen); mergewalk(v, f, gen);
if(v->addr) { if(v->addr) {
gen++; gen++;
for(r = v->use; r != nil; r = r->uselink) for(f = v->use; f != nil; f = (Flow*)f->data)
varkillwalk(v, r, gen); varkillwalk(v, f, gen);
} }
} }
...@@ -736,7 +737,7 @@ mergetemp(Prog *firstp) ...@@ -736,7 +737,7 @@ mergetemp(Prog *firstp)
if(v->merge) if(v->merge)
print(" merge %#N", v->merge->node); print(" merge %#N", v->merge->node);
if(v->start == v->end) if(v->start == v->end)
print(" %P", v->def->f.prog); print(" %P", v->def->prog);
print("\n"); print("\n");
} }
...@@ -745,8 +746,8 @@ mergetemp(Prog *firstp) ...@@ -745,8 +746,8 @@ mergetemp(Prog *firstp)
} }
// Update node references to use merged temporaries. // Update node references to use merged temporaries.
for(r = (TempFlow*)g->start; r != nil; r = (TempFlow*)r->f.link) { for(f = g->start; f != nil; f = f->link) {
p = r->f.prog; p = f->prog;
if((n = p->from.node) != N && (v = n->opt) != nil && v->merge != nil) if((n = p->from.node) != N && (v = n->opt) != nil && v->merge != nil)
p->from.node = v->merge->node; p->from.node = v->merge->node;
if((n = p->to.node) != N && (v = n->opt) != nil && v->merge != nil) if((n = p->to.node) != N && (v = n->opt) != nil && v->merge != nil)
...@@ -775,40 +776,40 @@ mergetemp(Prog *firstp) ...@@ -775,40 +776,40 @@ mergetemp(Prog *firstp)
} }
static void static void
mergewalk(TempVar *v, TempFlow *r0, uint32 gen) mergewalk(TempVar *v, Flow *f0, uint32 gen)
{ {
Prog *p; Prog *p;
TempFlow *r1, *r, *r2; Flow *f1, *f, *f2;
for(r1 = r0; r1 != nil; r1 = (TempFlow*)r1->f.p1) { for(f1 = f0; f1 != nil; f1 = f1->p1) {
if(r1->f.active == gen) if(f1->active == gen)
break; break;
r1->f.active = gen; f1->active = gen;
p = r1->f.prog; p = f1->prog;
if(v->end < p->pc) if(v->end < p->pc)
v->end = p->pc; v->end = p->pc;
if(r1 == v->def) { if(f1 == v->def) {
v->start = p->pc; v->start = p->pc;
break; break;
} }
} }
for(r = r0; r != r1; r = (TempFlow*)r->f.p1) for(f = f0; f != f1; f = f->p1)
for(r2 = (TempFlow*)r->f.p2; r2 != nil; r2 = (TempFlow*)r2->f.p2link) for(f2 = f->p2; f2 != nil; f2 = f2->p2link)
mergewalk(v, r2, gen); mergewalk(v, f2, gen);
} }
static void static void
varkillwalk(TempVar *v, TempFlow *r0, uint32 gen) varkillwalk(TempVar *v, Flow *f0, uint32 gen)
{ {
Prog *p; Prog *p;
TempFlow *r1, *r; Flow *f1, *f;
for(r1 = r0; r1 != nil; r1 = (TempFlow*)r1->f.s1) { for(f1 = f0; f1 != nil; f1 = f1->s1) {
if(r1->f.active == gen) if(f1->active == gen)
break; break;
r1->f.active = gen; f1->active = gen;
p = r1->f.prog; p = f1->prog;
if(v->end < p->pc) if(v->end < p->pc)
v->end = p->pc; v->end = p->pc;
if(v->start > p->pc) if(v->start > p->pc)
...@@ -817,8 +818,8 @@ varkillwalk(TempVar *v, TempFlow *r0, uint32 gen) ...@@ -817,8 +818,8 @@ varkillwalk(TempVar *v, TempFlow *r0, uint32 gen)
break; break;
} }
for(r = r0; r != r1; r = (TempFlow*)r->f.s1) for(f = f0; f != f1; f = f->s1)
varkillwalk(v, (TempFlow*)r->f.s2, gen); varkillwalk(v, f->s2, gen);
} }
// Eliminate redundant nil pointer checks. // Eliminate redundant nil pointer checks.
...@@ -836,25 +837,21 @@ varkillwalk(TempVar *v, TempFlow *r0, uint32 gen) ...@@ -836,25 +837,21 @@ varkillwalk(TempVar *v, TempFlow *r0, uint32 gen)
// each load. // each load.
typedef struct NilVar NilVar; typedef struct NilVar NilVar;
typedef struct NilFlow NilFlow;
struct NilFlow { static void nilwalkback(Flow *rcheck);
Flow f; static void nilwalkfwd(Flow *rcheck);
int kill;
};
static void nilwalkback(NilFlow *rcheck); static int killed; // f->data is either nil or &killed
static void nilwalkfwd(NilFlow *rcheck);
void void
nilopt(Prog *firstp) nilopt(Prog *firstp)
{ {
NilFlow *r; Flow *f;
Prog *p; Prog *p;
Graph *g; Graph *g;
int ncheck, nkill; int ncheck, nkill;
g = flowstart(firstp, sizeof(NilFlow)); g = flowstart(firstp, 0);
if(g == nil) if(g == nil)
return; return;
...@@ -863,35 +860,35 @@ nilopt(Prog *firstp) ...@@ -863,35 +860,35 @@ nilopt(Prog *firstp)
ncheck = 0; ncheck = 0;
nkill = 0; nkill = 0;
for(r = (NilFlow*)g->start; r != nil; r = (NilFlow*)r->f.link) { for(f = g->start; f != nil; f = f->link) {
p = r->f.prog; p = f->prog;
if(p->as != ACHECKNIL || !arch.regtyp(&p->from)) if(p->as != ACHECKNIL || !arch.regtyp(&p->from))
continue; continue;
ncheck++; ncheck++;
if(arch.stackaddr(&p->from)) { if(arch.stackaddr(&p->from)) {
if(debug_checknil && p->lineno > 1) if(debug_checknil && p->lineno > 1)
warnl(p->lineno, "removed nil check of SP address"); warnl(p->lineno, "removed nil check of SP address");
r->kill = 1; f->data = &killed;
continue; continue;
} }
nilwalkfwd(r); nilwalkfwd(f);
if(r->kill) { if(f->data != nil) {
if(debug_checknil && p->lineno > 1) if(debug_checknil && p->lineno > 1)
warnl(p->lineno, "removed nil check before indirect"); warnl(p->lineno, "removed nil check before indirect");
continue; continue;
} }
nilwalkback(r); nilwalkback(f);
if(r->kill) { if(f->data != nil) {
if(debug_checknil && p->lineno > 1) if(debug_checknil && p->lineno > 1)
warnl(p->lineno, "removed repeated nil check"); warnl(p->lineno, "removed repeated nil check");
continue; continue;
} }
} }
for(r = (NilFlow*)g->start; r != nil; r = (NilFlow*)r->f.link) { for(f = g->start; f != nil; f = f->link) {
if(r->kill) { if(f->data != nil) {
nkill++; nkill++;
arch.excise(&r->f); arch.excise(f);
} }
} }
...@@ -902,72 +899,72 @@ nilopt(Prog *firstp) ...@@ -902,72 +899,72 @@ nilopt(Prog *firstp)
} }
static void static void
nilwalkback(NilFlow *rcheck) nilwalkback(Flow *fcheck)
{ {
Prog *p; Prog *p;
ProgInfo info; ProgInfo info;
NilFlow *r; Flow *f;
for(r = rcheck; r != nil; r = (NilFlow*)uniqp(&r->f)) { for(f = fcheck; f != nil; f = uniqp(f)) {
p = r->f.prog; p = f->prog;
arch.proginfo(&info, p); arch.proginfo(&info, p);
if((info.flags & RightWrite) && arch.sameaddr(&p->to, &rcheck->f.prog->from)) { if((info.flags & RightWrite) && arch.sameaddr(&p->to, &fcheck->prog->from)) {
// Found initialization of value we're checking for nil. // Found initialization of value we're checking for nil.
// without first finding the check, so this one is unchecked. // without first finding the check, so this one is unchecked.
return; return;
} }
if(r != rcheck && p->as == ACHECKNIL && arch.sameaddr(&p->from, &rcheck->f.prog->from)) { if(f != fcheck && p->as == ACHECKNIL && arch.sameaddr(&p->from, &fcheck->prog->from)) {
rcheck->kill = 1; fcheck->data = &killed;
return; return;
} }
} }
// Here is a more complex version that scans backward across branches. // Here is a more complex version that scans backward across branches.
// It assumes rcheck->kill = 1 has been set on entry, and its job is to find a reason // It assumes fcheck->kill = 1 has been set on entry, and its job is to find a reason
// to keep the check (setting rcheck->kill = 0). // to keep the check (setting fcheck->kill = 0).
// It doesn't handle copying of aggregates as well as I would like, // It doesn't handle copying of aggregates as well as I would like,
// nor variables with their address taken, // nor variables with their address taken,
// and it's too subtle to turn on this late in Go 1.2. Perhaps for Go 1.3. // and it's too subtle to turn on this late in Go 1.2. Perhaps for Go 1.3.
/* /*
for(r1 = r0; r1 != nil; r1 = (NilFlow*)r1->f.p1) { for(f1 = f0; f1 != nil; f1 = f1->p1) {
if(r1->f.active == gen) if(f1->active == gen)
break; break;
r1->f.active = gen; f1->active = gen;
p = r1->f.prog; p = f1->prog;
// If same check, stop this loop but still check // If same check, stop this loop but still check
// alternate predecessors up to this point. // alternate predecessors up to this point.
if(r1 != rcheck && p->as == ACHECKNIL && arch.sameaddr(&p->from, &rcheck->f.prog->from)) if(f1 != fcheck && p->as == ACHECKNIL && arch.sameaddr(&p->from, &fcheck->prog->from))
break; break;
arch.proginfo(&info, p); arch.proginfo(&info, p);
if((info.flags & RightWrite) && arch.sameaddr(&p->to, &rcheck->f.prog->from)) { if((info.flags & RightWrite) && arch.sameaddr(&p->to, &fcheck->prog->from)) {
// Found initialization of value we're checking for nil. // Found initialization of value we're checking for nil.
// without first finding the check, so this one is unchecked. // without first finding the check, so this one is unchecked.
rcheck->kill = 0; fcheck->kill = 0;
return; return;
} }
if(r1->f.p1 == nil && r1->f.p2 == nil) { if(f1->p1 == nil && f1->p2 == nil) {
print("lost pred for %P\n", rcheck->f.prog); print("lost pred for %P\n", fcheck->prog);
for(r1=r0; r1!=nil; r1=(NilFlow*)r1->f.p1) { for(f1=f0; f1!=nil; f1=f1->p1) {
arch.proginfo(&info, r1->f.prog); arch.proginfo(&info, f1->prog);
print("\t%P %d %d %D %D\n", r1->f.prog, info.flags&RightWrite, arch.sameaddr(&r1->f.prog->to, &rcheck->f.prog->from), &r1->f.prog->to, &rcheck->f.prog->from); print("\t%P %d %d %D %D\n", r1->prog, info.flags&RightWrite, arch.sameaddr(&f1->prog->to, &fcheck->prog->from), &f1->prog->to, &fcheck->prog->from);
} }
fatal("lost pred trail"); fatal("lost pred trail");
} }
} }
for(r = r0; r != r1; r = (NilFlow*)r->f.p1) for(f = f0; f != f1; f = f->p1)
for(r2 = (NilFlow*)r->f.p2; r2 != nil; r2 = (NilFlow*)r2->f.p2link) for(f2 = f->p2; f2 != nil; f2 = f2->p2link)
nilwalkback(rcheck, r2, gen); nilwalkback(fcheck, f2, gen);
*/ */
} }
static void static void
nilwalkfwd(NilFlow *rcheck) nilwalkfwd(Flow *fcheck)
{ {
NilFlow *r, *last; Flow *f, *last;
Prog *p; Prog *p;
ProgInfo info; ProgInfo info;
...@@ -979,16 +976,16 @@ nilwalkfwd(NilFlow *rcheck) ...@@ -979,16 +976,16 @@ nilwalkfwd(NilFlow *rcheck)
// _ = *x // should panic // _ = *x // should panic
// for {} // no writes but infinite loop may be considered visible // for {} // no writes but infinite loop may be considered visible
last = nil; last = nil;
for(r = (NilFlow*)uniqs(&rcheck->f); r != nil; r = (NilFlow*)uniqs(&r->f)) { for(f = uniqs(fcheck); f != nil; f = uniqs(f)) {
p = r->f.prog; p = f->prog;
arch.proginfo(&info, p); arch.proginfo(&info, p);
if((info.flags & LeftRead) && arch.smallindir(&p->from, &rcheck->f.prog->from)) { if((info.flags & LeftRead) && arch.smallindir(&p->from, &fcheck->prog->from)) {
rcheck->kill = 1; fcheck->data = &killed;
return; return;
} }
if((info.flags & (RightRead|RightWrite)) && arch.smallindir(&p->to, &rcheck->f.prog->from)) { if((info.flags & (RightRead|RightWrite)) && arch.smallindir(&p->to, &fcheck->prog->from)) {
rcheck->kill = 1; fcheck->data = &killed;
return; return;
} }
...@@ -996,17 +993,14 @@ nilwalkfwd(NilFlow *rcheck) ...@@ -996,17 +993,14 @@ nilwalkfwd(NilFlow *rcheck)
if(p->as == ACHECKNIL) if(p->as == ACHECKNIL)
return; return;
// Stop if value is lost. // Stop if value is lost.
if((info.flags & RightWrite) && arch.sameaddr(&p->to, &rcheck->f.prog->from)) if((info.flags & RightWrite) && arch.sameaddr(&p->to, &fcheck->prog->from))
return; return;
// Stop if memory write. // Stop if memory write.
if((info.flags & RightWrite) && !arch.regtyp(&p->to)) if((info.flags & RightWrite) && !arch.regtyp(&p->to))
return; return;
// Stop if we jump backward. // Stop if we jump backward.
// This test is valid because all the NilFlow* are pointers into if(last != nil && f->id <= last->id)
// a single contiguous array. We will need to add an explicit
// numbering when the code is converted to Go.
if(last != nil && r <= last)
return; return;
last = r; last = f;
} }
} }
...@@ -68,11 +68,8 @@ uint64 STORE(Reg*); ...@@ -68,11 +68,8 @@ uint64 STORE(Reg*);
// A Reg is a wrapper around a single Prog (one instruction) that holds // A Reg is a wrapper around a single Prog (one instruction) that holds
// register optimization information while the optimizer runs. // register optimization information while the optimizer runs.
// r->prog is the instruction. // r->prog is the instruction.
// r->prog->opt points back to r.
struct Reg struct Reg
{ {
Flow f;
Bits set; // regopt variables written by this instruction. Bits set; // regopt variables written by this instruction.
Bits use1; // regopt variables read by prog->from. Bits use1; // regopt variables read by prog->from.
Bits use2; // regopt variables read by prog->to. Bits use2; // regopt variables read by prog->to.
...@@ -109,7 +106,7 @@ struct Reg ...@@ -109,7 +106,7 @@ struct Reg
// cost. // cost.
struct Rgn struct Rgn
{ {
Reg* enter; Flow* enter;
short cost; short cost;
short varno; short varno;
short regno; short regno;
...@@ -143,17 +140,7 @@ EXTERN struct ...@@ -143,17 +140,7 @@ EXTERN struct
/* /*
* reg.c * reg.c
*/ */
int rcmp(const void*, const void*);
void regopt(Prog*); void regopt(Prog*);
void addmove(Reg*, int, int, int);
Bits mkvar(Reg*, Adr*);
void prop(Reg*, Bits, Bits);
void synch(Reg*, Bits);
uint64 allreg(uint64, Rgn*);
void paint1(Reg*, int);
uint64 paint2(Reg*, int, int);
void paint3(Reg*, int, uint64, int);
void addreg(Adr*, int);
void dumpone(Flow*, int); void dumpone(Flow*, int);
void dumpit(char*, Flow*, int); void dumpit(char*, Flow*, int);
......
...@@ -33,10 +33,20 @@ ...@@ -33,10 +33,20 @@
#include "go.h" #include "go.h"
#include "popt.h" #include "popt.h"
static Reg* firstr; static Flow* firstf;
static int first = 1; static int first = 1;
int static void addmove(Flow*, int, int, int);
static Bits mkvar(Flow*, Adr*);
static void prop(Flow*, Bits, Bits);
static void synch(Flow*, Bits);
static uint64 allreg(uint64, Rgn*);
static void paint1(Flow*, int);
static uint64 paint2(Flow*, int, int);
static void paint3(Flow*, int, uint64, int);
static void addreg(Adr*, int);
static int
rcmp(const void *a1, const void *a2) rcmp(const void *a1, const void *a2)
{ {
Rgn *p1, *p2; Rgn *p1, *p2;
...@@ -76,12 +86,13 @@ setaddrs(Bits bit) ...@@ -76,12 +86,13 @@ setaddrs(Bits bit)
static Node* regnodes[64]; static Node* regnodes[64];
static void walkvardef(Node *n, Reg *r, int active); static void walkvardef(Node *n, Flow *r, int active);
void void
regopt(Prog *firstp) regopt(Prog *firstp)
{ {
Reg *r, *r1; Flow *f, *f1;
Reg *r;
Prog *p; Prog *p;
Graph *g; Graph *g;
ProgInfo info; ProgInfo info;
...@@ -134,10 +145,10 @@ regopt(Prog *firstp) ...@@ -134,10 +145,10 @@ regopt(Prog *firstp)
return; return;
} }
firstr = (Reg*)g->start; firstf = g->start;
for(r = firstr; r != R; r = (Reg*)r->f.link) { for(f = firstf; f != nil; f = f->link) {
p = r->f.prog; p = f->prog;
if(p->as == AVARDEF || p->as == AVARKILL) if(p->as == AVARDEF || p->as == AVARKILL)
continue; continue;
arch.proginfo(&info, p); arch.proginfo(&info, p);
...@@ -147,10 +158,11 @@ regopt(Prog *firstp) ...@@ -147,10 +158,11 @@ regopt(Prog *firstp)
continue; continue;
// from vs to doesn't matter for registers. // from vs to doesn't matter for registers.
r = (Reg*)f->data;
r->use1.b[0] |= info.reguse | info.regindex; r->use1.b[0] |= info.reguse | info.regindex;
r->set.b[0] |= info.regset; r->set.b[0] |= info.regset;
bit = mkvar(r, &p->from); bit = mkvar(f, &p->from);
if(bany(&bit)) { if(bany(&bit)) {
if(info.flags & LeftAddr) if(info.flags & LeftAddr)
setaddrs(bit); setaddrs(bit);
...@@ -171,7 +183,7 @@ regopt(Prog *firstp) ...@@ -171,7 +183,7 @@ regopt(Prog *firstp)
if(p->from3.type != TYPE_NONE) if(p->from3.type != TYPE_NONE)
fatal("regopt not implemented for from3"); fatal("regopt not implemented for from3");
bit = mkvar(r, &p->to); bit = mkvar(f, &p->to);
if(bany(&bit)) { if(bany(&bit)) {
if(info.flags & RightAddr) if(info.flags & RightAddr)
setaddrs(bit); setaddrs(bit);
...@@ -198,7 +210,7 @@ regopt(Prog *firstp) ...@@ -198,7 +210,7 @@ regopt(Prog *firstp)
} }
if(debug['R'] && debug['v']) if(debug['R'] && debug['v'])
dumpit("pass1", &firstr->f, 1); dumpit("pass1", firstf, 1);
/* /*
* pass 2 * pass 2
...@@ -207,7 +219,7 @@ regopt(Prog *firstp) ...@@ -207,7 +219,7 @@ regopt(Prog *firstp)
flowrpo(g); flowrpo(g);
if(debug['R'] && debug['v']) if(debug['R'] && debug['v'])
dumpit("pass2", &firstr->f, 1); dumpit("pass2", firstf, 1);
/* /*
* pass 2.5 * pass 2.5
...@@ -217,15 +229,16 @@ regopt(Prog *firstp) ...@@ -217,15 +229,16 @@ regopt(Prog *firstp)
* but we'll be done with it by then.) * but we'll be done with it by then.)
*/ */
active = 0; active = 0;
for(r = firstr; r != R; r = (Reg*)r->f.link) { for(f = firstf; f != nil; f = f->link) {
r->f.active = 0; f->active = 0;
r = (Reg*)f->data;
r->act = zbits; r->act = zbits;
} }
for(r = firstr; r != R; r = (Reg*)r->f.link) { for(f = firstf; f != nil; f = f->link) {
p = r->f.prog; p = f->prog;
if(p->as == AVARDEF && isfat(((Node*)(p->to.node))->type) && ((Node*)(p->to.node))->opt != nil) { if(p->as == AVARDEF && isfat(((Node*)(p->to.node))->type) && ((Node*)(p->to.node))->opt != nil) {
active++; active++;
walkvardef(p->to.node, r, active); walkvardef(p->to.node, f, active);
} }
} }
...@@ -236,18 +249,18 @@ regopt(Prog *firstp) ...@@ -236,18 +249,18 @@ regopt(Prog *firstp)
*/ */
loop1: loop1:
change = 0; change = 0;
for(r = firstr; r != R; r = (Reg*)r->f.link) for(f = firstf; f != nil; f = f->link)
r->f.active = 0; f->active = 0;
for(r = firstr; r != R; r = (Reg*)r->f.link) for(f = firstf; f != nil; f = f->link)
if(r->f.prog->as == ARET) if(f->prog->as == ARET)
prop(r, zbits, zbits); prop(f, zbits, zbits);
loop11: loop11:
/* pick up unreachable code */ /* pick up unreachable code */
i = 0; i = 0;
for(r = firstr; r != R; r = r1) { for(f = firstf; f != nil; f = f1) {
r1 = (Reg*)r->f.link; f1 = f->link;
if(r1 && r1->f.active && !r->f.active) { if(f1 && f1->active && !f->active) {
prop(r, zbits, zbits); prop(f, zbits, zbits);
i = 1; i = 1;
} }
} }
...@@ -257,7 +270,7 @@ loop11: ...@@ -257,7 +270,7 @@ loop11:
goto loop1; goto loop1;
if(debug['R'] && debug['v']) if(debug['R'] && debug['v'])
dumpit("pass3", &firstr->f, 1); dumpit("pass3", firstf, 1);
/* /*
* pass 4 * pass 4
...@@ -266,14 +279,14 @@ loop11: ...@@ -266,14 +279,14 @@ loop11:
*/ */
loop2: loop2:
change = 0; change = 0;
for(r = firstr; r != R; r = (Reg*)r->f.link) for(f = firstf; f != nil; f = f->link)
r->f.active = 0; f->active = 0;
synch(firstr, zbits); synch(firstf, zbits);
if(change) if(change)
goto loop2; goto loop2;
if(debug['R'] && debug['v']) if(debug['R'] && debug['v'])
dumpit("pass4", &firstr->f, 1); dumpit("pass4", firstf, 1);
/* /*
* pass 4.5 * pass 4.5
...@@ -283,7 +296,8 @@ loop2: ...@@ -283,7 +296,8 @@ loop2:
mask = ~0ULL; // can't rely on C to shift by 64 mask = ~0ULL; // can't rely on C to shift by 64
else else
mask = (1ULL<<nreg) - 1; mask = (1ULL<<nreg) - 1;
for(r = firstr; r != R; r = (Reg*)r->f.link) { for(f = firstf; f != nil; f = f->link) {
r = (Reg*)f->data;
r->regu = (r->refbehind.b[0] | r->set.b[0]) & mask; r->regu = (r->refbehind.b[0] | r->set.b[0]) & mask;
r->set.b[0] &= ~mask; r->set.b[0] &= ~mask;
r->use1.b[0] &= ~mask; r->use1.b[0] &= ~mask;
...@@ -297,47 +311,49 @@ loop2: ...@@ -297,47 +311,49 @@ loop2:
} }
if(debug['R'] && debug['v']) if(debug['R'] && debug['v'])
dumpit("pass4.5", &firstr->f, 1); dumpit("pass4.5", firstf, 1);
/* /*
* pass 5 * pass 5
* isolate regions * isolate regions
* calculate costs (paint1) * calculate costs (paint1)
*/ */
r = firstr; f = firstf;
if(r) { if(f) {
r = (Reg*)f->data;
for(z=0; z<BITS; z++) for(z=0; z<BITS; z++)
bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) & bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]); ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
if(bany(&bit) && !r->f.refset) { if(bany(&bit) && !f->refset) {
// should never happen - all variables are preset // should never happen - all variables are preset
if(debug['w']) if(debug['w'])
print("%L: used and not set: %Q\n", r->f.prog->lineno, bit); print("%L: used and not set: %Q\n", f->prog->lineno, bit);
r->f.refset = 1; f->refset = 1;
} }
} }
for(r = firstr; r != R; r = (Reg*)r->f.link) for(f = firstf; f != nil; f = f->link)
r->act = zbits; ((Reg*)f->data)->act = zbits;
rgp = region; rgp = region;
nregion = 0; nregion = 0;
for(r = firstr; r != R; r = (Reg*)r->f.link) { for(f = firstf; f != nil; f = f->link) {
r = (Reg*)f->data;
for(z=0; z<BITS; z++) for(z=0; z<BITS; z++)
bit.b[z] = r->set.b[z] & bit.b[z] = r->set.b[z] &
~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]); ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
if(bany(&bit) && !r->f.refset) { if(bany(&bit) && !f->refset) {
if(debug['w']) if(debug['w'])
print("%L: set and not used: %Q\n", r->f.prog->lineno, bit); print("%L: set and not used: %Q\n", f->prog->lineno, bit);
r->f.refset = 1; f->refset = 1;
arch.excise(&r->f); arch.excise(f);
} }
for(z=0; z<BITS; z++) for(z=0; z<BITS; z++)
bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]); bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
while(bany(&bit)) { while(bany(&bit)) {
i = bnum(bit); i = bnum(bit);
rgp->enter = r; rgp->enter = f;
rgp->varno = i; rgp->varno = i;
change = 0; change = 0;
paint1(r, i); paint1(f, i);
biclr(&bit, i); biclr(&bit, i);
if(change <= 0) if(change <= 0)
continue; continue;
...@@ -355,7 +371,7 @@ brk: ...@@ -355,7 +371,7 @@ brk:
qsort(region, nregion, sizeof(region[0]), rcmp); qsort(region, nregion, sizeof(region[0]), rcmp);
if(debug['R'] && debug['v']) if(debug['R'] && debug['v'])
dumpit("pass5", &firstr->f, 1); dumpit("pass5", firstf, 1);
/* /*
* pass 6 * pass 6
...@@ -367,7 +383,7 @@ brk: ...@@ -367,7 +383,7 @@ brk:
print("\nregisterizing\n"); print("\nregisterizing\n");
for(i=0; i<nregion; i++) { for(i=0; i<nregion; i++) {
if(debug['R'] && debug['v']) if(debug['R'] && debug['v'])
print("region %d: cost %d varno %d enter %lld\n", i, rgp->cost, rgp->varno, rgp->enter->f.prog->pc); print("region %d: cost %d varno %d enter %lld\n", i, rgp->cost, rgp->varno, rgp->enter->prog->pc);
bit = blsh(rgp->varno); bit = blsh(rgp->varno);
usedreg = paint2(rgp->enter, rgp->varno, 0); usedreg = paint2(rgp->enter, rgp->varno, 0);
vreg = allreg(usedreg, rgp); vreg = allreg(usedreg, rgp);
...@@ -390,15 +406,15 @@ brk: ...@@ -390,15 +406,15 @@ brk:
for(i=0; i<nvar; i++) for(i=0; i<nvar; i++)
var[i].node->opt = nil; var[i].node->opt = nil;
flowend(g); flowend(g);
firstr = R; firstf = nil;
if(debug['R'] && debug['v']) { if(debug['R'] && debug['v']) {
// Rebuild flow graph, since we inserted instructions // Rebuild flow graph, since we inserted instructions
g = flowstart(firstp, sizeof(Reg)); g = flowstart(firstp, 0);
firstr = (Reg*)g->start; firstf = g->start;
dumpit("pass6", &firstr->f, 1); dumpit("pass6", firstf, 0);
flowend(g); flowend(g);
firstr = R; firstf = nil;
} }
/* /*
...@@ -447,37 +463,37 @@ brk: ...@@ -447,37 +463,37 @@ brk:
} }
static void static void
walkvardef(Node *n, Reg *r, int active) walkvardef(Node *n, Flow *f, int active)
{ {
Reg *r1, *r2; Flow *f1, *f2;
int bn; int bn;
Var *v; Var *v;
for(r1=r; r1!=R; r1=(Reg*)r1->f.s1) { for(f1=f; f1!=nil; f1=f1->s1) {
if(r1->f.active == active) if(f1->active == active)
break; break;
r1->f.active = active; f1->active = active;
if(r1->f.prog->as == AVARKILL && r1->f.prog->to.node == n) if(f1->prog->as == AVARKILL && f1->prog->to.node == n)
break; break;
for(v=n->opt; v!=nil; v=v->nextinnode) { for(v=n->opt; v!=nil; v=v->nextinnode) {
bn = v - var; bn = v - var;
biset(&r1->act, bn); biset(&((Reg*)f1->data)->act, bn);
} }
if(r1->f.prog->as == ACALL) if(f1->prog->as == ACALL)
break; break;
} }
for(r2=r; r2!=r1; r2=(Reg*)r2->f.s1) for(f2=f; f2!=f1; f2=f2->s1)
if(r2->f.s2 != nil) if(f2->s2 != nil)
walkvardef(n, (Reg*)r2->f.s2, active); walkvardef(n, f2->s2, active);
} }
/* /*
* add mov b,rn * add mov b,rn
* just after r * just after r
*/ */
void static void
addmove(Reg *r, int bn, int rn, int f) addmove(Flow *r, int bn, int rn, int f)
{ {
Prog *p, *p1; Prog *p, *p1;
Adr *a; Adr *a;
...@@ -487,7 +503,7 @@ addmove(Reg *r, int bn, int rn, int f) ...@@ -487,7 +503,7 @@ addmove(Reg *r, int bn, int rn, int f)
clearp(p1); clearp(p1);
p1->pc = 9999; p1->pc = 9999;
p = r->f.prog; p = r->prog;
p1->link = p->link; p1->link = p->link;
p->link = p1; p->link = p1;
p1->lineno = p->lineno; p1->lineno = p->lineno;
...@@ -540,8 +556,8 @@ overlap(int64 o1, int w1, int64 o2, int w2) ...@@ -540,8 +556,8 @@ overlap(int64 o1, int w1, int64 o2, int w2)
return 1; return 1;
} }
Bits static Bits
mkvar(Reg *r, Adr *a) mkvar(Flow *f, Adr *a)
{ {
Var *v; Var *v;
int i, n, et, z, flag; int i, n, et, z, flag;
...@@ -550,6 +566,8 @@ mkvar(Reg *r, Adr *a) ...@@ -550,6 +566,8 @@ mkvar(Reg *r, Adr *a)
int64 o; int64 o;
Bits bit; Bits bit;
Node *node; Node *node;
Reg *r;
/* /*
* mark registers used * mark registers used
...@@ -557,7 +575,7 @@ mkvar(Reg *r, Adr *a) ...@@ -557,7 +575,7 @@ mkvar(Reg *r, Adr *a)
if(a->type == TYPE_NONE) if(a->type == TYPE_NONE)
goto none; goto none;
if(r != R) r = (Reg*)f->data;
r->use1.b[0] |= arch.doregbits(a->index); // TODO: Use RtoB r->use1.b[0] |= arch.doregbits(a->index); // TODO: Use RtoB
switch(a->type) { switch(a->type) {
...@@ -574,7 +592,7 @@ mkvar(Reg *r, Adr *a) ...@@ -574,7 +592,7 @@ mkvar(Reg *r, Adr *a)
if(arch.thechar == '9' || arch.thechar == '5') if(arch.thechar == '9' || arch.thechar == '5')
goto memcase; goto memcase;
a->type = TYPE_MEM; a->type = TYPE_MEM;
bit = mkvar(r, a); bit = mkvar(f, a);
setaddrs(bit); setaddrs(bit);
a->type = TYPE_ADDR; a->type = TYPE_ADDR;
ostats.naddr++; ostats.naddr++;
...@@ -729,14 +747,16 @@ none: ...@@ -729,14 +747,16 @@ none:
return zbits; return zbits;
} }
void static void
prop(Reg *r, Bits ref, Bits cal) prop(Flow *f, Bits ref, Bits cal)
{ {
Reg *r1, *r2; Flow *f1, *f2;
Reg *r, *r1;
int z, i, j; int z, i, j;
Var *v, *v1; Var *v, *v1;
for(r1 = r; r1 != R; r1 = (Reg*)r1->f.p1) { for(f1 = f; f1 != nil; f1 = f1->p1) {
r1 = (Reg*)f1->data;
for(z=0; z<BITS; z++) { for(z=0; z<BITS; z++) {
ref.b[z] |= r1->refahead.b[z]; ref.b[z] |= r1->refahead.b[z];
if(ref.b[z] != r1->refahead.b[z]) { if(ref.b[z] != r1->refahead.b[z]) {
...@@ -749,9 +769,9 @@ prop(Reg *r, Bits ref, Bits cal) ...@@ -749,9 +769,9 @@ prop(Reg *r, Bits ref, Bits cal)
change++; change++;
} }
} }
switch(r1->f.prog->as) { switch(f1->prog->as) {
case ACALL: case ACALL:
if(noreturn(r1->f.prog)) if(noreturn(f1->prog))
break; break;
// Mark all input variables (ivar) as used, because that's what the // Mark all input variables (ivar) as used, because that's what the
...@@ -831,22 +851,27 @@ prop(Reg *r, Bits ref, Bits cal) ...@@ -831,22 +851,27 @@ prop(Reg *r, Bits ref, Bits cal)
r1->refbehind.b[z] = ref.b[z]; r1->refbehind.b[z] = ref.b[z];
r1->calbehind.b[z] = cal.b[z]; r1->calbehind.b[z] = cal.b[z];
} }
if(r1->f.active) if(f1->active)
break; break;
r1->f.active = 1; f1->active = 1;
}
for(; f != f1; f = f->p1) {
r = (Reg*)f->data;
for(f2 = f->p2; f2 != nil; f2 = f2->p2link)
prop(f2, r->refbehind, r->calbehind);
} }
for(; r != r1; r = (Reg*)r->f.p1)
for(r2 = (Reg*)r->f.p2; r2 != R; r2 = (Reg*)r2->f.p2link)
prop(r2, r->refbehind, r->calbehind);
} }
void static void
synch(Reg *r, Bits dif) synch(Flow *f, Bits dif)
{ {
Flow *f1;
Reg *r1; Reg *r1;
int z; int z;
for(r1 = r; r1 != R; r1 = (Reg*)r1->f.s1) { for(f1 = f; f1 != nil; f1 = f1->s1) {
r1 = (Reg*)f1->data;
for(z=0; z<BITS; z++) { for(z=0; z<BITS; z++) {
dif.b[z] = (dif.b[z] & dif.b[z] = (dif.b[z] &
~(~r1->refbehind.b[z] & r1->refahead.b[z])) | ~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
...@@ -856,17 +881,17 @@ synch(Reg *r, Bits dif) ...@@ -856,17 +881,17 @@ synch(Reg *r, Bits dif)
change++; change++;
} }
} }
if(r1->f.active) if(f1->active)
break; break;
r1->f.active = 1; f1->active = 1;
for(z=0; z<BITS; z++) for(z=0; z<BITS; z++)
dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]); dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
if(r1->f.s2 != nil) if(f1->s2 != nil)
synch((Reg*)r1->f.s2, dif); synch(f1->s2, dif);
} }
} }
uint64 static uint64
allreg(uint64 b, Rgn *r) allreg(uint64 b, Rgn *r)
{ {
Var *v; Var *v;
...@@ -913,61 +938,66 @@ allreg(uint64 b, Rgn *r) ...@@ -913,61 +938,66 @@ allreg(uint64 b, Rgn *r)
return 0; return 0;
} }
void static void
paint1(Reg *r, int bn) paint1(Flow *f, int bn)
{ {
Reg *r1; Flow *f1;
Reg *r, *r1;
int z; int z;
uint64 bb; uint64 bb;
z = bn/64; z = bn/64;
bb = 1LL<<(bn%64); bb = 1LL<<(bn%64);
r = (Reg*)f->data;
if(r->act.b[z] & bb) if(r->act.b[z] & bb)
return; return;
for(;;) { for(;;) {
if(!(r->refbehind.b[z] & bb)) if(!(r->refbehind.b[z] & bb))
break; break;
r1 = (Reg*)r->f.p1; f1 = f->p1;
if(r1 == R) if(f1 == nil)
break; break;
r1 = (Reg*)f1->data;
if(!(r1->refahead.b[z] & bb)) if(!(r1->refahead.b[z] & bb))
break; break;
if(r1->act.b[z] & bb) if(r1->act.b[z] & bb)
break; break;
f = f1;
r = r1; r = r1;
} }
if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) { if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
change -= CLOAD * r->f.loop; change -= CLOAD * f->loop;
} }
for(;;) { for(;;) {
r->act.b[z] |= bb; r->act.b[z] |= bb;
if(r->f.prog->as != ANOP) { // don't give credit for NOPs if(f->prog->as != ANOP) { // don't give credit for NOPs
if(r->use1.b[z] & bb) if(r->use1.b[z] & bb)
change += CREF * r->f.loop; change += CREF * f->loop;
if((r->use2.b[z]|r->set.b[z]) & bb) if((r->use2.b[z]|r->set.b[z]) & bb)
change += CREF * r->f.loop; change += CREF * f->loop;
} }
if(STORE(r) & r->regdiff.b[z] & bb) { if(STORE(r) & r->regdiff.b[z] & bb) {
change -= CLOAD * r->f.loop; change -= CLOAD * f->loop;
} }
if(r->refbehind.b[z] & bb) if(r->refbehind.b[z] & bb)
for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link) for(f1 = f->p2; f1 != nil; f1 = f1->p2link)
if(r1->refahead.b[z] & bb) if(((Reg*)f1->data)->refahead.b[z] & bb)
paint1(r1, bn); paint1(f1, bn);
if(!(r->refahead.b[z] & bb)) if(!(r->refahead.b[z] & bb))
break; break;
r1 = (Reg*)r->f.s2; f1 = f->s2;
if(r1 != R) if(f1 != nil)
if(r1->refbehind.b[z] & bb) if(((Reg*)f1->data)->refbehind.b[z] & bb)
paint1(r1, bn); paint1(f1, bn);
r = (Reg*)r->f.s1; f = f->s1;
if(r == R) if(f == nil)
break; break;
r = (Reg*)f->data;
if(r->act.b[z] & bb) if(r->act.b[z] & bb)
break; break;
if(!(r->refbehind.b[z] & bb)) if(!(r->refbehind.b[z] & bb))
...@@ -975,52 +1005,57 @@ paint1(Reg *r, int bn) ...@@ -975,52 +1005,57 @@ paint1(Reg *r, int bn)
} }
} }
uint64 static uint64
paint2(Reg *r, int bn, int depth) paint2(Flow *f, int bn, int depth)
{ {
Reg *r1; Flow *f1;
Reg *r, *r1;
int z; int z;
uint64 bb, vreg; uint64 bb, vreg;
z = bn/64; z = bn/64;
bb = 1LL << (bn%64); bb = 1LL << (bn%64);
vreg = regbits; vreg = regbits;
r = (Reg*)f->data;
if(!(r->act.b[z] & bb)) if(!(r->act.b[z] & bb))
return vreg; return vreg;
for(;;) { for(;;) {
if(!(r->refbehind.b[z] & bb)) if(!(r->refbehind.b[z] & bb))
break; break;
r1 = (Reg*)r->f.p1; f1 = f->p1;
if(r1 == R) if(f1 == nil)
break; break;
r1 = (Reg*)f1->data;
if(!(r1->refahead.b[z] & bb)) if(!(r1->refahead.b[z] & bb))
break; break;
if(!(r1->act.b[z] & bb)) if(!(r1->act.b[z] & bb))
break; break;
f = f1;
r = r1; r = r1;
} }
for(;;) { for(;;) {
if(debug['R'] && debug['v']) if(debug['R'] && debug['v'])
print(" paint2 %d %P\n", depth, r->f.prog); print(" paint2 %d %P\n", depth, f->prog);
r->act.b[z] &= ~bb; r->act.b[z] &= ~bb;
vreg |= r->regu; vreg |= r->regu;
if(r->refbehind.b[z] & bb) if(r->refbehind.b[z] & bb)
for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link) for(f1 = f->p2; f1 != nil; f1 = f1->p2link)
if(r1->refahead.b[z] & bb) if(((Reg*)f1->data)->refahead.b[z] & bb)
vreg |= paint2(r1, bn, depth+1); vreg |= paint2(f1, bn, depth+1);
if(!(r->refahead.b[z] & bb)) if(!(r->refahead.b[z] & bb))
break; break;
r1 = (Reg*)r->f.s2; f1 = f->s2;
if(r1 != R) if(f1 != nil)
if(r1->refbehind.b[z] & bb) if(((Reg*)f1->data)->refbehind.b[z] & bb)
vreg |= paint2(r1, bn, depth+1); vreg |= paint2(f1, bn, depth+1);
r = (Reg*)r->f.s1; f = f->s1;
if(r == R) if(f == nil)
break; break;
r = (Reg*)f->data;
if(!(r->act.b[z] & bb)) if(!(r->act.b[z] & bb))
break; break;
if(!(r->refbehind.b[z] & bb)) if(!(r->refbehind.b[z] & bb))
...@@ -1030,36 +1065,40 @@ paint2(Reg *r, int bn, int depth) ...@@ -1030,36 +1065,40 @@ paint2(Reg *r, int bn, int depth)
return vreg; return vreg;
} }
void static void
paint3(Reg *r, int bn, uint64 rb, int rn) paint3(Flow *f, int bn, uint64 rb, int rn)
{ {
Reg *r1; Flow *f1;
Reg *r, *r1;
Prog *p; Prog *p;
int z; int z;
uint64 bb; uint64 bb;
z = bn/64; z = bn/64;
bb = 1LL << (bn%64); bb = 1LL << (bn%64);
r = (Reg*)f->data;
if(r->act.b[z] & bb) if(r->act.b[z] & bb)
return; return;
for(;;) { for(;;) {
if(!(r->refbehind.b[z] & bb)) if(!(r->refbehind.b[z] & bb))
break; break;
r1 = (Reg*)r->f.p1; f1 = f->p1;
if(r1 == R) if(f1 == nil)
break; break;
r1 = (Reg*)f1->data;
if(!(r1->refahead.b[z] & bb)) if(!(r1->refahead.b[z] & bb))
break; break;
if(r1->act.b[z] & bb) if(r1->act.b[z] & bb)
break; break;
f = f1;
r = r1; r = r1;
} }
if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb) if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
addmove(r, bn, rn, 0); addmove(f, bn, rn, 0);
for(;;) { for(;;) {
r->act.b[z] |= bb; r->act.b[z] |= bb;
p = r->f.prog; p = f->prog;
if(r->use1.b[z] & bb) { if(r->use1.b[z] & bb) {
if(debug['R'] && debug['v']) if(debug['R'] && debug['v'])
...@@ -1077,23 +1116,24 @@ paint3(Reg *r, int bn, uint64 rb, int rn) ...@@ -1077,23 +1116,24 @@ paint3(Reg *r, int bn, uint64 rb, int rn)
} }
if(STORE(r) & r->regdiff.b[z] & bb) if(STORE(r) & r->regdiff.b[z] & bb)
addmove(r, bn, rn, 1); addmove(f, bn, rn, 1);
r->regu |= rb; r->regu |= rb;
if(r->refbehind.b[z] & bb) if(r->refbehind.b[z] & bb)
for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link) for(f1 = f->p2; f1 != nil; f1 = f1->p2link)
if(r1->refahead.b[z] & bb) if(((Reg*)f1->data)->refahead.b[z] & bb)
paint3(r1, bn, rb, rn); paint3(f1, bn, rb, rn);
if(!(r->refahead.b[z] & bb)) if(!(r->refahead.b[z] & bb))
break; break;
r1 = (Reg*)r->f.s2; f1 = f->s2;
if(r1 != R) if(f1 != nil)
if(r1->refbehind.b[z] & bb) if(((Reg*)f1->data)->refbehind.b[z] & bb)
paint3(r1, bn, rb, rn); paint3(f1, bn, rb, rn);
r = (Reg*)r->f.s1; f = f->s1;
if(r == R) if(f == nil)
break; break;
r = (Reg*)f->data;
if(r->act.b[z] & bb) if(r->act.b[z] & bb)
break; break;
if(!(r->refbehind.b[z] & bb)) if(!(r->refbehind.b[z] & bb))
...@@ -1101,7 +1141,7 @@ paint3(Reg *r, int bn, uint64 rb, int rn) ...@@ -1101,7 +1141,7 @@ paint3(Reg *r, int bn, uint64 rb, int rn)
} }
} }
void static void
addreg(Adr *a, int rn) addreg(Adr *a, int rn)
{ {
a->sym = nil; a->sym = nil;
...@@ -1123,7 +1163,7 @@ dumpone(Flow *f, int isreg) ...@@ -1123,7 +1163,7 @@ dumpone(Flow *f, int isreg)
print("%d:%P", f->loop, f->prog); print("%d:%P", f->loop, f->prog);
if(isreg) { if(isreg) {
r = (Reg*)f; r = (Reg*)f->data;
for(z=0; z<BITS; z++) for(z=0; z<BITS; z++)
bit.b[z] = bit.b[z] =
r->set.b[z] | r->set.b[z] |
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment