mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-01 05:21:02 +00:00
[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:
parent
563de20208
commit
66528e34fc
8 changed files with 100 additions and 114 deletions
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
||||
///@}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 == '.') {
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue