Improve handling of temp aliases

This makes all tests pass when not optimizing. More work needs to be
done in dags.
This commit is contained in:
Bill Currie 2019-06-12 00:37:02 +09:00
parent b18a744288
commit fa69aeef0f
8 changed files with 62 additions and 23 deletions

View file

@ -46,6 +46,7 @@ typedef struct flowvar_s {
struct set_s *define; ///< set of statements that define this var struct set_s *define; ///< set of statements that define this var
struct operand_s *op; ///< an operand using this var struct operand_s *op; ///< an operand using this var
int number; ///< number of variable in func's ref list int number; ///< number of variable in func's ref list
int flowaddr; ///< psuedo address for local and temp vars
} flowvar_t; } flowvar_t;
typedef struct flowloop_s { typedef struct flowloop_s {

View file

@ -94,6 +94,7 @@ typedef struct function_s {
struct set_s *global_vars;///< set indicating which vars are global struct set_s *global_vars;///< set indicating which vars are global
struct statement_s **statements; struct statement_s **statements;
int num_statements; int num_statements;
int tmpaddr; ///< tmp var "address" for flow analysis
} function_t; } function_t;
extern function_t *current_func; extern function_t *current_func;

View file

@ -49,6 +49,7 @@ typedef struct {
struct operand_s *alias; struct operand_s *alias;
struct operand_s *alias_ops; struct operand_s *alias_ops;
int users; int users;
int flowaddr; ///< "address" of temp in flow analysis, != 0
} tempop_t; } tempop_t;
typedef struct operand_s { typedef struct operand_s {

View file

@ -1478,7 +1478,7 @@ fold_constants (expr_t *e)
} }
op = e->e.expr.op; op = e->e.expr.op;
if (op == 'i' || op == 'n' || op == 'c' || op == 's') { if (op == 'A' || op == 'i' || op == 'n' || op == 'c' || op == 's') {
return e; return e;
} }

View file

@ -158,8 +158,8 @@ operand_label (dag_t *dag, operand_t *op)
return 0; return 0;
if (op->op_type == op_temp) { if (op->op_type == op_temp) {
while (op->o.tempop.alias) //while (op->o.tempop.alias)
op = op->o.tempop.alias; // op = op->o.tempop.alias;
if (op->o.tempop.daglabel) if (op->o.tempop.daglabel)
return op->o.tempop.daglabel; return op->o.tempop.daglabel;
label = new_label (dag); label = new_label (dag);

View file

@ -91,10 +91,18 @@ get_operand_def (expr_t *expr, operand_t *op)
zero_def.type = &type_short; zero_def.type = &type_short;
return &zero_def; //FIXME return &zero_def; //FIXME
case op_temp: case op_temp:
while (op->o.tempop.alias) if (op->o.tempop.def) {
op = op->o.tempop.alias; return op->o.tempop.def;
if (!op->o.tempop.def) }
if (op->o.tempop.alias) {
def_t *tdef = get_operand_def (expr, op->o.tempop.alias);
int offset = op->o.tempop.offset;
type_t *type = ev_types[op->type];
op->o.tempop.def = alias_def (tdef, type, offset);
}
if (!op->o.tempop.def) {
op->o.tempop.def = temp_def (op->type, op->size); op->o.tempop.def = temp_def (op->type, op->size);
}
return op->o.tempop.def; return op->o.tempop.def;
case op_alias: case op_alias:
return get_operand_def (expr, op->o.alias); return get_operand_def (expr, op->o.alias);

View file

@ -204,6 +204,12 @@ flowvar_is_param (flowvar_t *var)
return 0; return 0;
return 1; return 1;
} }
static int
flowvar_is_local (flowvar_t *var)
{
return !(flowvar_is_global (var) || flowvar_is_param (var));
}
#if 0 #if 0
static int static int
flowvar_is_initialized (flowvar_t *var) flowvar_is_initialized (flowvar_t *var)
@ -263,6 +269,24 @@ count_operand (operand_t *op)
return 0; return 0;
} }
static int
get_temp_address (function_t *func, operand_t *op)
{
operand_t *top = op;
if (op->o.tempop.flowaddr) {
return op->o.tempop.flowaddr;
}
while (top->o.tempop.alias) {
top = top->o.tempop.alias;
}
if (!top->o.tempop.flowaddr) {
top->o.tempop.flowaddr = func->tmpaddr;
func->tmpaddr += top->size;
}
op->o.tempop.flowaddr = top->o.tempop.flowaddr + op->o.tempop.offset;
return op->o.tempop.flowaddr;
}
static void static void
add_operand (function_t *func, operand_t *op) add_operand (function_t *func, operand_t *op)
{ {
@ -280,6 +304,11 @@ add_operand (function_t *func, operand_t *op)
var->number = func->num_vars++; var->number = func->num_vars++;
var->op = op; var->op = op;
func->vars[var->number] = var; func->vars[var->number] = var;
if (op->op_type == op_temp) {
var->flowaddr = get_temp_address (func, op);
} else if (flowvar_is_local (var)) {
var->flowaddr = func->num_statements + def_offset (var->op->o.def);
}
} }
} }
@ -348,6 +377,9 @@ flow_build_vars (function_t *func)
stuse = set_new (); stuse = set_new ();
stdef = set_new (); stdef = set_new ();
// set up pseudo address space for temp vars so accessing tmp vars
// though aliases analyses correctly
func->tmpaddr = func->num_statements + func->symtab->space->size;
func->num_vars = 0; // incremented by add_operand func->num_vars = 0; // incremented by add_operand
// first, add .return and .param_[0-7] as they are always needed // first, add .return and .param_[0-7] as they are always needed
for (i = 0; i < num_flow_params; i++) for (i = 0; i < num_flow_params; i++)
@ -382,27 +414,18 @@ flow_build_vars (function_t *func)
// ([num_statements ... num_statements+localsize]) // ([num_statements ... num_statements+localsize])
// with a set element for each def used in the local space // with a set element for each def used in the local space
// //
// temporary vars add their var number to the size of the local space // temporary vars are pseudo allocated and their addresses are added as for
// before adding the number of statements in the function: // locals
// ([num_statements+localsize ... num_vars]) // add_operand takes care of setting flowaddr for both locals and temps
// temporary vars are always accessed as a full var, so only one set
// element per temporary var is needed. This can lead to holes in the
// temporary var set element space, but it does keep things simple
for (i = 0; i < func->num_vars; i++) { for (i = 0; i < func->num_vars; i++) {
int offset, size;
int j; int j;
var = func->vars[i]; var = func->vars[i];
if (flowvar_is_global (var) || flowvar_is_param (var)) if (flowvar_is_global (var) || flowvar_is_param (var)) {
continue; continue;
if (var->op->op_type == op_temp) { }
j = func->symtab->space->size + var->number; for (j = 0; j < var->op->size; j++) {
set_add (var->define, func->num_statements + j); set_add (var->define, var->flowaddr + j);
} else {
offset = def_offset (var->op->o.def);
size = def_size (var->op->o.def);
for (j = offset; j < offset + size; j++)
set_add (var->define, func->num_statements + j);
} }
} }

