commit 00d366a0535adf8b0bf934e398aae138426d7262
parent d603b01749058d99f191934ebbefb0f8a56328eb
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date: Tue, 31 Dec 2024 18:55:40 +0100
cc2: Add support for switch in the cfg
Switch introduces a new different type of link between basic
blocks because a single basic block can be linked with many
different basic blocks which does not fit well with the
true/false approach that we were using with basic blocks.
Diffstat:
4 files changed, 61 insertions(+), 5 deletions(-)
diff --git a/src/cmd/scc-cc/cc2/cc2.h b/src/cmd/scc-cc/cc2/cc2.h
@@ -161,6 +161,7 @@ struct swtch {
int nr;
TINT min, max;
Node *defnode;
+ Node *cases;
Node *first;
Node *last;
Swtch *next;
@@ -217,6 +218,7 @@ struct block {
int printed, visited;
Node *entryp, *exitp;
Block *true, *false;
+ Swtch *swtch;
Block *next;
};
diff --git a/src/cmd/scc-cc/cc2/cfg.c b/src/cmd/scc-cc/cc2/cfg.c
@@ -29,6 +29,10 @@ static struct cfg cfg;
static void
prbb(Block *bb)
{
+ Node *np;
+ Swtch *swt;
+ Block *casebb;
+
if (!bb || bb->printed)
return;
@@ -46,6 +50,28 @@ prbb(Block *bb)
}
prbb(bb->true);
prbb(bb->false);
+
+ swt = bb->swtch;
+ if (!swt)
+ return;
+
+ for (np = swt->cases; np->op != OESWITCH; np = np->next) {
+ casebb = np->u.sym->u.stmt->bb;
+
+ if (!np->left) {
+ fprintf(stderr,
+ "\t%d -> %d [label=\"default\"]\n",
+ bb->id,
+ casebb->id);
+ } else {
+ fprintf(stderr,
+ "\t%d -> %d [label=\"case %lld\"]\n",
+ bb->id,
+ casebb->id,
+ np->left->u.i);
+ }
+ prbb(casebb);
+ }
}
static void
@@ -84,6 +110,7 @@ newbb(Node *np)
bb = &cfg.blocks[cfg.nr];
bb->entryp = np;
bb->exitp = NULL;
+ bb->swtch = NULL;
bb->true = bb->false = NULL;
bb->id = cfg.nr++;
bb->visited = 0;
@@ -95,9 +122,6 @@ newbb(Node *np)
static Node *
mkcfg(Node *np)
{
- if ((np->flags & (BBENTRY|BBEXIT)) == 0)
- return np;
-
if (np->flags & BBENTRY)
cfg.cur = np->bb;
@@ -116,6 +140,12 @@ mkcfg(Node *np)
case ORET:
cfg.cur->true = laststmt->bb;
break;
+ case OBSWITCH:
+ cfg.cur->swtch = np->u.swtch;
+ break;
+ case OESWITCH:
+ cfg.cur->true = NULL;
+ break;
case OBRANCH:
cfg.cur->false = np->next->bb;
case OJMP:
@@ -152,6 +182,9 @@ newentry(Node *np)
static Node *
markbb(Node *np)
{
+ Swtch *swt;
+ Node *p;
+
switch (np->op) {
case OBFUN:
newentry(np);
@@ -160,6 +193,14 @@ markbb(Node *np)
newentry(laststmt);
newentry(np->next);
break;
+ case OBSWITCH:
+ swt = np->u.swtch;
+ for (p = swt->cases; p->op != OESWITCH; p = p->next)
+ newentry(p->u.sym->u.stmt);
+ break;
+ case OESWITCH:
+ np->flags |= BBEXIT;
+ break;
case OBRANCH:
case OJMP:
newentry(np->u.sym->u.stmt);
@@ -172,11 +213,21 @@ markbb(Node *np)
static void
visit(Block *bb)
{
+ Node *np;
+ Swtch *swt;
+
if (!bb || bb->visited)
return;
bb->visited = 1;
visit(bb->true);
visit(bb->false);
+
+ swt = bb->swtch;
+ if (!swt)
+ return;
+
+ for (np = swt->cases; np->op != OESWITCH; np = np->next)
+ visit(np->u.sym->u.stmt->bb);
}
static void
diff --git a/src/cmd/scc-cc/cc2/parser.c b/src/cmd/scc-cc/cc2/parser.c
@@ -385,14 +385,18 @@ bswitch(char *token, union tokenop u)
static void
eswitch(char *token, union tokenop u)
{
+ Node *first;
Swtch *cur;
if (swp == swtbl)
error(EWTACKU);
jump(token, u);
waft(pop());
+
cur = --swp;
- cur->first->u.swtch = newswitch(cur);
+ first = cur->first;
+ cur->cases = first->next;
+ first->u.swtch = newswitch(cur);
}
static void
diff --git a/src/cmd/scc-cc/cc2/swtch.c b/src/cmd/scc-cc/cc2/swtch.c
@@ -66,7 +66,6 @@ swtch_dir(Node *np, int n, TINT min, TINT max)
p->type = ptrtype;
p->op = OLABEL;
}
- np->next = p->next;
for (ip = its; ip < &its[n]; ++ip) {
if (*ip == NULL)