[qfcc] Move .return handling into statements.c

The means that the actual call expression is not in the statement lint
of the enclosing block expression, but just its result, whether the call
is void or not. This actually simplifies several things, but most
importantly will make Ruamoko calls easier to implement.

The test is because I had some trouble with double-calls, and is how I
found the return-postop issue :P
This commit is contained in:
Bill Currie 2022-01-21 13:09:23 +09:00
parent 64da1b603a
commit 33a3f92503
6 changed files with 73 additions and 8 deletions

View file

@ -647,6 +647,7 @@ int is_math_op (int op) __attribute__((const));
int is_logic (int op) __attribute__((const));
int has_function_call (expr_t *e) __attribute__((pure));
int is_function_call (expr_t *e) __attribute__((pure));
int is_nil (expr_t *e) __attribute__((pure));
int is_string_val (expr_t *e) __attribute__((pure));

View file

@ -216,9 +216,10 @@ get_type (expr_t *e)
convert_name (e);
switch (e->type) {
case ex_branch:
case ex_labelref:
type = e->e.branch.ret_type;
break;
case ex_labelref:
return &type_void;
case ex_memset:
return e->e.memset.type;
case ex_error:
@ -504,6 +505,7 @@ copy_expr (expr_t *e)
n = new_expr ();
*n = *e;
n->e.branch.target = copy_expr (e->e.branch.target);
n->e.branch.index = copy_expr (e->e.branch.index);
n->e.branch.test = copy_expr (e->e.branch.test);
n->e.branch.args = copy_expr (e->e.branch.args);
return n;
@ -1658,6 +1660,12 @@ has_function_call (expr_t *e)
internal_error (e, "invalid expression type");
}
int
is_function_call (expr_t *e)
{
return e->type == ex_branch && e->e.branch.type == pr_branch_call;
}
expr_t *
asx_expr (int op, expr_t *e1, expr_t *e2)
{
@ -2116,12 +2124,7 @@ build_function_call (expr_t *fexpr, const type_t *ftype, expr_t *params)
append_expr (call, e);
}
e = expr_file_line (call_expr (fexpr, args, ftype->t.func.type), fexpr);
append_expr (call, e);
if (!is_void(ftype->t.func.type)) {
call->e.block.result = new_ret_expr (ftype->t.func.type);
} else if (options.traditional) {
call->e.block.result = new_ret_expr (&type_float);
}
call->e.block.result = e;
return call;
}

View file

@ -248,6 +248,9 @@ message_expr (expr_t *receiver, keywordarg_t *message)
if (call->type == ex_error)
return receiver;
call->e.block.result = new_ret_expr (return_type);
if (!is_function_call (call->e.block.result)) {
internal_error (call, "unexpected block result type");
}
call->e.block.result->e.branch.ret_type = return_type;
return call;
}

View file

@ -1071,6 +1071,9 @@ expr_call_v6p (sblock_t *sblock, expr_t *call, operand_t **op)
sblock = statement_subexpr (sblock, func, &s->opa);
s->opb = arguments[0];
s->opc = arguments[1];
if (op) {
*op = return_operand (call->e.branch.ret_type, call);
}
sblock_add_statement (sblock, s);
sblock->next = new_sblock ();
return sblock->next;
@ -1118,6 +1121,16 @@ expr_call (sblock_t *sblock, expr_t *call, operand_t **op)
return sblock->next;
}
static sblock_t *
expr_branch (sblock_t *sblock, expr_t *e, operand_t **op)
{
if (e->e.branch.type != pr_branch_call) {
internal_error (e, "unexpected branch type in expression: %d",
e->e.branch.type);
}
return expr_call (sblock, e, op);
}
static sblock_t *
statement_branch (sblock_t *sblock, expr_t *e)
{
@ -1618,6 +1631,7 @@ statement_subexpr (sblock_t *sblock, expr_t *e, operand_t **op)
[ex_alias] = expr_alias,
[ex_address] = expr_address,
[ex_assign] = expr_assign,
[ex_branch] = expr_branch,
};
if (!e) {
*op = 0;
@ -1804,6 +1818,11 @@ statement_block (sblock_t *sblock, expr_t *e)
sblock = sblock->next;
}
sblock = statement_slist (sblock, e->e.block.head);
if (e->e.block.is_call) {
// for a fuction call, the call expresion is in only the result, not
// the actual block
sblock = statement_slist (sblock, e->e.block.result);
}
return sblock;
}

View file

@ -53,6 +53,7 @@ test_progs_dat=\
tools/qfcc/test/structstruct.dat \
tools/qfcc/test/swap.dat \
tools/qfcc/test/triangle.dat \
tools/qfcc/test/twice-called.dat \
tools/qfcc/test/typedef.dat \
tools/qfcc/test/typelinker.dat \
tools/qfcc/test/unaryminus.dat \
@ -605,6 +606,16 @@ tools/qfcc/test/triangle.run: $(qfcc_test_run_deps)
include $(triangle_dep) # am--include-marker
r_depfiles_remade += $(triangle_dep)
tools_qfcc_test_twice_called_dat_SOURCES=tools/qfcc/test/twice-called.r
twice_called_obj=$(tools_qfcc_test_twice_called_dat_SOURCES:.r=.o)
twice_called_dep=$(call qcautodep,$(tools_qfcc_test_twice_called_dat_SOURCES))
tools/qfcc/test/twice-called.dat$(EXEEXT): $(twice_called_obj) $(QFCC_DEP)
$(V_QFCCLD)$(QLINK) -o $@ $(twice_called_obj)
tools/qfcc/test/twice-called.run: $(qfcc_test_run_deps)
@$(top_srcdir)/tools/qfcc/test/build-run $@ 100000 100000 1.00005 50002.4961
include $(twice_called_dep) # am--include-marker
r_depfiles_remade += $(twice_called_dep)
tools_qfcc_test_typedef_dat_SOURCES=tools/qfcc/test/typedef.r
typedef_obj=$(tools_qfcc_test_typedef_dat_SOURCES:.r=.o)
typedef_dep=$(call qcautodep,$(tools_qfcc_test_typedef_dat_SOURCES))

View file

@ -0,0 +1,28 @@
#include "test-harness.h"
int counter;
int
function (void)
{
return ++counter;
}
int
main (void)
{
int ret = 0;
counter = 0;
//function ();
//if (counter != 1) {
//printf ("discarded return not called only once\n");
// ret = 1;
//}
counter = 0;
printf ("function: %d\n", function ());
if (counter != 1) {
//printf ("used return not called only once\n");
ret = 1;
}
return ret;
}