[qfcc] Give address expressions their own type

Definitely a pain to get working after the switch, but definitely worth
the effort. Still exposing type aliasing bugs.
This commit is contained in:
Bill Currie 2022-01-08 16:52:24 +09:00
parent cf8061c4d3
commit fa482e8ee5
8 changed files with 99 additions and 45 deletions

View file

@ -213,6 +213,12 @@ typedef struct {
struct expr_s *offset; ///< offset for alias
} ex_alias_t;
typedef struct {
struct type_s *type; ///< pointer type
struct expr_s *lvalue; ///< the lvalue being addressed
struct expr_s *offset; ///< offset from the address
} ex_address_t;
#define POINTER_VAL(p) (((p).def ? (p).def->offset : 0) + (p).val)
typedef struct expr_s {
@ -240,6 +246,7 @@ typedef struct expr_s {
element_chain_t compound; ///< compound initializer
ex_memset_t memset; ///< memset expr params
ex_alias_t alias; ///< alias expr params
ex_address_t address; ///< alias expr params
struct type_s *nil; ///< type for nil if known
} e;
} expr_t;
@ -654,6 +661,9 @@ expr_t *new_ret_expr (struct type_s *type);
expr_t *new_alias_expr (struct type_s *type, expr_t *expr);
expr_t *new_offset_alias_expr (struct type_s *type, expr_t *expr, int offset);
expr_t *new_address_expr (struct type_s *lvtype, expr_t *lvalue,
expr_t *offset);
/** Create an expression of the correct type that references the specified
parameter slot.

View file

@ -1,5 +1,5 @@
/*
expr.h
expr_names.h
expression construction and manipulations
@ -55,5 +55,6 @@ EX_EXPR(value) ///< constant value (::ex_value_t)
EX_EXPR(compound) ///< compound initializer
EX_EXPR(memset) ///< memset needs three params...
EX_EXPR(alias) ///< view expression as different type (::ex_alias_t)
EX_EXPR(address) ///< address of an lvalue expression (::ex_address_t)
///@}

View file

@ -568,7 +568,7 @@ do_op_entity (int op, expr_t *e, expr_t *e1, expr_t *e2)
{
type_t *type = get_type (e2);
if ((op == '.' || op == '&') && type->type == ev_field) {
if (op == '.' && type->type == ev_field) {
return e;
}
if (op == EQ || op == NE) {
@ -617,7 +617,7 @@ static expr_t *
do_op_pointer (int op, expr_t *e, expr_t *e1, expr_t *e2)
{
type_t *type;
static int valid[] = {'=', '-', '&', 'M', '.', EQ, NE, 0};
static int valid[] = {'=', '-', 'M', '.', EQ, NE, 0};
if (is_integral (type = get_type (e2)) && (op == '-' || op == '+')) {
// pointer arithmetic
@ -647,10 +647,10 @@ do_op_pointer (int op, expr_t *e, expr_t *e1, expr_t *e2)
else
e->e.expr.type = &type_float;
}
if (op != '.' && op != '&' && op != 'M'
if (op != '.' && op != 'M'
&& extract_type (e1) != extract_type (e2))
return type_mismatch (e1, e2, op);
if ((op == '.' || op == '&') && is_uinteger(get_type (e2)))
if (op == '.' && is_uinteger(get_type (e2)))
e->e.expr.e2 = cf_cast_expr (&type_integer, e2);
return e;
}

View file

@ -338,6 +338,27 @@ print_alias (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
dstring_delete (typestr);
}
static void
print_address (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
{
int indent = level * 2 + 2;
_print_expr (dstr, e->e.alias.expr, level, id, next);
dasprintf (dstr, "%*se_%p -> \"e_%p\" [label=\"&\"];\n", indent, "", e,
e->e.alias.expr);
if (e->e.alias.offset) {
_print_expr (dstr, e->e.alias.offset, level, id, next);
dasprintf (dstr, "%*se_%p -> \"e_%p\" [label=\"+\"];\n", indent, "", e,
e->e.alias.offset);
}
dstring_t *typestr = dstring_newstr();
print_type_str (typestr, e->e.alias.type);
dasprintf (dstr, "%*se_%p [label=\"%s (%s)\\n%d\"];\n", indent, "", e,
"&", typestr->str, e->line);
dstring_delete (typestr);
}
static void
print_uexpr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
{
@ -581,6 +602,7 @@ _print_expr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
[ex_compound] = print_compound,
[ex_memset] = print_memset,
[ex_alias] = print_alias,
[ex_address] = print_address,
};
int indent = level * 2 + 2;

View file

@ -260,6 +260,8 @@ get_type (expr_t *e)
return &type_SEL;
case ex_alias:
return e->e.alias.type;
case ex_address:
return e->e.address.type;
case ex_count:
internal_error (e, "invalid expression");
}
@ -477,6 +479,12 @@ copy_expr (expr_t *e)
n->e.alias.expr = copy_expr (e->e.alias.expr);
n->e.alias.offset = copy_expr (e->e.alias.offset);
return n;
case ex_address:
n = new_expr ();
*n = *e;
n->e.address.lvalue = copy_expr (e->e.address.lvalue);
n->e.address.offset = copy_expr (e->e.address.offset);
return n;
case ex_count:
break;
}
@ -1277,6 +1285,17 @@ new_offset_alias_expr (type_t *type, expr_t *expr, int offset)
return alias;
}
expr_t *
new_address_expr (type_t *lvtype, expr_t *lvalue, expr_t *offset)
{
expr_t *addr = new_expr ();
addr->type = ex_address;
addr->e.address.type = pointer_type (lvtype);
addr->e.address.lvalue = lvalue;
addr->e.address.offset = offset;
return addr;
}
static expr_t *
param_expr (const char *name, type_t *type)
{
@ -1406,8 +1425,7 @@ field_expr (expr_t *e1, expr_t *e2)
e2->type = ex_value;
e2->e.value = new_short_val (field->s.offset);
e = new_binary_expr ('&', e1, e2);
e->e.expr.type = pointer_type (field->type);
e = new_address_expr (field->type, e1, e2);
return unary_expr ('.', e);
} else if (is_class (t1->t.fldptr.type)) {
class_t *class = t1->t.fldptr.type->t.class;
@ -1420,8 +1438,7 @@ field_expr (expr_t *e1, expr_t *e2)
return new_error_expr ();
e2->type = ex_value;
e2->e.value = new_short_val (ivar->s.offset);
e = new_binary_expr ('&', e1, e2);
e->e.expr.type = pointer_type (ivar->type);
e = new_address_expr (ivar->type, e1, e2);
return unary_expr ('.', e);
}
} else if (is_vector (t1) || is_quaternion(t1) || is_struct (t1)) {
@ -1591,6 +1608,8 @@ has_function_call (expr_t *e)
return 0;
case ex_alias:
return has_function_call (e->e.alias.expr);
case ex_address:
return has_function_call (e->e.address.lvalue);
case ex_error:
case ex_state:
case ex_label:
@ -1735,6 +1754,7 @@ unary_expr (int op, expr_t *e)
return n;
}
case ex_nil:
case ex_address:
return error (e, "invalid type for unary -");
case ex_count:
internal_error (e, "invalid expression");
@ -1798,6 +1818,7 @@ unary_expr (int op, expr_t *e)
case ex_temp:
case ex_vector:
case ex_alias:
case ex_address:
{
expr_t *n = new_unary_expr (op, e);
@ -1890,6 +1911,7 @@ bitnot_expr:
return n;
}
case ex_nil:
case ex_address:
return error (e, "invalid type for unary ~");
case ex_count:
internal_error (e, "invalid expression");
@ -2312,9 +2334,7 @@ array_expr (expr_t *array, expr_t *index)
e = address_expr (array, index, array_type->t.array.type);
} else {
if (!is_short_val (index) || expr_short (index)) {
e = new_binary_expr ('&', array, index);
//e->e.expr.type = array_type->aux_type;
e->e.expr.type = array_type;
e = new_address_expr (array_type->t.array.type, array, index);
} else {
e = array;
}
@ -2382,9 +2402,8 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t)
return error (e1, "invalid type for unary &");
case ex_expr:
if (e1->e.expr.op == '.') {
e = e1;
e->e.expr.op = '&';
e->e.expr.type = pointer_type (e->e.expr.type);
e = new_address_expr (e1->e.expr.type,
e1->e.expr.e1, e1->e.expr.e2);
break;
}
if (e1->e.expr.op == 'm') {
@ -2402,8 +2421,7 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t)
if (e1->e.expr.op == '.') {
e = e1->e.expr.e1;
if (e->type == ex_expr && e->e.expr.op == '.') {
e->e.expr.type = pointer_type (e->e.expr.type);
e->e.expr.op = '&';
e = new_address_expr (e->e.expr.type, e->e.expr.e1, e->e.expr.e2);
}
break;
}
@ -2411,8 +2429,7 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t)
case ex_label:
return new_label_ref (&e1->e.label);
case ex_temp:
e = new_unary_expr ('&', e1);
e->e.expr.type = pointer_type (t);
e = new_address_expr (t, e1, 0);
break;
case ex_alias:
if (!t) {
@ -2438,19 +2455,17 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t)
def_t *def = e->e.value->v.pointer.def;
e->e.value = new_pointer_val (base + offset, t, def, 0);
} else {
if (!is_short_val (e2) || expr_short (e2)) {
if (e->type == ex_expr && e->e.expr.op == '&') {
e = new_binary_expr ('&', e->e.expr.e1,
binary_expr ('+', e->e.expr.e2, e2));
} else {
e = new_binary_expr ('&', e, e2);
}
expr_t *offset = 0;
if (e->type == ex_address) {
offset = e->e.address.offset;
e1 = e->e.address.lvalue;
} else {
e1 = e;
}
if (e->type == ex_expr || e->type == ex_uexpr) {
e->e.expr.type = pointer_type (t);
} else if (e->type == ex_alias) {
e->e.alias.type = pointer_type (t);
if (offset) {
e2 = binary_expr ('+', offset, e2);
}
e = new_address_expr (t, e1, e2);
}
}
return e;

View file

@ -115,6 +115,8 @@ is_lvalue (const expr_t *expr)
break;
case ex_alias:
return is_lvalue (expr->e.alias.expr);
case ex_address:
return 0;
case ex_uexpr:
if (expr->e.expr.op == '.') {
return 1;

View file

@ -486,8 +486,8 @@ get_selector (expr_t *sel)
if (sel->type == ex_selector) {
return sel->e.selector.sel;
}
if (sel->type != ex_expr && sel->e.expr.op != '&'
&& !is_SEL(sel->e.expr.type)) {
if (sel->type != ex_address && !sel->e.address.offset
&& !is_SEL(sel->e.address.type)) {
error (sel, "not a selector");
return 0;
}

View file

@ -744,8 +744,11 @@ 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, e);
sblock = statement_subexpr (sblock, e->e.address.lvalue, &s->opa);
if (e->e.address.offset) {
sblock = statement_subexpr (sblock, e->e.address.offset, &s->opb);
}
s->opc = temp_operand (e->e.address.type, e);
sblock_add_statement (sblock, s);
*(op) = s->opc;
return sblock;
@ -960,9 +963,12 @@ dereference_dst:
// to get the pointer and switch to storep instructions.
dst_expr = expr_file_line (address_expr (dst_expr, 0, 0), e);
opcode = ".="; // FIXME find a nicer representation (lose strings?)
if (dst_expr->type == ex_expr && !is_const_ptr (dst_expr->e.expr.e1)) {
sblock = statement_subexpr (sblock, dst_expr->e.expr.e1, &dst);
sblock = statement_subexpr (sblock, dst_expr->e.expr.e2, &ofs);
if (dst_expr->type == ex_address && dst_expr->e.address.offset
&& !is_const_ptr (dst_expr->e.address.lvalue)) {
sblock = statement_subexpr (sblock,
dst_expr->e.address.lvalue, &dst);
sblock = statement_subexpr (sblock,
dst_expr->e.address.offset, &ofs);
} else {
sblock = statement_subexpr (sblock, dst_expr, &dst);
ofs = 0;
@ -1127,17 +1133,17 @@ expr_deref (sblock_t *sblock, expr_t *deref, operand_t **op)
expr_t *e;
e = deref->e.expr.e1;
if (e->type == ex_uexpr && e->e.expr.op == '&'
&& e->e.expr.e1->type == ex_symbol) {
if (e->type == ex_address && !e->e.address.offset
&& e->e.address.lvalue->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, e);
} else if (e->type == ex_expr && e->e.expr.op == '&') {
} else if (e->type == ex_address && e->e.address.offset) {
statement_t *s;
operand_t *ptr = 0;
operand_t *offs = 0;
sblock = statement_subexpr (sblock, e->e.expr.e1, &ptr);
sblock = statement_subexpr (sblock, e->e.expr.e2, &offs);
sblock = statement_subexpr (sblock, e->e.address.lvalue, &ptr);
sblock = statement_subexpr (sblock, e->e.address.offset, &offs);
if (!*op)
*op = temp_operand (type, e);
if (low_level_type (type) == ev_void) {
@ -1329,9 +1335,6 @@ expr_uexpr (sblock_t *sblock, expr_t *e, operand_t **op)
statement_t *s;
switch (e->e.expr.op) {
case '&':
sblock = expr_address (sblock, e, op);
break;
case '.':
sblock = expr_deref (sblock, e, op);
break;
@ -1524,6 +1527,7 @@ statement_subexpr (sblock_t *sblock, expr_t *e, operand_t **op)
[ex_value] = expr_value,
[ex_selector] = expr_selector,
[ex_alias] = expr_alias,
[ex_address] = expr_address,
};
if (!e) {
*op = 0;