commit 46588de4ca1b0a4c47591d61c5947dc1a3238ce5
parent 34b628de0fe4f297e8e5ef969a6355748a8154ef
Author: Roberto E. Vargas Caballero <k0ga@shike2.net>
Date: Mon, 9 Feb 2026 16:08:49 +0100
cc1: Add support for non constant auto initializers
This has been an important miss in scc for a while. While this code is not
guranteed to work for all the cases, and it can generate really bad code,
it works for the most common casesa and it can be used to bootstrap them.
Diffstat:
5 files changed, 157 insertions(+), 5 deletions(-)
diff --git a/src/cmd/scc-cc/cc1/cc1.h b/src/cmd/scc-cc/cc1/cc1.h
@@ -487,8 +487,10 @@ Node *varnode(Symbol *sym);
Node *constnode(Symbol *sym);
Node *sizeofnode(Type *tp);
Node *offsetnode(Symbol *, Type *);
+Node *addrnode(unsigned long long);
void freetree(Node *np);
void icode(void);
+Node *zeronode(Type *);
#define BTYPE(np) ((np)->type->op)
/* fold.c */
diff --git a/src/cmd/scc-cc/cc1/code.c b/src/cmd/scc-cc/cc1/code.c
@@ -347,7 +347,7 @@ emitstring(Symbol *sym, Type *tp)
}
}
-static Node *
+Node *
zeronode(Type *tp)
{
return simplify(convert(constnode(zero), tp, 0));
@@ -590,6 +590,7 @@ sizeofnode(Type *tp)
sym = newsym(NS_IDEN, NULL);
sym->type = sizettype;
+ sym->flags |= SCONSTANT;
sym->u.u = tp->size;
DBG("EXPR sizeof %llu", sym->u.u);
return constnode(sym);
@@ -608,3 +609,16 @@ offsetnode(Symbol *field, Type *tp)
return constnode(sym);
}
+
+Node *
+addrnode(unsigned long long u)
+{
+ Symbol *sym;
+
+ sym = newsym(NS_IDEN, NULL);
+ sym->type = pvoidtype;
+ sym->flags |= SCONSTANT;
+ sym->u.u = u;
+
+ return constnode(sym);
+}
diff --git a/src/cmd/scc-cc/cc1/init.c b/src/cmd/scc-cc/cc1/init.c
@@ -343,20 +343,110 @@ initlist(Type *tp)
}
static void
+autofield(Symbol *sym, Node *np, Type *tp, unsigned long long *addr)
+{
+ int align;
+ Node *aux;
+ unsigned long long na;
+
+ align = tp->align - 1;
+ na = *addr;
+ na = (na + align) & ~align;
+ *addr = na;
+
+ aux = node(OADDR, pvoidtype, varnode(sym), NULL);
+ aux = node(OADD, pvoidtype, aux, addrnode(na));
+ aux = node(OPTR, tp, aux, NULL);
+ aux = node(OASSIGN, tp, aux, np);
+
+ emit(OEXPR, aux);
+ *addr += tp->size;
+}
+
+static void
+autocomp(Symbol *sym, Node *np, Type *tp, unsigned long long *addr)
+{
+ Type *p;
+ Node *aux;
+ Symbol *init;
+ unsigned long long n;
+
+ if (!np) {
+ init = NULL;
+ } else {
+ if (!np->sym)
+ goto expression;
+ init = np->sym;
+ if ((init->flags & SINITLST) == 0)
+ goto expression;
+ }
+
+ switch (tp->op) {
+ case PTR:
+ case INT:
+ case ENUM:
+ aux = init ? *init->u.init : zeronode(tp);
+ autofield(sym, aux, aux->type, addr);
+ break;
+ case UNION:
+ aux = (init) ? sym->u.init[0] : NULL;
+ p = (aux) ? aux->type : tp->p.fields[0]->type;
+ autocomp(sym, aux, p, addr);
+ break;
+ case STRUCT:
+ case ARY:
+ if ((np->flags & NCONST) != 0) {
+ Symbol *hidden = newsym(NS_IDEN, NULL);
+ hidden->id = newid();
+ hidden->type = init->type;
+ hidden->flags |= SLOCAL | SHASINIT;
+ emit(ODECL, hidden);
+ emit(OINIT, np);
+ np = varnode(hidden);
+ goto expression;
+ }
+ for (n = 0; n < tp->n.elem; ++n) {
+ aux = (init) ? init->u.init[n] : NULL;
+ p = (tp->op == ARY) ? tp->type : tp->p.fields[n]->type;
+ autocomp(sym, aux, p, addr);
+ }
+ break;
+ default:
+ abort();
+ }
+
+ if (init) {
+ free(init->u.init);
+ init->u.init = NULL;
+ }
+ freetree(np);
+ return;
+
+expression:
+ autofield(sym, np, tp, addr);
+}
+
+static void
emitstrings(Node *np)
{
unsigned f;
Symbol *sym;
+ long long i, n;
if (!np)
return;
if (np->op == OSYM) {
sym = np->sym;
- f = sym->flags & (SSTRING|SEMITTED);
+ f = sym->flags & (SSTRING|SEMITTED|SINITLST);
if (f == SSTRING) {
+ sym->flags |= SHASINIT;
emit(ODECL, sym);
emit(OINIT, constnode(sym));
+ } else if (f == SINITLST) {
+ n = np->type->n.elem;
+ for (i = 0; i < n; ++i)
+ emitstrings(sym->u.init[i]);
}
}
@@ -367,6 +457,7 @@ emitstrings(Node *np)
static void
autoinit(Symbol *sym, Node *np)
{
+ unsigned long long a;
Symbol *hidden;
Type *tp = sym->type;
@@ -383,8 +474,14 @@ repeat:
if (np->op != OSYM || (np->sym->flags & SINITLST) == 0)
goto expr;
hidden_data:
- if (!(np->flags & NCONST))
- abort(); /* TODO */
+ if (!(np->flags & NCONST)) {
+ a = 0;
+ emitstrings(np);
+ emit(ODECL, sym);
+ autocomp(sym, np, np->type, &a);
+ return;
+
+ }
hidden = newsym(NS_IDEN, NULL);
hidden->id = newid();
hidden->type = sym->type;
diff --git a/tests/cc/execute/0241-init.c b/tests/cc/execute/0241-init.c
@@ -0,0 +1,38 @@
+struct a {
+ int i;
+ char s[10];
+};
+
+int i = 3;
+
+int
+main(void)
+{
+ char *s;
+ struct a b = {i, "hola"};
+
+ s = b.s;
+ if (s[0] != 'h')
+ return 1;
+ if (s[1] != 'o')
+ return 2;
+ if (s[2] != 'l')
+ return 3;
+ if (s[3] != 'a')
+ return 4;
+ if (s[4] != '\0')
+ return 5;
+ if (s[5] != '\0')
+ return 6;
+ if (s[6] != '\0')
+ return 7;
+ if (s[7] != '\0')
+ return 8;
+ if (s[8] != '\0')
+ return 9;
+ if (s[9] != '\0')
+ return 10;
+ if (b.i != 3)
+ return 11;
+ return 0;
+}
diff --git a/tests/cc/execute/scc-tests.lst b/tests/cc/execute/scc-tests.lst
@@ -206,7 +206,7 @@
0213-decay.c [TODO]
0214-va_copy.c
0215-ret_struct.c
-0216-initialize.c [TODO]
+0216-initialize.c
0217-lchar.c
0218-initialize.c
0219-abbrev.c
@@ -231,3 +231,4 @@
0238-align.c
0239-fcasts.c
0240-init.c
+0241-init.c