blob: 8a5bb5beed81874ab9abed85e5325cca0197461b [file] [log] [blame]
#include <time.h>
#include <ctype.h>
#include "c.h"
#define I(f) s_##f
static char rcsid[] = "$Id: symbolic.c 355 2007-02-18 22:08:49Z drh $";
static Node *tail;
static int off, maxoff, uid = 0, verbose = 0, html = 0;
static const char *yyBEGIN(const char *tag) {
if (html)
print("<%s>", tag);
return tag;
}
static void yyEND(const char *tag) {
if (html)
print("</%s>", tag);
if (isupper(*tag))
print("\n");
}
#define BEGIN(tag) do { const char *yytag=yyBEGIN(#tag)
#define END yyEND(yytag); } while (0)
#define ITEM BEGIN(li)
#define START BEGIN(LI)
#define ANCHOR(attr,code) do { const char *yytag="a"; if (html) { printf("<a " #attr "=\""); code; print("\">"); }
#define NEWLINE print(html ? "<br>\n" : "\n")
static void emitCoord(Coordinate src) {
if (src.file && *src.file) {
ANCHOR(href,print("%s", src.file)); print("%s", src.file); END;
print(":");
}
print("%d.%d", src.y, src.x);
}
static void emitString(int len, const char *s) {
for ( ; len-- > 0; s++)
if (*s == '&' && html)
print("&amp;");
else if (*s == '<' && html)
print("&lt;");
else if (*s == '>' && html)
print("&lt;");
else if (*s == '"' || *s == '\\')
print("\\%c", *s);
else if (*s >= ' ' && *s < 0177)
print("%c", *s);
else
print("\\%d%d%d", (*s>>6)&3, (*s>>3)&7, *s&7);
}
static void emitSymRef(Symbol p) {
(*IR->defsymbol)(p);
ANCHOR(href,print("#%s", p->x.name)); BEGIN(code); print("%s", p->name); END; END;
}
static void emitSymbol(Symbol p) {
(*IR->defsymbol)(p);
ANCHOR(name,print("%s", p->x.name)); BEGIN(code); print("%s", p->name); END; END;
BEGIN(ul);
#define xx(field,code) ITEM; if (!html) print(" "); print(#field "="); code; END
if (verbose && (src.y || src.x))
xx(src,emitCoord(p->src));
xx(type,print("%t", p->type));
xx(sclass,print("%k", p->sclass));
switch (p->scope) {
case CONSTANTS: xx(scope,print("CONSTANTS")); break;
case LABELS: xx(scope,print("LABELS")); break;
case GLOBAL: xx(scope,print("GLOBAL")); break;
case PARAM: xx(scope,print("PARAM")); break;
case LOCAL: xx(scope,print("LOCAL")); break;
default:
if (p->scope > LOCAL)
xx(scope,print("LOCAL+%d", p->scope-LOCAL));
else
xx(scope,print("%d", p->scope));
}
ITEM;
int n = 0;
if (!html)
print(" ");
print("flags=");
#define yy(f) if (p->f) { if (n++) print("|"); print(#f); }
yy(structarg)
yy(addressed)
yy(computed)
yy(temporary)
yy(generated)
#undef yy
if (n == 0)
print("0");
END;
if (p->scope >= PARAM && p->sclass != STATIC)
xx(offset,print("%d", p->x.offset));
xx(ref,print("%f", p->ref));
if (p->temporary && p->u.t.cse)
xx(u.t.cse,print("%p", p->u.t.cse));
END;
#undef xx
}
/* address - initialize q for addressing expression p+n */
static void I(address)(Symbol q, Symbol p, long n) {
q->name = stringf("%s%s%D", p->name, n > 0 ? "+" : "", n);
(*IR->defsymbol)(q);
START; print("address "); emitSymbol(q); END;
}
/* blockbeg - start a block */
static void I(blockbeg)(Env *e) {
e->offset = off;
START; print("blockbeg off=%d", off); END;
}
/* blockend - start a block */
static void I(blockend)(Env *e) {
if (off > maxoff)
maxoff = off;
START; print("blockend off=%d", off); END;
off = e->offset;
}
/* defaddress - initialize an address */
static void I(defaddress)(Symbol p){
START; print("defaddress "); emitSymRef(p); END;
}
/* defconst - define a constant */
static void I(defconst)(int suffix, int size, Value v) {
START;
print("defconst ");
switch (suffix) {
case I:
print("int.%d ", size);
BEGIN(code);
if (size > sizeof (int))
print("%D", v.i);
else
print("%d", (int)v.i);
END;
break;
case U:
print("unsigned.%d ", size);
BEGIN(code);
if (size > sizeof (unsigned))
print("%U", v.u);
else
print("%u", (unsigned)v.u);
END;
break;
case P: print("void*.%d ", size); BEGIN(code); print("%p", v.p); END; break;
case F:
print("float.%d ", size);
BEGIN(code);
double d = v.d;
if (d == 0.0) {
static union { int x; char endian; } little = { 1 };
signed char *b = (signed char *)&d;
if (!little.endian && b[0] < 0
|| little.endian && b[sizeof (d)-1] < 0)
print("-0.0");
else
print("0.0");
} else
print("%g", d);
END;
break;
default: assert(0);
}
END;
}
/* defstring - emit a string constant */
static void I(defstring)(int len, char *s) {
START; print("defstring ");
BEGIN(code); print("\""); emitString(len, s); print("\""); END;
END;
}
/* defsymbol - define a symbol: initialize p->x */
static void I(defsymbol)(Symbol p) {
if (p->x.name == NULL)
p->x.name = stringd(++uid);
}
/* emit - emit the dags on list p */
static void I(emit)(Node p){
ITEM;
if (!html)
print(" ");
for (; p; p = p->x.next) {
if (p->op == LABEL+V) {
assert(p->syms[0]);
ANCHOR(name,print("%s", p->syms[0]->x.name));
BEGIN(code); print("%s", p->syms[0]->name); END;
END;
print(":");
} else {
int i;
if (p->x.listed) {
BEGIN(strong); print("%d", p->x.inst); END; print("'");
print(" %s", opname(p->op));
} else
print("%d. %s", p->x.inst, opname(p->op));
if (p->count > 1)
print(" count=%d", p->count);
for (i = 0; i < NELEMS(p->kids) && p->kids[i]; i++)
print(" #%d", p->kids[i]->x.inst);
if (generic(p->op) == CALL && p->syms[0] && p->syms[0]->type)
print(" {%t}", p->syms[0]->type);
else
for (i = 0; i < NELEMS(p->syms) && p->syms[i]; i++) {
print(" ");
if (p->syms[i]->scope == CONSTANTS)
print(p->syms[i]->name);
else
emitSymRef(p->syms[i]);
}
}
NEWLINE;
}
END;
}
/* export - announce p as exported */
static void I(export)(Symbol p) {
START; print("export "); emitSymRef(p); END;
}
/* function - generate code for a function */
static void I(function)(Symbol f, Symbol caller[], Symbol callee[], int ncalls) {
int i;
(*IR->defsymbol)(f);
off = 0;
for (i = 0; caller[i] && callee[i]; i++) {
off = roundup(off, caller[i]->type->align);
caller[i]->x.offset = callee[i]->x.offset = off;
off += caller[i]->type->size;
}
if (!html) {
print("function ");
emitSymbol(f);
print(" ncalls=%d\n", ncalls);
for (i = 0; caller[i]; i++)
START; print("caller "); emitSymbol(caller[i]); END;
for (i = 0; callee[i]; i++)
START; print("callee "); emitSymbol(callee[i]); END;
} else {
START;
print("function");
BEGIN(UL);
#define xx(field,code) ITEM; print(#field "="); code; END
xx(f,emitSymbol(f));
xx(ncalls,print("%d", ncalls));
if (caller[0]) {
ITEM; print("caller"); BEGIN(OL);
for (i = 0; caller[i]; i++)
ITEM; emitSymbol(caller[i]); END;
END; END;
ITEM; print("callee"); BEGIN(OL);
for (i = 0; callee[i]; i++)
ITEM; emitSymbol(callee[i]); END;
END; END;
} else {
xx(caller,BEGIN(em); print("empty"); END);
xx(callee,BEGIN(em); print("empty"); END);
}
END;
END;
}
maxoff = off = 0;
gencode(caller, callee);
if (html)
START; print("emitcode"); BEGIN(ul); emitcode(); END; END;
else
emitcode();
START; print("maxoff=%d", maxoff); END;
#undef xx
}
/* visit - generate code for *p */
static int visit(Node p, int n) {
if (p && p->x.inst == 0) {
p->x.inst = ++n;
n = visit(p->kids[0], n);
n = visit(p->kids[1], n);
*tail = p;
tail = &p->x.next;
}
return n;
}
/* gen0 - generate code for the dags on list p */
static Node I(gen)(Node p) {
int n;
Node nodelist;
tail = &nodelist;
for (n = 0; p; p = p->link) {
switch (generic(p->op)) { /* check for valid forest */
case CALL:
assert(IR->wants_dag || p->count == 0);
break;
case ARG:
case ASGN: case JUMP: case LABEL: case RET:
case EQ: case GE: case GT: case LE: case LT: case NE:
assert(p->count == 0);
break;
case INDIR:
assert(IR->wants_dag && p->count > 0);
break;
default:
assert(0);
}
check(p);
p->x.listed = 1;
n = visit(p, n);
}
*tail = 0;
return nodelist;
}
/* global - announce a global */
static void I(global)(Symbol p) {
START; print("global "); emitSymbol(p); END;
}
/* import - import a symbol */
static void I(import)(Symbol p) {
START; print("import "); emitSymRef(p); END;
}
/* local - local variable */
static void I(local)(Symbol p) {
if (p->temporary)
p->name = stringf("t%s", p->name);
(*IR->defsymbol)(p);
off = roundup(off, p->type->align);
p->x.offset = off;
off += p->type->size;
START; print(p->temporary ? "temporary " : "local "); emitSymbol(p); END;
}
/* progbeg - beginning of program */
static void I(progbeg)(int argc, char *argv[]) {
int i;
for (i = 1; i < argc; i++)
if (strcmp(argv[i], "-v") == 0)
verbose++;
else if (strcmp(argv[i], "-html") == 0)
html++;
if (html) {
print("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n");
print("<html>");
BEGIN(head);
if (firstfile && *firstfile)
BEGIN(title); emitString(strlen(firstfile), firstfile); END;
print("<link rev=made href=\"mailto:drh@microsoft.com\">\n");
END;
print("<body>\n");
if (firstfile && *firstfile)
BEGIN(h1); emitString(strlen(firstfile), firstfile); END;
BEGIN(P); BEGIN(em);
print("Links lead from uses of identifiers and labels to their definitions.");
END; END;
print("<ul>\n");
START;
print("progbeg");
BEGIN(ol);
for (i = 1; i < argc; i++) {
ITEM;
BEGIN(code); print("\""); emitString(strlen(argv[i]), argv[i]); print("\""); END;
END;
}
END;
END;
}
}
/* progend - end of program */
static void I(progend)(void) {
START; print("progend"); END;
if (html) {
time_t t;
print("</ul>\n");
time(&t);
print("<hr><address>%s</address>\n", ctime(&t));
print("</body></html>\n");
}
}
/* segment - switch to segment s */
static void I(segment)(int s) {
START; print("segment %s", &"text\0bss\0.data\0lit\0.sym\0."[5*s-5]); END;
}
/* space - initialize n bytes of space */
static void I(space)(int n) {
START; print("space %d", n); END;
}
static void I(stabblock)(int brace, int lev, Symbol *p) {}
/* stabend - finalize stab output */
static void I(stabend)(Coordinate *cp, Symbol p, Coordinate **cpp, Symbol *sp, Symbol *stab) {
int i;
if (p)
emitSymRef(p);
print("\n");
if (cpp && sp)
for (i = 0; cpp[i] && sp[i]; i++) {
print("%w.%d: ", cpp[i], cpp[i]->x);
emitSymRef(sp[i]);
print("\n");
}
}
static void I(stabfend)(Symbol p, int lineno) {}
static void I(stabinit)(char *file, int argc, char *argv[]) {}
/* stabline - emit line number information for source coordinate *cp */
static void I(stabline)(Coordinate *cp) {
if (cp->file)
print("%s:", cp->file);
print("%d.%d:\n", cp->y, cp->x);
}
static void I(stabsym)(Symbol p) {}
static void I(stabtype)(Symbol p) {}
Interface symbolicIR = {
1, 1, 0, /* char */
2, 2, 0, /* short */
4, 4, 0, /* int */
4, 4, 0, /* long */
4, 4, 0, /* long long */
4, 4, 1, /* float */
8, 8, 1, /* double */
8, 8, 1, /* long double */
4, 4, 0, /* T* */
0, 4, 0, /* struct */
0, /* little_endian */
0, /* mulops_calls */
0, /* wants_callb */
1, /* wants_argb */
1, /* left_to_right */
1, /* wants_dag */
0, /* unsigned_char */
I(address),
I(blockbeg),
I(blockend),
I(defaddress),
I(defconst),
I(defstring),
I(defsymbol),
I(emit),
I(export),
I(function),
I(gen),
I(global),
I(import),
I(local),
I(progbeg),
I(progend),
I(segment),
I(space),
I(stabblock),
I(stabend),
I(stabfend),
I(stabinit),
I(stabline),
I(stabsym),
I(stabtype)
};
Interface symbolic64IR = {
1, 1, 0, /* char */
2, 2, 0, /* short */
4, 4, 0, /* int */
8, 8, 0, /* long */
8, 8, 0, /* long long */
4, 4, 1, /* float */
8, 8, 1, /* double */
8, 8, 1, /* long double */
8, 8, 0, /* T* */
0, 1, 0, /* struct */
1, /* little_endian */
0, /* mulops_calls */
0, /* wants_callb */
1, /* wants_argb */
1, /* left_to_right */
1, /* wants_dag */
0, /* unsigned_char */
I(address),
I(blockbeg),
I(blockend),
I(defaddress),
I(defconst),
I(defstring),
I(defsymbol),
I(emit),
I(export),
I(function),
I(gen),
I(global),
I(import),
I(local),
I(progbeg),
I(progend),
I(segment),
I(space),
I(stabblock),
I(stabend),
I(stabfend),
I(stabinit),
I(stabline),
I(stabsym),
I(stabtype)
};