mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-13 00:24:12 +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 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);
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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':
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue