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/3962
Reviewed-by: Austin Clements <austin@google.com>
Prog *p;
int t;
- g = flowstart(firstp, sizeof(Flow));
+ g = flowstart(firstp, 0);
if(g == nil)
return;
gactive = 0;
Prog *p, *p1;
int t;
- g = flowstart(firstp, sizeof(Flow));
+ g = flowstart(firstp, 0);
if(g == nil)
return;
gactive = 0;
Prog *p, *p1;
int t;
- g = flowstart(firstp, sizeof(Flow));
+ g = flowstart(firstp, 0);
if(g == nil)
return;
gactive = 0;
Prog *p, *p1;
int t;
- g = flowstart(firstp, sizeof(Flow));
+ g = flowstart(firstp, 0);
if(g == nil)
return;
gactive = 0;
int32 active; // usable by client
+ int32 id; // sequence number in flow graph
int32 rpo; // reverse post ordering
uint16 loop; // x5 for every loop
uchar refset; // diagnostic generated
+
+ void* data; // for use by client
};
struct Graph
// Control flow analysis. The Flow structures hold predecessor and successor
// information as well as basic loop analysis.
//
-// graph = flowstart(firstp, sizeof(Flow));
+// graph = flowstart(firstp, 0);
// ... use flow graph ...
// flowend(graph); // free graph
//
// f->p1 and this list:
//
// for(f2 = f->p2; f2 != nil; f2 = f2->p2link)
-//
-// Often the Flow struct is embedded as the first field inside a larger struct S.
-// In that case casts are needed to convert Flow* to S* in many places but the
-// idea is the same. Pass sizeof(S) instead of sizeof(Flow) to flowstart.
+//
+// The size argument to flowstart specifies an amount of zeroed memory
+// to allocate in every f->data field, for use by the client.
+// If size == 0, f->data will be nil.
Graph*
flowstart(Prog *firstp, int size)
{
- int nf;
+ int id, nf;
Flow *f, *f1, *start, *last;
Graph *graph;
Prog *p;
ProgInfo info;
+ char *data;
// Count and mark instructions to annotate.
nf = 0;
}
// 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)
fatal("out of memory");
start = (Flow*)(graph+1);
last = nil;
f = start;
+ data = (char*)(f+nf);
+ if(size == 0)
+ data = nil;
+ id = 0;
for(p = firstp; p != P; p = p->link) {
if(p->opt == nil)
continue;
if(last)
last->link = f;
last = f;
-
- f = (Flow*)((uchar*)f + size);
+ f->data = data;
+ f->id = id;
+ f++;
+ id++;
+ data += size;
}
// Fill in pred/succ information.
// ACM TOPLAS 1999.
typedef struct TempVar TempVar;
-typedef struct TempFlow TempFlow;
struct TempVar
{
Node *node;
- TempFlow *def; // definition of temp var
- TempFlow *use; // use list, chained through TempFlow.uselink
+ Flow *def; // definition of temp var
+ Flow *use; // use list, chained through Flow.data
TempVar *freelink; // next free temp in Type.opt list
TempVar *merge; // merge var with this one
vlong start; // smallest Prog.pc in live range
uchar removed; // removed from program
};
-struct TempFlow
-{
- Flow f;
- TempFlow *uselink;
-};
-
static int
startcmp(const void *va, const void *vb)
{
return n->class == PAUTO && strncmp(n->sym->name, "autotmp", 7) == 0;
}
-static void mergewalk(TempVar*, TempFlow*, uint32);
-static void varkillwalk(TempVar*, TempFlow*, uint32);
+static void mergewalk(TempVar*, Flow*, uint32);
+static void varkillwalk(TempVar*, Flow*, uint32);
void
mergetemp(Prog *firstp)
{
int i, j, nvar, ninuse, nfree, nkill;
TempVar *var, *v, *v1, **bystart, **inuse;
- TempFlow *r;
+ Flow *f;
NodeList *l, **lp;
Node *n;
Prog *p, *p1;
enum { Debug = 0 };
- g = flowstart(firstp, sizeof(TempFlow));
+ g = flowstart(firstp, 0);
if(g == nil)
return;
// 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
// single-use (that's why we have so many!).
- for(r = (TempFlow*)g->start; r != nil; r = (TempFlow*)r->f.link) {
- p = r->f.prog;
+ for(f = g->start; f != nil; f = f->link) {
+ p = f->prog;
arch.proginfo(&info, p);
if(p->from.node != N && ((Node*)(p->from.node))->opt && p->to.node != N && ((Node*)(p->to.node))->opt)
v = n->opt;
if(v != nil) {
if(v->def == nil)
- v->def = r;
- r->uselink = v->use;
- v->use = r;
+ v->def = f;
+ f->data = v->use;
+ v->use = f;
if(n == p->from.node && (info.flags & LeftAddr))
v->addr = 1;
}
if(v->addr)
continue;
// Used in only one instruction, which had better be a write.
- if((r = v->use) != nil && r->uselink == nil) {
- p = r->f.prog;
+ if((f = v->use) != nil && (Flow*)f->data == nil) {
+ p = f->prog;
arch.proginfo(&info, p);
if(p->to.node == v->node && (info.flags & RightWrite) && !(info.flags & RightRead)) {
p->as = ANOP;
// Written in one instruction, read in the next, otherwise unused,
// 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) {
- p = r->f.prog;
+ if((f = v->use) != nil && f->link == (Flow*)f->data && (Flow*)((Flow*)f->data)->data == nil && uniqp(f->link) == f) {
+ p = f->prog;
arch.proginfo(&info, p);
- p1 = r->f.link->prog;
+ p1 = f->link->prog;
arch.proginfo(&info1, p1);
enum {
SizeAny = SizeB | SizeW | SizeL | SizeQ | SizeF | SizeD,
!((info.flags|info1.flags) & (LeftAddr|RightAddr)) &&
(info.flags & SizeAny) == (info1.flags & SizeAny)) {
p1->from = p->from;
- arch.excise(&r->f);
+ arch.excise(f);
v->removed = 1;
if(Debug)
print("drop immediate-use %S\n", v->node->sym);
// Traverse live range of each variable to set start, end.
// 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;
for(v = var; v < var+nvar; v++) {
gen++;
- for(r = v->use; r != nil; r = r->uselink)
- mergewalk(v, r, gen);
+ for(f = v->use; f != nil; f = (Flow*)f->data)
+ mergewalk(v, f, gen);
if(v->addr) {
gen++;
- for(r = v->use; r != nil; r = r->uselink)
- varkillwalk(v, r, gen);
+ for(f = v->use; f != nil; f = (Flow*)f->data)
+ varkillwalk(v, f, gen);
}
}
if(v->merge)
print(" merge %#N", v->merge->node);
if(v->start == v->end)
- print(" %P", v->def->f.prog);
+ print(" %P", v->def->prog);
print("\n");
}
}
// Update node references to use merged temporaries.
- for(r = (TempFlow*)g->start; r != nil; r = (TempFlow*)r->f.link) {
- p = r->f.prog;
+ for(f = g->start; f != nil; f = f->link) {
+ p = f->prog;
if((n = p->from.node) != N && (v = n->opt) != nil && v->merge != nil)
p->from.node = v->merge->node;
if((n = p->to.node) != N && (v = n->opt) != nil && v->merge != nil)
}
static void
-mergewalk(TempVar *v, TempFlow *r0, uint32 gen)
+mergewalk(TempVar *v, Flow *f0, uint32 gen)
{
Prog *p;
- TempFlow *r1, *r, *r2;
+ Flow *f1, *f, *f2;
- for(r1 = r0; r1 != nil; r1 = (TempFlow*)r1->f.p1) {
- if(r1->f.active == gen)
+ for(f1 = f0; f1 != nil; f1 = f1->p1) {
+ if(f1->active == gen)
break;
- r1->f.active = gen;
- p = r1->f.prog;
+ f1->active = gen;
+ p = f1->prog;
if(v->end < p->pc)
v->end = p->pc;
- if(r1 == v->def) {
+ if(f1 == v->def) {
v->start = p->pc;
break;
}
}
- for(r = r0; r != r1; r = (TempFlow*)r->f.p1)
- for(r2 = (TempFlow*)r->f.p2; r2 != nil; r2 = (TempFlow*)r2->f.p2link)
- mergewalk(v, r2, gen);
+ for(f = f0; f != f1; f = f->p1)
+ for(f2 = f->p2; f2 != nil; f2 = f2->p2link)
+ mergewalk(v, f2, gen);
}
static void
-varkillwalk(TempVar *v, TempFlow *r0, uint32 gen)
+varkillwalk(TempVar *v, Flow *f0, uint32 gen)
{
Prog *p;
- TempFlow *r1, *r;
+ Flow *f1, *f;
- for(r1 = r0; r1 != nil; r1 = (TempFlow*)r1->f.s1) {
- if(r1->f.active == gen)
+ for(f1 = f0; f1 != nil; f1 = f1->s1) {
+ if(f1->active == gen)
break;
- r1->f.active = gen;
- p = r1->f.prog;
+ f1->active = gen;
+ p = f1->prog;
if(v->end < p->pc)
v->end = p->pc;
if(v->start > p->pc)
break;
}
- for(r = r0; r != r1; r = (TempFlow*)r->f.s1)
- varkillwalk(v, (TempFlow*)r->f.s2, gen);
+ for(f = f0; f != f1; f = f->s1)
+ varkillwalk(v, f->s2, gen);
}
// Eliminate redundant nil pointer checks.
// each load.
typedef struct NilVar NilVar;
-typedef struct NilFlow NilFlow;
-struct NilFlow {
- Flow f;
- int kill;
-};
+static void nilwalkback(Flow *rcheck);
+static void nilwalkfwd(Flow *rcheck);
-static void nilwalkback(NilFlow *rcheck);
-static void nilwalkfwd(NilFlow *rcheck);
+static int killed; // f->data is either nil or &killed
void
nilopt(Prog *firstp)
{
- NilFlow *r;
+ Flow *f;
Prog *p;
Graph *g;
int ncheck, nkill;
- g = flowstart(firstp, sizeof(NilFlow));
+ g = flowstart(firstp, 0);
if(g == nil)
return;
ncheck = 0;
nkill = 0;
- for(r = (NilFlow*)g->start; r != nil; r = (NilFlow*)r->f.link) {
- p = r->f.prog;
+ for(f = g->start; f != nil; f = f->link) {
+ p = f->prog;
if(p->as != ACHECKNIL || !arch.regtyp(&p->from))
continue;
ncheck++;
if(arch.stackaddr(&p->from)) {
if(debug_checknil && p->lineno > 1)
warnl(p->lineno, "removed nil check of SP address");
- r->kill = 1;
+ f->data = &killed;
continue;
}
- nilwalkfwd(r);
- if(r->kill) {
+ nilwalkfwd(f);
+ if(f->data != nil) {
if(debug_checknil && p->lineno > 1)
warnl(p->lineno, "removed nil check before indirect");
continue;
}
- nilwalkback(r);
- if(r->kill) {
+ nilwalkback(f);
+ if(f->data != nil) {
if(debug_checknil && p->lineno > 1)
warnl(p->lineno, "removed repeated nil check");
continue;
}
}
- for(r = (NilFlow*)g->start; r != nil; r = (NilFlow*)r->f.link) {
- if(r->kill) {
+ for(f = g->start; f != nil; f = f->link) {
+ if(f->data != nil) {
nkill++;
- arch.excise(&r->f);
+ arch.excise(f);
}
}
}
static void
-nilwalkback(NilFlow *rcheck)
+nilwalkback(Flow *fcheck)
{
Prog *p;
ProgInfo info;
- NilFlow *r;
+ Flow *f;
- for(r = rcheck; r != nil; r = (NilFlow*)uniqp(&r->f)) {
- p = r->f.prog;
+ for(f = fcheck; f != nil; f = uniqp(f)) {
+ p = f->prog;
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.
// without first finding the check, so this one is unchecked.
return;
}
- if(r != rcheck && p->as == ACHECKNIL && arch.sameaddr(&p->from, &rcheck->f.prog->from)) {
- rcheck->kill = 1;
+ if(f != fcheck && p->as == ACHECKNIL && arch.sameaddr(&p->from, &fcheck->prog->from)) {
+ fcheck->data = &killed;
return;
}
}
// 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
- // to keep the check (setting rcheck->kill = 0).
+ // It assumes fcheck->kill = 1 has been set on entry, and its job is to find a reason
+ // to keep the check (setting fcheck->kill = 0).
// It doesn't handle copying of aggregates as well as I would like,
// 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.
/*
- for(r1 = r0; r1 != nil; r1 = (NilFlow*)r1->f.p1) {
- if(r1->f.active == gen)
+ for(f1 = f0; f1 != nil; f1 = f1->p1) {
+ if(f1->active == gen)
break;
- r1->f.active = gen;
- p = r1->f.prog;
+ f1->active = gen;
+ p = f1->prog;
// If same check, stop this loop but still check
// 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;
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.
// without first finding the check, so this one is unchecked.
- rcheck->kill = 0;
+ fcheck->kill = 0;
return;
}
- if(r1->f.p1 == nil && r1->f.p2 == nil) {
- print("lost pred for %P\n", rcheck->f.prog);
- for(r1=r0; r1!=nil; r1=(NilFlow*)r1->f.p1) {
- arch.proginfo(&info, r1->f.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);
+ if(f1->p1 == nil && f1->p2 == nil) {
+ print("lost pred for %P\n", fcheck->prog);
+ for(f1=f0; f1!=nil; f1=f1->p1) {
+ arch.proginfo(&info, f1->prog);
+ 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");
}
}
- for(r = r0; r != r1; r = (NilFlow*)r->f.p1)
- for(r2 = (NilFlow*)r->f.p2; r2 != nil; r2 = (NilFlow*)r2->f.p2link)
- nilwalkback(rcheck, r2, gen);
+ for(f = f0; f != f1; f = f->p1)
+ for(f2 = f->p2; f2 != nil; f2 = f2->p2link)
+ nilwalkback(fcheck, f2, gen);
*/
}
static void
-nilwalkfwd(NilFlow *rcheck)
+nilwalkfwd(Flow *fcheck)
{
- NilFlow *r, *last;
+ Flow *f, *last;
Prog *p;
ProgInfo info;
// _ = *x // should panic
// for {} // no writes but infinite loop may be considered visible
last = nil;
- for(r = (NilFlow*)uniqs(&rcheck->f); r != nil; r = (NilFlow*)uniqs(&r->f)) {
- p = r->f.prog;
+ for(f = uniqs(fcheck); f != nil; f = uniqs(f)) {
+ p = f->prog;
arch.proginfo(&info, p);
- if((info.flags & LeftRead) && arch.smallindir(&p->from, &rcheck->f.prog->from)) {
- rcheck->kill = 1;
+ if((info.flags & LeftRead) && arch.smallindir(&p->from, &fcheck->prog->from)) {
+ fcheck->data = &killed;
return;
}
- if((info.flags & (RightRead|RightWrite)) && arch.smallindir(&p->to, &rcheck->f.prog->from)) {
- rcheck->kill = 1;
+ if((info.flags & (RightRead|RightWrite)) && arch.smallindir(&p->to, &fcheck->prog->from)) {
+ fcheck->data = &killed;
return;
}
if(p->as == ACHECKNIL)
return;
// 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;
// Stop if memory write.
if((info.flags & RightWrite) && !arch.regtyp(&p->to))
return;
// Stop if we jump backward.
- // This test is valid because all the NilFlow* are pointers into
- // a single contiguous array. We will need to add an explicit
- // numbering when the code is converted to Go.
- if(last != nil && r <= last)
+ if(last != nil && f->id <= last->id)
return;
- last = r;
+ last = f;
}
}
// A Reg is a wrapper around a single Prog (one instruction) that holds
// register optimization information while the optimizer runs.
// r->prog is the instruction.
-// r->prog->opt points back to r.
struct Reg
{
- Flow f;
-
Bits set; // regopt variables written by this instruction.
Bits use1; // regopt variables read by prog->from.
Bits use2; // regopt variables read by prog->to.
// cost.
struct Rgn
{
- Reg* enter;
+ Flow* enter;
short cost;
short varno;
short regno;
/*
* reg.c
*/
-int rcmp(const void*, const void*);
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 dumpit(char*, Flow*, int);
#include "go.h"
#include "popt.h"
-static Reg* firstr;
+static Flow* firstf;
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)
{
Rgn *p1, *p2;
static Node* regnodes[64];
-static void walkvardef(Node *n, Reg *r, int active);
+static void walkvardef(Node *n, Flow *r, int active);
void
regopt(Prog *firstp)
{
- Reg *r, *r1;
+ Flow *f, *f1;
+ Reg *r;
Prog *p;
Graph *g;
ProgInfo info;
return;
}
- firstr = (Reg*)g->start;
+ firstf = g->start;
- for(r = firstr; r != R; r = (Reg*)r->f.link) {
- p = r->f.prog;
+ for(f = firstf; f != nil; f = f->link) {
+ p = f->prog;
if(p->as == AVARDEF || p->as == AVARKILL)
continue;
arch.proginfo(&info, p);
continue;
// from vs to doesn't matter for registers.
+ r = (Reg*)f->data;
r->use1.b[0] |= info.reguse | info.regindex;
r->set.b[0] |= info.regset;
- bit = mkvar(r, &p->from);
+ bit = mkvar(f, &p->from);
if(bany(&bit)) {
if(info.flags & LeftAddr)
setaddrs(bit);
if(p->from3.type != TYPE_NONE)
fatal("regopt not implemented for from3");
- bit = mkvar(r, &p->to);
+ bit = mkvar(f, &p->to);
if(bany(&bit)) {
if(info.flags & RightAddr)
setaddrs(bit);
}
if(debug['R'] && debug['v'])
- dumpit("pass1", &firstr->f, 1);
+ dumpit("pass1", firstf, 1);
/*
* pass 2
flowrpo(g);
if(debug['R'] && debug['v'])
- dumpit("pass2", &firstr->f, 1);
+ dumpit("pass2", firstf, 1);
/*
* pass 2.5
* but we'll be done with it by then.)
*/
active = 0;
- for(r = firstr; r != R; r = (Reg*)r->f.link) {
- r->f.active = 0;
+ for(f = firstf; f != nil; f = f->link) {
+ f->active = 0;
+ r = (Reg*)f->data;
r->act = zbits;
}
- for(r = firstr; r != R; r = (Reg*)r->f.link) {
- p = r->f.prog;
+ for(f = firstf; f != nil; f = f->link) {
+ p = f->prog;
if(p->as == AVARDEF && isfat(((Node*)(p->to.node))->type) && ((Node*)(p->to.node))->opt != nil) {
active++;
- walkvardef(p->to.node, r, active);
+ walkvardef(p->to.node, f, active);
}
}
*/
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);
+ for(f = firstf; f != nil; f = f->link)
+ f->active = 0;
+ for(f = firstf; f != nil; f = f->link)
+ if(f->prog->as == ARET)
+ prop(f, 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);
+ for(f = firstf; f != nil; f = f1) {
+ f1 = f->link;
+ if(f1 && f1->active && !f->active) {
+ prop(f, zbits, zbits);
i = 1;
}
}
goto loop1;
if(debug['R'] && debug['v'])
- dumpit("pass3", &firstr->f, 1);
+ dumpit("pass3", firstf, 1);
/*
* pass 4
*/
loop2:
change = 0;
- for(r = firstr; r != R; r = (Reg*)r->f.link)
- r->f.active = 0;
- synch(firstr, zbits);
+ for(f = firstf; f != nil; f = f->link)
+ f->active = 0;
+ synch(firstf, zbits);
if(change)
goto loop2;
if(debug['R'] && debug['v'])
- dumpit("pass4", &firstr->f, 1);
+ dumpit("pass4", firstf, 1);
/*
* pass 4.5
mask = ~0ULL; // can't rely on C to shift by 64
else
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->set.b[0] &= ~mask;
r->use1.b[0] &= ~mask;
}
if(debug['R'] && debug['v'])
- dumpit("pass4.5", &firstr->f, 1);
+ dumpit("pass4.5", firstf, 1);
/*
* pass 5
* isolate regions
* calculate costs (paint1)
*/
- r = firstr;
- if(r) {
+ f = firstf;
+ if(f) {
+ r = (Reg*)f->data;
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) {
+ if(bany(&bit) && !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;
+ print("%L: used and not set: %Q\n", f->prog->lineno, bit);
+ f->refset = 1;
}
}
- for(r = firstr; r != R; r = (Reg*)r->f.link)
- r->act = zbits;
+ for(f = firstf; f != nil; f = f->link)
+ ((Reg*)f->data)->act = zbits;
rgp = region;
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++)
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(bany(&bit) && !f->refset) {
if(debug['w'])
- print("%L: set and not used: %Q\n", r->f.prog->lineno, bit);
- r->f.refset = 1;
- arch.excise(&r->f);
+ print("%L: set and not used: %Q\n", f->prog->lineno, bit);
+ f->refset = 1;
+ arch.excise(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->enter = f;
rgp->varno = i;
change = 0;
- paint1(r, i);
+ paint1(f, i);
biclr(&bit, i);
if(change <= 0)
continue;
qsort(region, nregion, sizeof(region[0]), rcmp);
if(debug['R'] && debug['v'])
- dumpit("pass5", &firstr->f, 1);
+ dumpit("pass5", firstf, 1);
/*
* pass 6
print("\nregisterizing\n");
for(i=0; i<nregion; i++) {
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);
usedreg = paint2(rgp->enter, rgp->varno, 0);
vreg = allreg(usedreg, rgp);
for(i=0; i<nvar; i++)
var[i].node->opt = nil;
flowend(g);
- firstr = R;
+ firstf = nil;
if(debug['R'] && debug['v']) {
// Rebuild flow graph, since we inserted instructions
- g = flowstart(firstp, sizeof(Reg));
- firstr = (Reg*)g->start;
- dumpit("pass6", &firstr->f, 1);
+ g = flowstart(firstp, 0);
+ firstf = g->start;
+ dumpit("pass6", firstf, 0);
flowend(g);
- firstr = R;
+ firstf = nil;
}
/*
}
static void
-walkvardef(Node *n, Reg *r, int active)
+walkvardef(Node *n, Flow *f, int active)
{
- Reg *r1, *r2;
+ Flow *f1, *f2;
int bn;
Var *v;
- for(r1=r; r1!=R; r1=(Reg*)r1->f.s1) {
- if(r1->f.active == active)
+ for(f1=f; f1!=nil; f1=f1->s1) {
+ if(f1->active == active)
break;
- r1->f.active = active;
- if(r1->f.prog->as == AVARKILL && r1->f.prog->to.node == n)
+ f1->active = active;
+ if(f1->prog->as == AVARKILL && f1->prog->to.node == n)
break;
for(v=n->opt; v!=nil; v=v->nextinnode) {
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;
}
- for(r2=r; r2!=r1; r2=(Reg*)r2->f.s1)
- if(r2->f.s2 != nil)
- walkvardef(n, (Reg*)r2->f.s2, active);
+ for(f2=f; f2!=f1; f2=f2->s1)
+ if(f2->s2 != nil)
+ walkvardef(n, f2->s2, active);
}
/*
* add mov b,rn
* just after r
*/
-void
-addmove(Reg *r, int bn, int rn, int f)
+static void
+addmove(Flow *r, int bn, int rn, int f)
{
Prog *p, *p1;
Adr *a;
clearp(p1);
p1->pc = 9999;
- p = r->f.prog;
+ p = r->prog;
p1->link = p->link;
p->link = p1;
p1->lineno = p->lineno;
return 1;
}
-Bits
-mkvar(Reg *r, Adr *a)
+static Bits
+mkvar(Flow *f, Adr *a)
{
Var *v;
int i, n, et, z, flag;
int64 o;
Bits bit;
Node *node;
+ Reg *r;
+
/*
* mark registers used
if(a->type == TYPE_NONE)
goto none;
- if(r != R)
- r->use1.b[0] |= arch.doregbits(a->index); // TODO: Use RtoB
+ r = (Reg*)f->data;
+ r->use1.b[0] |= arch.doregbits(a->index); // TODO: Use RtoB
switch(a->type) {
default:
if(arch.thechar == '9' || arch.thechar == '5')
goto memcase;
a->type = TYPE_MEM;
- bit = mkvar(r, a);
+ bit = mkvar(f, a);
setaddrs(bit);
a->type = TYPE_ADDR;
ostats.naddr++;
return zbits;
}
-void
-prop(Reg *r, Bits ref, Bits cal)
+static void
+prop(Flow *f, Bits ref, Bits cal)
{
- Reg *r1, *r2;
+ Flow *f1, *f2;
+ Reg *r, *r1;
int z, i, j;
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++) {
ref.b[z] |= r1->refahead.b[z];
if(ref.b[z] != r1->refahead.b[z]) {
change++;
}
}
- switch(r1->f.prog->as) {
+ switch(f1->prog->as) {
case ACALL:
- if(noreturn(r1->f.prog))
+ if(noreturn(f1->prog))
break;
// Mark all input variables (ivar) as used, because that's what the
r1->refbehind.b[z] = ref.b[z];
r1->calbehind.b[z] = cal.b[z];
}
- if(r1->f.active)
+ if(f1->active)
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
-synch(Reg *r, Bits dif)
+static void
+synch(Flow *f, Bits dif)
{
+ Flow *f1;
Reg *r1;
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++) {
dif.b[z] = (dif.b[z] &
~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
change++;
}
}
- if(r1->f.active)
+ if(f1->active)
break;
- r1->f.active = 1;
+ f1->active = 1;
for(z=0; z<BITS; z++)
dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
- if(r1->f.s2 != nil)
- synch((Reg*)r1->f.s2, dif);
+ if(f1->s2 != nil)
+ synch(f1->s2, dif);
}
}
-uint64
+static uint64
allreg(uint64 b, Rgn *r)
{
Var *v;
return 0;
}
-void
-paint1(Reg *r, int bn)
+static void
+paint1(Flow *f, int bn)
{
- Reg *r1;
+ Flow *f1;
+ Reg *r, *r1;
int z;
uint64 bb;
z = bn/64;
bb = 1LL<<(bn%64);
+ r = (Reg*)f->data;
if(r->act.b[z] & bb)
return;
for(;;) {
if(!(r->refbehind.b[z] & bb))
break;
- r1 = (Reg*)r->f.p1;
- if(r1 == R)
+ f1 = f->p1;
+ if(f1 == nil)
break;
+ r1 = (Reg*)f1->data;
if(!(r1->refahead.b[z] & bb))
break;
if(r1->act.b[z] & bb)
break;
+ f = f1;
r = r1;
}
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(;;) {
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)
- change += CREF * r->f.loop;
+ change += CREF * f->loop;
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) {
- change -= CLOAD * r->f.loop;
+ change -= CLOAD * f->loop;
}
if(r->refbehind.b[z] & bb)
- for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
- if(r1->refahead.b[z] & bb)
- paint1(r1, bn);
+ for(f1 = f->p2; f1 != nil; f1 = f1->p2link)
+ if(((Reg*)f1->data)->refahead.b[z] & bb)
+ paint1(f1, bn);
if(!(r->refahead.b[z] & bb))
break;
- r1 = (Reg*)r->f.s2;
- if(r1 != R)
- if(r1->refbehind.b[z] & bb)
- paint1(r1, bn);
- r = (Reg*)r->f.s1;
- if(r == R)
+ f1 = f->s2;
+ if(f1 != nil)
+ if(((Reg*)f1->data)->refbehind.b[z] & bb)
+ paint1(f1, bn);
+ f = f->s1;
+ if(f == nil)
break;
+ r = (Reg*)f->data;
if(r->act.b[z] & bb)
break;
if(!(r->refbehind.b[z] & bb))
}
}
-uint64
-paint2(Reg *r, int bn, int depth)
+static uint64
+paint2(Flow *f, int bn, int depth)
{
- Reg *r1;
+ Flow *f1;
+ Reg *r, *r1;
int z;
uint64 bb, vreg;
z = bn/64;
bb = 1LL << (bn%64);
vreg = regbits;
+ r = (Reg*)f->data;
if(!(r->act.b[z] & bb))
return vreg;
for(;;) {
if(!(r->refbehind.b[z] & bb))
break;
- r1 = (Reg*)r->f.p1;
- if(r1 == R)
+ f1 = f->p1;
+ if(f1 == nil)
break;
+ r1 = (Reg*)f1->data;
if(!(r1->refahead.b[z] & bb))
break;
if(!(r1->act.b[z] & bb))
break;
+ f = f1;
r = r1;
}
for(;;) {
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;
vreg |= r->regu;
if(r->refbehind.b[z] & bb)
- for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
- if(r1->refahead.b[z] & bb)
- vreg |= paint2(r1, bn, depth+1);
+ for(f1 = f->p2; f1 != nil; f1 = f1->p2link)
+ if(((Reg*)f1->data)->refahead.b[z] & bb)
+ vreg |= paint2(f1, bn, depth+1);
if(!(r->refahead.b[z] & bb))
break;
- r1 = (Reg*)r->f.s2;
- if(r1 != R)
- if(r1->refbehind.b[z] & bb)
- vreg |= paint2(r1, bn, depth+1);
- r = (Reg*)r->f.s1;
- if(r == R)
+ f1 = f->s2;
+ if(f1 != nil)
+ if(((Reg*)f1->data)->refbehind.b[z] & bb)
+ vreg |= paint2(f1, bn, depth+1);
+ f = f->s1;
+ if(f == nil)
break;
+ r = (Reg*)f->data;
if(!(r->act.b[z] & bb))
break;
if(!(r->refbehind.b[z] & bb))
return vreg;
}
-void
-paint3(Reg *r, int bn, uint64 rb, int rn)
+static void
+paint3(Flow *f, int bn, uint64 rb, int rn)
{
- Reg *r1;
+ Flow *f1;
+ Reg *r, *r1;
Prog *p;
int z;
uint64 bb;
z = bn/64;
bb = 1LL << (bn%64);
+ r = (Reg*)f->data;
if(r->act.b[z] & bb)
return;
for(;;) {
if(!(r->refbehind.b[z] & bb))
break;
- r1 = (Reg*)r->f.p1;
- if(r1 == R)
+ f1 = f->p1;
+ if(f1 == nil)
break;
+ r1 = (Reg*)f1->data;
if(!(r1->refahead.b[z] & bb))
break;
if(r1->act.b[z] & bb)
break;
+ f = f1;
r = r1;
}
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(;;) {
r->act.b[z] |= bb;
- p = r->f.prog;
+ p = f->prog;
if(r->use1.b[z] & bb) {
if(debug['R'] && debug['v'])
}
if(STORE(r) & r->regdiff.b[z] & bb)
- addmove(r, bn, rn, 1);
+ addmove(f, bn, rn, 1);
r->regu |= rb;
if(r->refbehind.b[z] & bb)
- for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
- if(r1->refahead.b[z] & bb)
- paint3(r1, bn, rb, rn);
+ for(f1 = f->p2; f1 != nil; f1 = f1->p2link)
+ if(((Reg*)f1->data)->refahead.b[z] & bb)
+ paint3(f1, bn, rb, rn);
if(!(r->refahead.b[z] & bb))
break;
- r1 = (Reg*)r->f.s2;
- if(r1 != R)
- if(r1->refbehind.b[z] & bb)
- paint3(r1, bn, rb, rn);
- r = (Reg*)r->f.s1;
- if(r == R)
+ f1 = f->s2;
+ if(f1 != nil)
+ if(((Reg*)f1->data)->refbehind.b[z] & bb)
+ paint3(f1, bn, rb, rn);
+ f = f->s1;
+ if(f == nil)
break;
+ r = (Reg*)f->data;
if(r->act.b[z] & bb)
break;
if(!(r->refbehind.b[z] & bb))
}
}
-void
+static void
addreg(Adr *a, int rn)
{
a->sym = nil;
print("%d:%P", f->loop, f->prog);
if(isreg) {
- r = (Reg*)f;
+ r = (Reg*)f->data;
for(z=0; z<BITS; z++)
bit.b[z] =
r->set.b[z] |