[qfcc] Handle Ruamoko's call return destination

Since the call instruction in the Ruamoko ISA specifies the destination
of the return value of the called function, it is much like any
expression type instruction in that the def referenced by its c operand
is both defined and killed by the instruction. However, unlike other
instructions, it really has many pseudo-operands: the arguments placed
on the stack. The problem is that when one of the arguments is also the
destination of the return value, the dags code wants to use the stack
argument as it was the last use of the real argument. Thus, instead of
using the value of the child node for the result, use the value label
attached to the call node (there should be only one such label).

This fixes iterfunc, typedef, zerolinker and vkgen when optimizing. Now
all but the double tests and return postop tests pass (and the retun
postop test is not related to the Ruamoko ISA, so fails either way).
This commit is contained in:
Bill Currie 2022-02-01 21:46:28 +09:00
parent 9b81d27f1a
commit 93840d9892
2 changed files with 46 additions and 1 deletions

View file

@ -1135,6 +1135,43 @@ generate_memsetps (dag_t *dag, sblock_t *block, dagnode_t *dagnode)
return dst;
}
static operand_t *
generate_call (dag_t *dag, sblock_t *block, dagnode_t *dagnode)
{
set_iter_t *var_iter;
daglabel_t *var = 0;
operand_t *operands[3] = {0, 0, 0};
statement_t *st;
operand_t *dst;
operands[0] = make_operand (dag, block, dagnode, 0);
if (dagnode->children[1]) {
operands[1] = make_operand (dag, block, dagnode, 1);
}
dst = operands[0];
for (var_iter = set_first (dagnode->identifiers); var_iter;
var_iter = set_next (var_iter)) {
if (var) {
internal_error (var->expr, "more than one return value for call");
}
var = dag->labels[var_iter->element];
operands[2] = var->op;
dst = operands[2];
st = build_statement ("call", operands, var->expr);
sblock_add_statement (block, st);
}
if (var_iter) {
set_del_iter (var_iter);
}
if (!var) {
// void call or return value ignored, still have to call
operands[2] = make_operand (dag, block, dagnode, 2);
st = build_statement ("call", operands, dagnode->label->expr);
sblock_add_statement (block, st);
}
return dst;
}
static operand_t *
generate_assignments (dag_t *dag, sblock_t *block, operand_t *src,
set_iter_t *var_iter, type_t *type)
@ -1222,8 +1259,13 @@ dag_gencode (dag_t *dag, sblock_t *block, dagnode_t *dagnode)
case st_ptrmemset:
dst = generate_memsetps (dag, block, dagnode);
break;
case st_state:
case st_func:
if (!strcmp (dagnode->label->opcode, "call")) {
dst = generate_call (dag, block, dagnode);
break;
}
// fallthrough
case st_state:
for (i = 0; i < 3; i++)
if (dagnode->children[i])
operands[i] = make_operand (dag, block, dagnode, i);

View file

@ -1290,6 +1290,9 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill,
flow_add_op_var (def, s->opc, 0);
// don't want old argument processing
calln = -1;
if (operands && s->opc->op_type != op_value) {
operands[0] = s->opc;
}
} else if (strncmp (s->opcode, "call", 4) == 0) {
start = 0;
calln = s->opcode[5] - '0';