diff options
Diffstat (limited to 'code/tools/lcc/src/prof.c')
-rw-r--r-- | code/tools/lcc/src/prof.c | 228 |
1 files changed, 228 insertions, 0 deletions
diff --git a/code/tools/lcc/src/prof.c b/code/tools/lcc/src/prof.c new file mode 100644 index 0000000..02709ed --- /dev/null +++ b/code/tools/lcc/src/prof.c @@ -0,0 +1,228 @@ +#include "c.h" + + +struct callsite { + char *file, *name; + union coordinate { + unsigned int coord; + struct { unsigned int y:16,x:10,index:6; } le; + struct { unsigned int index:6,x:10,y:16; } be; + } u; +}; +struct func { + struct func *link; + struct caller *callers; + char *name; + union coordinate src; +}; +struct map { /* source code map; 200 coordinates/map */ + int size; + union coordinate u[200]; +}; + +int npoints; /* # of execution points if -b specified */ +int ncalled = -1; /* #times prof.out says current function was called */ +static Symbol YYlink; /* symbol for file's struct _bbdata */ +static Symbol YYcounts; /* symbol for _YYcounts if -b specified */ +static List maplist; /* list of struct map *'s */ +static List filelist; /* list of file names */ +static Symbol funclist; /* list of struct func *'s */ +static Symbol afunc; /* current function's struct func */ + +/* bbcall - build tree to set _callsite at call site *cp, emit call site data */ +static void bbcall(Symbol yycounts, Coordinate *cp, Tree *e) { + static Symbol caller; + Value v; + union coordinate u; + Symbol p = genident(STATIC, array(voidptype, 0, 0), GLOBAL); + Tree t = *e; + + defglobal(p, LIT); + defpointer(cp->file ? mkstr(cp->file)->u.c.loc : (Symbol)0); + defpointer(mkstr(cfunc->name)->u.c.loc); + if (IR->little_endian) { + u.le.x = cp->x; + u.le.y = cp->y; + } else { + u.be.x = cp->x; + u.be.y = cp->y; + } + (*IR->defconst)(U, unsignedtype->size, (v.u = u.coord, v)); + if (caller == 0) { + caller = mksymbol(EXTERN, "_caller", ptr(voidptype)); + caller->defined = 0; + } + if (generic((*e)->op) != CALL) + t = (*e)->kids[0]; + assert(generic(t->op) == CALL); + t = tree(t->op, t->type, + tree(RIGHT, t->kids[0]->type, + t->kids[0], + tree(RIGHT, t->kids[0]->type, asgn(caller, idtree(p)), t->kids[0])), + t->kids[1]); + if (generic((*e)->op) != CALL) + t = tree((*e)->op, (*e)->type, t, (*e)->kids[1]); + *e = t; +} + +/* bbentry - return tree for _prologue(&afunc, &YYlink)' */ +static void bbentry(Symbol yylink, Symbol f) { + static Symbol prologue; + + afunc = genident(STATIC, array(voidptype, 4, 0), GLOBAL); + if (prologue == 0) { + prologue = mksymbol(EXTERN, "_prologue", ftype(inttype, voidptype)); + prologue->defined = 0; + } + walk(vcall(prologue, voidtype, pointer(idtree(afunc)), pointer(idtree(yylink)), NULL), 0, 0); + +} + +/* bbexit - return tree for _epilogue(&afunc)' */ +static void bbexit(Symbol yylink, Symbol f, Tree e) { + static Symbol epilogue; + + if (epilogue == 0) { + epilogue = mksymbol(EXTERN, "_epilogue", ftype(inttype, voidptype)); + epilogue->defined = 0; + } + walk(vcall(epilogue, voidtype, pointer(idtree(afunc)), NULL), 0, 0); +} + +/* bbfile - add file to list of file names, return its index */ +static int bbfile(char *file) { + if (file) { + List lp; + int i = 1; + if ((lp = filelist) != NULL) + do { + lp = lp->link; + if (((Symbol)lp->x)->u.c.v.p == file) + return i; + i++; + } while (lp != filelist); + filelist = append(mkstr(file), filelist); + return i; + } + return 0; +} + +/* bbfunc - emit function name and src coordinates */ +static void bbfunc(Symbol yylink, Symbol f) { + Value v; + union coordinate u; + + defglobal(afunc, DATA); + defpointer(funclist); + defpointer(NULL); + defpointer(mkstr(f->name)->u.c.loc); + if (IR->little_endian) { + u.le.x = f->u.f.pt.x; + u.le.y = f->u.f.pt.y; + u.le.index = bbfile(f->u.f.pt.file); + } else { + u.be.x = f->u.f.pt.x; + u.be.y = f->u.f.pt.y; + u.be.index = bbfile(f->u.f.pt.file); + } + (*IR->defconst)(U, unsignedtype->size, (v.u = u.coord, v)); + funclist = afunc; +} + +/* bbincr - build tree to increment execution point at *cp */ +static void bbincr(Symbol yycounts, Coordinate *cp, Tree *e) { + struct map *mp = maplist->x; + Tree t; + + /* append *cp to source map */ + if (mp->size >= NELEMS(mp->u)) { + NEW(mp, PERM); + mp->size = 0; + maplist = append(mp, maplist); + } + if (IR->little_endian) { + mp->u[mp->size].le.x = cp->x; + mp->u[mp->size].le.y = cp->y; + mp->u[mp->size++].le.index = bbfile(cp->file); + } else { + mp->u[mp->size].be.x = cp->x; + mp->u[mp->size].be.y = cp->y; + mp->u[mp->size++].be.index = bbfile(cp->file); + } + t = incr('+', rvalue((*optree['+'])(ADD, pointer(idtree(yycounts)), + consttree(npoints++, inttype))), consttree(1, inttype)); + if (*e) + *e = tree(RIGHT, (*e)->type, t, *e); + else + *e = t; +} + +/* bbvars - emit definition for basic block counting data */ +static void bbvars(Symbol yylink) { + int i, j, n = npoints; + Value v; + struct map **mp; + Symbol coords, files, *p; + + if (!YYcounts && !yylink) + return; + if (YYcounts) { + if (n <= 0) + n = 1; + YYcounts->type = array(unsignedtype, n, 0); + defglobal(YYcounts, BSS); + } + files = genident(STATIC, array(charptype, 1, 0), GLOBAL); + defglobal(files, LIT); + for (p = ltov(&filelist, PERM); *p; p++) + defpointer((*p)->u.c.loc); + defpointer(NULL); + coords = genident(STATIC, array(unsignedtype, n, 0), GLOBAL); + defglobal(coords, LIT); + for (i = n, mp = ltov(&maplist, PERM); *mp; i -= (*mp)->size, mp++) + for (j = 0; j < (*mp)->size; j++) + (*IR->defconst)(U, unsignedtype->size, (v.u = (*mp)->u[j].coord, v)); + if (i > 0) + (*IR->space)(i*coords->type->type->size); + defpointer(NULL); + defglobal(yylink, DATA); + defpointer(NULL); + (*IR->defconst)(U, unsignedtype->size, (v.u = n, v)); + defpointer(YYcounts); + defpointer(coords); + defpointer(files); + defpointer(funclist); +} + +/* profInit - initialize basic block profiling options */ +void prof_init(int argc, char *argv[]) { + int i; + static int inited; + + if (inited) + return; + inited = 1; + type_init(argc, argv); + if (IR) { + for (i = 1; i < argc; i++) + if (strncmp(argv[i], "-a", 2) == 0) { + if (ncalled == -1 + && process(argv[i][2] ? &argv[i][2] : "prof.out") > 0) + ncalled = 0; + } else if ((strcmp(argv[i], "-b") == 0 + || strcmp(argv[i], "-C") == 0) && YYlink == 0) { + YYlink = genident(STATIC, array(unsignedtype, 0, 0), GLOBAL); + attach((Apply)bbentry, YYlink, &events.entry); + attach((Apply)bbexit, YYlink, &events.returns); + attach((Apply)bbfunc, YYlink, &events.exit); + attach((Apply)bbvars, YYlink, &events.end); + if (strcmp(argv[i], "-b") == 0) { + YYcounts = genident(STATIC, array(unsignedtype, 0, 0), GLOBAL); + maplist = append(allocate(sizeof (struct map), PERM), maplist); + ((struct map *)maplist->x)->size = 0; + attach((Apply)bbcall, YYcounts, &events.calls); + attach((Apply)bbincr, YYcounts, &events.points); + } + } + } +} |