mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 15:22:04 +00:00
[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:
parent
9b81d27f1a
commit
93840d9892
2 changed files with 46 additions and 1 deletions
|
@ -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);
|
||||
|
|
|
@ -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';
|
||||
|
|
Loading…
Reference in a new issue