From 8bd8cede03e32c55844cfc433f66fc6da0564c8a Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 14 Jan 2014 10:40:16 -0500 Subject: [PATCH] cmd/gc: add -live flag for debugging liveness maps R=khr CC=golang-codereviews https://golang.org/cl/51820043 --- src/cmd/gc/go.h | 1 + src/cmd/gc/lex.c | 1 + src/cmd/gc/plive.c | 92 ++++++++++++++++++++++++++++++---------------- 3 files changed, 63 insertions(+), 31 deletions(-) diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index a00f5c8ab0..d124de643b 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -972,6 +972,7 @@ EXTERN char* flag_installsuffix; EXTERN int flag_race; EXTERN int flag_largemodel; EXTERN int noescape; +EXTERN int debuglive; EXTERN Link* ctxt; EXTERN int nointerface; diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c index c2116b4c6f..738ac494e5 100644 --- a/src/cmd/gc/lex.c +++ b/src/cmd/gc/lex.c @@ -264,6 +264,7 @@ main(int argc, char *argv[]) flagstr("installsuffix", "pkg directory suffix", &flag_installsuffix); flagcount("j", "debug runtime-initialized variables", &debug['j']); flagcount("l", "disable inlining", &debug['l']); + flagcount("live", "debug liveness analysis", &debuglive); flagcount("m", "print optimization decisions", &debug['m']); flagstr("o", "obj: set output file", &outfile); flagstr("p", "path: set expected package import path", &myimportpath); diff --git a/src/cmd/gc/plive.c b/src/cmd/gc/plive.c index 00a06e4f95..b2d3c40419 100644 --- a/src/cmd/gc/plive.c +++ b/src/cmd/gc/plive.c @@ -238,10 +238,9 @@ blockany(BasicBlock *bb, int (*callback)(Prog*)) } // Collects and returns and array of Node*s for functions arguments and local -// variables. TODO(cshapiro): only return pointer containing nodes if we are -// not also generating a dead value map. +// variables. static Array* -getvariables(Node *fn) +getvariables(Node *fn, int allvalues) { Array *result; NodeList *ll; @@ -249,11 +248,13 @@ getvariables(Node *fn) result = arraynew(0, sizeof(Node*)); for(ll = fn->dcl; ll != nil; ll = ll->next) { if(ll->n->op == ONAME) { - switch(ll->n->class & ~PHEAP) { + switch(ll->n->class) { case PAUTO: case PPARAM: case PPARAMOUT: - arrayadd(result, &ll->n); + if(haspointers(ll->n->type) || allvalues) + arrayadd(result, &ll->n); + break; } } } @@ -657,7 +658,7 @@ progeffects(Prog *prog, Array *vars, Bvec *uevar, Bvec *varkill) case PPARAMOUT: pos = arrayindexof(vars, from->node); if(pos == -1) - fatal("progeffects: variable %N is unknown", prog->from.node); + goto Next; if(info.flags & (LeftRead | LeftAddr)) bvset(uevar, pos); if(info.flags & LeftWrite) @@ -666,6 +667,7 @@ progeffects(Prog *prog, Array *vars, Bvec *uevar, Bvec *varkill) } } } +Next: if(info.flags & (RightRead | RightWrite | RightAddr)) { to = &prog->to; if (to->node != nil && to->sym != nil && !isfunny(to->node)) { @@ -675,7 +677,7 @@ progeffects(Prog *prog, Array *vars, Bvec *uevar, Bvec *varkill) case PPARAMOUT: pos = arrayindexof(vars, to->node); if(pos == -1) - fatal("progeffects: variable %N is unknown", to->node); + goto Next1; if(info.flags & (RightRead | RightAddr)) bvset(uevar, pos); if(info.flags & RightWrite) @@ -684,6 +686,7 @@ progeffects(Prog *prog, Array *vars, Bvec *uevar, Bvec *varkill) } } } +Next1:; } // Constructs a new liveness structure used to hold the global state of the @@ -1304,22 +1307,19 @@ static void livenessepilogue(Liveness *lv) { BasicBlock *bb; - Bvec *livein; - Bvec *liveout; - Bvec *uevar; - Bvec *varkill; - Bvec *args; - Bvec *locals; + Bvec *livein, *liveout, *uevar, *varkill, *args, *locals; Prog *p, *next; - int32 i; - int32 nvars; - int32 pos; + int32 i, j, nmsg, nvars, pos; + char **msg; + Fmt fmt; nvars = arraylength(lv->vars); livein = bvalloc(nvars); liveout = bvalloc(nvars); uevar = bvalloc(nvars); varkill = bvalloc(nvars); + msg = nil; + nmsg = 0; for(i = 0; i < arraylength(lv->cfg); i++) { bb = *(BasicBlock**)arrayget(lv->cfg, i); @@ -1347,6 +1347,13 @@ livenessepilogue(Liveness *lv) arrayadd(lv->deadvalues, &locals); } } + + if(debuglive) { + nmsg = arraylength(lv->livepointers); + msg = xmalloc(nmsg*sizeof msg[0]); + for(j=0; jlivepointers) - 1; @@ -1372,8 +1379,35 @@ livenessepilogue(Liveness *lv) } if(issafepoint(p)) { // Found an interesting instruction, record the - // corresponding liveness information. Only - // CALL instructions need a PCDATA annotation. + // corresponding liveness information. + + if(debuglive) { + fmtstrinit(&fmt); + fmtprint(&fmt, "%L: live at ", p->lineno); + if(p->as == ACALL) + fmtprint(&fmt, "CALL %lS:", p->to.sym); + else + fmtprint(&fmt, "TEXT %lS:", p->from.sym); + for(j = 0; j < arraylength(lv->vars); j++) + if(bvget(liveout, j)) + fmtprint(&fmt, " %N", *(Node**)arrayget(lv->vars, j)); + fmtprint(&fmt, "\n"); + msg[pos] = fmtstrflush(&fmt); + } + + // Record live pointers. + args = *(Bvec**)arrayget(lv->argslivepointers, pos); + locals = *(Bvec**)arrayget(lv->livepointers, pos); + twobitlivepointermap(lv, liveout, lv->vars, args, locals); + + // Record dead values. + if(lv->deadvalues != nil) { + args = *(Bvec**)arrayget(lv->argsdeadvalues, pos); + locals = *(Bvec**)arrayget(lv->deadvalues, pos); + twobitdeadvaluemap(lv, liveout, lv->vars, args, locals); + } + + // Only CALL instructions need a PCDATA annotation. // The TEXT instruction annotation is implicit. if(p->as == ACALL) { if(isdeferreturn(p)) { @@ -1394,21 +1428,17 @@ livenessepilogue(Liveness *lv) } } - // Record live pointers. - args = *(Bvec**)arrayget(lv->argslivepointers, pos); - locals = *(Bvec**)arrayget(lv->livepointers, pos); - twobitlivepointermap(lv, liveout, lv->vars, args, locals); - - // Record dead values. - if(lv->deadvalues != nil) { - args = *(Bvec**)arrayget(lv->argsdeadvalues, pos); - locals = *(Bvec**)arrayget(lv->deadvalues, pos); - twobitdeadvaluemap(lv, liveout, lv->vars, args, locals); - } - pos--; } } + if(debuglive) { + for(j=0; j