commit 131909381604e13b78b084fb3d59c8dc8b6689ac
parent f9abdd7888869258a99de6ce8e1f894035a1d9e3
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date: Fri, 27 Dec 2024 23:48:59 +0100
cc2: Add cfg generation
This is just the first iteration of the control flow transformations
and more changes are expected.
Diffstat:
6 files changed, 299 insertions(+), 11 deletions(-)
diff --git a/src/cmd/scc-cc/cc2/Makefile b/src/cmd/scc-cc/cc2/Makefile
@@ -14,13 +14,37 @@ include $(PROJECTDIR)/scripts/rules.mk
MORE_LDLIBS = -lscc
-OBJS =\
+QBE_OBJS =\
code.o\
main.o\
node.o\
parser.o\
symbol.o\
+OBJS =\
+ cfg.o\
+ $(QBE_OBJS)\
+
+AMD64_SYSV_OBJS =\
+ amd64-sysv/builtin.o\
+ $(OBJS) \
+
+I386_SYSV_OBJS =\
+ i386-sysv/builtin.o\
+ $(OBJS)
+
+QBE_AMD64_SYSV_OBJS=\
+ qbe_amd64-sysv/builtin.o\
+ $(QBE_OBJS)\
+
+QBE_ARM64_SYSV_OBJS=\
+ qbe_arm64-sysv/builtin.o\
+ $(QBE_OBJS)\
+
+Z80_SCC_OBJS =\
+ z80-scc/builtin.o\
+ $(OBJS) \
+
TARGET =\
cc2-amd64-sysv\
cc2-i386-sysv\
@@ -43,20 +67,20 @@ error.h: cc2.h
trap 'rm -f $$$$.h' EXIT INT QUIT TERM HUP;\
awk -f generror.awk cc2.h > $$$$.h && mv $$$$.h $@
-cc2-amd64-sysv: $(LIBSCC) $(OBJS) amd64-sysv/builtin.o
- $(CC) $(PROJ_LDFLAGS) $(OBJS) amd64-sysv/builtin.o $(PROJ_LDLIBS) -o $@
+cc2-amd64-sysv: $(LIBSCC) $(AMD64_SYSV_OBJS)
+ $(CC) $(PROJ_LDFLAGS) $(AMD64_SYSV_OBJS) $(PROJ_LDLIBS) -o $@
-cc2-i386-sysv: $(LIBSCC) $(OBJS) i386-sysv/builtin.o
- $(CC) $(PROJ_LDFLAGS) $(OBJS) i386-sysv/builtin.o $(PROJ_LDLIBS) -o $@
+cc2-i386-sysv: $(LIBSCC) $(I386_SYSV_OBJS)
+ $(CC) $(PROJ_LDFLAGS) $(I386_SYSV_OBJS) $(PROJ_LDLIBS) -o $@
-cc2-qbe_amd64-sysv: $(LIBSCC) $(OBJS) qbe_amd64-sysv/builtin.o
- $(CC) $(PROJ_LDFLAGS) $(OBJS) qbe_amd64-sysv/builtin.o $(PROJ_LDLIBS) -o $@
+cc2-qbe_amd64-sysv: $(LIBSCC) $(QBE_AMD64_SYSV_OBJS)
+ $(CC) $(PROJ_LDFLAGS) $(QBE_AMD64_SYSV_OBJS) $(PROJ_LDLIBS) -o $@
-cc2-qbe_arm64-sysv: $(LIBSCC) $(OBJS) qbe_arm64-sysv/builtin.o
- $(CC) $(PROJ_LDFLAGS) $(OBJS) qbe_arm64-sysv/builtin.o $(PROJ_LDLIBS) -o $@
+cc2-qbe_arm64-sysv: $(LIBSCC) $(QBE_ARM64_SYSV_OBJS)
+ $(CC) $(PROJ_LDFLAGS) $(QBE_ARM64_SYSV_OBJS) $(PROJ_LDLIBS) -o $@
-cc2-z80-scc: $(LIBSCC) $(OBJS) z80-scc/builtin.o
- $(CC) $(PROJ_LDFLAGS) $(OBJS) z80-scc/builtin.o $(PROJ_LDLIBS) -o $@
+cc2-z80-scc: $(LIBSCC) $(Z80_SCC_OBJS)
+ $(CC) $(PROJ_LDFLAGS) $(Z80_SCC_OBJS) $(PROJ_LDLIBS) -o $@
clean:
rm -f error.h
diff --git a/src/cmd/scc-cc/cc2/cc2.h b/src/cmd/scc-cc/cc2/cc2.h
@@ -286,6 +286,10 @@ extern void popctx(void);
extern void pushctx(void);
extern void freesym(Symbol *sym);
+/* bb.c */
+extern void gencfg(void);
+extern void cleancfg(void);
+
/* globals */
extern Symbol *curfun;
extern Symbol *locals;
diff --git a/src/cmd/scc-cc/cc2/cfg.c b/src/cmd/scc-cc/cc2/cfg.c
@@ -0,0 +1,248 @@
+/*
+ * This file is very tied with nodes.c and the main reason why
+ * this is not included directly in node.c is because all this
+ * code is not needed in qbe targets.
+ */
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <scc/scc.h>
+
+#include "cc2.h"
+
+#ifdef NDEBUG
+#define PRCFG(msg)
+#define PRTREE(msg)
+#else
+#define PRCFG(msg) (enadebug ? prcfg(msg) : NULL)
+#define PRTREE(msg) (enadebug ? prforest(msg) : NULL)
+#endif
+
+/* TODO: ignore OCASE, OBSWITCH, ODEFAULT for now */
+#define NBLOCKS 10
+
+struct cfg {
+ int nr;
+ int dirty;
+ Block *entryb, *exitb;
+ Block *cur;
+ Block *blocks;
+};
+
+static struct cfg cfg;
+
+#ifndef NDEBUG
+#include <stdio.h>
+
+static void
+prbb(Block *bb)
+{
+ if (!bb || bb->printed)
+ return;
+
+ assert(bb->id != -1);
+ bb->printed = 1;
+ if (bb->true) {
+ fprintf(stderr,
+ "\t%d -> %d [label=\"true\"]\n",
+ bb->id, bb->true->id);
+ }
+ if (bb->false) {
+ fprintf(stderr,
+ "\t%d -> %d [label=\"false\"]\n",
+ bb->id, bb->false->id);
+ }
+ prbb(bb->true);
+ prbb(bb->false);
+}
+
+static void
+prcfg(char *msg)
+{
+ Block *bb;
+ Node *np;
+
+ fprintf(stderr, "{digraph %s_%d {\n", msg, curfun->id);
+
+ for (bb = cfg.blocks; bb < &cfg.blocks[cfg.nr]; ++bb) {
+ if (bb->id == -1)
+ continue;
+ bb->printed = 0;
+
+ fprintf(stderr, "\t%d [shape=box;label=\"", bb->id);
+ for (np = bb->entryp; np; np = np->next) {
+ prtree(np);
+ putc('\n', stderr);
+ if (np == bb->exitp)
+ break;
+ }
+ fputs("\"]\n", stderr);
+ }
+
+ prbb(cfg.entryb);
+ fputs("}}\n", stderr);
+}
+#endif
+
+static Block *
+newbb(Node *np)
+{
+ Block *bb;
+
+ bb = &cfg.blocks[cfg.nr];
+ bb->entryp = np;
+ bb->exitp = NULL;
+ bb->true = bb->false = NULL;
+ bb->id = cfg.nr++;
+ bb->visited = 0;
+ np->bb = bb;
+
+ return bb;
+}
+
+static Node *
+mkcfg(Node *np)
+{
+ if ((np->flags & (BBENTRY|BBEXIT)) == 0)
+ return np;
+
+ if (np->flags & BBENTRY)
+ cfg.cur = np->bb;
+
+ if (np->flags & BBEXIT) {
+ cfg.cur->exitp = np;
+ cfg.cur->true = np->next->bb;
+ }
+
+ switch (np->op) {
+ case OBFUN:
+ cfg.entryb = cfg.cur;
+ break;
+ case OEFUN:
+ cfg.exitb = cfg.cur;
+ break;
+ case ORET:
+ cfg.cur->true = curfun->u.body->end->bb;
+ break;
+ case OBRANCH:
+ cfg.cur->false = np->next->bb;
+ case OJMP:
+ cfg.cur->true = np->u.sym->u.stmt->bb;
+ break;
+ }
+
+ return np;
+}
+
+static Node *
+mkbb(Node *np)
+{
+ if (np->flags & BBENTRY)
+ newbb(np);
+ return np;
+}
+
+static void
+newentry(Node *np)
+{
+ if (np->flags & BBENTRY)
+ return;
+
+ np->flags |= BBENTRY;
+ if (np->prev)
+ np->prev->flags |= BBEXIT;
+ cfg.nr++;
+ DBG("new entry point %d", cfg.nr);
+}
+
+static Node *
+markbb(Node *np)
+{
+ switch (np->op) {
+ case OBFUN:
+ newentry(np);
+ break;
+ case ORET:
+ newentry(curfun->u.body->end);
+ newentry(np->next);
+ break;
+ case OBRANCH:
+ case OJMP:
+ newentry(np->u.sym->u.stmt);
+ newentry(np->next);
+ break;
+ }
+ return np;
+}
+
+static void
+visit(Block *bb)
+{
+ if (!bb || bb->visited)
+ return;
+ bb->visited = 1;
+ visit(bb->true);
+ visit(bb->false);
+}
+
+static void
+trimcfg(void)
+{
+ Block *bb, *prev, *next;
+ Range r;
+
+ visit(cfg.entryb);
+ for (bb = cfg.blocks; bb < &cfg.blocks[cfg.nr]; ++bb) {
+ if (bb->visited)
+ continue;
+
+ r = range(bb->entryp, bb->exitp);
+ delrange(&r);
+ bb->id = -1;
+ }
+ PRCFG("trimmed_cfg");
+}
+
+static void
+buildcfg(void)
+{
+ int nr;
+
+ apply(markbb);
+ PRTREE("bb_mark");
+
+ cfg.blocks = xcalloc(cfg.nr, sizeof(Block));
+ nr = cfg.nr;
+ cfg.nr = 0;
+ apply(mkbb);
+ assert(cfg.nr == nr);
+
+ PRTREE("bb_mk");
+ apply(mkcfg);
+ PRCFG("cfg");
+}
+
+void
+gencfg(void)
+{
+ PRTREE("before_cfgopt");
+ buildcfg();
+ trimcfg();
+ PRTREE("after_cfgopt");
+}
+
+static Node *
+cleanbb(Node *np)
+{
+ np->flags &= ~(BBENTRY | BBEXIT);
+ return np;
+}
+
+void
+cleancfg(void)
+{
+ free(cfg.blocks);
+ memset(&cfg, 0, sizeof(cfg));
+ apply(cleanbb);
+}
diff --git a/src/cmd/scc-cc/cc2/main.c b/src/cmd/scc-cc/cc2/main.c
@@ -61,6 +61,7 @@ main(int argc, char *argv[])
while (moreinput()) {
parse();
genaddr();
+ gencfg();
genasm();
peephole();
writeout();
diff --git a/src/cmd/scc-cc/cc2/parser.c b/src/cmd/scc-cc/cc2/parser.c
@@ -700,6 +700,7 @@ void
parse(void)
{
/* clean from previous function */
+ cleancfg();
cleannodes();
popctx();
endf = 0;
diff --git a/src/cmd/scc-cc/cc2/qbe/stubs.c b/src/cmd/scc-cc/cc2/qbe/stubs.c
@@ -10,3 +10,13 @@ void
peephole(void)
{
}
+
+void
+gencfg(void)
+{
+}
+
+void
+cleancfg(void)
+{
+}