From a3c37201b2d493873578540965844323785ca467 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 3 Feb 2022 14:41:46 +0900 Subject: [PATCH] [qfcc] Emit constant pointers as direct def references When possible, of course. However, this tightens up struct and constant index array accesses, and avoids issues with flow analysis losing track of the def (such trucking is something I want to do, but haven't decided out to get the information out to the right statements). --- tools/qfcc/source/statements.c | 74 +++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 11 deletions(-) diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 7fed3cef0..aaba453ff 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -947,7 +947,7 @@ expr_assign (sblock_t *sblock, expr_t *e, operand_t **op) operand_t *ofs = 0; pr_ushort_t mode = 0; // assign const char *opcode = "assign"; - st_type_t type; + st_type_t type = st_assign; if (src_expr->type == ex_assign) { sblock = statement_subexpr (sblock, src_expr, &src); @@ -983,15 +983,18 @@ expr_assign (sblock_t *sblock, expr_t *e, operand_t **op) sblock = statement_subexpr (sblock, src_expr, &src); } } - type = st_assign; if (0) { dereference_dst: // dst_expr is a dereferenced pointer, so need to get its addressing // parameters (base and offset) and switch to storep instructions. sblock = addressing_mode (sblock, dst_expr, &dst, &ofs, &mode); - opcode = "store"; - type = st_ptrassign; + if (mode != 0) { + opcode = "store"; + type = st_ptrassign; + } else { + ofs = 0; + } } if (op) { *op = src; @@ -1290,11 +1293,45 @@ static sblock_t * ptr_addressing_mode (sblock_t *sblock, expr_t *ref, operand_t **base, operand_t **offset, pr_ushort_t *mode) { - if (!is_ptr (get_type (ref))) { + type_t *type = get_type (ref); + if (!is_ptr (type)) { internal_error (ref, "expected pointer in ref"); } - if (ref->type != ex_alias || ref->e.alias.offset) { + if (ref->type == ex_address + && (!ref->e.address.offset || is_constant (ref->e.address.offset)) + && ref->e.address.lvalue->type == ex_alias + && (!ref->e.address.lvalue->e.alias.offset + || is_constant (ref->e.address.lvalue->e.alias.offset))) { + expr_t *lvalue = ref->e.address.lvalue; + expr_t *offs = ref->e.address.offset; + expr_t *alias; + if (lvalue->e.alias.offset) { + if (offs) { + offs = binary_expr ('+', offs, lvalue->e.alias.offset); + } else { + offs = lvalue->e.alias.offset; + } + } + type = type->t.fldptr.type; + if (offs) { + expr_t *lv = lvalue->e.alias.expr; + type_t *lvtype = get_type (lv); + int o = expr_int (offs); + if (o < 0 || o + type_size (type) > type_size (lvtype)) { + // not a valid offset for the type, which technically should + // be an error, but there may be legitimate reasons for doing + // such pointer shenanigans + goto just_a_pointer; + } + alias = new_offset_alias_expr (type, lv, expr_int (offs)); + } else { + alias = new_alias_expr (type, lvalue->e.alias.expr); + } + expr_file_line (alias, ref); + return addressing_mode (sblock, alias, base, offset, mode); + } else if (ref->type != ex_alias || ref->e.alias.offset) { // probably just a pointer +just_a_pointer: sblock = statement_subexpr (sblock, ref, base); *offset = short_operand (0, ref); *mode = 2; // mode C: ptr + constant index @@ -1468,6 +1505,15 @@ load_statement (operand_t *ptr, operand_t *offs, operand_t *op, expr_t *e) return s; } +static statement_t * +assign_statement (operand_t *dst, operand_t *src, expr_t *e) +{ + statement_t *s = new_statement (st_assign, "assign", e); + s->opa = dst; + s->opc = src; + return s; +} + static sblock_t * expr_deref (sblock_t *sblock, expr_t *deref, operand_t **op) { @@ -1476,10 +1522,21 @@ expr_deref (sblock_t *sblock, expr_t *deref, operand_t **op) operand_t *base = 0; operand_t *offset = 0; pr_ushort_t mode; + statement_t *s; sblock = addressing_mode (sblock, deref, &base, &offset, &mode); + if (!*op) { + *op = temp_operand (load_type, deref); + } + switch (mode) { + case 0://direct def access + // FIXME should check that offset is 0, but currently, + // addressing_mode always sets offset to 0 for mode 0 + s = assign_statement (*op, base, deref); + sblock_add_statement (sblock, s); + return sblock; case 1://entity.field case 2://const indexed pointer case 3://var indexed pointer @@ -1488,11 +1545,6 @@ expr_deref (sblock_t *sblock, expr_t *deref, operand_t **op) internal_error (deref, "unexpected addressing mode: %d", mode); } - if (!*op) { - *op = temp_operand (load_type, deref); - } - - statement_t *s; if (low_level_type (load_type) == ev_void) { s = lea_statement (base, offset, ptr_expr); sblock_add_statement (sblock, s);