[qfcc] Give alias expressions their own type

While this was a pain to get working, that pain only went to prove the
value of using proper "types" (even if only an enum) for different
expression types: just finding all the places to edit was a chore, and
easy to make mistakes (forgetting bits here and there).

Strangely enough, this exposed a pile of *type* aliasing bugs (next
commit).
This commit is contained in:
Bill Currie 2022-01-08 12:06:52 +09:00
parent 420d55406f
commit 23c9a317f8
9 changed files with 118 additions and 81 deletions

View file

@ -207,6 +207,12 @@ typedef struct ex_value_s {
} v; } v;
} ex_value_t; } ex_value_t;
typedef struct {
struct type_s *type; ///< type to view the expression
struct expr_s *expr; ///< the expression to alias
struct expr_s *offset; ///< offset for alias
} ex_alias_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 {
@ -233,6 +239,7 @@ typedef struct expr_s {
ex_value_t *value; ///< constant value ex_value_t *value; ///< constant value
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
struct type_s *nil; ///< type for nil if known struct type_s *nil; ///< type for nil if known
} e; } e;
} expr_t; } expr_t;

View file

@ -54,5 +54,6 @@ EX_EXPR(nil) ///< umm, nil, null. nuff said (0 of any type)
EX_EXPR(value) ///< constant value (::ex_value_t) 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)
///@} ///@}

View file

@ -1718,7 +1718,7 @@ fold_constants (expr_t *e)
return e; return e;
} }
op = e->e.expr.op; op = e->e.expr.op;
if (op == 'A' || op == 'g' || op == 'r') if (op == 'g' || op == 'r')
return e; return e;
t1 = extract_type (e1); t1 = extract_type (e1);
if (t1 >= ev_type_count || !do_unary_op[t1]) { if (t1 >= ev_type_count || !do_unary_op[t1]) {
@ -1734,7 +1734,7 @@ fold_constants (expr_t *e)
} }
op = e->e.expr.op; op = e->e.expr.op;
if (op == 'A' || op == 'i' || op == 'n' || op == 'c' || op == 's') { if (op == 'i' || op == 'n' || op == 'c' || op == 's') {
return e; return e;
} }

View file

