mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-22 20:41:20 +00:00
[qfcc] Switch internal statement format to ruamoko
For the most part, it wasn't too bad as it's just a rotation of the operands for some instructions (store, assign, branch), but dealing with all the direct accesses to specific operands was a small pain. I am very glad I made all those automated tests :)
This commit is contained in:
parent
875d4dc7cf
commit
a5a8017220
4 changed files with 94 additions and 54 deletions
|
@ -1116,12 +1116,12 @@ generate_assignments (dag_t *dag, sblock_t *block, operand_t *src,
|
|||
operand_t *operands[3] = {0, 0, 0};
|
||||
daglabel_t *var;
|
||||
|
||||
operands[0] = fix_op_type (src, type);
|
||||
operands[2] = fix_op_type (src, type);
|
||||
for ( ; var_iter; var_iter = set_next (var_iter)) {
|
||||
var = dag->labels[var_iter->element];
|
||||
operands[1] = fix_op_type (var->op, type);
|
||||
operands[0] = fix_op_type (var->op, type);
|
||||
if (!dst)
|
||||
dst = operands[1];
|
||||
dst = operands[0];
|
||||
|
||||
st = build_statement ("assign", operands, var->expr);
|
||||
sblock_add_statement (block, st);
|
||||
|
@ -1172,15 +1172,15 @@ dag_gencode (dag_t *dag, sblock_t *block, dagnode_t *dagnode)
|
|||
case st_assign:
|
||||
internal_error (0, "unexpected assignment node");
|
||||
case st_ptrassign:
|
||||
operands[0] = make_operand (dag, block, dagnode, 0);
|
||||
operands[2] = make_operand (dag, block, dagnode, 0);
|
||||
operands[0] = make_operand (dag, block, dagnode, 2);
|
||||
if (dagnode->children[1])
|
||||
operands[1] = make_operand (dag, block, dagnode, 1);
|
||||
if (dagnode->children[2])
|
||||
operands[2] = make_operand (dag, block, dagnode, 2);
|
||||
st = build_statement (dagnode->label->opcode, operands,
|
||||
dagnode->label->expr);
|
||||
sblock_add_statement (block, st);
|
||||
// the source location is suitable for use in other nodes
|
||||
dst = operands[0];
|
||||
dst = operands[2];
|
||||
break;
|
||||
case st_move:
|
||||
dst = generate_moves (dag, block, dagnode);
|
||||
|
@ -1207,6 +1207,8 @@ dag_gencode (dag_t *dag, sblock_t *block, dagnode_t *dagnode)
|
|||
operands[0] = make_operand (dag, block, dagnode, 0);
|
||||
if (dagnode->children[1])
|
||||
operands[1] = make_operand (dag, block, dagnode, 1);
|
||||
if (dagnode->children[2])
|
||||
operands[2] = make_operand (dag, block, dagnode, 2);
|
||||
st = build_statement (dagnode->label->opcode, operands,
|
||||
dagnode->label->expr);
|
||||
sblock_add_statement (block, st);
|
||||
|
|
|
@ -183,20 +183,36 @@ static void
|
|||
emit_statement (statement_t *statement)
|
||||
{
|
||||
const char *opcode = statement->opcode;
|
||||
operand_t *op_a, *op_b, *op_c;
|
||||
def_t *def_a, *def_b, *def_c;
|
||||
instruction_t *inst;
|
||||
dstatement_t *s;
|
||||
|
||||
def_a = get_operand_def (statement->expr, statement->opa);
|
||||
if (options.code.progsversion < PROG_VERSION
|
||||
&& (strcmp (statement->opcode, "store") == 0
|
||||
|| strcmp (statement->opcode, "assign") == 0
|
||||
|| statement_is_cond (statement))) {
|
||||
// the operands for assign, store and branch instructions are rotated
|
||||
// when comparing v6/v6p and ruamoko
|
||||
op_a = statement->opc;
|
||||
op_b = statement->opa;
|
||||
op_c = statement->opb;
|
||||
} else {
|
||||
op_a = statement->opa;
|
||||
op_b = statement->opb;
|
||||
op_c = statement->opc;
|
||||
}
|
||||
def_a = get_operand_def (statement->expr, op_a);
|
||||
use_tempop (statement->opa, statement->expr);
|
||||
def_b = get_operand_def (statement->expr, statement->opb);
|
||||
def_b = get_operand_def (statement->expr, op_b);
|
||||
use_tempop (statement->opb, statement->expr);
|
||||
def_c = get_operand_def (statement->expr, statement->opc);
|
||||
def_c = get_operand_def (statement->expr, op_c);
|
||||
use_tempop (statement->opc, statement->expr);
|
||||
inst = opcode_find (opcode, statement->opa, statement->opb, statement->opc);
|
||||
inst = opcode_find (opcode, op_a, op_b, op_c);
|
||||
|
||||
if (!inst) {
|
||||
print_expr (statement->expr);
|
||||
printf ("%d ", pr.code->size);
|
||||
print_statement (statement);
|
||||
internal_error (statement->expr, "ice ice baby");
|
||||
}
|
||||
|
@ -225,9 +241,9 @@ emit_statement (statement_t *statement)
|
|||
add_statement_def_ref (def_b, s, 1);
|
||||
add_statement_def_ref (def_c, s, 2);
|
||||
|
||||
add_statement_op_ref (statement->opa, s, 0);
|
||||
add_statement_op_ref (statement->opb, s, 1);
|
||||
add_statement_op_ref (statement->opc, s, 2);
|
||||
add_statement_op_ref (op_a, s, 0);
|
||||
add_statement_op_ref (op_b, s, 1);
|
||||
add_statement_op_ref (op_c, s, 2);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -1149,9 +1149,11 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill,
|
|||
operand_t *operands[FLOW_OPERANDS])
|
||||
{
|
||||
int i, start, calln = -1;
|
||||
operand_t *src_op = 0;
|
||||
operand_t *res_op = 0;
|
||||
operand_t *aux_op1 = 0;
|
||||
operand_t *aux_op2 = 0;
|
||||
operand_t *aux_op3 = 0;
|
||||
|
||||
if (use) {
|
||||
set_empty (use);
|
||||
|
@ -1191,11 +1193,11 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill,
|
|||
}
|
||||
break;
|
||||
case st_assign:
|
||||
flow_add_op_var (def, s->opb, 0);
|
||||
flow_add_op_var (use, s->opa, 1);
|
||||
flow_add_op_var (def, s->opa, 0);
|
||||
flow_add_op_var (use, s->opc, 1);
|
||||
if (operands) {
|
||||
operands[0] = s->opb;
|
||||
operands[1] = s->opa;
|
||||
operands[0] = s->opa;
|
||||
operands[1] = s->opc;
|
||||
}
|
||||
break;
|
||||
case st_ptrassign:
|
||||
|
@ -1205,23 +1207,28 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill,
|
|||
case st_ptrmemset:
|
||||
flow_add_op_var (use, s->opa, 1);
|
||||
flow_add_op_var (use, s->opb, 1);
|
||||
aux_op1 = s->opb;
|
||||
if (!strcmp (s->opcode, "move")
|
||||
|| !strcmp (s->opcode, "memset")) {
|
||||
flow_add_op_var (def, s->opc, 0);
|
||||
src_op = s->opa;
|
||||
res_op = s->opc;
|
||||
} else if (!strcmp (s->opcode, "movep")) {
|
||||
flow_add_op_var (use, s->opc, 0);
|
||||
aux_op2 = flow_analyze_pointer_operand (s->opa, use);
|
||||
aux_op3 = flow_analyze_pointer_operand (s->opa, use);
|
||||
res_op = flow_analyze_pointer_operand (s->opc, def);
|
||||
aux_op1 = s->opc;
|
||||
src_op = s->opa;
|
||||
aux_op2 = s->opc;
|
||||
} else if (!strcmp (s->opcode, "memsetp")) {
|
||||
flow_add_op_var (use, s->opc, 0);
|
||||
res_op = flow_analyze_pointer_operand (s->opc, def);
|
||||
aux_op1 = s->opc;
|
||||
src_op = s->opa;
|
||||
aux_op2 = s->opc;
|
||||
} else if (!strcmp (s->opcode, "store")) {
|
||||
flow_add_op_var (use, s->opc, 1);
|
||||
res_op = flow_analyze_pointer_operand (s->opb, def);
|
||||
aux_op1 = s->opc;
|
||||
flow_add_op_var (use, s->opb, 1);
|
||||
res_op = flow_analyze_pointer_operand (s->opa, def);
|
||||
src_op = s->opc;
|
||||
aux_op2 = s->opa;
|
||||
} else {
|
||||
internal_error (s->expr, "unexpected opcode '%s' for %d",
|
||||
s->opcode, s->type);
|
||||
|
@ -1231,10 +1238,10 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill,
|
|||
}
|
||||
if (operands) {
|
||||
operands[0] = res_op;
|
||||
operands[1] = s->opa;
|
||||
operands[2] = s->opb;
|
||||
operands[3] = aux_op1;
|
||||
operands[4] = aux_op2;
|
||||
operands[1] = src_op;
|
||||
operands[2] = aux_op1;
|
||||
operands[3] = aux_op2;
|
||||
operands[4] = aux_op3;
|
||||
}
|
||||
break;
|
||||
case st_state:
|
||||
|
@ -1296,14 +1303,21 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill,
|
|||
}
|
||||
break;
|
||||
case st_flow:
|
||||
if (strcmp (s->opcode, "jump") != 0) {
|
||||
if (statement_is_goto (s)) {
|
||||
// opa is just a label
|
||||
} else if (statement_is_jumpb (s)) {
|
||||
flow_add_op_var (use, s->opa, 1);
|
||||
if (strcmp (s->opcode, "jumpb") == 0)
|
||||
flow_add_op_var (use, s->opb, 1);
|
||||
} else if (statement_is_cond (s)) {
|
||||
flow_add_op_var (use, s->opc, 1);
|
||||
} else {
|
||||
internal_error (s->expr, "unexpected flow statement: %s",
|
||||
s->opcode);
|
||||
}
|
||||
if (operands) {
|
||||
operands[1] = s->opa;
|
||||
operands[2] = s->opb;
|
||||
operands[3] = s->opc;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -642,14 +642,22 @@ statement_is_return (statement_t *s)
|
|||
return !strncmp (s->opcode, "return", 6);
|
||||
}
|
||||
|
||||
static ex_label_t **
|
||||
statement_get_labelref (statement_t *s)
|
||||
{
|
||||
if (statement_is_cond (s)
|
||||
|| statement_is_goto (s)
|
||||
|| statement_is_jumpb (s)) {
|
||||
return &s->opa->label;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
sblock_t *
|
||||
statement_get_target (statement_t *s)
|
||||
{
|
||||
if (statement_is_cond (s))
|
||||
return s->opb->label->dest;
|
||||
if (statement_is_goto (s))
|
||||
return s->opa->label->dest;
|
||||
return 0;
|
||||
ex_label_t **label = statement_get_labelref (s);
|
||||
return label ? (*label)->dest : 0;
|
||||
}
|
||||
|
||||
sblock_t **
|
||||
|
@ -961,9 +969,9 @@ dereference_dst:
|
|||
ofs = 0;
|
||||
}
|
||||
s = new_statement (type, opcode, e);
|
||||
s->opa = src;
|
||||
s->opb = dst;
|
||||
s->opc = ofs;
|
||||
s->opa = dst;
|
||||
s->opb = ofs;
|
||||
s->opc = src;
|
||||
sblock_add_statement (sblock, s);
|
||||
return sblock;
|
||||
}
|
||||
|
@ -1038,8 +1046,8 @@ expr_call (sblock_t *sblock, expr_t *call, operand_t **op)
|
|||
sblock = statement_subexpr (sblock, a, &arg);
|
||||
if (arg != p) {
|
||||
s = new_statement (st_assign, "assign", a);
|
||||
s->opa = arg;
|
||||
s->opb = p;
|
||||
s->opa = p;
|
||||
s->opc = arg;
|
||||
sblock_add_statement (sblock, s);
|
||||
}
|
||||
}
|
||||
|
@ -1086,8 +1094,8 @@ statement_branch (sblock_t *sblock, expr_t *e)
|
|||
} else {
|
||||
opcode = opcodes [e->e.branch.type];
|
||||
s = new_statement (st_flow, opcode, e);
|
||||
sblock = statement_subexpr (sblock, e->e.branch.test, &s->opa);
|
||||
s->opb = label_operand (e->e.branch.target);
|
||||
sblock = statement_subexpr (sblock, e->e.branch.test, &s->opc);
|
||||
s->opa = label_operand (e->e.branch.target);
|
||||
}
|
||||
|
||||
sblock_add_statement (sblock, s);
|
||||
|
@ -1928,14 +1936,15 @@ thread_jumps (sblock_t *blocks)
|
|||
(*label)->symbol = 0;
|
||||
}
|
||||
} else if (statement_is_cond (s)) {
|
||||
label = &s->opb->label;
|
||||
label = &s->opa->label;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
for (l = *label;
|
||||
l->dest && l->dest->statements
|
||||
&& statement_is_goto (l->dest->statements);
|
||||
l = l->dest->statements->opa->label) {
|
||||
l = *statement_get_labelref (l->dest->statements)) {
|
||||
// empty loop
|
||||
}
|
||||
if (l != *label) {
|
||||
unuse_label (*label);
|
||||
|
@ -1988,11 +1997,12 @@ remove_dead_blocks (sblock_t *blocks)
|
|||
s = (statement_t *) sblock->tail;
|
||||
if (statement_is_cond (s)
|
||||
&& sb->statements && statement_is_goto (sb->statements)
|
||||
&& s->opb->label->dest == sb->next) {
|
||||
&& statement_get_target (s) == sb->next) {
|
||||
debug (0, "merging if/goto %p %p", sblock, sb);
|
||||
unuse_label (s->opb->label);
|
||||
s->opb->label = sb->statements->opa->label;
|
||||
s->opb->label->used++;
|
||||
ex_label_t **labelref = statement_get_labelref(s);
|
||||
unuse_label (*labelref);
|
||||
*labelref = *statement_get_labelref (sb->statements);
|
||||
(*labelref)->used++;
|
||||
invert_conditional (s);
|
||||
sb->reachable = 0;
|
||||
for (sb = sb->next; sb; sb = sb->next)
|
||||
|
@ -2014,10 +2024,8 @@ remove_dead_blocks (sblock_t *blocks)
|
|||
|
||||
if (sb->statements) {
|
||||
s = (statement_t *) sb->tail;
|
||||
if (statement_is_goto (s))
|
||||
label = s->opa->label;
|
||||
else if (statement_is_cond (s))
|
||||
label = s->opb->label;
|
||||
ex_label_t **labelref = statement_get_labelref (s);
|
||||
label = labelref ? *labelref : 0;
|
||||
}
|
||||
unuse_label (label);
|
||||
did_something = 1;
|
||||
|
|
Loading…
Reference in a new issue