[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 struct expr_s *offset; ///< offset for alias
} ex_alias_t; } 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) #define POINTER_VAL(p) (((p).def ? (p).def->offset : 0) + (p).val)
typedef struct expr_s { typedef struct expr_s {
@ -240,6 +246,7 @@ typedef struct expr_s {
element_chain_t compound; ///< compound initializer element_chain_t compound; ///< compound initializer
ex_memset_t memset; ///< memset expr params ex_memset_t memset; ///< memset expr params
ex_alias_t alias; ///< alias 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 struct type_s *nil; ///< type for nil if known
} e; } e;
} expr_t; } 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_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_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 /** Create an expression of the correct type that references the specified
parameter slot. parameter slot.

View file

@ -1,5 +1,5 @@
/* /*
expr.h expr_names.h
expression construction and manipulations expression construction and manipulations
@ -55,5 +55,6 @@ EX_EXPR(value) ///< constant value (::ex_value_t)
EX_EXPR(compound) ///< compound initializer EX_EXPR(compound) ///< compound initializer
EX_EXPR(memset) ///< memset needs three params... EX_EXPR(memset) ///< memset needs three params...
EX_EXPR(alias) ///< view expression as different type (::ex_alias_t) 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); type_t *type = get_type (e2);
if ((op == '.' || op == '&') && type->type == ev_field) { if (op == '.' && type->type == ev_field) {
return e; return e;
} }
if (op == EQ || op == NE) { 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) do_op_pointer (int op, expr_t *e, expr_t *e1, expr_t *e2)
{ {
type_t *type; 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 == '+')) { if (is_integral (type = get_type (e2)) && (op == '-' || op == '+')) {
// pointer arithmetic // pointer arithmetic
@ -647,10 +647,10 @@ do_op_pointer (int op, expr_t *e, expr_t *e1, expr_t *e2)
else else
e->e.expr.type = &type_float; e->e.expr.type = &type_float;
} }
if (op != '.' && op != '&' && op != 'M' if (op != '.' && op != 'M'
&& extract_type (e1) != extract_type (e2)) && extract_type (e1) != extract_type (e2))
return type_mismatch (e1, e2, op); 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); e->e.expr.e2 = cf_cast_expr (&type_integer, e2);
return e; 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); 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 static void
print_uexpr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) 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_compound] = print_compound,
[ex_memset] = print_memset, [ex_memset] = print_memset,
[ex_alias] = print_alias, [ex_alias] = print_alias,
[ex_address] = print_address,
}; };
int indent = level * 2 + 2; int indent = level * 2 + 2;

View file

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

View file

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

View file

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

View file

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