@ -608,12 +608,11 @@ initialize_def (symbol_t *sym, expr_t *init, defspace_t *space,
error (init, "non-constant initializier"); error (init, "non-constant initializier");
return; return;
} }
while ((init->type == ex_uexpr || init->type == ex_expr) while (init->type == ex_alias) {
&& init->e.expr.op == 'A') { if (init->e.alias.offset) {
if (init->type == ex_expr) { offset += expr_integer (init->e.alias.offset);
offset += expr_integer (init->e.expr.e2);
} }
init = init->e.expr.e1; init = init->e.alias.expr;
} }
if (init->type != ex_value) { //FIXME enum etc if (init->type != ex_value) { //FIXME enum etc
internal_error (0, "initializier not a value"); internal_error (0, "initializier not a value");

View file

@ -100,7 +100,6 @@ get_op_string (int op)
case 'r': return "<return>"; case 'r': return "<return>";
case 's': return "<state>"; case 's': return "<state>";
case 'c': return "<call>"; case 'c': return "<call>";
case 'A': return "<alias>";
case 'C': return "<cast>"; case 'C': return "<cast>";
case 'M': return "<move>"; case 'M': return "<move>";
case 'm': return "<move>"; case 'm': return "<move>";
@ -314,36 +313,43 @@ print_subexpr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
dasprintf (dstr, "%*se_%p -> \"e_%p\" [label=\"r\"];\n", indent, "", e, dasprintf (dstr, "%*se_%p -> \"e_%p\" [label=\"r\"];\n", indent, "", e,
e->e.expr.e2); e->e.expr.e2);
} }
if (e->e.expr.op == 'A') { dasprintf (dstr, "%*se_%p [label=\"%s\\n%d\"];\n", indent, "", e,
dstring_t *typestr = dstring_newstr(); get_op_string (e->e.expr.op), e->line);
print_type_str (typestr, e->e.expr.type); }
dasprintf (dstr, "%*se_%p [label=\"%s (%s)\\n%d\"];\n", indent, "", e,
get_op_string (e->e.expr.op), typestr->str, e->line); static void
dstring_delete (typestr); print_alias (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
} else { {
dasprintf (dstr, "%*se_%p [label=\"%s\\n%d\"];\n", indent, "", e, int indent = level * 2 + 2;
get_op_string (e->e.expr.op), e->line);
_print_expr (dstr, e->e.alias.expr, level, id, next);
dasprintf (dstr, "%*se_%p -> \"e_%p\" [label=\"a\"];\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=\"o\"];\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,
"<alias>", 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)
{ {
int indent = level * 2 + 2; int indent = level * 2 + 2;
dstring_t *typestr = dstring_newstr();
if (e->e.expr.op != 'g' && e->e.expr.e1) if (e->e.expr.op != 'g' && e->e.expr.e1)
_print_expr (dstr, e->e.expr.e1, level, id, next); _print_expr (dstr, e->e.expr.e1, level, id, next);
if (e->e.expr.op == 'A') {
dstring_copystr (typestr, "\\n");
print_type_str (typestr, e->e.expr.type);
}
if (e->e.expr.op != 'r' || e->e.expr.e1) if (e->e.expr.op != 'r' || e->e.expr.e1)
dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e,
e->e.expr.e1); e->e.expr.e1);
dasprintf (dstr, "%*se_%p [label=\"%s%s\\n%d\"];\n", indent, "", e, dasprintf (dstr, "%*se_%p [label=\"%s\\n%d\"];\n", indent, "", e,
get_op_string (e->e.expr.op), typestr->str, e->line); get_op_string (e->e.expr.op), e->line);
dstring_delete (typestr);
} }
static void static void
@ -574,6 +580,7 @@ _print_expr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
[ex_value] = print_value, [ex_value] = print_value,
[ex_compound] = print_compound, [ex_compound] = print_compound,
[ex_memset] = print_memset, [ex_memset] = print_memset,
[ex_alias] = print_alias,
}; };
int indent = level * 2 + 2; int indent = level * 2 + 2;
@ -585,7 +592,7 @@ _print_expr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
return; return;
e->printid = id; e->printid = id;
if ((int) e->type < 0 || e->type > ex_memset || !print_funcs[e->type]) { if ((int) e->type < 0 || e->type >= ex_count || !print_funcs[e->type]) {
dasprintf (dstr, "%*se_%p [label=\"(bad expr type)\\n%d\"];\n", dasprintf (dstr, "%*se_%p [label=\"(bad expr type)\\n%d\"];\n",
indent, "", e, e->line); indent, "", e, e->line);
return; return;

View file

@ -258,6 +258,8 @@ get_type (expr_t *e)
return e->e.vector.type; return e->e.vector.type;
case ex_selector: case ex_selector:
return &type_SEL; return &type_SEL;
case ex_alias:
return e->e.alias.type;
case ex_count: case ex_count:
internal_error (e, "invalid expression"); internal_error (e, "invalid expression");
} }
@ -315,7 +317,7 @@ cast_error (expr_t *e, type_t *t1, type_t *t2)
print_type_str (s1, t1); print_type_str (s1, t1);
print_type_str (s2, t2); print_type_str (s2, t2);
e = error (e, "cannot cast from %s to %s", s1->str, s2->str); e = error (e, "cannot cast from %s to %s", s1->str, s2->str);
dstring_delete (s1); dstring_delete (s1);
dstring_delete (s2); dstring_delete (s2);
return e; return e;
@ -469,6 +471,12 @@ copy_expr (expr_t *e)
n->e.memset.val = copy_expr (e->e.memset.val); n->e.memset.val = copy_expr (e->e.memset.val);
n->e.memset.count = copy_expr (e->e.memset.count); n->e.memset.count = copy_expr (e->e.memset.count);
return n; return n;
case ex_alias:
n = new_expr ();
*n = *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_count: case ex_count:
break; break;
} }
@ -875,9 +883,8 @@ new_short_expr (short short_val)
int int
is_constant (expr_t *e) is_constant (expr_t *e)
{ {
while ((e->type == ex_uexpr || e->type == ex_expr) while (e->type == ex_alias) {
&& e->e.expr.op == 'A') { e = e->e.alias.expr;
e = e->e.expr.e1;
} }
if (e->type == ex_nil || e->type == ex_value || e->type == ex_labelref if (e->type == ex_nil || e->type == ex_value || e->type == ex_labelref
|| (e->type == ex_symbol && e->e.symbol->sy_type == sy_const) || (e->type == ex_symbol && e->e.symbol->sy_type == sy_const)
@ -1231,15 +1238,14 @@ is_pointer_val (expr_t *e)
expr_t * expr_t *
new_alias_expr (type_t *type, expr_t *expr) new_alias_expr (type_t *type, expr_t *expr)
{ {
expr_t *alias; if (expr->type == ex_alias) {
alias = new_unary_expr ('A', expr);
alias->e.expr.type = type;
//if (expr->type == ex_uexpr && expr->e.expr.op == 'A')
// bug (alias, "aliasing an alias expression");
if (expr->type == ex_expr && expr->e.expr.op == 'A') {
return new_offset_alias_expr (type, expr, 0); return new_offset_alias_expr (type, expr, 0);
} }
expr_t *alias = new_expr ();
alias->type = ex_alias;
alias->e.alias.type = type;
alias->e.alias.expr = expr;
alias->file = expr->file; alias->file = expr->file;
alias->line = expr->line; alias->line = expr->line;
return alias; return alias;
@ -1248,18 +1254,24 @@ new_alias_expr (type_t *type, expr_t *expr)
expr_t * expr_t *
new_offset_alias_expr (type_t *type, expr_t *expr, int offset) new_offset_alias_expr (type_t *type, expr_t *expr, int offset)
{ {
expr_t *alias; if (expr->type == ex_alias && expr->e.alias.offset) {
expr_t *ofs_expr = expr->e.alias.offset;
if (expr->type == ex_expr && expr->e.expr.op == 'A') {
expr_t *ofs_expr = expr->e.expr.e2;
expr = expr->e.expr.e1;
if (!is_constant (ofs_expr)) { if (!is_constant (ofs_expr)) {
internal_error (ofs_expr, "non-constant offset for alias expr"); internal_error (ofs_expr, "non-constant offset for alias expr");
} }
offset += expr_integer (ofs_expr); offset += expr_integer (ofs_expr);
if (expr->e.alias.expr->type == ex_alias) {
internal_error (expr, "alias expr of alias expr");
}
expr = expr->e.alias.expr;
} }
alias = new_binary_expr ('A', expr, new_integer_expr (offset));
alias->e.expr.type = type; expr_t *alias = new_expr ();
alias->type = ex_alias;
alias->e.alias.type = type;
alias->e.alias.expr = expr;
alias->e.alias.offset = new_integer_expr (offset);
alias->file = expr->file; alias->file = expr->file;
alias->line = expr->line; alias->line = expr->line;
return alias; return alias;
@ -1576,9 +1588,27 @@ has_function_call (expr_t *e)
case ex_uexpr: case ex_uexpr:
if (e->e.expr.op != 'g') if (e->e.expr.op != 'g')
return has_function_call (e->e.expr.e1); return has_function_call (e->e.expr.e1);
default:
return 0; return 0;
case ex_alias:
return has_function_call (e->e.alias.expr);
case ex_error:
case ex_state:
case ex_label:
case ex_labelref:
case ex_def:
case ex_symbol:
case ex_temp:
case ex_vector:
case ex_selector:
case ex_nil:
case ex_value:
case ex_compound:
case ex_memset:
return 0;
case ex_count:
break;
} }
internal_error (e, "invalid expression type");
} }
expr_t * expr_t *
@ -1683,6 +1713,7 @@ unary_expr (int op, expr_t *e)
case ex_bool: case ex_bool:
case ex_temp: case ex_temp:
case ex_vector: case ex_vector:
case ex_alias:
{ {
expr_t *n = new_unary_expr (op, e); expr_t *n = new_unary_expr (op, e);
@ -1766,6 +1797,7 @@ unary_expr (int op, expr_t *e)
case ex_symbol: case ex_symbol:
case ex_temp: case ex_temp:
case ex_vector: case ex_vector:
case ex_alias:
{ {
expr_t *n = new_unary_expr (op, e); expr_t *n = new_unary_expr (op, e);
@ -1842,6 +1874,7 @@ unary_expr (int op, expr_t *e)
case ex_symbol: case ex_symbol:
case ex_temp: case ex_temp:
case ex_vector: case ex_vector:
case ex_alias:
bitnot_expr: bitnot_expr:
if (options.code.progsversion == PROG_ID_VERSION) { if (options.code.progsversion == PROG_ID_VERSION) {
expr_t *n1 = new_integer_expr (-1); expr_t *n1 = new_integer_expr (-1);
@ -2364,16 +2397,6 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t)
e = e1->e.expr.e2; e = e1->e.expr.e2;
break; break;
} }
if (e1->e.expr.op == 'A') {
if (!t)
t = e1->e.expr.type;
if (e2) {
e2 = binary_expr ('+', e1->e.expr.e2, e2);
} else {
e2 = e1->e.expr.e2;
}
return address_expr (e1->e.expr.e1, e2, t);
}
return error (e1, "invalid type for unary &"); return error (e1, "invalid type for unary &");
case ex_uexpr: case ex_uexpr:
if (e1->e.expr.op == '.') { if (e1->e.expr.op == '.') {
@ -2384,11 +2407,6 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t)
} }
break; break;
} }
if (e1->e.expr.op == 'A') {
if (!t)
t = e1->e.expr.type;
return address_expr (e1->e.expr.e1, e2, t);
}
return error (e1, "invalid type for unary &"); return error (e1, "invalid type for unary &");
case ex_label: case ex_label:
return new_label_ref (&e1->e.label); return new_label_ref (&e1->e.label);
@ -2396,6 +2414,18 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t)
e = new_unary_expr ('&', e1); e = new_unary_expr ('&', e1);
e->e.expr.type = pointer_type (t); e->e.expr.type = pointer_type (t);
break; break;
case ex_alias:
if (!t) {
t = e1->e.alias.type;
}
if (e1->e.alias.offset) {
if (e2) {
e2 = binary_expr ('+', e1->e.alias.offset, e2);
} else {
e2 = e1->e.alias.offset;
}
}
return address_expr (e1->e.alias.expr, e2, t);
default: default:
return error (e1, "invalid type for unary &"); return error (e1, "invalid type for unary &");
} }
@ -2416,8 +2446,11 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t)
e = new_binary_expr ('&', e, e2); e = new_binary_expr ('&', e, e2);
} }
} }
if (e->type == ex_expr || e->type == ex_uexpr) if (e->type == ex_expr || e->type == ex_uexpr) {
e->e.expr.type = pointer_type (t); 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

@ -112,17 +112,13 @@ is_lvalue (const expr_t *expr)
if (expr->e.expr.op == '.') { if (expr->e.expr.op == '.') {
return 1; return 1;
} }
if (expr->e.expr.op == 'A') {
return is_lvalue (expr->e.expr.e1);
}
break; break;
case ex_alias:
return is_lvalue (expr->e.alias.expr);
case ex_uexpr: case ex_uexpr:
if (expr->e.expr.op == '.') { if (expr->e.expr.op == '.') {
return 1; return 1;
} }
if (expr->e.expr.op == 'A') {
return is_lvalue (expr->e.expr.e1);
}
break; break;
case ex_memset: case ex_memset:
case ex_compound: case ex_compound:

View file

@ -970,12 +970,11 @@ binary_expr (int op, expr_t *e1, expr_t *e2)
e1 = convert_vector (e1); e1 = convert_vector (e1);
// FIXME this is target-specific info and should not be in the // FIXME this is target-specific info and should not be in the
// expression tree // expression tree
if ((e1->type == ex_expr || e1->type == ex_uexpr) && e1->e.expr.op == 'A' if (e1->type == ex_alias && is_call (e1->e.alias.expr)) {
&& is_call (e1->e.expr.e1)) {
// move the alias expression inside the block so the following check // move the alias expression inside the block so the following check
// can detect the call and move the temp assignment into the block // can detect the call and move the temp assignment into the block
expr_t *block = e1->e.expr.e1; expr_t *block = e1->e.alias.expr;
e1->e.expr.e1 = block->e.block.result; e1->e.alias.expr = block->e.block.result;
block->e.block.result = e1; block->e.block.result = e1;
e1 = block; e1 = block;
} }

View file

@ -1202,11 +1202,11 @@ expr_alias (sblock_t *sblock, expr_t *e, operand_t **op)
def_t *def; def_t *def;
int offset = 0; int offset = 0;
if (e->type == ex_expr) { if (e->e.alias.offset) {
offset = expr_integer (e->e.expr.e2); offset = expr_integer (e->e.alias.offset);
} }
type = e->e.expr.type; type = e->e.alias.type;
sblock = statement_subexpr (sblock, e->e.expr.e1, &aop); sblock = statement_subexpr (sblock, e->e.alias.expr, &aop);
if (type_compatible (aop->type, type)) { if (type_compatible (aop->type, type)) {
//FIXME type_compatible??? shouldn't that be type_size ==? //FIXME type_compatible??? shouldn't that be type_size ==?
if (offset) { if (offset) {
@ -1268,9 +1268,6 @@ expr_expr (sblock_t *sblock, expr_t *e, operand_t **op)
case 'M': case 'M':
sblock = expr_move (sblock, e, op); sblock = expr_move (sblock, e, op);
break; break;
case 'A':
sblock = expr_alias (sblock, e, op);
break;
default: default:
opcode = convert_op (e->e.expr.op); opcode = convert_op (e->e.expr.op);
if (!opcode) if (!opcode)
@ -1338,9 +1335,6 @@ expr_uexpr (sblock_t *sblock, expr_t *e, operand_t **op)
case '.': case '.':
sblock = expr_deref (sblock, e, op); sblock = expr_deref (sblock, e, op);
break; break;
case 'A':
sblock = expr_alias (sblock, e, op);
break;
case 'C': case 'C':
sblock = expr_cast (sblock, e, op); sblock = expr_cast (sblock, e, op);
break; break;
@ -1529,6 +1523,7 @@ statement_subexpr (sblock_t *sblock, expr_t *e, operand_t **op)
[ex_nil] = expr_nil, [ex_nil] = expr_nil,
[ex_value] = expr_value, [ex_value] = expr_value,
[ex_selector] = expr_selector, [ex_selector] = expr_selector,
[ex_alias] = expr_alias,
}; };
if (!e) { if (!e) {
*op = 0; *op = 0;