[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.
This commit is contained in:
Bill Currie 2022-01-09 16:28:08 +09:00
parent 563de20208
commit 66528e34fc
8 changed files with 100 additions and 114 deletions

View file

@ -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.

View file

@ -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)
///@}

View file

@ -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);

View file

@ -89,7 +89,6 @@ get_op_string (int op)
case SHL: return "<<";
case SHR: return ">>";
case '.': return ".";
case 'r': return "<return>";
case 'C': return "<cast>";
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;

View file

@ -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 == '.') {

View file

@ -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");

View file

@ -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 = $<storage>3;

View file

@ -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 = "<RETURN>";
if (!e->e.retrn.ret_val) {
if (options.code.progsversion != PROG_ID_VERSION) {
opcode = "<RETURN_V>";
} 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 = "<RETURN>";
if (!e->e.expr.e1) {
if (options.code.progsversion != PROG_ID_VERSION) {
opcode = "<RETURN_V>";
} 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) {