Move flowvar/deflabel from symbol_t to def_t.

With the need to handle aliasing in the optimizer, it has become apparent
that having the flow data attached to symbols is not nearly as useful as
having it attached to defs (which are views of the actual variables).

This also involves a bit of a cleanup of operand types: op_pointer and
op_alias are gone (this seems to greatly simplify the optimizer)

There is a bit of a problem with enums in switch statements, but this might
actually be a sign that something is not quite right in the switch code
(other than enums not being recognized as ints for jump table
optimization).
This commit is contained in:
Bill Currie 2012-12-05 19:47:22 +09:00
parent 3bb8b1b9d2
commit 3f3b501c58
7 changed files with 149 additions and 211 deletions

View file

@ -65,6 +65,8 @@ typedef struct def_s {
struct def_s *alias; ///< real def which this def aliases
struct reloc_s *relocs; ///< for relocations
struct expr_s *initializer;///< initialer expression
struct daglabel_s *daglabel;///< daglabel for this def
struct flowvar_s *flowvar; ///< flowvar for this def
unsigned offset_reloc:1; ///< use *_def_ofs relocs
unsigned initialized:1; ///< the def has been initialized

View file

@ -33,12 +33,10 @@
#include "QF/pr_comp.h"
typedef enum {
op_symbol,
op_def,
op_value,
op_label,
op_temp,
op_pointer,
op_alias,
} op_type_e;
typedef struct {
@ -46,20 +44,20 @@ typedef struct {
struct type_s *type;
struct flowvar_s *flowvar;
struct daglabel_s *daglabel;
struct operand_s *alias;
int users;
} tempop_t;
typedef struct operand_s {
struct operand_s *next;
op_type_e op_type;
etype_t type; ///< possibly override symbol's type
etype_t type; ///< possibly override def's type
int size; ///< for structures
union {
struct symbol_s *symbol;
struct def_s *def;
struct ex_value_s *value;
struct ex_label_s *label;
tempop_t tempop;
struct operand_s *alias;
} o;
} operand_t;
@ -108,7 +106,8 @@ typedef struct sblock_s {
struct expr_s;
struct type_s;
operand_t *alias_operand (operand_t *op, etype_t type);
const char *optype_str (op_type_e type);
operand_t *temp_operand (struct type_s *type);
sblock_t *new_sblock (void);
statement_t *new_statement (st_type_t type, const char *opcode,

View file

@ -64,8 +64,6 @@ typedef struct symbol_s {
sy_type_e sy_type; ///< symbol type
struct type_s *type; ///< type of object to which symbol refers
struct param_s *params; ///< the parameters if a function
struct flowvar_s *flowvar;
struct daglabel_s *daglabel;///< dag label for this symbol
union {
int offset; ///< sy_var (in a struct/union)
struct def_s *def; ///< sy_var

View file

@ -65,13 +65,11 @@ flush_daglabels (void)
operand_t *op;
if ((op = daglabel_chain->op)) {
while (op->op_type == op_alias)
op = op->o.alias;
if (op->op_type == op_symbol)
op->o.symbol->daglabel = 0;
if (op->op_type == op_def)
op->o.def->daglabel = 0;
else if (op->op_type == op_temp)
op->o.tempop.daglabel = 0;
else if (op->op_type == op_value || op->op_type == op_pointer)
else if (op->op_type == op_value)
op->o.value->daglabel = 0;
else if (op->op_type == op_label)
op->o.label->daglabel = 0;
@ -146,14 +144,12 @@ opcode_label (dag_t *dag, const char *opcode, expr_t *expr)
static daglabel_t *
operand_label (dag_t *dag, operand_t *op)
{
symbol_t *sym = 0;
def_t *def = 0;
ex_value_t *val = 0;
daglabel_t *label;
if (!op)
return 0;
while (op->op_type == op_alias)
op = op->o.alias;
if (op->op_type == op_temp) {
if (op->o.tempop.daglabel)
@ -161,14 +157,14 @@ operand_label (dag_t *dag, operand_t *op)
label = new_label (dag);
label->op = op;
op->o.tempop.daglabel = label;
} else if (op->op_type == op_symbol) {
sym = op->o.symbol;
if (sym->daglabel)
return sym->daglabel;
} else if (op->op_type == op_def) {
def = op->o.def;
if (def->daglabel)
return def->daglabel;
label = new_label (dag);
label->op = op;
sym->daglabel = label;
} else if (op->op_type == op_value || op->op_type == op_pointer) {
def->daglabel = label;
} else if (op->op_type == op_value) {
val = op->o.value;
if (val->daglabel)
return val->daglabel;
@ -207,23 +203,19 @@ leaf_node (dag_t *dag, operand_t *op, expr_t *expr)
static dagnode_t *
dag_node (operand_t *op)
{
symbol_t *sym;
def_t *def;
dagnode_t *node = 0;
if (!op)
return 0;
while (op->op_type == op_alias)
op = op->o.alias;
if (op->op_type == op_symbol) {
sym = op->o.symbol;
//if (sym->sy_type == sy_const)
// return 0;
if (sym->daglabel)
node = sym->daglabel->dagnode;
if (op->op_type == op_def) {
def = op->o.def;
if (def->daglabel)
node = def->daglabel->dagnode;
} else if (op->op_type == op_temp) {
if (op->o.tempop.daglabel)
node = op->o.tempop.daglabel->dagnode;
} else if (op->op_type == op_value || op->op_type == op_pointer) {
} else if (op->op_type == op_value) {
if (op->o.value->daglabel)
node = op->o.value->daglabel->dagnode;
} else if (op->op_type == op_label) {
@ -337,19 +329,13 @@ dagnode_set_edges (dagnode_t *n)
static int
op_is_identifier (operand_t *op)
{
while (op->op_type == op_alias)
op = op->o.alias;
if (op->op_type == op_label)
return 0;
if (op->op_type == op_value)
return 0;
if (op->op_type == op_pointer)
return 1;
if (op->op_type == op_temp)
return 1;
if (op->op_type != op_symbol)
return 0;
if (op->o.symbol->sy_type != sy_var)
if (op->op_type != op_def)
return 0;
return 1;
}
@ -569,10 +555,11 @@ build_statement (const char *opcode, operand_t **operands, expr_t *expr)
for (i = 0; i < 3; i++) {
if ((op = operands[i])) {
while (op->op_type == op_alias)
op = op->o.alias;
if (op->op_type == op_temp)
if (op->op_type == op_temp) {
while (op->o.tempop.alias)
op = op->o.tempop.alias;
op->o.tempop.users++;
}
}
}
st->opa = operands[0];
@ -614,13 +601,6 @@ dag_calc_node_costs (dagnode_t *dagnode)
}
}
#endif
static operand_t *
fix_op_type (operand_t *op, etype_t type)
{
if (op && op->op_type != op_label && op->type != type)
op = alias_operand (op, type);
return op;
}
static operand_t *
generate_assignments (dag_t *dag, sblock_t *block, operand_t *src,
@ -631,15 +611,12 @@ generate_assignments (dag_t *dag, sblock_t *block, operand_t *src,
operand_t *operands[3] = {0, 0, 0};
daglabel_t *var;
operands[0] = fix_op_type (src, type);
operands[0] = src;
for ( ; var_iter; var_iter = set_next (var_iter)) {
var = dag->labels[var_iter->member];
operands[1] = fix_op_type (var->op, type);
if (!dst) {
operands[1] = var->op;
if (!dst)
dst = operands[1];
while (dst->op_type == op_alias)
dst = dst->o.alias;
}
st = build_statement ("=", operands, var->expr);
sblock_add_statement (block, st);
@ -653,9 +630,6 @@ make_operand (dag_t *dag, sblock_t *block, const dagnode_t *dagnode, int index)
operand_t *op;
op = dagnode->children[index]->value;
while (op->op_type == op_alias)
op = op->o.alias;
op = fix_op_type (op, dagnode->types[index]);
return op;
}
@ -676,9 +650,9 @@ dag_gencode (dag_t *dag, sblock_t *block, dagnode_t *dagnode)
dst = dagnode->label->op;
if ((var_iter = set_first (dagnode->identifiers))) {
type = dst->type;
if (dst->op_type == op_symbol
&& !strcmp (dst->o.symbol->name, ".return"))
type = dag->flownode->return_type.in;
//if (dst->op_type == op_def
// && !strcmp (dst->o.def->name, ".return"))
// type = dag->flownode->return_type.in;
dst = generate_assignments (dag, block, dst, var_iter, type);
}
break;
@ -692,7 +666,7 @@ dag_gencode (dag_t *dag, sblock_t *block, dagnode_t *dagnode)
} else {
daglabel_t *var = dag->labels[var_iter->member];
operands[2] = fix_op_type (var->op, type);
operands[2] = var->op;
var_iter = set_next (var_iter);
}
dst = operands[2];

View file

@ -79,28 +79,11 @@ get_value_def (ex_value_t *value, etype_t type)
static def_t *
get_operand_def (expr_t *expr, operand_t *op)
{
def_t *def;
if (!op)
return 0;
switch (op->op_type) {
case op_symbol:
switch (op->o.symbol->sy_type) {
case sy_var:
if (op->type != op->o.symbol->type->type)
return alias_def (op->o.symbol->s.def,
ev_types[op->type], 0);
return op->o.symbol->s.def;
case sy_func:
return op->o.symbol->s.func->def;
case sy_const:
return get_value_def (op->o.symbol->s.value, op->type);
case sy_type:
case sy_expr:
case sy_class:
internal_error (expr, "invalid operand type");
}
break;
case op_def:
return op->o.def;
case op_value:
return get_value_def (op->o.value, op->type);
case op_label:
@ -108,22 +91,11 @@ get_operand_def (expr_t *expr, operand_t *op)
zero_def.type = &type_short;
return &zero_def; //FIXME
case op_temp:
while (op->o.tempop.alias)
op = op->o.tempop.alias;
if (!op->o.tempop.def)
op->o.tempop.def = temp_def (op->type, op->size);
return op->o.tempop.def;
case op_pointer:
def = op->o.value->v.pointer.def;
if (op->o.value->v.pointer.val || op->type != def->type->type) {
def = alias_def (def, ev_types[op->type],
op->o.value->v.pointer.val);
}
return def;
case op_alias:
def = get_operand_def (expr, op->o.alias);
if (def->alias)
def = def->alias;
def = alias_def (def, ev_types[op->type], 0);
return def;
}
return 0;
}
@ -172,10 +144,10 @@ add_statement_op_ref (operand_t *op, dstatement_t *st, int field)
static void
use_tempop (operand_t *op, expr_t *expr)
{
while (op && op->op_type == op_alias)
op = op->o.alias;
if (!op || op->op_type != op_temp)
return;
while (op->o.tempop.alias)
op = op->o.tempop.alias;
if (--op->o.tempop.users == 0)
free_temp_def (op->o.tempop.def);
if (op->o.tempop.users <= -1)

View file

@ -64,15 +64,15 @@ static struct {
const char *name;
operand_t op;
} flow_params[] = {
{".return", {0, op_symbol}},
{".param_0", {0, op_symbol}},
{".param_1", {0, op_symbol}},
{".param_2", {0, op_symbol}},
{".param_3", {0, op_symbol}},
{".param_4", {0, op_symbol}},
{".param_5", {0, op_symbol}},
{".param_6", {0, op_symbol}},
{".param_7", {0, op_symbol}},
{".return", {0, op_def}},
{".param_0", {0, op_def}},
{".param_1", {0, op_def}},
{".param_2", {0, op_def}},
{".param_3", {0, op_def}},
{".param_4", {0, op_def}},
{".param_5", {0, op_def}},
{".param_6", {0, op_def}},
{".param_7", {0, op_def}},
};
static const int num_flow_params = sizeof(flow_params)/sizeof(flow_params[0]);
@ -156,36 +156,27 @@ flowvar_get_def (flowvar_t *var)
{
operand_t *op = var->op;
while (op->op_type == op_alias)
op = op->o.alias;
switch (op->op_type) {
case op_symbol:
return op->o.symbol->s.def;
case op_def:
return op->o.def;
case op_value:
case op_label:
return 0;
case op_temp:
return op->o.tempop.def;
case op_pointer:
return op->o.value->v.pointer.def;
case op_alias:
internal_error (0, "oops, blue pill");
}
internal_error (0, "oops, blue pill");
return 0;
}
static int
flowvar_is_global (flowvar_t *var)
{
symbol_t *sym;
def_t *def;
if (var->op->op_type != op_symbol)
if (var->op->op_type != op_def)
return 0;
sym = var->op->o.symbol;
if (sym->sy_type != sy_var)
return 0;
def = sym->s.def;
def = var->op->o.def;
if (def->local)
return 0;
return 1;
@ -194,15 +185,11 @@ flowvar_is_global (flowvar_t *var)
static int
flowvar_is_param (flowvar_t *var)
{
symbol_t *sym;
def_t *def;
if (var->op->op_type != op_symbol)
if (var->op->op_type != op_def)
return 0;
sym = var->op->o.symbol;
if (sym->sy_type != sy_var)
return 0;
def = sym->s.def;
def = var->op->o.def;
if (!def->local)
return 0;
if (!def->param)
@ -213,15 +200,11 @@ flowvar_is_param (flowvar_t *var)
static int
flowvar_is_initialized (flowvar_t *var)
{
symbol_t *sym;
def_t *def;
if (var->op->op_type != op_symbol)
if (var->op->op_type != op_def)
return 0;
sym = var->op->o.symbol;
if (sym->sy_type != sy_var)
return 0;
def = sym->s.def;
def = var->op->o.def;
return def->initialized;
}
@ -231,18 +214,15 @@ flow_get_var (operand_t *op)
if (!op)
return 0;
while (op->op_type == op_alias)
op = op->o.alias;
if (op->op_type == op_temp) {
if (!op->o.tempop.flowvar)
op->o.tempop.flowvar = new_flowvar ();
return op->o.tempop.flowvar;
}
if (op->op_type == op_symbol && op->o.symbol->sy_type == sy_var) {
if (!op->o.symbol->flowvar)
op->o.symbol->flowvar = new_flowvar ();
return op->o.symbol->flowvar;
if (op->op_type == op_def) {
if (!op->o.def->flowvar)
op->o.def->flowvar = new_flowvar ();
return op->o.def->flowvar;
}
//FIXME functions? (some are variable) values?
return 0;
@ -283,8 +263,6 @@ add_operand (function_t *func, operand_t *op)
if (!op)
return;
while (op->op_type == op_alias)
op = op->o.alias;
if (op->op_type == op_label)
return;
@ -319,7 +297,7 @@ flow_build_vars (function_t *func)
// first, count .return and .param_[0-7] as they are always needed
for (i = 0; i < num_flow_params; i++) {
flow_params[i].op.o.symbol = param_symbol (flow_params[i].name);
flow_params[i].op.o.def = param_symbol (flow_params[i].name)->s.def;
num_vars += count_operand (&flow_params[i].op);
}
// then run through the statements in the function looking for accessed
@ -561,10 +539,8 @@ 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 (op->op_type == op_def) {
type = op->o.def->type;
if (type->type != ev_func)
internal_error (0, "not a function symbol");
type = type->t.func.type;

View file

@ -55,16 +55,29 @@
#include "type.h"
#include "qc-parse.h"
static const char *op_type_names[] = {
"op_def",
"op_value",
"op_label",
"op_temp",
};
const char *
optype_str (op_type_e type)
{
if (type < 0 || type > op_temp)
return "<invalid op_type>";
return op_type_names[type];
}
const char *
operand_string (operand_t *op)
{
type_t *type;
if (!op)
return "";
switch (op->op_type) {
case op_symbol:
return op->o.symbol->name;
case op_def:
return op->o.def->name;
case op_value:
switch (op->o.value->type) {
case ev_string:
@ -108,20 +121,9 @@ operand_string (operand_t *op)
case op_label:
return op->o.label->name;
case op_temp:
while (op->o.tempop.alias)
op = op->o.tempop.alias;
return va ("<tmp %p:%d>", op, op->o.tempop.users);
case op_pointer:
type = op->o.value->v.pointer.type;
if (op->o.value->v.pointer.def)
return va ("(%s)[%d]<%s>",
type ? pr_type_name[type->type] : "???",
op->o.value->v.pointer.val,
op->o.value->v.pointer.def->name);
else
return va ("(%s)[%d]",
type ? pr_type_name[type->type] : "???",
op->o.value->v.pointer.val);
case op_alias:
return operand_string (op->o.alias);//FIXME better output
}
return ("??");
}
@ -130,9 +132,9 @@ static void
print_operand (operand_t *op)
{
switch (op->op_type) {
case op_symbol:
case op_def:
printf ("(%s) ", pr_type_name[op->type]);
printf ("%s", op->o.symbol->name);
printf ("%s", op->o.def->name);
break;
case op_value:
printf ("(%s) ", pr_type_name[op->type]);
@ -187,15 +189,6 @@ print_operand (operand_t *op)
if (op->o.tempop.def)
printf (" %s", op->o.tempop.def->name);
break;
case op_pointer:
printf ("ptr (%s)[%d]",
pr_type_name[op->o.value->v.pointer.type->type],
op->o.value->v.pointer.val);
break;
case op_alias:
printf ("alias %s ", pr_type_name[op->type]);
print_operand (op->o.alias);
break;
}
}
@ -259,14 +252,6 @@ new_operand (op_type_e op)
static void __attribute__((unused)) //FIXME
free_operand (operand_t *op)
{
if (op->next) {
//FIXME this should be an error, but due to the way operands are used,
//it can happen.
debug (0, "free_operand: double free");
return;
}
if (op->op_type == op_alias)
free_operand (op->o.alias);
FREE (operands, op);
}
@ -304,16 +289,6 @@ temp_operand (type_t *type)
return op;
}
operand_t *
alias_operand (operand_t *op, etype_t type)
{
operand_t *alias = new_operand (op_alias);
alias->type = type;
alias->size = pr_type_size[type];
alias->o.alias = op;
return alias;
}
static operand_t *
short_operand (short short_val)
{
@ -433,7 +408,7 @@ statement_get_targetlist (statement_t *s)
} else if (statement_is_goto (s)) {
count = 1;
} else if (statement_is_jumpb (s)) {
table = s->opa->o.alias->o.symbol->s.def; //FIXME check!!!
table = s->opa->o.def;
count = table->type->t.array.size;
}
target_list = malloc ((count + 1) * sizeof (sblock_t *));
@ -709,9 +684,11 @@ expr_deref (sblock_t *sblock, expr_t *deref, operand_t **op)
e = deref->e.expr.e1;
if (e->type == ex_uexpr && e->e.expr.op == '&'
&& e->e.expr.e1->type == ex_symbol) {
*op = new_operand (op_symbol);
if (e->e.expr.e1->e.symbol->sy_type != sy_var)
internal_error (e, "address of non-var");
*op = new_operand (op_def);
(*op)->type = low_level_type (type);
(*op)->o.symbol = e->e.expr.e1->e.symbol;
(*op)->o.def = e->e.expr.e1->e.symbol->s.def;
} else if (e->type == ex_expr && e->e.expr.op == '&') {
statement_t *s;
operand_t *ptr = 0;
@ -746,9 +723,10 @@ expr_deref (sblock_t *sblock, expr_t *deref, operand_t **op)
sblock_add_statement (sblock, s);
}
} else if (e->type == ex_value && e->e.value->type == ev_pointer) {
*op = new_operand (op_pointer);
(*op)->type = low_level_type (e->e.value->v.pointer.type);
(*op)->o.value = e->e.value;
ex_pointer_t *ptr = &e->e.value->v.pointer;
*op = new_operand (op_def);
(*op)->type = low_level_type (ptr->type);
(*op)->o.def = alias_def (ptr->def, ptr->type, ptr->val);
} else {
statement_t *s;
operand_t *ptr = 0;
@ -813,12 +791,33 @@ static sblock_t *
expr_alias (sblock_t *sblock, expr_t *e, operand_t **op)
{
operand_t *aop = 0;
def_t *def;
sblock = statement_subexpr (sblock, e->e.expr.e1, &aop);
while (aop->op_type == op_alias)
aop = aop->o.alias;
*op = new_operand (op_alias);
(*op)->type = low_level_type (e->e.expr.type);
(*op)->o.alias = aop;
if (aop->op_type == op_temp) {
while (aop->o.tempop.alias) {
aop = aop->o.tempop.alias;
if (aop->op_type != op_temp)
internal_error (e, "temp alias of non-temp var");
}
*op = new_operand (op_temp);
(*op)->type = low_level_type (e->e.expr.type);
(*op)->o.tempop.alias = aop;
} else if (aop->op_type == op_def) {
def = aop->o.def;
while (def->alias)
def = def->alias;
*op = new_operand (op_def);
(*op)->type = low_level_type (e->e.expr.type);
(*op)->o.def = alias_def (def, ev_types[(*op)->type], 0);
} else if (aop->op_type == op_value && aop->o.value->type == ev_pointer) {
ex_pointer_t *ptr = &aop->o.value->v.pointer;
*op = new_operand (op_def);
(*op)->type = low_level_type (ptr->type);
(*op)->o.def = alias_def (ptr->def, ptr->type, ptr->val);
} else {
internal_error (e, "invalid alias target: %s: %s",
optype_str (aop->op_type), operand_string (aop));
}
return sblock;
}
@ -901,9 +900,24 @@ expr_uexpr (sblock_t *sblock, expr_t *e, operand_t **op)
static sblock_t *
expr_symbol (sblock_t *sblock, expr_t *e, operand_t **op)
{
*op = new_operand (op_symbol);
(*op)->type = low_level_type (e->e.symbol->type);
(*op)->o.symbol = e->e.symbol;
symbol_t *sym = e->e.symbol;
if (sym->sy_type == sy_var) {
*op = new_operand (op_def);
(*op)->type = low_level_type (sym->type);
(*op)->o.def = sym->s.def;
} else if (sym->sy_type == sy_const) {
*op = new_operand (op_value);
(*op)->type = sym->s.value->type;
(*op)->o.value = sym->s.value;
} else if (sym->sy_type == sy_func) {
*op = new_operand (op_def);
(*op)->type = ev_func;
(*op)->o.def = sym->s.func->def;
} else {
internal_error (e, "unexpected symbol type: %s",
symtype_str(sym->sy_type));
}
return sblock;
}
@ -1463,6 +1477,7 @@ check_final_block (sblock_t *sblock)
{
statement_t *s;
symbol_t *return_symbol = 0;
def_t *return_def = 0;
operand_t *return_operand = 0;
const char *return_opcode = "<RETURN_V>";
@ -1482,12 +1497,13 @@ check_final_block (sblock_t *sblock)
if (options.traditional || options.code.progsversion == PROG_ID_VERSION) {
return_symbol = make_symbol (".return", &type_param, pr.symtab->space,
sc_extern);
return_def = return_symbol->s.def;
return_opcode = "<RETURN>";
}
if (return_symbol) {
return_operand = new_operand (op_symbol);
return_operand = new_operand (op_def);
return_operand->type = ev_void;
return_operand->o.symbol = return_symbol;
return_operand->o.def = return_def;
}
s = new_statement (st_func, return_opcode, 0);
s->opa = return_operand;
@ -1529,10 +1545,11 @@ count_temp (operand_t *op)
{
if (!op)
return;
while (op->op_type == op_alias)
op = op->o.alias;
if (op->op_type == op_temp)
if (op->op_type == op_temp) {
while (op->o.tempop.alias)
op = op->o.tempop.alias;
op->o.tempop.users++;
}
}
void