mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-01-19 07:20:50 +00:00
[qfcc] Add expression tracking to operands
Not much uses it yet, but it will make for better diagnostics.
This commit is contained in:
parent
1cd5ea5732
commit
4a8854d9ed
4 changed files with 52 additions and 46 deletions
|
@ -57,6 +57,7 @@ typedef struct operand_s {
|
|||
op_type_e op_type;
|
||||
struct type_s *type; ///< possibly override def's type
|
||||
int size; ///< for structures
|
||||
struct expr_s *expr; ///< expression generating this operand
|
||||
union {
|
||||
struct def_s *def;
|
||||
struct ex_value_s *value;
|
||||
|
@ -115,14 +116,16 @@ struct dstring_s;
|
|||
|
||||
const char *optype_str (op_type_e type) __attribute__((const));
|
||||
|
||||
operand_t *def_operand (struct def_s *def, struct type_s *type);
|
||||
operand_t *return_operand (struct type_s *type);
|
||||
operand_t *value_operand (struct ex_value_s *value);
|
||||
operand_t *def_operand (struct def_s *def, struct type_s *type,
|
||||
struct expr_s *expr);
|
||||
operand_t *return_operand (struct type_s *type, struct expr_s *expr);
|
||||
operand_t *value_operand (struct ex_value_s *value, struct expr_s *expr);
|
||||
int tempop_overlap (tempop_t *t1, tempop_t *t2) __attribute__((pure));
|
||||
operand_t *temp_operand (struct type_s *type);
|
||||
operand_t *temp_operand (struct type_s *type, struct expr_s *expr);
|
||||
int tempop_visit_all (tempop_t *tempop, int overlap,
|
||||
int (*visit) (tempop_t *, void *), void *data);
|
||||
operand_t *alias_operand (struct type_s *type, operand_t *op);
|
||||
operand_t *alias_operand (struct type_s *type, operand_t *op,
|
||||
struct expr_s *expr);
|
||||
void free_operand (operand_t *op);
|
||||
|
||||
sblock_t *new_sblock (void);
|
||||
|
|
|
@ -821,7 +821,7 @@ static operand_t *
|
|||
fix_op_type (operand_t *op, type_t *type)
|
||||
{
|
||||
if (op && op->op_type != op_label && op->type != type)
|
||||
op = alias_operand (type, op);
|
||||
op = alias_operand (type, op, op->expr);
|
||||
return op;
|
||||
}
|
||||
|
||||
|
@ -882,7 +882,8 @@ generate_moveps (dag_t *dag, sblock_t *block, dagnode_t *dagnode)
|
|||
offset = dstDef->offset;
|
||||
dstDef = dstDef->alias;
|
||||
}
|
||||
operands[2] = value_operand (new_pointer_val (offset, type, dstDef));
|
||||
operands[2] = value_operand (new_pointer_val (offset, type, dstDef),
|
||||
operands[1]->expr);
|
||||
st = build_statement ("<MOVEP>", operands, var->expr);
|
||||
sblock_add_statement (block, st);
|
||||
}
|
||||
|
@ -937,7 +938,8 @@ dag_gencode (dag_t *dag, sblock_t *block, dagnode_t *dagnode)
|
|||
operands[1] = make_operand (dag, block, dagnode, 1);
|
||||
type = get_type (dagnode->label->expr);
|
||||
if (!(var_iter = set_first (dagnode->identifiers))) {
|
||||
operands[2] = temp_operand (get_type (dagnode->label->expr));
|
||||
operands[2] = temp_operand (get_type (dagnode->label->expr),
|
||||
dagnode->label->expr);
|
||||
} else {
|
||||
daglabel_t *var = dag->labels[var_iter->element];
|
||||
|
||||
|
|
|
@ -1102,7 +1102,7 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill,
|
|||
def_t *alias;
|
||||
ex_pointer_t *ptr = &s->opc->o.value->v.pointer;
|
||||
alias = alias_def (ptr->def, ptr->type, ptr->val);
|
||||
op = def_operand (alias, ptr->type);
|
||||
op = def_operand (alias, ptr->type, s->opc->expr);
|
||||
flow_add_op_var (def, op, 0);
|
||||
if (operands)
|
||||
operands[0] = op;
|
||||
|
|
|
@ -273,11 +273,12 @@ new_statement (st_type_t type, const char *opcode, expr_t *expr)
|
|||
}
|
||||
|
||||
static operand_t *
|
||||
new_operand (op_type_e op)
|
||||
new_operand (op_type_e op, expr_t *expr)
|
||||
{
|
||||
operand_t *operand;
|
||||
ALLOC (256, operand_t, operands, operand);
|
||||
operand->op_type = op;
|
||||
operand->expr = expr;
|
||||
return operand;
|
||||
}
|
||||
|
||||
|
@ -311,13 +312,13 @@ free_sblock (sblock_t *sblock)
|
|||
}
|
||||
|
||||
operand_t *
|
||||
def_operand (def_t *def, type_t *type)
|
||||
def_operand (def_t *def, type_t *type, expr_t *expr)
|
||||
{
|
||||
operand_t *op;
|
||||
|
||||
if (!type)
|
||||
type = def->type;
|
||||
op = new_operand (op_def);
|
||||
op = new_operand (op_def, expr);
|
||||
op->type = type;
|
||||
op->size = type_size (type);
|
||||
op->o.def = def;
|
||||
|
@ -325,28 +326,28 @@ def_operand (def_t *def, type_t *type)
|
|||
}
|
||||
|
||||
operand_t *
|
||||
return_operand (type_t *type)
|
||||
return_operand (type_t *type, expr_t *expr)
|
||||
{
|
||||
symbol_t *return_symbol;
|
||||
return_symbol = make_symbol (".return", &type_param, pr.symtab->space,
|
||||
sc_extern);
|
||||
return def_operand (return_symbol->s.def, type);
|
||||
return def_operand (return_symbol->s.def, type, expr);
|
||||
}
|
||||
|
||||
operand_t *
|
||||
value_operand (ex_value_t *value)
|
||||
value_operand (ex_value_t *value, expr_t *expr)
|
||||
{
|
||||
operand_t *op;
|
||||
op = new_operand (op_value);
|
||||
op = new_operand (op_value, expr);
|
||||
op->type = value->type;
|
||||
op->o.value = value;
|
||||
return op;
|
||||
}
|
||||
|
||||
operand_t *
|
||||
temp_operand (type_t *type)
|
||||
temp_operand (type_t *type, expr_t *expr)
|
||||
{
|
||||
operand_t *op = new_operand (op_temp);
|
||||
operand_t *op = new_operand (op_temp, expr);
|
||||
|
||||
op->o.tempop.type = type;
|
||||
op->type = type;
|
||||
|
@ -412,7 +413,7 @@ tempop_visit_all (tempop_t *tempop, int overlap,
|
|||
}
|
||||
|
||||
operand_t *
|
||||
alias_operand (type_t *type, operand_t *op)
|
||||
alias_operand (type_t *type, operand_t *op, expr_t *expr)
|
||||
{
|
||||
operand_t *aop;
|
||||
|
||||
|
@ -420,7 +421,7 @@ alias_operand (type_t *type, operand_t *op)
|
|||
internal_error (0, "\naliasing operand with type of different size"
|
||||
" (%d, %d)", type_size (type), type_size (op->type));
|
||||
}
|
||||
aop = new_operand (op_alias);
|
||||
aop = new_operand (op_alias, expr);
|
||||
aop->o.alias = op;
|
||||
aop->type = type;
|
||||
aop->size = type_size (type);
|
||||
|
@ -428,10 +429,10 @@ alias_operand (type_t *type, operand_t *op)
|
|||
}
|
||||
|
||||
static operand_t *
|
||||
short_operand (short short_val)
|
||||
short_operand (short short_val, expr_t *expr)
|
||||
{
|
||||
ex_value_t *val = new_short_val (short_val);
|
||||
return value_operand (val);
|
||||
return value_operand (val, expr);
|
||||
}
|
||||
|
||||
static const char *
|
||||
|
@ -593,7 +594,7 @@ statement_branch (sblock_t *sblock, expr_t *e)
|
|||
|
||||
if (e->type == ex_uexpr && e->e.expr.op == 'g') {
|
||||
s = new_statement (st_flow, "<GOTO>", e);
|
||||
s->opa = new_operand (op_label);
|
||||
s->opa = new_operand (op_label, e);
|
||||
s->opa->o.label = &e->e.expr.e1->e.label;
|
||||
} else {
|
||||
if (e->e.expr.op == 'g') {
|
||||
|
@ -604,7 +605,7 @@ statement_branch (sblock_t *sblock, expr_t *e)
|
|||
opcode = convert_op (e->e.expr.op);
|
||||
s = new_statement (st_flow, opcode, e);
|
||||
sblock = statement_subexpr (sblock, e->e.expr.e1, &s->opa);
|
||||
s->opb = new_operand (op_label);
|
||||
s->opb = new_operand (op_label, e);
|
||||
s->opb->o.label = &e->e.expr.e2->e.label;
|
||||
}
|
||||
}
|
||||
|
@ -783,7 +784,7 @@ expr_address (sblock_t *sblock, expr_t *e, operand_t **op)
|
|||
statement_t *s;
|
||||
s = new_statement (st_expr, "&", e);
|
||||
sblock = statement_subexpr (sblock, e->e.expr.e1, &s->opa);
|
||||
s->opc = temp_operand (e->e.expr.type);
|
||||
s->opc = temp_operand (e->e.expr.type, e);
|
||||
sblock_add_statement (sblock, s);
|
||||
*(op) = s->opc;
|
||||
return sblock;
|
||||
|
@ -795,7 +796,7 @@ lea_statement (operand_t *pointer, operand_t *offset, expr_t *e)
|
|||
statement_t *s = new_statement (st_expr, "&", e);
|
||||
s->opa = pointer;
|
||||
s->opb = offset;
|
||||
s->opc = temp_operand (&type_pointer);
|
||||
s->opc = temp_operand (&type_pointer, e);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
@ -804,7 +805,7 @@ address_statement (operand_t *value, expr_t *e)
|
|||
{
|
||||
statement_t *s = new_statement (st_expr, "&", e);
|
||||
s->opa = value;
|
||||
s->opc = temp_operand (&type_pointer);
|
||||
s->opc = temp_operand (&type_pointer, e);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
@ -819,7 +820,7 @@ expr_deref (sblock_t *sblock, expr_t *deref, operand_t **op)
|
|||
&& e->e.expr.e1->type == ex_symbol) {
|
||||
if (e->e.expr.e1->e.symbol->sy_type != sy_var)
|
||||
internal_error (e, "address of non-var");
|
||||
*op = def_operand (e->e.expr.e1->e.symbol->s.def, type);
|
||||
*op = def_operand (e->e.expr.e1->e.symbol->s.def, type, e);
|
||||
} else if (e->type == ex_expr && e->e.expr.op == '&') {
|
||||
statement_t *s;
|
||||
operand_t *ptr = 0;
|
||||
|
@ -827,7 +828,7 @@ expr_deref (sblock_t *sblock, expr_t *deref, operand_t **op)
|
|||
sblock = statement_subexpr (sblock, e->e.expr.e1, &ptr);
|
||||
sblock = statement_subexpr (sblock, e->e.expr.e2, &offs);
|
||||
if (!*op)
|
||||
*op = temp_operand (type);
|
||||
*op = temp_operand (type, e);
|
||||
if (low_level_type (type) == ev_void) {
|
||||
operand_t *src_addr;
|
||||
operand_t *dst_addr;
|
||||
|
@ -843,7 +844,7 @@ expr_deref (sblock_t *sblock, expr_t *deref, operand_t **op)
|
|||
|
||||
s = new_statement (st_move, "<MOVEP>", deref);
|
||||
s->opa = src_addr;
|
||||
s->opb = short_operand (type_size (type));
|
||||
s->opb = short_operand (type_size (type), e);
|
||||
s->opc = dst_addr;
|
||||
sblock_add_statement (sblock, s);
|
||||
} else {
|
||||
|
@ -856,17 +857,17 @@ expr_deref (sblock_t *sblock, expr_t *deref, operand_t **op)
|
|||
} else if (e->type == ex_value && e->e.value->lltype == ev_pointer) {
|
||||
ex_pointer_t *ptr = &e->e.value->v.pointer;
|
||||
*op = def_operand (alias_def (ptr->def, ptr->type, ptr->val),
|
||||
ptr->type);
|
||||
ptr->type, e);
|
||||
} else {
|
||||
statement_t *s;
|
||||
operand_t *ptr = 0;
|
||||
|
||||
sblock = statement_subexpr (sblock, e, &ptr);
|
||||
if (!*op)
|
||||
*op = temp_operand (type);
|
||||
*op = temp_operand (type, e);
|
||||
s = new_statement (st_expr, ".", deref);
|
||||
s->opa = ptr;
|
||||
s->opb = short_operand (0);
|
||||
s->opb = short_operand (0, e);
|
||||
s->opc = *op;
|
||||
sblock_add_statement (sblock, s);
|
||||
}
|
||||
|
@ -919,7 +920,7 @@ expr_alias (sblock_t *sblock, expr_t *e, operand_t **op)
|
|||
}
|
||||
}
|
||||
if (!top) {
|
||||
top = temp_operand (type);
|
||||
top = temp_operand (type, e);
|
||||
top->o.tempop.alias = aop;
|
||||
top->o.tempop.offset = offset;
|
||||
top->next = aop->o.tempop.alias_ops;
|
||||
|
@ -930,9 +931,9 @@ expr_alias (sblock_t *sblock, expr_t *e, operand_t **op)
|
|||
def = aop->o.def;
|
||||
while (def->alias)
|
||||
def = def->alias;
|
||||
*op = def_operand (alias_def (def, type, offset), 0);
|
||||
*op = def_operand (alias_def (def, type, offset), 0, e);
|
||||
} else if (aop->op_type == op_value) {
|
||||
*op = value_operand (aop->o.value);
|
||||
*op = value_operand (aop->o.value, e);
|
||||
(*op)->type = type;
|
||||
} else {
|
||||
internal_error (e, "invalid alias target: %s: %s",
|
||||
|
@ -970,7 +971,7 @@ expr_expr (sblock_t *sblock, expr_t *e, operand_t **op)
|
|||
sblock = statement_subexpr (sblock, e->e.expr.e1, &s->opa);
|
||||
sblock = statement_subexpr (sblock, e->e.expr.e2, &s->opb);
|
||||
if (!*op)
|
||||
*op = temp_operand (e->e.expr.type);
|
||||
*op = temp_operand (e->e.expr.type, e);
|
||||
s->opc = *op;
|
||||
sblock_add_statement (sblock, s);
|
||||
break;
|
||||
|
@ -989,7 +990,7 @@ expr_cast (sblock_t *sblock, expr_t *e, operand_t **op)
|
|||
if (is_scalar (src_type) && is_scalar (type)) {
|
||||
operand_t *src = 0;
|
||||
sblock = statement_subexpr (sblock, e->e.expr.e1, &src);
|
||||
*op = temp_operand (e->e.expr.type);
|
||||
*op = temp_operand (e->e.expr.type, e);
|
||||
s = new_statement (st_expr, "<CONV>", e);
|
||||
s->opa = src;
|
||||
s->opc = *op;
|
||||
|
@ -1046,7 +1047,7 @@ expr_uexpr (sblock_t *sblock, expr_t *e, operand_t **op)
|
|||
s = new_statement (st_expr, opcode, e);
|
||||
sblock = statement_subexpr (sblock, e->e.expr.e1, &s->opa);
|
||||
if (!*op)
|
||||
*op = temp_operand (e->e.expr.type);
|
||||
*op = temp_operand (e->e.expr.type, e);
|
||||
s->opc = *op;
|
||||
sblock_add_statement (sblock, s);
|
||||
}
|
||||
|
@ -1059,11 +1060,11 @@ expr_symbol (sblock_t *sblock, expr_t *e, operand_t **op)
|
|||
symbol_t *sym = e->e.symbol;
|
||||
|
||||
if (sym->sy_type == sy_var) {
|
||||
*op = def_operand (sym->s.def, sym->type);
|
||||
*op = def_operand (sym->s.def, sym->type, e);
|
||||
} else if (sym->sy_type == sy_const) {
|
||||
*op = value_operand (sym->s.value);
|
||||
*op = value_operand (sym->s.value, e);
|
||||
} else if (sym->sy_type == sy_func) {
|
||||
*op = def_operand (sym->s.func->def, 0);
|
||||
*op = def_operand (sym->s.func->def, 0, e);
|
||||
} else {
|
||||
internal_error (e, "unexpected symbol type: %s for %s",
|
||||
symtype_str (sym->sy_type), sym->name);
|
||||
|
@ -1075,7 +1076,7 @@ static sblock_t *
|
|||
expr_temp (sblock_t *sblock, expr_t *e, operand_t **op)
|
||||
{
|
||||
if (!e->e.temp.op)
|
||||
e->e.temp.op = temp_operand (e->e.temp.type);
|
||||
e->e.temp.op = temp_operand (e->e.temp.type, e);
|
||||
*op = e->e.temp.op;
|
||||
return sblock;
|
||||
}
|
||||
|
@ -1151,7 +1152,7 @@ expr_vector_e (sblock_t *sblock, expr_t *e, operand_t **op)
|
|||
static sblock_t *
|
||||
expr_value (sblock_t *sblock, expr_t *e, operand_t **op)
|
||||
{
|
||||
*op = value_operand (e->e.value);
|
||||
*op = value_operand (e->e.value, e);
|
||||
return sblock;
|
||||
}
|
||||
|
||||
|
@ -1414,7 +1415,7 @@ statement_uexpr (sblock_t *sblock, expr_t *e)
|
|||
}
|
||||
s = new_statement (st_func, opcode, e);
|
||||
if (e->e.expr.e1) {
|
||||
s->opa = return_operand (get_type (e->e.expr.e1));
|
||||
s->opa = return_operand (get_type (e->e.expr.e1), e);
|
||||
sblock = statement_subexpr (sblock, e->e.expr.e1, &s->opa);
|
||||
}
|
||||
sblock_add_statement (sblock, s);
|
||||
|
@ -1718,7 +1719,7 @@ check_final_block (sblock_t *sblock)
|
|||
s = new_statement (st_func, "<RETURN_V>", 0);
|
||||
if (options.traditional || options.code.progsversion == PROG_ID_VERSION) {
|
||||
s->opcode = save_string ("<RETURN>");
|
||||
s->opa = return_operand (&type_void);
|
||||
s->opa = return_operand (&type_void, 0);
|
||||
}
|
||||
sblock_add_statement (sblock, s);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue