From fa482e8ee5a8bd5e2e6bc03062bc801b51dd9dbf Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 8 Jan 2022 16:52:24 +0900 Subject: [PATCH] [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. --- tools/qfcc/include/expr.h | 10 +++++ tools/qfcc/include/expr_names.h | 3 +- tools/qfcc/source/constfold.c | 8 ++-- tools/qfcc/source/dot_expr.c | 22 +++++++++++ tools/qfcc/source/expr.c | 65 ++++++++++++++++++++------------- tools/qfcc/source/expr_assign.c | 2 + tools/qfcc/source/method.c | 4 +- tools/qfcc/source/statements.c | 30 ++++++++------- 8 files changed, 99 insertions(+), 45 deletions(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 817c82e7b..5debb0058 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -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. diff --git a/tools/qfcc/include/expr_names.h b/tools/qfcc/include/expr_names.h index a37355bcc..0842c2b2b 100644 --- a/tools/qfcc/include/expr_names.h +++ b/tools/qfcc/include/expr_names.h @@ -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) ///@} diff --git a/tools/qfcc/source/constfold.c b/tools/qfcc/source/constfold.c index 497f51642..76c8c74fc 100644 --- a/tools/qfcc/source/constfold.c +++ b/tools/qfcc/source/constfold.c @@ -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; } diff --git a/tools/qfcc/source/dot_expr.c b/tools/qfcc/source/dot_expr.c index feaf3defd..32ceea58c 100644 --- a/tools/qfcc/source/dot_expr.c +++ b/tools/qfcc/source/dot_expr.c @@ -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; diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 7f1424cb0..257eeed17 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -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; diff --git a/tools/qfcc/source/expr_assign.c b/tools/qfcc/source/expr_assign.c index 80c95d1dc..eae003bc9 100644 --- a/tools/qfcc/source/expr_assign.c +++ b/tools/qfcc/source/expr_assign.c @@ -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; diff --git a/tools/qfcc/source/method.c b/tools/qfcc/source/method.c index 55a4f2344..134f1cc64 100644 --- a/tools/qfcc/source/method.c +++ b/tools/qfcc/source/method.c @@ -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; } diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index b34b201f0..205c22c3e 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -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;