mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 15:22:04 +00:00
[qfcc] Implement flow analysis for Ruamoko calls
Thanks to the use/def/kill lists attached to statements for pseudo-ops, it turned out to be a lot easier to implement flow analysis (and thus dags processing) than I expected. I suspect I should go back and make the old call code use them too, and probably several other places, as that will greatly simplify the edge setting.
This commit is contained in:
parent
c53127707b
commit
616a52efb5
4 changed files with 35 additions and 7 deletions
|
@ -113,9 +113,9 @@ typedef struct statement_s {
|
||||||
operand_t *opc;
|
operand_t *opc;
|
||||||
struct expr_s *expr; ///< source expression for this statement
|
struct expr_s *expr; ///< source expression for this statement
|
||||||
int number; ///< number of this statement in function
|
int number; ///< number of this statement in function
|
||||||
operand_t *use; ///< list of pseudo operands used
|
operand_t *use; ///< list of auxiliary operands used
|
||||||
operand_t *def; ///< list of pseudo operands defined
|
operand_t *def; ///< list of auxiliary operands defined
|
||||||
operand_t *kill; ///< list of pseudo operands killed
|
operand_t *kill; ///< list of auxiliary operands killed
|
||||||
} statement_t;
|
} statement_t;
|
||||||
|
|
||||||
typedef struct sblock_s {
|
typedef struct sblock_s {
|
||||||
|
|
|
@ -406,7 +406,7 @@ dag_find_node (def_t *def, void *_daglabel)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dagnode_set_edges (dag_t *dag, dagnode_t *n)
|
dagnode_set_edges (dag_t *dag, dagnode_t *n, statement_t *s)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -447,13 +447,21 @@ dagnode_set_edges (dag_t *dag, dagnode_t *n)
|
||||||
set_add (n->edges, child->number);
|
set_add (n->edges, child->number);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (operand_t *use = s->use; use; use = use->next) {
|
||||||
|
if (use->op_type == op_pseudo) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
daglabel_t *label = operand_label (dag, use);
|
||||||
|
label->live = 1;
|
||||||
|
set_add (n->edges, label->dagnode->number);
|
||||||
|
}
|
||||||
if (n->type == st_func) {
|
if (n->type == st_func) {
|
||||||
const char *num_params = 0;
|
const char *num_params = 0;
|
||||||
int first_param = 0;
|
int first_param = 0;
|
||||||
flowvar_t **flowvars = dag->flownode->graph->func->vars;
|
flowvar_t **flowvars = dag->flownode->graph->func->vars;
|
||||||
|
|
||||||
if (!strcmp (n->label->opcode, "call")) {
|
if (!strcmp (n->label->opcode, "call")) {
|
||||||
internal_error (0, "not implemented");
|
// nothing to do
|
||||||
} else if (!strncmp (n->label->opcode, "rcall", 5)) {
|
} else if (!strncmp (n->label->opcode, "rcall", 5)) {
|
||||||
num_params = n->label->opcode + 6;
|
num_params = n->label->opcode + 6;
|
||||||
first_param = 2;
|
first_param = 2;
|
||||||
|
@ -864,7 +872,7 @@ dag_create (flownode_t *flownode)
|
||||||
n->type = s->type;
|
n->type = s->type;
|
||||||
n->label = op;
|
n->label = op;
|
||||||
dagnode_add_children (dag, n, operands, children);
|
dagnode_add_children (dag, n, operands, children);
|
||||||
dagnode_set_edges (dag, n);
|
dagnode_set_edges (dag, n, s);
|
||||||
dagnode_set_reachable (dag, n);
|
dagnode_set_reachable (dag, n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1278,7 +1278,12 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (strcmp (s->opcode, "call") == 0) {
|
if (strcmp (s->opcode, "call") == 0) {
|
||||||
internal_error (s->expr, "not implemented");
|
// call uses opc to specify the destination of the return value
|
||||||
|
// parameter usage is taken care of by the statement's use
|
||||||
|
// list
|
||||||
|
flow_add_op_var (def, s->opc, 0);
|
||||||
|
// don't want old argument processing
|
||||||
|
calln = -1;
|
||||||
} else if (strncmp (s->opcode, "call", 4) == 0) {
|
} else if (strncmp (s->opcode, "call", 4) == 0) {
|
||||||
start = 0;
|
start = 0;
|
||||||
calln = s->opcode[5] - '0';
|
calln = s->opcode[5] - '0';
|
||||||
|
|
|
@ -1091,6 +1091,8 @@ expr_call (sblock_t *sblock, expr_t *call, operand_t **op)
|
||||||
defspace_t *arg_space = current_func->arguments;
|
defspace_t *arg_space = current_func->arguments;
|
||||||
expr_t *func = call->e.branch.target;
|
expr_t *func = call->e.branch.target;
|
||||||
expr_t *args = call->e.branch.args;
|
expr_t *args = call->e.branch.args;
|
||||||
|
operand_t *use = 0;
|
||||||
|
operand_t *kill = 0;
|
||||||
|
|
||||||
defspace_reset (arg_space);
|
defspace_reset (arg_space);
|
||||||
|
|
||||||
|
@ -1112,6 +1114,17 @@ expr_call (sblock_t *sblock, expr_t *call, operand_t **op)
|
||||||
expr_t *assign = assign_expr (new_def_expr (def), a);
|
expr_t *assign = assign_expr (new_def_expr (def), a);
|
||||||
expr_file_line (assign, call);
|
expr_file_line (assign, call);
|
||||||
sblock = statement_slist (sblock, assign);
|
sblock = statement_slist (sblock, assign);
|
||||||
|
|
||||||
|
// The call both uses and kills the arguments: use is obvious, but kill
|
||||||
|
// is because the callee has direct access to them and might modify
|
||||||
|
// them
|
||||||
|
// need two ops for the one def because there's two lists
|
||||||
|
operand_t *u = def_operand (def, arg_type, call);
|
||||||
|
operand_t *k = def_operand (def, arg_type, call);
|
||||||
|
u->next = use;
|
||||||
|
use = u;
|
||||||
|
k->next = kill;
|
||||||
|
kill = k;
|
||||||
}
|
}
|
||||||
statement_t *s = new_statement (st_func, "call", call);
|
statement_t *s = new_statement (st_func, "call", call);
|
||||||
sblock = statement_subexpr (sblock, func, &s->opa);
|
sblock = statement_subexpr (sblock, func, &s->opa);
|
||||||
|
@ -1123,6 +1136,8 @@ expr_call (sblock_t *sblock, expr_t *call, operand_t **op)
|
||||||
}
|
}
|
||||||
s->opc = *op;
|
s->opc = *op;
|
||||||
}
|
}
|
||||||
|
s->use = use;
|
||||||
|
s->kill = kill;
|
||||||
sblock_add_statement (sblock, s);
|
sblock_add_statement (sblock, s);
|
||||||
sblock->next = new_sblock ();
|
sblock->next = new_sblock ();
|
||||||
return sblock->next;
|
return sblock->next;
|
||||||
|
|
Loading…
Reference in a new issue