wcc: c-side mangles private decls; main exempt as entry-point convention
This commit is contained in:
111
cmd/w6c/cgen.c
111
cmd/w6c/cgen.c
@@ -301,6 +301,94 @@ ffi_collect(Cg *c, Node *file)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Module-private symbol map. Mirrors selfhost/cmd/wcc/cgen.ww. Each
|
||||||
|
* non-exported, non-FFI top-level decl is mangled to <module>.<name>
|
||||||
|
* at emission time so two modules can each privately define the same
|
||||||
|
* helper without colliding at link time. */
|
||||||
|
typedef struct Mod Mod;
|
||||||
|
struct Mod {
|
||||||
|
const char *name;
|
||||||
|
const char *module;
|
||||||
|
Mod *next;
|
||||||
|
};
|
||||||
|
static Mod *mod_map;
|
||||||
|
|
||||||
|
static int
|
||||||
|
decl_has_ffisym(Node *d)
|
||||||
|
{
|
||||||
|
for (Node *a = d->attr; a; a = a->next) {
|
||||||
|
if (a->kind != N_ATTR) continue;
|
||||||
|
if (strcmp(a->str, "symbol") == 0) return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mod_collect(Cg *c, Node *file)
|
||||||
|
{
|
||||||
|
mod_map = NULL;
|
||||||
|
if (file == NULL) return;
|
||||||
|
for (Node *d = file->list; d; d = d->next) {
|
||||||
|
int track = (d->kind == N_FNDECL) || (d->kind == N_TYPEDECL)
|
||||||
|
|| (d->kind == N_DEF) || (d->kind == N_LET);
|
||||||
|
if (!track) continue;
|
||||||
|
if (d->export) continue;
|
||||||
|
if (d->module == NULL || d->module[0] == '\0') continue;
|
||||||
|
if (decl_has_ffisym(d)) continue;
|
||||||
|
/* `main` is the linker entry-point convention. Even when not
|
||||||
|
* marked `export`, it must keep its bare name so w6l can
|
||||||
|
* resolve `_start`'s `CALL main(SB)`. */
|
||||||
|
if (d->str && strcmp(d->str, "main") == 0) continue;
|
||||||
|
Mod *m = amalloc(c->a, sizeof *m);
|
||||||
|
m->name = d->str;
|
||||||
|
m->module = d->module;
|
||||||
|
m->next = mod_map;
|
||||||
|
mod_map = m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the originating module for a name, or NULL if the name
|
||||||
|
* isn't a registered private decl. */
|
||||||
|
static const char *
|
||||||
|
mod_lookup(const char *name)
|
||||||
|
{
|
||||||
|
for (Mod *m = mod_map; m; m = m->next)
|
||||||
|
if (strcmp(m->name, name) == 0) return m->module;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mangle an AST identifier into its asm linker symbol:
|
||||||
|
* - @symbol("...") binding wins (return mapped name).
|
||||||
|
* - module-private decl → <module>.<name>.
|
||||||
|
* - else → name unchanged.
|
||||||
|
* Used at every CALL/MOVQ/LEAQ site that targets an AST name. Plain
|
||||||
|
* `asym(s)` still emits `s` verbatim — use it for strlit labels and
|
||||||
|
* hard-coded runtime symbols like "rt_streq". */
|
||||||
|
static const char *
|
||||||
|
mod_mangle(Cg *c, const char *ident)
|
||||||
|
{
|
||||||
|
const char *resolved = ffi_resolve(ident);
|
||||||
|
if (resolved != ident) return resolved;
|
||||||
|
const char *mod = mod_lookup(ident);
|
||||||
|
if (mod == NULL) return ident;
|
||||||
|
size_t mn = strlen(mod), in = strlen(ident);
|
||||||
|
char *buf = amalloc(c->a, mn + 1 + in + 1);
|
||||||
|
memcpy(buf, mod, mn);
|
||||||
|
buf[mn] = '.';
|
||||||
|
memcpy(buf + mn + 1, ident, in);
|
||||||
|
buf[mn + 1 + in] = '\0';
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Forward decl — masym below depends on asym defined further down. */
|
||||||
|
static Adr asym(const char *s);
|
||||||
|
|
||||||
|
static Adr
|
||||||
|
masym(Cg *c, const char *ident)
|
||||||
|
{
|
||||||
|
return asym(mod_mangle(c, ident));
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
cg_init(Cg *c, Arena *a)
|
cg_init(Cg *c, Arena *a)
|
||||||
{
|
{
|
||||||
@@ -514,7 +602,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
|||||||
* the same `$symname` for both call and
|
* the same `$symname` for both call and
|
||||||
* address-of via QBE; here we mirror that. */
|
* address-of via QBE; here we mirror that. */
|
||||||
ins2(c, A_LEAQ,
|
ins2(c, A_LEAQ,
|
||||||
asym(ffi_resolve(n->str)), areg(D_AX));
|
masym(c, n->str), areg(D_AX));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
for (Sdef *s = sdefs; s; s = s->next) {
|
for (Sdef *s = sdefs; s; s = s->next) {
|
||||||
@@ -526,7 +614,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
|||||||
areg(D_BX));
|
areg(D_BX));
|
||||||
goto ident_done;
|
goto ident_done;
|
||||||
}
|
}
|
||||||
ins2(c, A_MOVQ, asym(n->str), areg(D_AX));
|
ins2(c, A_MOVQ, masym(c, n->str), areg(D_AX));
|
||||||
}
|
}
|
||||||
ident_done:
|
ident_done:
|
||||||
break;
|
break;
|
||||||
@@ -1253,7 +1341,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
|||||||
ins2(c, A_LEAQ, amem(D_BP, sn_off), areg(D_AX));
|
ins2(c, A_LEAQ, amem(D_BP, sn_off), areg(D_AX));
|
||||||
ins1(c, A_POPQ, areg(D_SI));
|
ins1(c, A_POPQ, areg(D_SI));
|
||||||
ins2(c, A_MOVQ, areg(D_AX), areg(D_DI));
|
ins2(c, A_MOVQ, areg(D_AX), areg(D_DI));
|
||||||
ins1(c, A_CALL, asym(fn));
|
ins1(c, A_CALL, masym(c, fn));
|
||||||
ins2(c, A_ADDQ, aimm(1), amem(D_SP, 0));
|
ins2(c, A_ADDQ, aimm(1), amem(D_SP, 0));
|
||||||
ins1(c, A_JMP, abranch(ll));
|
ins1(c, A_JMP, abranch(ll));
|
||||||
label(c, le);
|
label(c, le);
|
||||||
@@ -1266,7 +1354,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
|||||||
ins2(c, A_LEAQ, amem(D_BP, sn_off), areg(D_AX));
|
ins2(c, A_LEAQ, amem(D_BP, sn_off), areg(D_AX));
|
||||||
ins1(c, A_POPQ, areg(D_SI));
|
ins1(c, A_POPQ, areg(D_SI));
|
||||||
ins2(c, A_MOVQ, areg(D_AX), areg(D_DI));
|
ins2(c, A_MOVQ, areg(D_AX), areg(D_DI));
|
||||||
ins1(c, A_CALL, asym(fn));
|
ins1(c, A_CALL, masym(c, fn));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1452,7 +1540,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
|||||||
ins1(c, A_CALL, areg(D_AX));
|
ins1(c, A_CALL, areg(D_AX));
|
||||||
} else {
|
} else {
|
||||||
ins1(c, A_CALL,
|
ins1(c, A_CALL,
|
||||||
asym(ffi_resolve(n->lhs->str)));
|
masym(c, n->lhs->str));
|
||||||
}
|
}
|
||||||
} else if (n->lhs->kind == N_DOT && n->lhs->lhs &&
|
} else if (n->lhs->kind == N_DOT && n->lhs->lhs &&
|
||||||
n->lhs->lhs->kind == N_IDENT) {
|
n->lhs->lhs->kind == N_IDENT) {
|
||||||
@@ -1462,7 +1550,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
|||||||
* function pointer — we load the field and indirect. */
|
* function pointer — we load the field and indirect. */
|
||||||
Type *bt = n->lhs->lhs->type;
|
Type *bt = n->lhs->lhs->type;
|
||||||
if (bt == NULL || bt == ty_err) {
|
if (bt == NULL || bt == ty_err) {
|
||||||
ins1(c, A_CALL, asym(ffi_resolve(n->lhs->str)));
|
ins1(c, A_CALL, masym(c, n->lhs->str));
|
||||||
} else {
|
} else {
|
||||||
cgexpr(c, n->lhs, locals); /* AX = fn ptr */
|
cgexpr(c, n->lhs, locals); /* AX = fn ptr */
|
||||||
ins1(c, A_CALL, areg(D_AX));
|
ins1(c, A_CALL, areg(D_AX));
|
||||||
@@ -1669,7 +1757,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
|||||||
Type *tu = (t && t->kind == TY_NAMED) ? t->under : t;
|
Type *tu = (t && t->kind == TY_NAMED) ? t->under : t;
|
||||||
if (tu && tu->kind == TY_FN) {
|
if (tu && tu->kind == TY_FN) {
|
||||||
ins2(c, A_LEAQ,
|
ins2(c, A_LEAQ,
|
||||||
asym(ffi_resolve(n->str)), areg(D_AX));
|
masym(c, n->str), areg(D_AX));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
for (Sdef *s = sdefs; s; s = s->next) {
|
for (Sdef *s = sdefs; s; s = s->next) {
|
||||||
@@ -1681,7 +1769,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
|||||||
areg(D_BX));
|
areg(D_BX));
|
||||||
goto dot_done;
|
goto dot_done;
|
||||||
}
|
}
|
||||||
ins2(c, A_MOVQ, asym(n->str), areg(D_AX));
|
ins2(c, A_MOVQ, masym(c, n->str), areg(D_AX));
|
||||||
goto dot_done;
|
goto dot_done;
|
||||||
}
|
}
|
||||||
int lenfld = (n->str && strcmp(n->str, "len") == 0);
|
int lenfld = (n->str && strcmp(n->str, "len") == 0);
|
||||||
@@ -2513,7 +2601,9 @@ cgfn(Cg *c, FILE *out, Node *fn)
|
|||||||
|
|
||||||
/* TEXT directive comes first; framesize is filled at the end. */
|
/* TEXT directive comes first; framesize is filled at the end. */
|
||||||
Prog *text = newprog(c, A_TEXT);
|
Prog *text = newprog(c, A_TEXT);
|
||||||
text->to = asym(fn->str);
|
/* Mangle the label for non-exported, non-FFI decls; mod_mangle
|
||||||
|
* does the FFI/module lookup in one step. */
|
||||||
|
text->to = masym(c, fn->str);
|
||||||
text->from.offset = 0; /* framesize patched below */
|
text->from.offset = 0; /* framesize patched below */
|
||||||
emit(c, text);
|
emit(c, text);
|
||||||
|
|
||||||
@@ -2630,7 +2720,7 @@ emit_defs(Cg *c, FILE *out, Node *file)
|
|||||||
} else {
|
} else {
|
||||||
continue; /* skip non-integer-literal defs */
|
continue; /* skip non-integer-literal defs */
|
||||||
}
|
}
|
||||||
fprintf(out, "DATA %s(SB),\"", d->str);
|
fprintf(out, "DATA %s(SB),\"", mod_mangle(c, d->str));
|
||||||
for (int i = 0; i < 8; i++) {
|
for (int i = 0; i < 8; i++) {
|
||||||
unsigned b = (unsigned)((v >> (i * 8)) & 0xff);
|
unsigned b = (unsigned)((v >> (i * 8)) & 0xff);
|
||||||
if (b == '"' || b == '\\')
|
if (b == '"' || b == '\\')
|
||||||
@@ -2672,6 +2762,7 @@ cg_file(Cg *c, FILE *out, Node *file)
|
|||||||
{
|
{
|
||||||
if (file == NULL || file->kind != N_FILE) return;
|
if (file == NULL || file->kind != N_FILE) return;
|
||||||
ffi_collect(c, file);
|
ffi_collect(c, file);
|
||||||
|
mod_collect(c, file);
|
||||||
sdef_collect(c, file);
|
sdef_collect(c, file);
|
||||||
strlits = NULL;
|
strlits = NULL;
|
||||||
strlit_seq = 0;
|
strlit_seq = 0;
|
||||||
|
|||||||
@@ -94,6 +94,27 @@ skipws(Lex *l)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (c == '/' && lpeek(l, 1) == '/') {
|
if (c == '/' && lpeek(l, 1) == '/') {
|
||||||
|
lget(l); lget(l); /* consume '//' */
|
||||||
|
/* `// MODULE: foo` directive emitted by the ww
|
||||||
|
* driver before each source-file's section in
|
||||||
|
* combined.ww. Captured so cgen can mangle
|
||||||
|
* non-exported symbols by module. */
|
||||||
|
if (lpeek(l, 0) == ' '
|
||||||
|
&& lpeek(l, 1) == 'M' && lpeek(l, 2) == 'O'
|
||||||
|
&& lpeek(l, 3) == 'D' && lpeek(l, 4) == 'U'
|
||||||
|
&& lpeek(l, 5) == 'L' && lpeek(l, 6) == 'E'
|
||||||
|
&& lpeek(l, 7) == ':' && lpeek(l, 8) == ' ') {
|
||||||
|
for (int i = 0; i < 9; i++) lget(l);
|
||||||
|
u64 start = l->pos;
|
||||||
|
while ((c = lpeek(l, 0)) >= 0
|
||||||
|
&& c != '\n' && c != '\r')
|
||||||
|
lget(l);
|
||||||
|
u64 n = l->pos - start;
|
||||||
|
char *m = amalloc(l->a, n + 1);
|
||||||
|
memcpy(m, l->src + start, n);
|
||||||
|
m[n] = '\0';
|
||||||
|
l->module = m;
|
||||||
|
}
|
||||||
while ((c = lpeek(l, 0)) >= 0 && c != '\n')
|
while ((c = lpeek(l, 0)) >= 0 && c != '\n')
|
||||||
lget(l);
|
lget(l);
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -1174,6 +1174,10 @@ parsefile(Parser *p)
|
|||||||
advance(p);
|
advance(p);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
/* Stamp the lex's current `// MODULE: foo` directive on the
|
||||||
|
* decl. cgen uses it to mangle non-exported names so two
|
||||||
|
* modules can each privately define `cstrlen`/`streq`/etc. */
|
||||||
|
if (d != NULL) d->module = p->l->module;
|
||||||
if (head == NULL) head = d;
|
if (head == NULL) head = d;
|
||||||
else tail->next = d;
|
else tail->next = d;
|
||||||
tail = d;
|
tail = d;
|
||||||
|
|||||||
@@ -196,6 +196,7 @@ struct Lex {
|
|||||||
i32 col;
|
i32 col;
|
||||||
Arena *a; /* token-text arena */
|
Arena *a; /* token-text arena */
|
||||||
int errs;
|
int errs;
|
||||||
|
const char *module; /* current `// MODULE: foo` directive, or NULL */
|
||||||
};
|
};
|
||||||
|
|
||||||
void lexinit(Lex*, Arena*, const char *file, const char *src, u64 len);
|
void lexinit(Lex*, Arena*, const char *file, const char *src, u64 len);
|
||||||
@@ -303,6 +304,11 @@ struct Node {
|
|||||||
int export;
|
int export;
|
||||||
Type *type; /* filled in by checker */
|
Type *type; /* filled in by checker */
|
||||||
const char *tsuffix; /* typed numeric literal suffix */
|
const char *tsuffix; /* typed numeric literal suffix */
|
||||||
|
const char *module; /* `// MODULE: foo` directive at the
|
||||||
|
* decl's section in combined.ww.
|
||||||
|
* NULL for nested nodes; only top-
|
||||||
|
* level decls (fn/def/type/let)
|
||||||
|
* carry it. */
|
||||||
};
|
};
|
||||||
|
|
||||||
Node *newnode(Arena*, Nkind, Pos);
|
Node *newnode(Arena*, Nkind, Pos);
|
||||||
|
|||||||
@@ -4238,6 +4238,7 @@ fn collectmods(c: *cgen, file: *node) void = {
|
|||||||
if (d.kind == N_FNDECL) {
|
if (d.kind == N_FNDECL) {
|
||||||
if (d.exported == 0) {
|
if (d.exported == 0) {
|
||||||
if (d.module.len > 0) {
|
if (d.module.len > 0) {
|
||||||
|
if (!streq(d.str, "main")) {
|
||||||
let m: *modent = amalloc(c.a, 48u64): *modent;
|
let m: *modent = amalloc(c.a, 48u64): *modent;
|
||||||
m.mname = d.str;
|
m.mname = d.str;
|
||||||
m.module = d.module;
|
m.module = d.module;
|
||||||
@@ -4246,6 +4247,7 @@ fn collectmods(c: *cgen, file: *node) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
};
|
||||||
if (d.kind == N_DEF) {
|
if (d.kind == N_DEF) {
|
||||||
if (d.exported == 0) {
|
if (d.exported == 0) {
|
||||||
if (d.module.len > 0) {
|
if (d.module.len > 0) {
|
||||||
|
|||||||
@@ -598,6 +598,7 @@ fn collectmods(c: *cgen, file: *node) void = {
|
|||||||
if (d.kind == N_FNDECL) {
|
if (d.kind == N_FNDECL) {
|
||||||
if (d.exported == 0) {
|
if (d.exported == 0) {
|
||||||
if (d.module.len > 0) {
|
if (d.module.len > 0) {
|
||||||
|
if (!streq(d.str, "main")) {
|
||||||
let m: *modent = amalloc(c.a, 48u64): *modent;
|
let m: *modent = amalloc(c.a, 48u64): *modent;
|
||||||
m.mname = d.str;
|
m.mname = d.str;
|
||||||
m.module = d.module;
|
m.module = d.module;
|
||||||
@@ -606,6 +607,7 @@ fn collectmods(c: *cgen, file: *node) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
};
|
||||||
if (d.kind == N_DEF) {
|
if (d.kind == N_DEF) {
|
||||||
if (d.exported == 0) {
|
if (d.exported == 0) {
|
||||||
if (d.module.len > 0) {
|
if (d.module.len > 0) {
|
||||||
|
|||||||
@@ -4238,6 +4238,7 @@ fn collectmods(c: *cgen, file: *node) void = {
|
|||||||
if (d.kind == N_FNDECL) {
|
if (d.kind == N_FNDECL) {
|
||||||
if (d.exported == 0) {
|
if (d.exported == 0) {
|
||||||
if (d.module.len > 0) {
|
if (d.module.len > 0) {
|
||||||
|
if (!streq(d.str, "main")) {
|
||||||
let m: *modent = amalloc(c.a, 48u64): *modent;
|
let m: *modent = amalloc(c.a, 48u64): *modent;
|
||||||
m.mname = d.str;
|
m.mname = d.str;
|
||||||
m.module = d.module;
|
m.module = d.module;
|
||||||
@@ -4246,6 +4247,7 @@ fn collectmods(c: *cgen, file: *node) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
};
|
||||||
if (d.kind == N_DEF) {
|
if (d.kind == N_DEF) {
|
||||||
if (d.exported == 0) {
|
if (d.exported == 0) {
|
||||||
if (d.module.len > 0) {
|
if (d.module.len > 0) {
|
||||||
|
|||||||
Reference in New Issue
Block a user