Calculate a node's successors and predecessors.

The dot graphs are a little odd (arrow heads on the wrong end of the
predecessor edges), but things seem to be correct.
This commit is contained in:
Bill Currie 2012-10-30 19:25:35 +09:00
parent 739ebc522c
commit 7853bf1859
8 changed files with 115 additions and 40 deletions

View file

@ -36,7 +36,13 @@
//@{ //@{
struct function_s; struct function_s;
struct sblock_s;
struct statement_s;
int flow_is_cond (struct statement_s *s);
int flow_is_goto (struct statement_s *s);
int flow_is_return (struct statement_s *s);
struct sblock_s *flow_get_target (struct statement_s *s);
void flow_build_vars (struct function_s *func); void flow_build_vars (struct function_s *func);
void flow_build_graph (struct function_s *func); void flow_build_graph (struct function_s *func);

View file

@ -73,6 +73,7 @@ typedef struct {
qboolean dead; qboolean dead;
qboolean final; qboolean final;
qboolean dags; qboolean dags;
qboolean flow;
} blockdot_options_t; } blockdot_options_t;
typedef struct { typedef struct {

View file

@ -71,6 +71,8 @@ typedef struct statement_s {
typedef struct sblock_s { typedef struct sblock_s {
struct sblock_s *next; struct sblock_s *next;
struct sblock_s **pred; ///< predecessors of this node
struct sblock_s **succ; ///< successors of this node
struct reloc_s *relocs; struct reloc_s *relocs;
struct ex_label_s *labels; struct ex_label_s *labels;
struct dagnode_s *dag; struct dagnode_s *dag;

View file

@ -44,6 +44,7 @@
#include <QF/va.h> #include <QF/va.h>
#include "dags.h" #include "dags.h"
#include "flow.h"
#include "expr.h" #include "expr.h"
#include "statements.h" #include "statements.h"
#include "strpool.h" #include "strpool.h"
@ -61,34 +62,6 @@ flow_statement (dstring_t *dstr, statement_t *s)
dasprintf (dstr, "</tr>\n"); dasprintf (dstr, "</tr>\n");
} }
static int
is_goto (statement_t *s)
{
if (!s)
return 0;
return !strcmp (s->opcode, "<GOTO>");
}
static int
is_return (statement_t *s)
{
if (!s)
return 0;
return !strncmp (s->opcode, "<RETURN", 7);
}
static sblock_t *
get_target (statement_t *s)
{
if (!s)
return 0;
if (!strncmp (s->opcode, "<IF", 3))
return s->opb->o.label->dest;
if (!strcmp (s->opcode, "<GOTO>"))
return s->opa->o.label->dest;
return 0;
}
static void static void
flow_sblock (dstring_t *dstr, sblock_t *sblock, int blockno) flow_sblock (dstring_t *dstr, sblock_t *sblock, int blockno)
{ {
@ -120,12 +93,22 @@ flow_sblock (dstring_t *dstr, sblock_t *sblock, int blockno)
dasprintf (dstr, " <td></td>\n"); dasprintf (dstr, " <td></td>\n");
dasprintf (dstr, " </tr>\n"); dasprintf (dstr, " </tr>\n");
dasprintf (dstr, " </table>>];\n"); dasprintf (dstr, " </table>>];\n");
if (sblock->next && !is_goto ((statement_t *) sblock->tail) if (!sblock->succ) {
&& !is_return ((statement_t *) sblock->tail)) if (sblock->next && !flow_is_goto ((statement_t *) sblock->tail)
dasprintf (dstr, " sb_%p:e -> sb_%p:s;\n", sblock, sblock->next); && !flow_is_return ((statement_t *) sblock->tail))
if ((target = get_target ((statement_t *) sblock->tail))) dasprintf (dstr, " sb_%p:e -> sb_%p:s;\n", sblock, sblock->next);
dasprintf (dstr, " sb_%p:e -> sb_%p:s [label=\"%s\"];\n", sblock, if ((target = flow_get_target ((statement_t *) sblock->tail)))
target, ((statement_t *) sblock->tail)->opcode); dasprintf (dstr, " sb_%p:e -> sb_%p:s [label=\"%s\"];\n", sblock,
target, ((statement_t *) sblock->tail)->opcode);
} else {
sblock_t **sb;
for (sb = sblock->succ; *sb; sb++)
dasprintf (dstr, " sb_%p:e -> sb_%p:s [label=\"s\"];\n", sblock,
*sb);
for (sb = sblock->pred; sb && *sb; sb++)
dasprintf (dstr, " sb_%p:e -> sb_%p:s [label=\"p\"];\n", *sb,
sblock);
}
dasprintf (dstr, "\n"); dasprintf (dstr, "\n");
} }

View file

@ -136,10 +136,45 @@ flow_build_vars (function_t *func)
} }
} }
int
flow_is_cond (statement_t *s)
{
if (!s)
return 0;
return !strncmp (s->opcode, "<IF", 3);
}
int
flow_is_goto (statement_t *s)
{
if (!s)
return 0;
return !strcmp (s->opcode, "<GOTO>");
}
int
flow_is_return (statement_t *s)
{
if (!s)
return 0;
return !strncmp (s->opcode, "<RETURN", 7);
}
sblock_t *
flow_get_target (statement_t *s)
{
if (flow_is_cond (s))
return s->opb->o.label->dest;
if (flow_is_goto (s))
return s->opa->o.label->dest;
return 0;
}
void void
flow_build_graph (function_t *func) flow_build_graph (function_t *func)
{ {
sblock_t *sblock; sblock_t *sblock;
statement_t *st;
int num_blocks = 0; int num_blocks = 0;
for (sblock = func->sblock; sblock; sblock = sblock->next) for (sblock = func->sblock; sblock; sblock = sblock->next)
@ -148,4 +183,46 @@ flow_build_graph (function_t *func)
for (sblock = func->sblock; sblock; sblock = sblock->next) for (sblock = func->sblock; sblock; sblock = sblock->next)
func->graph[sblock->number] = sblock; func->graph[sblock->number] = sblock;
func->num_nodes = num_blocks; func->num_nodes = num_blocks;
for (sblock = func->sblock; sblock; sblock = sblock->next) {
if (sblock->statements) {
st = (statement_t *) sblock->tail;
//FIXME jump/jumpb
if (flow_is_goto (st)) {
sblock->succ = calloc (2, sizeof (sblock_t *));
sblock->succ[0] = flow_get_target (st);
} else if (flow_is_cond (st)) {
sblock->succ = calloc (3, sizeof (sblock_t *));
sblock->succ[0] = sblock->next;
sblock->succ[1] = flow_get_target (st);
} else if (flow_is_return (st)) {
sblock->succ = calloc (1, sizeof (sblock_t *));
} else {
sblock->succ = calloc (2, sizeof (sblock_t *));
sblock->succ[0] = sblock->next;
}
}
}
for (sblock = func->sblock; sblock; sblock = sblock->next) {
int num_pred;
sblock_t *sb, **ss;
for (num_pred = 0, sb = func->sblock; sb; sb = sb->next) {
for (ss = sb->succ; *ss; ss++) {
if (*ss == sblock) {
num_pred++;
break;
}
}
}
sblock->pred = calloc (num_pred + 1, sizeof (sblock_t *));
for (num_pred = 0, sb = func->sblock; sb; sb = sb->next) {
for (ss = sb->succ; *ss; ss++) {
if (*ss == sblock) {
sblock->pred[num_pred++] = sb;
break;
}
}
}
}
} }

