mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-26 06:10:56 +00:00
[qfcc] Record referenced def in pointer dereferences
When the def can be found. This fixes direct assignments to arrays (and probably structs) getting lost when the array is later read using a variable index.
This commit is contained in:
parent
246518f487
commit
2f117dd12e
1 changed files with 88 additions and 10 deletions
|
@ -361,6 +361,33 @@ new_statement (st_type_t type, const char *opcode, expr_t *expr)
|
||||||
return statement;
|
return statement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
statement_add_use (statement_t *s, operand_t *use)
|
||||||
|
{
|
||||||
|
if (use) {
|
||||||
|
use->next = s->use;
|
||||||
|
s->use = use;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
statement_add_def (statement_t *s, operand_t *def)
|
||||||
|
{
|
||||||
|
if (def) {
|
||||||
|
def->next = s->def;
|
||||||
|
s->def = def;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
statement_add_kill (statement_t *s, operand_t *kill)
|
||||||
|
{
|
||||||
|
if (kill) {
|
||||||
|
kill->next = s->kill;
|
||||||
|
s->kill = kill;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static pseudoop_t *
|
static pseudoop_t *
|
||||||
new_pseudoop (const char *name)
|
new_pseudoop (const char *name)
|
||||||
{
|
{
|
||||||
|
@ -382,6 +409,18 @@ new_operand (op_type_e op, expr_t *expr, void *return_addr)
|
||||||
return operand;
|
return operand;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static operand_t *
|
||||||
|
copy_operand (operand_t *src)
|
||||||
|
{
|
||||||
|
if (!src) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
operand_t *cpy = new_operand (src->op_type, src->expr, 0);
|
||||||
|
*cpy = *src;
|
||||||
|
cpy->return_addr = __builtin_return_address (0);
|
||||||
|
return cpy;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
free_operand (operand_t *op)
|
free_operand (operand_t *op)
|
||||||
{
|
{
|
||||||
|
@ -730,6 +769,8 @@ typedef sblock_t *(*expr_f) (sblock_t *, expr_t *, operand_t **);
|
||||||
static sblock_t *statement_subexpr (sblock_t *sblock, expr_t *e,
|
static sblock_t *statement_subexpr (sblock_t *sblock, expr_t *e,
|
||||||
operand_t **op);
|
operand_t **op);
|
||||||
static sblock_t *statement_slist (sblock_t *sblock, expr_t *e);
|
static sblock_t *statement_slist (sblock_t *sblock, expr_t *e);
|
||||||
|
static sblock_t *expr_symbol (sblock_t *sblock, expr_t *e, operand_t **op);
|
||||||
|
static sblock_t *expr_def (sblock_t *sblock, expr_t *e, operand_t **op);
|
||||||
|
|
||||||
static sblock_t *
|
static sblock_t *
|
||||||
expr_address (sblock_t *sblock, expr_t *e, operand_t **op)
|
expr_address (sblock_t *sblock, expr_t *e, operand_t **op)
|
||||||
|
@ -808,7 +849,7 @@ is_indirect (expr_t *e)
|
||||||
|
|
||||||
static sblock_t *addressing_mode (sblock_t *sblock, expr_t *ref,
|
static sblock_t *addressing_mode (sblock_t *sblock, expr_t *ref,
|
||||||
operand_t **base, operand_t **offset,
|
operand_t **base, operand_t **offset,
|
||||||
pr_ushort_t *mode);
|
pr_ushort_t *mode, operand_t **target);
|
||||||
static statement_t *lea_statement (operand_t *pointer, operand_t *offset,
|
static statement_t *lea_statement (operand_t *pointer, operand_t *offset,
|
||||||
expr_t *e);
|
expr_t *e);
|
||||||
|
|
||||||
|
@ -945,6 +986,7 @@ expr_assign (sblock_t *sblock, expr_t *e, operand_t **op)
|
||||||
operand_t *src = 0;
|
operand_t *src = 0;
|
||||||
operand_t *dst = 0;
|
operand_t *dst = 0;
|
||||||
operand_t *ofs = 0;
|
operand_t *ofs = 0;
|
||||||
|
operand_t *target = 0;
|
||||||
pr_ushort_t mode = 0; // assign
|
pr_ushort_t mode = 0; // assign
|
||||||
const char *opcode = "assign";
|
const char *opcode = "assign";
|
||||||
st_type_t type = st_assign;
|
st_type_t type = st_assign;
|
||||||
|
@ -987,8 +1029,8 @@ expr_assign (sblock_t *sblock, expr_t *e, operand_t **op)
|
||||||
if (0) {
|
if (0) {
|
||||||
dereference_dst:
|
dereference_dst:
|
||||||
// dst_expr is a dereferenced pointer, so need to get its addressing
|
// dst_expr is a dereferenced pointer, so need to get its addressing
|
||||||
// parameters (base and offset) and switch to storep instructions.
|
// parameters (base and offset) and switch to store instructions.
|
||||||
sblock = addressing_mode (sblock, dst_expr, &dst, &ofs, &mode);
|
sblock = addressing_mode (sblock, dst_expr, &dst, &ofs, &mode, &target);
|
||||||
if (mode != 0) {
|
if (mode != 0) {
|
||||||
opcode = "store";
|
opcode = "store";
|
||||||
type = st_ptrassign;
|
type = st_ptrassign;
|
||||||
|
@ -1021,6 +1063,8 @@ dereference_dst:
|
||||||
s->opa = dst;
|
s->opa = dst;
|
||||||
s->opb = ofs;
|
s->opb = ofs;
|
||||||
s->opc = src;
|
s->opc = src;
|
||||||
|
statement_add_def (s, copy_operand (target));
|
||||||
|
statement_add_kill (s, target);
|
||||||
sblock_add_statement (sblock, s);
|
sblock_add_statement (sblock, s);
|
||||||
return sblock;
|
return sblock;
|
||||||
}
|
}
|
||||||
|
@ -1290,9 +1334,29 @@ statement_branch (sblock_t *sblock, expr_t *e)
|
||||||
return sblock->next;
|
return sblock->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static operand_t *
|
||||||
|
find_def_operand (expr_t *ref)
|
||||||
|
{
|
||||||
|
operand_t *op = 0;
|
||||||
|
if (ref->type == ex_alias) {
|
||||||
|
return find_def_operand (ref->e.alias.expr);
|
||||||
|
} else if (ref->type == ex_address) {
|
||||||
|
return find_def_operand (ref->e.address.lvalue);
|
||||||
|
} else if (ref->type == ex_symbol) {
|
||||||
|
expr_symbol (0, ref, &op);
|
||||||
|
} else if (ref->type == ex_def) {
|
||||||
|
expr_def (0, ref, &op);
|
||||||
|
} else {
|
||||||
|
internal_error (ref, "unexpected expr type: %s",
|
||||||
|
expr_names[ref->type]);
|
||||||
|
}
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
static sblock_t *
|
static sblock_t *
|
||||||
ptr_addressing_mode (sblock_t *sblock, expr_t *ref,
|
ptr_addressing_mode (sblock_t *sblock, expr_t *ref,
|
||||||
operand_t **base, operand_t **offset, pr_ushort_t *mode)
|
operand_t **base, operand_t **offset, pr_ushort_t *mode,
|
||||||
|
operand_t **target)
|
||||||
{
|
{
|
||||||
type_t *type = get_type (ref);
|
type_t *type = get_type (ref);
|
||||||
if (!is_ptr (type)) {
|
if (!is_ptr (type)) {
|
||||||
|
@ -1329,7 +1393,7 @@ ptr_addressing_mode (sblock_t *sblock, expr_t *ref,
|
||||||
alias = new_alias_expr (type, lvalue->e.alias.expr);
|
alias = new_alias_expr (type, lvalue->e.alias.expr);
|
||||||
}
|
}
|
||||||
expr_file_line (alias, ref);
|
expr_file_line (alias, ref);
|
||||||
return addressing_mode (sblock, alias, base, offset, mode);
|
return addressing_mode (sblock, alias, base, offset, mode, target);
|
||||||
} else if (ref->type != ex_alias || ref->e.alias.offset) {
|
} else if (ref->type != ex_alias || ref->e.alias.offset) {
|
||||||
// probably just a pointer
|
// probably just a pointer
|
||||||
just_a_pointer:
|
just_a_pointer:
|
||||||
|
@ -1339,7 +1403,7 @@ just_a_pointer:
|
||||||
} else if (is_ptr (get_type (ref->e.alias.expr))) {
|
} else if (is_ptr (get_type (ref->e.alias.expr))) {
|
||||||
// cast of one pointer type to another
|
// cast of one pointer type to another
|
||||||
return ptr_addressing_mode (sblock, ref->e.alias.expr, base, offset,
|
return ptr_addressing_mode (sblock, ref->e.alias.expr, base, offset,
|
||||||
mode);
|
mode, target);
|
||||||
} else {
|
} else {
|
||||||
// alias with no offset
|
// alias with no offset
|
||||||
if (!is_integral (get_type (ref->e.alias.expr))) {
|
if (!is_integral (get_type (ref->e.alias.expr))) {
|
||||||
|
@ -1357,6 +1421,12 @@ just_a_pointer:
|
||||||
expr_t *ptr = intptr->e.expr.e1;
|
expr_t *ptr = intptr->e.expr.e1;
|
||||||
expr_t *offs = intptr->e.expr.e2;
|
expr_t *offs = intptr->e.expr.e2;
|
||||||
int const_offs;
|
int const_offs;
|
||||||
|
if (target) {
|
||||||
|
if (ptr->type == ex_alias
|
||||||
|
&& is_ptr (get_type (ptr->e.alias.expr))) {
|
||||||
|
*target = find_def_operand (ptr->e.alias.expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
// move the +/- to the offset
|
// move the +/- to the offset
|
||||||
offs = unary_expr (intptr->e.expr.op, offs);
|
offs = unary_expr (intptr->e.expr.op, offs);
|
||||||
// make the base a pointer again
|
// make the base a pointer again
|
||||||
|
@ -1378,7 +1448,8 @@ just_a_pointer:
|
||||||
|
|
||||||
static sblock_t *
|
static sblock_t *
|
||||||
addressing_mode (sblock_t *sblock, expr_t *ref,
|
addressing_mode (sblock_t *sblock, expr_t *ref,
|
||||||
operand_t **base, operand_t **offset, pr_ushort_t *mode)
|
operand_t **base, operand_t **offset, pr_ushort_t *mode,
|
||||||
|
operand_t **target)
|
||||||
{
|
{
|
||||||
if (is_indirect (ref)) {
|
if (is_indirect (ref)) {
|
||||||
// ref is known to be either ex_expr or ex_uexpr, with '.' for
|
// ref is known to be either ex_expr or ex_uexpr, with '.' for
|
||||||
|
@ -1396,7 +1467,7 @@ addressing_mode (sblock_t *sblock, expr_t *ref,
|
||||||
*mode = 1;//entity.field
|
*mode = 1;//entity.field
|
||||||
} else if (ref->type == ex_uexpr) {
|
} else if (ref->type == ex_uexpr) {
|
||||||
sblock = ptr_addressing_mode (sblock, ref->e.expr.e1, base, offset,
|
sblock = ptr_addressing_mode (sblock, ref->e.expr.e1, base, offset,
|
||||||
mode);
|
mode, target);
|
||||||
} else {
|
} else {
|
||||||
internal_error (ref, "unexpected expression type for indirect: %s",
|
internal_error (ref, "unexpected expression type for indirect: %s",
|
||||||
expr_names[ref->type]);
|
expr_names[ref->type]);
|
||||||
|
@ -1405,6 +1476,7 @@ addressing_mode (sblock_t *sblock, expr_t *ref,
|
||||||
sblock = statement_subexpr (sblock, ref, base);
|
sblock = statement_subexpr (sblock, ref, base);
|
||||||
*offset = short_operand (0, ref);
|
*offset = short_operand (0, ref);
|
||||||
*mode = 0;
|
*mode = 0;
|
||||||
|
*target = 0;
|
||||||
}
|
}
|
||||||
return sblock;
|
return sblock;
|
||||||
}
|
}
|
||||||
|
@ -1441,11 +1513,14 @@ statement_return (sblock_t *sblock, expr_t *e)
|
||||||
if (!e->e.retrn.at_return && e->e.retrn.ret_val) {
|
if (!e->e.retrn.at_return && e->e.retrn.ret_val) {
|
||||||
expr_t *ret_val = e->e.retrn.ret_val;
|
expr_t *ret_val = e->e.retrn.ret_val;
|
||||||
type_t *ret_type = get_type (ret_val);
|
type_t *ret_type = get_type (ret_val);
|
||||||
|
operand_t *target = 0;
|
||||||
pr_ushort_t ret_crtl = type_size (ret_type) - 1;
|
pr_ushort_t ret_crtl = type_size (ret_type) - 1;
|
||||||
pr_ushort_t mode = 0;
|
pr_ushort_t mode = 0;
|
||||||
sblock = addressing_mode (sblock, ret_val, &s->opa, &s->opb, &mode);
|
sblock = addressing_mode (sblock, ret_val, &s->opa, &s->opb, &mode,
|
||||||
|
&target);
|
||||||
ret_crtl |= mode << 5;
|
ret_crtl |= mode << 5;
|
||||||
s->opc = short_operand (ret_crtl, e);
|
s->opc = short_operand (ret_crtl, e);
|
||||||
|
statement_add_use (s, target);
|
||||||
} else {
|
} else {
|
||||||
if (e->e.retrn.at_return) {
|
if (e->e.retrn.at_return) {
|
||||||
expr_t *call = e->e.retrn.ret_val;
|
expr_t *call = e->e.retrn.ret_val;
|
||||||
|
@ -1544,10 +1619,11 @@ expr_deref (sblock_t *sblock, expr_t *deref, operand_t **op)
|
||||||
expr_t *ptr_expr = deref->e.expr.e1;
|
expr_t *ptr_expr = deref->e.expr.e1;
|
||||||
operand_t *base = 0;
|
operand_t *base = 0;
|
||||||
operand_t *offset = 0;
|
operand_t *offset = 0;
|
||||||
|
operand_t *target = 0;
|
||||||
pr_ushort_t mode;
|
pr_ushort_t mode;
|
||||||
statement_t *s;
|
statement_t *s;
|
||||||
|
|
||||||
sblock = addressing_mode (sblock, deref, &base, &offset, &mode);
|
sblock = addressing_mode (sblock, deref, &base, &offset, &mode, &target);
|
||||||
|
|
||||||
if (!*op) {
|
if (!*op) {
|
||||||
*op = temp_operand (load_type, deref);
|
*op = temp_operand (load_type, deref);
|
||||||
|
@ -1559,6 +1635,7 @@ expr_deref (sblock_t *sblock, expr_t *deref, operand_t **op)
|
||||||
// addressing_mode always sets offset to 0 for mode 0
|
// addressing_mode always sets offset to 0 for mode 0
|
||||||
s = assign_statement (*op, base, deref);
|
s = assign_statement (*op, base, deref);
|
||||||
sblock_add_statement (sblock, s);
|
sblock_add_statement (sblock, s);
|
||||||
|
statement_add_use (s, target);
|
||||||
return sblock;
|
return sblock;
|
||||||
case 1://entity.field
|
case 1://entity.field
|
||||||
case 2://const indexed pointer
|
case 2://const indexed pointer
|
||||||
|
@ -1578,6 +1655,7 @@ expr_deref (sblock_t *sblock, expr_t *deref, operand_t **op)
|
||||||
s = load_statement (base, offset, *op, deref);
|
s = load_statement (base, offset, *op, deref);
|
||||||
sblock_add_statement (sblock, s);
|
sblock_add_statement (sblock, s);
|
||||||
}
|
}
|
||||||
|
statement_add_use (s, target);
|
||||||
|
|
||||||
return sblock;
|
return sblock;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue