/* 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); }
/* tracefinis - complete & generate the trace call to print */ static void tracefinis(Symbol printer) { Tree *ap; Symbol p; *fp = 0; p = mkstr(string(fmt)); for (ap = &args; *ap; ap = &(*ap)->kids[1]) ; *ap = tree(ARG+P, charptype, pointer(idtree(p->u.c.loc)), 0); walk(calltree(pointer(idtree(printer)), freturn(printer->type), args, NULL), 0, 0); args = 0; fp = fmtend = 0; }
/* 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; }
/* addrof - address of p */ Tree addrof(Tree p) { Tree q = p; for (;;) switch (generic(q->op)) { case RIGHT: assert(q->kids[0] || q->kids[1]); q = q->kids[1] ? q->kids[1] : q->kids[0]; continue; case ASGN: q = q->kids[1]; continue; case COND: { Symbol t1 = q->u.sym; q->u.sym = 0; q = idtree(t1); /* fall thru */ } case INDIR: if (p == q) return q->kids[0]; q = q->kids[0]; return tree(RIGHT, q->type, root(p), q); default: error("addressable object required\n"); return value(p); } }
/* 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; }
/* call_hook - called at function calls. If *e is a call, call_hook changes the expression to the equivalent of the C expression (tos.ip = i, *e) where i is the stopping point index for the execution point of the expression in which the call appears. */ static void call_hook(void *cl, Coordinate *cp, Tree *e) { assert(*e); *e = tree(RIGHT, (*e)->type, asgntree(ASGN, field(lvalue(idtree(tos)), string("ip")), cnsttree(inttype, Seq_length(pickle->spoints))), *e); }
static void cmp(int op, Symbol p, long n, int lab) { Type ty = signedint(p->type); listnodes(eqtree(op, cast(idtree(p), ty), cnsttree(ty, n)), lab, 0); }
/* asgn - generate tree for assignment of expr e to symbol p sans qualifiers */ Tree asgn(Symbol p, Tree e) { if (isarray(p->type)) e = tree(ASGN+B, p->type, idtree(p), tree(INDIR+B, e->type, e, NULL)); else { Type ty = p->type; p->type = unqual(p->type); if (isstruct(p->type) && p->type->u.sym->u.s.cfields) { p->type->u.sym->u.s.cfields = 0; e = asgntree(ASGN, idtree(p), e); p->type->u.sym->u.s.cfields = 1; } else e = asgntree(ASGN, idtree(p), e); p->type = ty; } return e; }
void retcode(Tree p) { Type ty; if (p == NULL) { if (events.returns) apply(events.returns, cfunc, NULL); return; } p = pointer(p); ty = assign(freturn(cfunc->type), p); if (ty == NULL) { error("illegal return type; found `%t' expected `%t'\n", p->type, freturn(cfunc->type)); return; } p = cast(p, ty); if (retv) { if (iscallb(p)) p = tree(RIGHT, p->type, tree(CALL+B, p->type, p->kids[0]->kids[0], idtree(retv)), rvalue(idtree(retv))); else { Type ty = retv->type->type; assert(isstruct(ty)); if (ty->u.sym->u.s.cfields) { ty->u.sym->u.s.cfields = 0; p = asgntree(ASGN, rvalue(idtree(retv)), p); ty->u.sym->u.s.cfields = 1; } else p = asgntree(ASGN, rvalue(idtree(retv)), p); } walk(p, 0, 0); if (events.returns) apply(events.returns, cfunc, rvalue(idtree(retv))); return; } if (events.returns) { Symbol t1 = genident(AUTO, p->type, level); addlocal(t1); walk(asgn(t1, p), 0, 0); apply(events.returns, cfunc, idtree(t1)); p = idtree(t1); } if (!isfloat(p->type)) p = cast(p, promote(p->type)); if (isptr(p->type)) { Symbol q = localaddr(p); if (q && (q->computed || q->generated)) warning("pointer to a %s is an illegal return value\n", q->scope == PARAM ? "parameter" : "local"); else if (q) warning("pointer to %s `%s' is an illegal return value\n", q->scope == PARAM ? "parameter" : "local", q->name); } walk(tree(mkop(RET,p->type), p->type, p, 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); }
/* tracereturn - generate code to trace return e */ static void tracereturn(Symbol printer, Symbol f, Tree e) { appendstr(f->name); appendstr("#"); tracevalue(idtree(frameno), 0); appendstr(" returned"); if (freturn(f->type) != voidtype && e) { appendstr(" "); tracevalue(e, 0); } appendstr("\n"); tracefinis(printer); }
Tree calltree(Tree f, Type ty, Tree args, Symbol t3) { Tree p; if (args) f = tree(RIGHT, f->type, args, f); if (isstruct(ty)) assert(t3), p = tree(RIGHT, ty, tree(CALL+B, ty, f, addrof(idtree(t3))), idtree(t3)); else { Type rty = ty; if (isenum(ty)) rty = unqual(ty)->type; if (!isfloat(rty)) rty = promote(rty); p = tree(mkop(CALL, rty), rty, f, NULL); if (isptr(ty) || p->type->size > ty->size) p = cast(p, ty); } return p; }
/* tracecall - generate code to trace entry to f */ static void tracecall(Symbol printer, Symbol f, void *ignore) { int i; Symbol counter = genident(STATIC, inttype, GLOBAL); defglobal(counter, BSS); (*IR->space)(counter->type->size); frameno = genident(AUTO, inttype, level); addlocal(frameno); appendstr(f->name); appendstr("#"); tracevalue(asgn(frameno, incr(INCR, idtree(counter), consttree(1, inttype))), 0); appendstr("("); for (i = 0; f->u.f.callee[i]; i++) { if (i) appendstr(","); appendstr(f->u.f.callee[i]->name); appendstr("="); tracevalue(idtree(f->u.f.callee[i]), 0); } if (variadic(f->type)) appendstr(",..."); appendstr(") called\n"); tracefinis(printer); }
/* entry_hook - called an function entry */ static void entry_hook(void *cl, Symbol cfunc) { static int nfuncs; Type ty; /* Simulate the declaration of an sframe structure, but without the tag. */ ty = newstruct(STRUCT, ""); #define addfield(name,t) \ ty->size = roundup(ty->size, t->align);\ if (ty->align < t->align) ty->align = t->align; \ newfield(string(name), ty, t)->offset = ty->size; \ ty->size += t->size addfield("up", voidptype); addfield("down", voidptype); addfield("func", inttype); addfield("module",inttype); addfield("ip", inttype); #undef addfield ty->size = roundup(ty->size, ty->align); ty->u.sym->defined = 1; ty->u.sym->generated = 1; tos = genident(AUTO, ty, LOCAL); addlocal(tos); tos->defined = 1; /* Generated the assignments to the shadow frame fields. */ #define set(name,e) walk(asgntree(ASGN,field(lvalue(idtree(tos)),string(#name)),(e)),0,0) set(down, idtree(nub_tos)); set(func, cnsttree(inttype, symboluid(cfunc))); set(module, cnsttree(inttype, uname)); #undef set walk(asgn(nub_tos, lvalue(idtree(tos))), 0, 0); foreach(identifiers, PARAM, setoffset, tos); }
Tree asgntree(int op, Tree l, Tree r) { Type aty, ty; r = pointer(r); ty = assign(l->type, r); if (ty) r = cast(r, ty); else { typeerror(ASGN, l, r); if (r->type == voidtype) r = retype(r, inttype); ty = r->type; } if (l->op != FIELD) l = lvalue(l); aty = l->type; if (isptr(aty)) aty = unqual(aty)->type; if (isconst(aty) || (isstruct(aty) && unqual(aty)->u.sym->u.s.cfields)) { if (isaddrop(l->op) && !l->u.sym->computed && !l->u.sym->generated) error("assignment to const identifier `%s'\n", l->u.sym->name); else error("assignment to const location\n"); } if (l->op == FIELD) { long n = 8 * l->u.field->type->size - fieldsize(l->u.field); if (n > 0 && isunsigned(l->u.field->type)) r = bittree(BAND, r, cnsttree(r->type, (unsigned long)fieldmask(l->u.field))); else if (n > 0) { if (r->op == CNST + I) { n = r->u.v.i; if (n & (1 << (fieldsize(l->u.field) - 1))) n |= ~0UL << fieldsize(l->u.field); r = cnsttree(r->type, n); } else r = shtree(RSH, shtree(LSH, r, cnsttree(inttype, n)), cnsttree(inttype, n)); } } if (isstruct(ty) && isaddrop(l->op) && iscallb(r)) return tree(RIGHT, ty, tree(CALL + B, ty, r->kids[0]->kids[0], l), idtree(l->u.sym)); return tree(mkop(op, ty), ty, l, r); }
Tree vcall(Symbol func, Type ty, ...) { va_list ap; Tree args = NULL, e, f = pointer(idtree(func)), r = NULL; assert(isfunc(func->type)); if (ty == NULL) ty = freturn(func->type); va_start(ap, ty); while ((e = va_arg(ap, Tree)) != NULL) { if (hascall(e)) r = r == NULL ? e : tree(RIGHT, voidtype, r, e); args = tree(mkop(ARG, e->type), e->type, e, args); } va_end(ap); if (r != NULL) args = tree(RIGHT, voidtype, r, args); return calltree(f, ty, args, NULL); }
/* point_hook - called at each execution point */ static void point_hook(void *cl, Coordinate *cp, Tree *e) { Tree t; /* add breakpoint test to *e: (_Nub_bpflags[i] != 0 && _Nub_bp(i), *e) */ t = tree(AND, voidtype, (*optree[NEQ])(NE, rvalue((*optree['+'])(ADD, pointer(idtree(nub_bpflags)), cnsttree(inttype, Seq_length(pickle->spoints)))), cnsttree(inttype, 0L)), vcall(nub_bp, voidtype, cnsttree(inttype, Seq_length(pickle->spoints)), NULL)); if (*e) *e = tree(RIGHT, (*e)->type, t, *e); else *e = t; Seq_addhi(pickle->spoints, sym_spoint(sym_coordinate(cp->file ? cp->file : string(""), cp->x, cp->y), tail())); }
void swcode(Swtch swp, int b[], int lb, int ub) { int hilab, lolab, l, u, k = (lb + ub)/2; long *v = swp->values; if (k > lb && k < ub) { lolab = genlabel(1); hilab = genlabel(1); } else if (k > lb) { lolab = genlabel(1); hilab = swp->deflab->u.l.label; } else if (k < ub) { lolab = swp->deflab->u.l.label; hilab = genlabel(1); } else lolab = hilab = swp->deflab->u.l.label; l = b[k]; u = b[k+1] - 1; if (u - l + 1 <= 3) { int i; for (i = l; i <= u; i++) cmp(EQ, swp->sym, v[i], swp->labels[i]->u.l.label); if (k > lb && k < ub) cmp(GT, swp->sym, v[u], hilab); else if (k > lb) cmp(GT, swp->sym, v[u], hilab); else if (k < ub) cmp(LT, swp->sym, v[l], lolab); else assert(lolab == hilab), branch(lolab); walk(NULL, 0, 0); } else { Tree e; Type ty = signedint(swp->sym->type); Symbol table = genident(STATIC, array(voidptype, u - l + 1, 0), GLOBAL); (*IR->defsymbol)(table); if (!isunsigned(swp->sym->type) || v[l] != 0) cmp(LT, swp->sym, v[l], lolab); cmp(GT, swp->sym, v[u], hilab); e = (*optree['-'])(SUB, cast(idtree(swp->sym), ty), cnsttree(ty, v[l])); if (e->type->size < unsignedptr->size) e = cast(e, unsignedlong); walk(tree(JUMP, voidtype, rvalue((*optree['+'])(ADD, pointer(idtree(table)), e)), NULL), 0, 0); code(Switch); codelist->u.swtch.table = table; codelist->u.swtch.sym = swp->sym; codelist->u.swtch.deflab = swp->deflab; codelist->u.swtch.size = u - l + 1; codelist->u.swtch.values = &v[l]; codelist->u.swtch.labels = &swp->labels[l]; if (v[u] - v[l] + 1 >= 10000) warning("switch generates a huge table\n"); } if (k > lb) { assert(lolab != swp->deflab->u.l.label); definelab(lolab); swcode(swp, b, lb, k - 1); } if (k < ub) { assert(hilab != swp->deflab->u.l.label); definelab(hilab); swcode(swp, b, k + 1, ub); } }
/* return_hook - called at return statements. For return *e, return_hook changes the expression to be the equivalent of the C expression (_Nub_tos = tos.down, *e) */ static void return_hook(void *cl, Symbol cfunc, Tree *e) { walk(asgn(nub_tos, field(lvalue(idtree(tos)), string("down"))), 0, 0); }
Tree call(Tree f, Type fty, Coordinate src) { int n = 0; Tree args = NULL, r = NULL, e; Type *proto, rty = unqual(freturn(fty)); Symbol t3 = NULL; if (fty->u.f.oldstyle) proto = NULL; else proto = fty->u.f.proto; if (hascall(f)) r = f; if (isstruct(rty)) { t3 = temporary(AUTO, unqual(rty)); if (rty->size == 0) error("illegal use of incomplete type `%t'\n", rty); } if (t != ')') for (;;) { Tree q = pointer(expr1(0)); if (proto && *proto && *proto != voidtype) { Type aty; q = value(q); aty = assign(*proto, q); if (aty) q = cast(q, aty); else error("type error in argument %d to %s; found `%t' expected `%t'\n", n + 1, funcname(f), q->type, *proto); if ((isint(q->type) || isenum(q->type)) && q->type->size != inttype->size) q = cast(q, promote(q->type)); ++proto; } else { if (!fty->u.f.oldstyle && *proto == NULL) error("too many arguments to %s\n", funcname(f)); q = value(q); if (isarray(q->type) || q->type->size == 0) error("type error in argument %d to %s; `%t' is illegal\n", n + 1, funcname(f), q->type); else q = cast(q, promote(q->type)); } if (!IR->wants_argb && isstruct(q->type)) if (iscallb(q)) q = addrof(q); else { Symbol t1 = temporary(AUTO, unqual(q->type)); q = asgn(t1, q); q = tree(RIGHT, ptr(t1->type), root(q), lvalue(idtree(t1))); } if (q->type->size == 0) q->type = inttype; if (hascall(q)) r = r ? tree(RIGHT, voidtype, r, q) : q; args = tree(mkop(ARG, q->type), q->type, q, args); n++; if (Aflag >= 2 && n == 32) warning("more than 31 arguments in a call to %s\n", funcname(f)); if (t != ',') break; t = gettok(); } expect(')'); if (proto && *proto && *proto != voidtype) error("insufficient number of arguments to %s\n", funcname(f)); if (r) args = tree(RIGHT, voidtype, r, args); e = calltree(f, rty, args, t3); if (events.calls) apply(events.calls, &src, &e); return e; }
/* tracevalue - append format and argument to print the value of e */ static void tracevalue(Tree e, int lev) { Type ty = unqual(e->type); switch (ty->op) { case INT: if (ty == chartype || ty == signedchar) appendstr("'\\x%02x'"); else if (ty == longtype) appendstr("0x%ld"); else appendstr("0x%d"); break; case UNSIGNED: if (ty == chartype || ty == unsignedchar) appendstr("'\\x%02x'"); else if (ty == unsignedlong) appendstr("0x%lx"); else appendstr("0x%x"); break; case FLOAT: if (ty == longdouble) appendstr("%Lg"); else appendstr("%g"); break; case POINTER: if (unqual(ty->type) == chartype || unqual(ty->type) == signedchar || unqual(ty->type) == unsignedchar) { static Symbol null; if (null == NULL) null = mkstr("(null)"); tracevalue(cast(e, unsignedtype), lev + 1); appendstr(" \"%.30s\""); e = condtree(e, e, pointer(idtree(null->u.c.loc))); } else { appendstr("("); appendstr(typestring(ty, "")); appendstr(")0x%x"); } break; case STRUCT: { Field q; appendstr("("); appendstr(typestring(ty, "")); appendstr("){"); for (q = ty->u.sym->u.s.flist; q; q = q->link) { appendstr(q->name); appendstr("="); tracevalue(field(addrof(e), q->name), lev + 1); if (q->link) appendstr(","); } appendstr("}"); return; } case UNION: appendstr("("); appendstr(typestring(ty, "")); appendstr("){...}"); return; case ARRAY: if (lev && ty->type->size > 0) { int i; e = pointer(e); appendstr("{"); for (i = 0; i < ty->size/ty->type->size; i++) { Tree p = (*optree['+'])(ADD, e, consttree(i, inttype)); if (isptr(p->type) && isarray(p->type->type)) p = retype(p, p->type->type); else p = rvalue(p); if (i) appendstr(","); tracevalue(p, lev + 1); } appendstr("}"); } else appendstr(typestring(ty, "")); return; default: assert(0); } e = cast(e, promote(ty)); args = tree(mkop(ARG,e->type), e->type, e, args); }