View file

@ -643,8 +643,11 @@ emit_function (function_t *f, expr_t *e)
f->code = pr.code->size; f->code = pr.code->size;
lineno_base = f->def->line; lineno_base = f->def->line;
f->sblock = make_statements (e); f->sblock = make_statements (e);
flow_build_graph (f);
flow_build_vars (f); flow_build_vars (f);
flow_build_graph (f);
if (options.block_dot.flow)
print_flow (f->sblock, nva ("%s.%s.%s.dot", GETSTR (pr.source_file),
f->name, "flow"));
printf ("%s %d %d\n", f->name, f->num_nodes, f->num_vars); printf ("%s %d %d\n", f->name, f->num_nodes, f->num_vars);
emit_statements (f->sblock); emit_statements (f->sblock);
} }

View file

@ -391,6 +391,8 @@ DecodeArgs (int argc, char **argv)
options.block_dot.final = flag; options.block_dot.final = flag;
} else if (!(strcasecmp (temp, "dags"))) { } else if (!(strcasecmp (temp, "dags"))) {
options.block_dot.dags = flag; options.block_dot.dags = flag;
} else if (!(strcasecmp (temp, "flow"))) {
options.block_dot.flow = flag;
} }
temp = strtok (NULL, ","); temp = strtok (NULL, ",");
} }
@ -401,6 +403,7 @@ DecodeArgs (int argc, char **argv)
options.block_dot.dead = true; options.block_dot.dead = true;
options.block_dot.final = true; options.block_dot.final = true;
options.block_dot.dags = true; options.block_dot.dags = true;
options.block_dot.flow = true;
} }
break; break;
case 'c': case 'c':

View file

@ -1397,7 +1397,7 @@ sblock_t *
make_statements (expr_t *e) make_statements (expr_t *e)
{ {
sblock_t *sblock = new_sblock (); sblock_t *sblock = new_sblock ();
sblock_t *s; //sblock_t *s;
// print_expr (e); // print_expr (e);
statement_slist (sblock, e); statement_slist (sblock, e);
if (options.block_dot.initial) if (options.block_dot.initial)
@ -1414,9 +1414,9 @@ make_statements (expr_t *e)
if (options.block_dot.final) if (options.block_dot.final)
dump_flow (sblock, "final"); dump_flow (sblock, "final");
for (s = sblock; s; s = s->next) //for (s = sblock; s; s = s->next)
s->dag = make_dag (s); // s->dag = make_dag (s);
if (options.block_dot.dags) //if (options.block_dot.dags)
dump_flow (sblock, "dags"); // dump_flow (sblock, "dags");
return sblock; return sblock;
} }