View file

@ -126,10 +126,11 @@ operand_string (operand_t *op)
return op->o.label->name; return op->o.label->name;
case op_temp: case op_temp:
if (op->o.tempop.alias) if (op->o.tempop.alias)
return va ("<tmp %s %p:%d:%p:%d>", return va ("<tmp %s %p:%d:%p:%d:%d>",
pr_type_name[op->type], pr_type_name[op->type],
op, op->o.tempop.users, op, op->o.tempop.users,
op->o.tempop.alias, op->o.tempop.alias,
op->o.tempop.offset,
op->o.tempop.alias->o.tempop.users); op->o.tempop.alias->o.tempop.users);
return va ("<tmp %s %p:%d>", pr_type_name[op->o.tempop.type->type], return va ("<tmp %s %p:%d>", pr_type_name[op->o.tempop.type->type],
op, op->o.tempop.users); op, op->o.tempop.users);
@ -307,6 +308,7 @@ def_operand (def_t *def, type_t *type)
type = def->type; type = def->type;
op = new_operand (op_def); op = new_operand (op_def);
op->type = low_level_type (type); op->type = low_level_type (type);
op->size = type_size (type);
op->o.def = def; op->o.def = def;
return op; return op;
} }
@ -830,6 +832,8 @@ expr_alias (sblock_t *sblock, expr_t *e, operand_t **op)
aop = aop->o.tempop.alias; aop = aop->o.tempop.alias;
if (aop->op_type != op_temp) if (aop->op_type != op_temp)
internal_error (e, "temp alias of non-temp var"); internal_error (e, "temp alias of non-temp var");
if (aop->o.tempop.alias)
bug (e, "aliased temp alias");
} }
for (top = aop->o.tempop.alias_ops; top; top = top->next) { for (top = aop->o.tempop.alias_ops; top; top = top->next) {
if (top->type == type && top->o.tempop.offset == offset) { if (top->type == type && top->o.tempop.offset == offset) {
@ -839,6 +843,7 @@ expr_alias (sblock_t *sblock, expr_t *e, operand_t **op)
if (!top) { if (!top) {
top = new_operand (op_temp); top = new_operand (op_temp);
top->type = type; top->type = type;
top->size = pr_type_size[type];
top->o.tempop.alias = aop; top->o.tempop.alias = aop;
top->o.tempop.offset = offset; top->o.tempop.offset = offset;
top->next = aop->o.tempop.alias_ops; top->next = aop->o.tempop.alias_ops;