scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | Submodules | README | LICENSE

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:
Msrc/cmd/scc-cc/cc2/Makefile | 46+++++++++++++++++++++++++++++++++++-----------
Msrc/cmd/scc-cc/cc2/cc2.h | 4++++
Asrc/cmd/scc-cc/cc2/cfg.c | 248+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/cmd/scc-cc/cc2/main.c | 1+
Msrc/cmd/scc-cc/cc2/parser.c | 1+
Msrc/cmd/scc-cc/cc2/qbe/stubs.c | 10++++++++++
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) +{ +}