mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-16 17:01:53 +00:00
[qfcc] Give lea its own statement type
This makes it much easier to check (and more robust to name changes), allowing for effectively killing the node to which the variable being addressed is attached. This fixes the incorrect address being used for va_list, which is what caused double-alias to fail.
This commit is contained in:
parent
38550922cc
commit
a64f91129f
4 changed files with 23 additions and 11 deletions
|
@ -102,6 +102,7 @@ typedef enum {
|
|||
st_state, ///< state (a, b); or state (a, b, c)
|
||||
st_func, ///< call, rcall or return/done
|
||||
st_flow, ///< if/ifa/ifae/ifb/ifbe/ifnot or goto or jump/jumpb
|
||||
st_address, ///< lea
|
||||
} st_type_t;
|
||||
|
||||
typedef struct statement_s {
|
||||
|
|
|
@ -282,8 +282,11 @@ dag_make_children (dag_t *dag, statement_t *s,
|
|||
dagnode_t *node = dag_node (operands[i + 1]);
|
||||
dagnode_t *killer = 0;
|
||||
|
||||
if (node && node->killed) {
|
||||
if (node && (node->killed || s->type == st_address)) {
|
||||
// If the node has been killed, then a new node is needed
|
||||
// taking the address of a variable effectively kills the node it's
|
||||
// attached to. FIXME should this be for only when the variable is
|
||||
// in the attached identifiers list and is not the node's label?
|
||||
killer = node->killed;
|
||||
node = 0;
|
||||
}
|
||||
|
@ -1214,6 +1217,7 @@ dag_gencode (dag_t *dag, sblock_t *block, dagnode_t *dagnode)
|
|||
dst = generate_assignments (dag, block, dst, var_iter, type);
|
||||
}
|
||||
break;
|
||||
case st_address:
|
||||
case st_expr:
|
||||
operands[0] = make_operand (dag, block, dagnode, 0);
|
||||
if (dagnode->children[1])
|
||||
|
|
|
@ -1181,15 +1181,21 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill,
|
|||
switch (s->type) {
|
||||
case st_none:
|
||||
internal_error (s->expr, "not a statement");
|
||||
case st_address:
|
||||
if (s->opb) {
|
||||
flow_add_op_var (use, s->opa, 1);
|
||||
flow_add_op_var (use, s->opb, 1);
|
||||
}
|
||||
flow_add_op_var (def, s->opc, 0);
|
||||
if (operands) {
|
||||
operands[0] = s->opc;
|
||||
operands[1] = s->opa;
|
||||
operands[2] = s->opb;
|
||||
}
|
||||
break;
|
||||
case st_expr:
|
||||
flow_add_op_var (def, s->opc, 0);
|
||||
if (strcmp (s->opcode, "lea") == 0) {
|
||||
if (s->opb) {
|
||||
flow_add_op_var (use, s->opa, 1);
|
||||
}
|
||||
} else {
|
||||
flow_add_op_var (use, s->opa, 1);
|
||||
}
|
||||
flow_add_op_var (use, s->opa, 1);
|
||||
if (s->opb)
|
||||
flow_add_op_var (use, s->opb, 1);
|
||||
if (operands) {
|
||||
|
|
|
@ -87,6 +87,7 @@ const char *st_type_names[] = {
|
|||
"st_state",
|
||||
"st_func",
|
||||
"st_flow",
|
||||
"st_address",
|
||||
};
|
||||
|
||||
const char *
|
||||
|
@ -744,7 +745,7 @@ expr_address (sblock_t *sblock, expr_t *e, operand_t **op)
|
|||
offset = 0;
|
||||
}
|
||||
|
||||
s = new_statement (st_expr, "lea", e);
|
||||
s = new_statement (st_address, "lea", e);
|
||||
sblock = statement_subexpr (sblock, lvalue, &s->opa);
|
||||
if (offset) {
|
||||
sblock = statement_subexpr (sblock, offset, &s->opb);
|
||||
|
@ -1005,7 +1006,7 @@ dereference_dst:
|
|||
// one directly. FIXME it was probably a mistake extracting the operand
|
||||
// type from the statement expression in dags
|
||||
dst_expr = expr_file_line (address_expr (dst_expr, 0), dst_expr);
|
||||
s = new_statement (st_expr, "lea", dst_expr);
|
||||
s = new_statement (st_address, "lea", dst_expr);
|
||||
s->opa = dst;
|
||||
s->opb = ofs;
|
||||
s->opc = temp_operand (&type_ptr, dst_expr);
|
||||
|
@ -1438,7 +1439,7 @@ statement_with (sblock_t *sblock, expr_t *e)
|
|||
static statement_t *
|
||||
lea_statement (operand_t *pointer, operand_t *offset, expr_t *e)
|
||||
{
|
||||
statement_t *s = new_statement (st_expr, "lea", e);
|
||||
statement_t *s = new_statement (st_address, "lea", e);
|
||||
s->opa = pointer;
|
||||
s->opb = offset;
|
||||
s->opc = temp_operand (&type_ptr, e);
|
||||
|
|
Loading…
Reference in a new issue