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 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_graph (struct function_s *func);

View file

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

View file

@ -71,6 +71,8 @@ typedef struct statement_s {
typedef struct sblock_s {
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 ex_label_s *labels;
struct dagnode_s *dag;

View file

@ -44,6 +44,7 @@
#include <QF/va.h>
#include "dags.h"
#include "flow.h"
#include "expr.h"
#include "statements.h"
#include "strpool.h"
@ -61,34 +62,6 @@ flow_statement (dstring_t *dstr, statement_t *s)
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
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, " </tr>\n");
dasprintf (dstr, " </table>>];\n");
if (sblock->next && !is_goto ((statement_t *) sblock->tail)
&& !is_return ((statement_t *) sblock->tail))
dasprintf (dstr, " sb_%p:e -> sb_%p:s;\n", sblock, sblock->next);
if ((target = get_target ((statement_t *) sblock->tail)))
dasprintf (dstr, " sb_%p:e -> sb_%p:s [label=\"%s\"];\n", sblock,
target, ((statement_t *) sblock->tail)->opcode);
if (!sblock->succ) {
if (sblock->next && !flow_is_goto ((statement_t *) sblock->tail)
&& !flow_is_return ((statement_t *) sblock->tail))
dasprintf (dstr, " sb_%p:e -> sb_%p:s;\n", sblock, sblock->next);
if ((target = flow_get_target ((statement_t *) sblock->tail)))
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");
}

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
flow_build_graph (function_t *func)
{
sblock_t *sblock;
statement_t *st;
int num_blocks = 0;
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)
func->graph[sblock->number] = sblock;
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;
lineno_base = f->def->line;
f->sblock = make_statements (e);
flow_build_graph (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);
emit_statements (f->sblock);
}

View file

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

View file

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