mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-01-19 07:20:50 +00:00
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:
parent
b18a744288
commit
fa69aeef0f
8 changed files with 62 additions and 23 deletions
|
@ -46,6 +46,7 @@ typedef struct flowvar_s {
|
|||
struct set_s *define; ///< set of statements that define this var
|
||||
struct operand_s *op; ///< an operand using this var
|
||||
int number; ///< number of variable in func's ref list
|
||||
int flowaddr; ///< psuedo address for local and temp vars
|
||||
} flowvar_t;
|
||||
|
||||
typedef struct flowloop_s {
|
||||
|
|
|
@ -94,6 +94,7 @@ typedef struct function_s {
|
|||
struct set_s *global_vars;///< set indicating which vars are global
|
||||
struct statement_s **statements;
|
||||
int num_statements;
|
||||
int tmpaddr; ///< tmp var "address" for flow analysis
|
||||
} function_t;
|
||||
|
||||
extern function_t *current_func;
|
||||
|
|
|
@ -49,6 +49,7 @@ typedef struct {
|
|||
struct operand_s *alias;
|
||||
struct operand_s *alias_ops;
|
||||
int users;
|
||||
int flowaddr; ///< "address" of temp in flow analysis, != 0
|
||||
} tempop_t;
|
||||
|
||||
typedef struct operand_s {
|
||||
|
|
|
@ -1478,7 +1478,7 @@ fold_constants (expr_t *e)
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -158,8 +158,8 @@ operand_label (dag_t *dag, operand_t *op)
|
|||
return 0;
|
||||
|
||||
if (op->op_type == op_temp) {
|
||||
while (op->o.tempop.alias)
|
||||
op = op->o.tempop.alias;
|
||||
//while (op->o.tempop.alias)
|
||||
// op = op->o.tempop.alias;
|
||||
if (op->o.tempop.daglabel)
|
||||
return op->o.tempop.daglabel;
|
||||
label = new_label (dag);
|
||||
|
|
|
@ -91,10 +91,18 @@ 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)
|
||||
if (op->o.tempop.def) {
|
||||
return 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);
|
||||
}
|
||||
return op->o.tempop.def;
|
||||
case op_alias:
|
||||
return get_operand_def (expr, op->o.alias);
|
||||
|
|
|
@ -204,6 +204,12 @@ flowvar_is_param (flowvar_t *var)
|
|||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
flowvar_is_local (flowvar_t *var)
|
||||
{
|
||||
return !(flowvar_is_global (var) || flowvar_is_param (var));
|
||||
}
|
||||
#if 0
|
||||
static int
|
||||
flowvar_is_initialized (flowvar_t *var)
|
||||
|
@ -263,6 +269,24 @@ count_operand (operand_t *op)
|
|||
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
|
||||
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->op = op;
|
||||
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 ();
|
||||
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
|
||||
// first, add .return and .param_[0-7] as they are always needed
|
||||
for (i = 0; i < num_flow_params; i++)
|
||||
|
@ -382,27 +414,18 @@ flow_build_vars (function_t *func)
|
|||
// ([num_statements ... num_statements+localsize])
|
||||
// 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
|
||||
// before adding the number of statements in the function:
|
||||
// ([num_statements+localsize ... num_vars])
|
||||
// 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
|
||||
// temporary vars are pseudo allocated and their addresses are added as for
|
||||
// locals
|
||||
// add_operand takes care of setting flowaddr for both locals and temps
|
||||
for (i = 0; i < func->num_vars; i++) {
|
||||
int offset, size;
|
||||
int j;
|
||||
|
||||
var = func->vars[i];
|
||||
if (flowvar_is_global (var) || flowvar_is_param (var))
|
||||
if (flowvar_is_global (var) || flowvar_is_param (var)) {
|
||||
continue;
|
||||
if (var->op->op_type == op_temp) {
|
||||
j = func->symtab->space->size + var->number;
|
||||
set_add (var->define, func->num_statements + 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);
|
||||
}
|
||||
for (j = 0; j < var->op->size; j++) {
|
||||
set_add (var->define, var->flowaddr + j);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -126,10 +126,11 @@ operand_string (operand_t *op)
|
|||
return op->o.label->name;
|
||||
case op_temp:
|
||||
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],
|
||||
op, op->o.tempop.users,
|
||||
op->o.tempop.alias,
|
||||
op->o.tempop.offset,
|
||||
op->o.tempop.alias->o.tempop.users);
|
||||
return va ("<tmp %s %p:%d>", pr_type_name[op->o.tempop.type->type],
|
||||
op, op->o.tempop.users);
|
||||
|
@ -307,6 +308,7 @@ def_operand (def_t *def, type_t *type)
|
|||
type = def->type;
|
||||
op = new_operand (op_def);
|
||||
op->type = low_level_type (type);
|
||||
op->size = type_size (type);
|
||||
op->o.def = def;
|
||||
return op;
|
||||
}
|
||||
|
@ -830,6 +832,8 @@ expr_alias (sblock_t *sblock, expr_t *e, operand_t **op)
|
|||
aop = aop->o.tempop.alias;
|
||||
if (aop->op_type != op_temp)
|
||||
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) {
|
||||
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) {
|
||||
top = new_operand (op_temp);
|
||||
top->type = type;
|
||||
top->size = pr_type_size[type];
|
||||
top->o.tempop.alias = aop;
|
||||
top->o.tempop.offset = offset;
|
||||
top->next = aop->o.tempop.alias_ops;
|
||||
|
|
Loading…
Reference in a new issue