mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 15:22:04 +00:00
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:
parent
739ebc522c
commit
7853bf1859
8 changed files with 115 additions and 40 deletions
|
@ -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);
|
||||
|
||||
|
|
|
@ -73,6 +73,7 @@ typedef struct {
|
|||
qboolean dead;
|
||||
qboolean final;
|
||||
qboolean dags;
|
||||
qboolean flow;
|
||||
} blockdot_options_t;
|
||||
|
||||
typedef struct {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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':
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue