From 66528e34fc9dcbf2220ad8a3754a9cb9dd1e264a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 9 Jan 2022 16:28:08 +0900 Subject: [PATCH] [qfcc] Give return expressions their own type Very simple for now (just the return value if not a void return), but that's the last of the statements masquerading as expressions. --- tools/qfcc/include/expr.h | 6 ++ tools/qfcc/include/expr_names.h | 1 + tools/qfcc/source/constfold.c | 2 - tools/qfcc/source/dot_expr.c | 19 ++++- tools/qfcc/source/expr.c | 45 +++++++---- tools/qfcc/source/expr_assign.c | 1 + tools/qfcc/source/qp-parse.y | 2 +- tools/qfcc/source/statements.c | 138 +++++++++++--------------------- 8 files changed, 100 insertions(+), 114 deletions(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index ff8c25cf7..59ac358e4 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -233,6 +233,10 @@ typedef struct { struct type_s *ret_type; ///< void for non-call } ex_branch_t; +typedef struct { + struct expr_s *ret_val; +} ex_return_t; + #define POINTER_VAL(p) (((p).def ? (p).def->offset : 0) + (p).val) typedef struct expr_s { @@ -263,6 +267,7 @@ typedef struct expr_s { ex_address_t address; ///< alias expr params ex_assign_t assign; ///< assignment expr params ex_branch_t branch; ///< branch expr params + ex_return_t retrn; ///< return expr params struct type_s *nil; ///< type for nil if known } e; } expr_t; @@ -680,6 +685,7 @@ 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); expr_t *new_assign_expr (expr_t *dst, expr_t *src); +expr_t *new_return_expr (expr_t *ret_val); /** 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 fab5c0fdb..08285c94a 100644 --- a/tools/qfcc/include/expr_names.h +++ b/tools/qfcc/include/expr_names.h @@ -58,5 +58,6 @@ EX_EXPR(alias) ///< view expression as different type (::ex_alias_t) EX_EXPR(address) ///< address of an lvalue expression (::ex_address_t) EX_EXPR(assign) ///< assignment of src expr to dst expr (::ex_assing_t) EX_EXPR(branch) ///< branch expression (::ex_branch_t) +EX_EXPR(return) ///< return expression (::ex_return_t) ///@} diff --git a/tools/qfcc/source/constfold.c b/tools/qfcc/source/constfold.c index 92ae4c330..6ee98f70e 100644 --- a/tools/qfcc/source/constfold.c +++ b/tools/qfcc/source/constfold.c @@ -1680,8 +1680,6 @@ fold_constants (expr_t *e) return e; } op = e->e.expr.op; - if (op == 'r') - return e; t1 = extract_type (e1); if (t1 >= ev_type_count || !do_unary_op[t1]) { print_expr (e); diff --git a/tools/qfcc/source/dot_expr.c b/tools/qfcc/source/dot_expr.c index a29920881..a66009bd5 100644 --- a/tools/qfcc/source/dot_expr.c +++ b/tools/qfcc/source/dot_expr.c @@ -89,7 +89,6 @@ get_op_string (int op) case SHL: return "<<"; case SHR: return ">>"; case '.': return "."; - case 'r': return ""; case 'C': return ""; default: return "unknown"; @@ -401,14 +400,25 @@ print_branch (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) } } +static void +print_return (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) +{ + int indent = level * 2 + 2; + + if (e->e.retrn.ret_val) { + dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, + e->e.retrn.ret_val); + } + dasprintf (dstr, "%*se_%p [label=\"%s\\n%d\"];\n", indent, "", e, + "return", e->line); +} + static void print_uexpr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) { int indent = level * 2 + 2; - if (e->e.expr.op != 'r' || e->e.expr.e1) - dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, - e->e.expr.e1); + dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, e->e.expr.e1); dasprintf (dstr, "%*se_%p [label=\"%s\\n%d\"];\n", indent, "", e, get_op_string (e->e.expr.op), e->line); } @@ -645,6 +655,7 @@ _print_expr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) [ex_address] = print_address, [ex_assign] = print_assign, [ex_branch] = print_branch, + [ex_return] = print_return, }; int indent = level * 2 + 2; diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 06f4ba944..ae3f919dc 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -221,10 +221,12 @@ get_type (expr_t *e) break; case ex_memset: return e->e.memset.type; - case ex_label: case ex_error: + case ex_return: + internal_error (e, "unexpected expression type"); + case ex_label: case ex_compound: - return 0; // something went very wrong + return 0; case ex_bool: if (options.code.progsversion == PROG_ID_VERSION) return &type_float; @@ -504,6 +506,11 @@ copy_expr (expr_t *e) n->e.branch.test = copy_expr (e->e.branch.test); n->e.branch.args = copy_expr (e->e.branch.args); return n; + case ex_return: + n = new_expr (); + *n = *e; + n->e.retrn.ret_val = copy_expr (n->e.retrn.ret_val); + return n; case ex_count: break; } @@ -1325,6 +1332,15 @@ new_assign_expr (expr_t *dst, expr_t *src) return addr; } +expr_t * +new_return_expr (expr_t *ret_val) +{ + expr_t *retrn = new_expr (); + retrn->type = ex_return; + retrn->e.retrn.ret_val = ret_val; + return retrn; +} + static expr_t * param_expr (const char *name, type_t *type) { @@ -1619,6 +1635,8 @@ has_function_call (expr_t *e) return 0; } return has_function_call (e->e.branch.test); + case ex_return: + return has_function_call (e->e.retrn.ret_val); case ex_error: case ex_state: case ex_label: @@ -1716,7 +1734,8 @@ unary_expr (int op, expr_t *e) case ex_compound: case ex_memset: case ex_selector: - internal_error (e, 0); + case ex_return: + internal_error (e, "unexpected expression type"); case ex_uexpr: if (e->e.expr.op == '-') { return e->e.expr.e1; @@ -1816,7 +1835,8 @@ unary_expr (int op, expr_t *e) case ex_compound: case ex_memset: case ex_selector: - internal_error (e, 0); + case ex_return: + internal_error (e, "unexpected expression type"); case ex_bool: return new_bool_expr (e->e.bool.false_list, e->e.bool.true_list, e); @@ -1894,7 +1914,8 @@ unary_expr (int op, expr_t *e) case ex_compound: case ex_memset: case ex_selector: - internal_error (e, 0); + case ex_return: + internal_error (e, "unexpected expression type"); case ex_uexpr: if (e->e.expr.op == '~') return e->e.expr.e1; @@ -2222,7 +2243,7 @@ return_expr (function_t *f, expr_t *e) } // the traditional check above may have set e if (!e) { - return new_unary_expr ('r', 0); + return new_return_expr (0); } } @@ -2279,7 +2300,7 @@ return_expr (function_t *f, expr_t *e) if (e->type == ex_block) { e->e.block.result->rvalue = 1; } - return new_unary_expr ('r', e); + return new_return_expr (e); } expr_t * @@ -2471,16 +2492,6 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t) e1->e.expr.e1, e1->e.expr.e2); break; } - if (e1->e.expr.op == 'm') { - // direct move, so obtain the address of the source - e = address_expr (e1->e.expr.e2, 0, t); - break; - } - if (e1->e.expr.op == 'M') { - // indirect move, so we already have the address of the source - e = e1->e.expr.e2; - break; - } return error (e1, "invalid type for unary &"); case ex_uexpr: if (e1->e.expr.op == '.') { diff --git a/tools/qfcc/source/expr_assign.c b/tools/qfcc/source/expr_assign.c index ed23270c1..a961e113d 100644 --- a/tools/qfcc/source/expr_assign.c +++ b/tools/qfcc/source/expr_assign.c @@ -137,6 +137,7 @@ is_lvalue (const expr_t *expr) case ex_value: case ex_error: case ex_selector: + case ex_return: break; case ex_count: internal_error (expr, "invalid expression"); diff --git a/tools/qfcc/source/qp-parse.y b/tools/qfcc/source/qp-parse.y index 59ddaceec..b45e6d0ee 100644 --- a/tools/qfcc/source/qp-parse.y +++ b/tools/qfcc/source/qp-parse.y @@ -270,7 +270,7 @@ subprogram_declaration } declarations compound_statement ';' { - append_expr ($5, new_unary_expr ('r', 0)); + append_expr ($5, new_return_expr (0)); build_code_function ($1, 0, $5); current_symtab = current_symtab->parent; current_storage = $3; diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 76caa4eaf..1c2cbc965 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -963,35 +963,6 @@ dereference_dst: return sblock; } -static sblock_t * -expr_move (sblock_t *sblock, expr_t *e, operand_t **op) -{ - statement_t *s; - type_t *type = e->e.expr.type; - expr_t *dst_expr = e->e.expr.e1; - expr_t *src_expr = e->e.expr.e2; - expr_t *size_expr; - operand_t *dst = 0; - operand_t *src = 0; - operand_t *size = 0; - - if (!op) - op = &dst; - size_expr = new_short_expr (type_size (type)); - sblock = statement_subexpr (sblock, dst_expr, op); - dst = *op; - sblock = statement_subexpr (sblock, src_expr, &src); - sblock = statement_subexpr (sblock, size_expr, &size); - s = new_statement (e->e.expr.op == 'm' ? st_move : st_ptrmove, - convert_op (e->e.expr.op), e); - s->opa = src; - s->opb = size; - s->opc = dst; - sblock_add_statement (sblock, s); - - return sblock; -} - static sblock_t * vector_call (sblock_t *sblock, expr_t *earg, expr_t *param, int ind, operand_t **op) @@ -1119,6 +1090,33 @@ statement_branch (sblock_t *sblock, expr_t *e) return sblock->next; } +static sblock_t * +statement_return (sblock_t *sblock, expr_t *e) +{ + const char *opcode; + statement_t *s; + + debug (e, "RETURN"); + opcode = ""; + if (!e->e.retrn.ret_val) { + if (options.code.progsversion != PROG_ID_VERSION) { + opcode = ""; + } else { + e->e.retrn.ret_val = new_float_expr (0); + } + } + s = new_statement (st_func, opcode, e); + if (e->e.retrn.ret_val) { + s->opa = return_operand (get_type (e->e.retrn.ret_val), e); + sblock = statement_subexpr (sblock, e->e.retrn.ret_val, &s->opa); + } + sblock_add_statement (sblock, s); + sblock->next = new_sblock (); + sblock = sblock->next; + + return sblock; +} + static statement_t * lea_statement (operand_t *pointer, operand_t *offset, expr_t *e) { @@ -1266,24 +1264,17 @@ expr_expr (sblock_t *sblock, expr_t *e, operand_t **op) const char *opcode; statement_t *s; - switch (e->e.expr.op) { - case 'm': - case 'M': - sblock = expr_move (sblock, e, op); - break; - default: - opcode = convert_op (e->e.expr.op); - if (!opcode) - internal_error (e, "ice ice baby"); - s = new_statement (st_expr, opcode, e); - sblock = statement_subexpr (sblock, e->e.expr.e1, &s->opa); - sblock = statement_subexpr (sblock, e->e.expr.e2, &s->opb); - if (!*op) - *op = temp_operand (e->e.expr.type, e); - s->opc = *op; - sblock_add_statement (sblock, s); - break; - } + opcode = convert_op (e->e.expr.op); + if (!opcode) + internal_error (e, "ice ice baby"); + s = new_statement (st_expr, opcode, e); + sblock = statement_subexpr (sblock, e->e.expr.e1, &s->opa); + sblock = statement_subexpr (sblock, e->e.expr.e2, &s->opb); + if (!*op) + *op = temp_operand (e->e.expr.type, e); + s->opc = *op; + sblock_add_statement (sblock, s); + return sblock; } @@ -1718,55 +1709,21 @@ statement_block (sblock_t *sblock, expr_t *e) static sblock_t * statement_expr (sblock_t *sblock, expr_t *e) { - switch (e->e.expr.op) { - case 'm': - case 'M': - sblock = expr_move (sblock, e, 0); - break; - default: - if (e->e.expr.op < 256) - debug (e, "e %c", e->e.expr.op); - else - debug (e, "e %d", e->e.expr.op); - if (options.warnings.executable) - warning (e, "Non-executable statement;" - " executing programmer instead."); - } + if (e->e.expr.op < 256) + debug (e, "e %c", e->e.expr.op); + else + debug (e, "e %d", e->e.expr.op); + if (options.warnings.executable) + warning (e, "Non-executable statement; executing programmer instead."); return sblock; } static sblock_t * statement_uexpr (sblock_t *sblock, expr_t *e) { - const char *opcode; - statement_t *s; - - switch (e->e.expr.op) { - case 'r': - debug (e, "RETURN"); - opcode = ""; - if (!e->e.expr.e1) { - if (options.code.progsversion != PROG_ID_VERSION) { - opcode = ""; - } else { - e->e.expr.e1 = new_float_expr (0); - } - } - s = new_statement (st_func, opcode, e); - if (e->e.expr.e1) { - s->opa = return_operand (get_type (e->e.expr.e1), e); - sblock = statement_subexpr (sblock, e->e.expr.e1, &s->opa); - } - sblock_add_statement (sblock, s); - sblock->next = new_sblock (); - sblock = sblock->next; - break; - default: - debug (e, "e ue %d", e->e.expr.op); - if (options.warnings.executable) - warning (e, "Non-executable statement;" - " executing programmer instead."); - } + debug (e, "e ue %d", e->e.expr.op); + if (options.warnings.executable) + warning (e, "Non-executable statement; executing programmer instead."); return sblock; } @@ -1830,6 +1787,7 @@ statement_slist (sblock_t *sblock, expr_t *e) [ex_memset] = statement_memset, [ex_assign] = statement_assign, [ex_branch] = statement_branch, + [ex_return] = statement_return, }; for (/**/; e; e = e->next) {