Add flow analysis to determin the type of .return.

It doesn't quite work yet, but...

It has proven necessary to know what type .return has at any point in the
function. The segfault in ctf is caused by the return statement added to
the end of the void function messing with the expr pointer stored in the
daglabel for .return. While this is actually by design (though the
statement really should have a valid expr pointer rather than), it actually
highlights a bigger problem: there's no stable knowledge of the current
type of .return. This is not a problem in expression statements as the
dagnodes for expression statements store the desired types of all operands.
However, when assigning from .return to attached variables in a leaf node,
the type of .return is not stored anywhere but the expression last
accessing .return.
This commit is contained in:
Bill Currie 2012-11-30 17:04:18 +09:00
parent 388247791d
commit 554b2e4710
5 changed files with 96 additions and 0 deletions

View file

@ -82,6 +82,10 @@ typedef struct flownode_s {
struct set_s *in;
struct set_s *out;
} init_vars;
struct {
etype_t in;
etype_t out; ///< if different from in, then block defines
} return_type; ///< type of .return for this node
struct sblock_s *sblock; ///< original statement block
struct dag_s *dag; ///< dag for this node
} flownode_t;
@ -112,6 +116,7 @@ struct sblock_s *flow_generate (flowgraph_t *graph);
void dump_dot_flow (void *g, const char *filename);
void dump_dot_flow_dags (void *g, const char *filename);
void dump_dot_flow_live (void *g, const char *filename);
void dump_dot_flow_return (void *g, const char *filename);
//@}

View file

@ -115,6 +115,7 @@ statement_t *new_statement (st_type_t type, const char *opcode,
int statement_is_cond (statement_t *s);
int statement_is_goto (statement_t *s);
int statement_is_jumpb (statement_t *s);
int statement_is_call (statement_t *s);
int statement_is_return (statement_t *s);
sblock_t *statement_get_target (statement_t *s);
sblock_t **statement_get_targetlist (statement_t *s);

View file

@ -200,10 +200,23 @@ print_flow_node_live (dstring_t *dstr, flowgraph_t *graph, flownode_t *node,
}
}
static void
print_flow_node_return (dstring_t *dstr, flowgraph_t *graph, flownode_t *node,
int level)
{
int indent = level * 2 + 2;
dasprintf (dstr, "%*s\"fn_%p\" [label=\"%d (%d)\\n%s\\n%s\"];\n",
indent, "", node, node->id, node->dfn,
pr_type_name[node->return_type.in],
pr_type_name[node->return_type.out]);
}
static flow_dot_t flow_dot_methods[] = {
{"", print_flow_node, print_flow_edge},
{"dag", print_flow_node_dag, print_flow_edge_dag},
{"live", print_flow_node_live, print_flow_edge},
{"return", print_flow_node_return, print_flow_edge},
};
static void
@ -254,3 +267,9 @@ dump_dot_flow_live (void *g, const char *filename)
{
print_flowgraph (&flow_dot_methods[2], (flowgraph_t *) g, filename);
}
void
dump_dot_flow_return (void *g, const char *filename)
{
print_flowgraph (&flow_dot_methods[3], (flowgraph_t *) g, filename);
}

View file

@ -558,6 +558,64 @@ flow_uninitialized (flowgraph_t *graph)
set_delete (predecessors);
}
static etype_t
get_function_type (operand_t *op)
{
type_t *type = &type_void;
//FIXME fuction type casts?
while (op->op_type == op_alias)
op = op->o.alias;
if (op->op_type == op_symbol) {
type = op->o.symbol->type;
if (type->type != ev_func)
internal_error (0, "not a function symbol");
type = type->t.func.type;
} else if (op->op_type == op_value) {
if (op->o.value->type != ev_func)
internal_error (0, "not a function value");
type = op->o.value->v.func_val.type;
}
// fixme temps?
return low_level_type (type);
}
static void
flow_set_return_type (flownode_t *node, etype_t type)
{
statement_t *st = (statement_t *) node->sblock->tail;
node->return_type.in = type;
node->return_type.out = node->return_type.in;
if (node->sblock->statements
&& statement_is_call (st))
node->return_type.out = get_function_type (st->opa);
}
static void
flow_return_type (flowgraph_t *graph)
{
etype_t return_type;
flownode_t *node;
set_iter_t *pred_iter;
flownode_t *pred;
int i;
node = graph->nodes[0];
flow_set_return_type (node, ev_void);
for (i = 1; i < graph->num_nodes; i++) {
node = graph->nodes[graph->dfo[i]];
for (pred_iter = set_first (node->predecessors); pred_iter;
pred_iter = set_next (pred_iter)) {
pred = graph->nodes[pred_iter->member];
if (return_type == ev_type_count)
return_type = pred->return_type.out;
if (return_type != pred->return_type.out)
return_type = ev_void;
}
flow_set_return_type (node, return_type);
}
}
static void
flow_build_dags (flowgraph_t *graph)
{
@ -599,6 +657,7 @@ flow_data_flow (flowgraph_t *graph)
}
flow_live_vars (graph);
flow_uninitialized (graph);
flow_return_type (graph);
flow_build_dags (graph);
if (options.block_dot.flow)
dump_dot ("flow", graph, dump_dot_flow);

View file

@ -392,6 +392,18 @@ statement_is_jumpb (statement_t *s)
return !strcmp (s->opcode, "<JUMPB>");
}
int
statement_is_call (statement_t *s)
{
if (!s)
return 0;
if (!strncmp (s->opcode, "<CALL", 5))
return 1;
if (!strncmp (s->opcode, "<RCALL", 6))
return 2;
return 0;
}
int
statement_is_return (statement_t *s)
{