From acde6ca0a049329cd76b51609162376296a06261 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 3 Nov 2012 18:59:15 +0900 Subject: [PATCH] Handle jumpb statements in dot_sblock and flow graphs. --- tools/qfcc/include/flow.h | 2 ++ tools/qfcc/source/dot_sblock.c | 13 +++++++--- tools/qfcc/source/flow.c | 46 ++++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 4 deletions(-) diff --git a/tools/qfcc/include/flow.h b/tools/qfcc/include/flow.h index 1086bdae3..9076f711f 100644 --- a/tools/qfcc/include/flow.h +++ b/tools/qfcc/include/flow.h @@ -76,8 +76,10 @@ typedef struct flowgraph_s { int flow_is_cond (struct statement_s *s); int flow_is_goto (struct statement_s *s); +int flow_is_jumpb (struct statement_s *s); int flow_is_return (struct statement_s *s); struct sblock_s *flow_get_target (struct statement_s *s); +struct sblock_s **flow_get_targetlist (struct statement_s *s); void flow_build_vars (struct function_s *func); flowgraph_t *flow_build_graph (struct sblock_s *func); void flow_del_graph (flowgraph_t *graph); diff --git a/tools/qfcc/source/dot_sblock.c b/tools/qfcc/source/dot_sblock.c index 87f92468d..22e1c8e60 100644 --- a/tools/qfcc/source/dot_sblock.c +++ b/tools/qfcc/source/dot_sblock.c @@ -66,7 +66,8 @@ static void flow_sblock (dstring_t *dstr, sblock_t *sblock, int blockno) { statement_t *s; - sblock_t *target; + sblock_t **target; + sblock_t **target_list; ex_label_t *l; if (sblock->dag) { @@ -94,11 +95,15 @@ flow_sblock (dstring_t *dstr, sblock_t *sblock, int blockno) dasprintf (dstr, " \n"); dasprintf (dstr, " >];\n"); if (sblock->next && !flow_is_goto ((statement_t *) sblock->tail) + && !flow_is_jumpb ((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); + if ((target_list = flow_get_targetlist ((statement_t *) sblock->tail))) { + for (target = target_list; *target; target++) + dasprintf (dstr, " sb_%p:e -> sb_%p:s [label=\"%s\"];\n", sblock, + *target, ((statement_t *) sblock->tail)->opcode); + free (target_list); + } dasprintf (dstr, "\n"); } diff --git a/tools/qfcc/source/flow.c b/tools/qfcc/source/flow.c index 344ce5490..3e3ea4696 100644 --- a/tools/qfcc/source/flow.c +++ b/tools/qfcc/source/flow.c @@ -42,12 +42,14 @@ #include "QF/dstring.h" #include "dags.h" +#include "def.h" #include "flow.h" #include "function.h" #include "qfcc.h" #include "set.h" #include "statements.h" #include "symtab.h" +#include "type.h" static flowloop_t *free_loops; static flownode_t *free_nodes; @@ -229,6 +231,14 @@ flow_is_goto (statement_t *s) return !strcmp (s->opcode, ""); } +int +flow_is_jumpb (statement_t *s) +{ + if (!s) + return 0; + return !strcmp (s->opcode, ""); +} + int flow_is_return (statement_t *s) { @@ -247,6 +257,36 @@ flow_get_target (statement_t *s) return 0; } +sblock_t ** +flow_get_targetlist (statement_t *s) +{ + sblock_t **target_list; + int count, i; + def_t *table = 0; + expr_t *e; + + if (flow_is_cond (s)) { + count = 1; + } else if (flow_is_goto (s)) { + count = 1; + } else if (flow_is_jumpb (s)) { + table = s->opa->o.alias->o.symbol->s.def; //FIXME check!!! + count = table->type->t.array.size; + } + target_list = malloc ((count + 1) * sizeof (sblock_t *)); + target_list[count] = 0; + if (flow_is_cond (s)) { + target_list[0] = flow_get_target (s); + } else if (flow_is_goto (s)) { + target_list[0] = flow_get_target (s); + } else if (flow_is_jumpb (s)) { + e = table->initializer->e.block.head; //FIXME check!!! + for (i = 0; i < count; e = e->next, i++) + target_list[i] = e->e.labelref.label->dest; + } + return target_list; +} + static void flow_find_predecessors (flowgraph_t *graph) { @@ -413,6 +453,7 @@ flow_build_graph (sblock_t *sblock) flowgraph_t *graph; flownode_t *node; sblock_t *sb; + sblock_t **target_list, **target; statement_t *st; set_iter_t *succ; int i, j; @@ -445,6 +486,11 @@ flow_build_graph (sblock_t *sblock) if (flow_is_goto (st)) { // sb's next is never followed. set_add (node->successors, flow_get_target (st)->number); + } else if (flow_is_jumpb (st)) { + target_list = flow_get_targetlist (st); + for (target = target_list; *target; target++) + set_add (node->successors, (*target)->number); + free (target_list); } else if (flow_is_cond (st)) { // branch: either sb's next or the conditional statment's // target will be followed.