[qfcc] Use non-invasive lists for block expressions

They will be used for other expression types too. Invasive lists make it
difficult to do expression dags.
This commit is contained in:
Bill Currie 2023-09-24 11:54:06 +09:00
parent 345eba45d5
commit cc67e69923
11 changed files with 200 additions and 106 deletions

View file

@ -93,12 +93,25 @@ typedef struct element_chain_s {
element_t **tail;
} element_chain_t;
typedef struct {
struct expr_s *head; ///< the first expression in the block
struct expr_s **tail; ///< last expression in the block, for appending
struct expr_s *result; ///< the result of this block if non-void
int is_call; ///< this block exprssion forms a function call
void *return_addr;///< who allocated this
typedef struct ex_listitem_s {
struct ex_listitem_s *next;
struct expr_s *expr;
} ex_listitem_t;
typedef struct ex_list_s {
ex_listitem_t *head;
ex_listitem_t **tail;
} ex_list_t;
typedef union {
ex_list_t list;
struct {
ex_listitem_t *head;
ex_listitem_t **tail;
struct expr_s *result; ///< the result of this block if non-void
int is_call; ///< this block exprssion forms a function call
void *return_addr;///< who allocated this
};
} ex_block_t;
typedef struct {
@ -304,6 +317,7 @@ typedef struct expr_s {
ex_labelref_t labelref; ///< label reference expression (&)
ex_state_t state; ///< state expression
ex_bool_t boolean; ///< boolean logic expression
ex_list_t list; ///< noninvasive expression list
ex_block_t block; ///< statement block expression
ex_expr_t expr; ///< binary or unary expression
struct def_s *def; ///< def reference expression
@ -364,6 +378,11 @@ struct type_s *get_type (expr_t *e);
*/
etype_t extract_type (expr_t *e);
ex_listitem_t *new_listitem (expr_t *e);
int list_count (ex_list_t *list) __attribute__((pure));
void list_scatter (ex_list_t *list, expr_t **exprs);
void list_gather (ex_list_t *dst, expr_t **exprs, int count);
/** Create a new expression node.
Sets the source file and line number information. The expression node is

View file

@ -66,5 +66,6 @@ EX_EXPR(horizontal) ///< horizontal vector operation (::ex_horzontal_t)
EX_EXPR(swizzle) ///< vector swizzle operation (::ex_swizzle_t)
EX_EXPR(extend) ///< vector extend operation (::ex_extend_t)
EX_EXPR(multivec) ///< geometric algebra multivector (::ex_multivec_t)
EX_EXPR(list) ///< non-invasive list of expressions (::ex_list_t)
///@}

View file

@ -175,7 +175,8 @@ sblock_t *statement_get_target (statement_t *s) __attribute__((pure));
sblock_t **statement_get_targetlist (statement_t *s);
void sblock_add_statement (sblock_t *sblock, statement_t *statement);
sblock_t *make_statements (struct expr_s *expr);
sblock_t *statement_slist (sblock_t *sblock, struct expr_s *e);
struct ex_list_s;
sblock_t *statement_slist (sblock_t *sblock, struct ex_list_s *slist);
void statements_count_temps (sblock_t *sblock);
void print_operand (operand_t *op);

View file

@ -547,7 +547,7 @@ static int
num_elements (expr_t *e)
{
int count = 0;
for (e = e->block.head; e; e = e->next) {
for (auto ele = e->compound.head; ele; ele = ele->next) {
count++;
}
return count;

View file

@ -221,21 +221,32 @@ static void
print_block (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
{
int indent = level * 2 + 2;
int i;
expr_t *se;
int num_exprs = list_count (&e->block.list);
expr_t *exprs[num_exprs + 1];
list_scatter (&e->block.list, exprs);
exprs[num_exprs] = 0;
dasprintf (dstr, "%*se_%p [shape=none,label=<\n", indent, "", e);
dasprintf (dstr, "%*s<table border=\"0\" cellborder=\"1\" "
"cellspacing=\"0\">\n", indent + 2, "");
dasprintf (dstr, "%*s<tr><td colspan=\"2\">&lt;block&gt;(%d)%s</td>"
"</tr>\n", indent + 4, "", e->line,
dasprintf (dstr, "%*s<tr><td colspan=\"%d\">&lt;block&gt;(%d)%s</td>"
"</tr>\n", indent + 4, "", num_exprs, e->line,
e->block.is_call ? "c" : "");
if (e->block.result)
dasprintf (dstr, "%*s<tr><td colspan=\"2\" port=\"result\">=</td>"
"</tr>\n", indent + 4, "");
for (se = e->block.head, i = 0; se; se = se->next, i++)
dasprintf (dstr, "%*s<tr><td>%d</td><td port=\"b%d\">%s</td></tr>\n",
indent + 4, "", se->line, i, expr_names[se->type]);
dasprintf (dstr, "%*s<tr><td colspan=\"%d\" port=\"result\">=</td>"
"</tr>\n", indent + 4, "", num_exprs);
dasprintf (dstr, "%*s<tr>\n", indent + 4, "");
for (int i = 0; i < num_exprs; i++) {
dasprintf (dstr, "%*s<td>%d</td>\n", indent + 8, "", exprs[i]->line);
}
dasprintf (dstr, "%*s</tr>\n", indent + 4, "");
dasprintf (dstr, "%*s<tr>\n", indent + 4, "");
for (int i = 0; i < num_exprs; i++) {
dasprintf (dstr, "%*s<td port=\"b%d\">%s</td>\n", indent + 8, "",
i, expr_names[exprs[i]->type]);
}
dasprintf (dstr, "%*s</tr>\n", indent + 4, "");
dasprintf (dstr, "%*s</table>\n", indent + 2, "");
dasprintf (dstr, "%*s>];\n", indent, "");
@ -244,12 +255,10 @@ print_block (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
dasprintf (dstr, "%*se_%p:result -> e_%p;\n", indent, "", e,
e->block.result);
}
if (e->next)
next = e->next;
for (se = e->block.head, i = 0; se; se = se->next, i++) {
_print_expr (dstr, se, level + 1, id, next);
for (int i = 0; i < num_exprs; i++) {
_print_expr (dstr, exprs[i], level + 1, id, exprs[i + 1]);
dasprintf (dstr, "%*se_%p:b%d -> e_%p;\n", indent, "", e,
i, se);
i, exprs[i]);
}
}

View file

@ -245,7 +245,9 @@ evaluate_constexpr (expr_t *e)
sblock_t sblock = {
.tail = &sblock.statements,
};
auto sb = statement_slist (&sblock, new_return_expr (e));
ex_listitem_t return_expr = { .expr = new_return_expr (e) };
ex_list_t return_st = { .head = &return_expr, .tail = &return_expr.next };
auto sb = statement_slist (&sblock, &return_st);
if (sblock.next != sb && sb->statements) {
internal_error (e, "statement_slist did too much");
}

View file

@ -67,6 +67,7 @@
#include "tools/qfcc/source/qc-parse.h"
ALLOC_STATE (expr_t, exprs);
ALLOC_STATE (ex_listitem_t, listitems);
expr_t *
convert_name (expr_t *e)
@ -201,6 +202,11 @@ get_type (expr_t *e)
return e->extend.type;
case ex_multivec:
return e->multivec.type;
case ex_list:
if (e->list.head) {
return get_type ((*e->list.tail)->expr);
}
return 0;
case ex_count:
internal_error (e, "invalid expression");
}
@ -258,6 +264,46 @@ new_expr (void)
return e;
}
ex_listitem_t *
new_listitem (expr_t *e)
{
ex_listitem_t *li;
ALLOC (16384, ex_listitem_t, listitems, li);
li->expr = e;
return li;
}
int
list_count (ex_list_t *list)
{
int count = 0;
for (auto li = list->head; li; li = li->next) {
count++;
}
return count;
}
void
list_scatter (ex_list_t *list, expr_t **exprs)
{
for (auto li = list->head; li; li = li->next) {
*exprs++ = li->expr;
}
}
void
list_gather (ex_list_t *list, expr_t **exprs, int count)
{
if (!list->tail) {
list->tail = &list->head;
}
while (count-- > 0) {
auto li = new_listitem (*exprs++);
*list->tail = li;
list->tail = &li->next;
}
}
expr_t *
copy_expr (expr_t *e)
{
@ -318,12 +364,12 @@ copy_expr (expr_t *e)
n->block.head = 0;
n->block.tail = &n->block.head;
n->block.result = 0;
for (t = e->block.head; t; t = t->next) {
if (t == e->block.result) {
n->block.result = copy_expr (t);
for (auto t = e->block.head; t; t = t->next) {
if (t->expr == e->block.result) {
n->block.result = copy_expr (t->expr);
append_expr (n, n->block.result);
} else {
append_expr (n, copy_expr (t));
append_expr (n, copy_expr (t->expr));
}
}
if (e->block.result && !n->block.result)
@ -453,6 +499,8 @@ copy_expr (expr_t *e)
t = t->next;
}
return n;
case ex_list:
break;//FIXME
case ex_count:
break;
}
@ -1434,8 +1482,9 @@ append_expr (expr_t *block, expr_t *e)
if (e->next)
internal_error (e, "append_expr: expr loop detected");
*block->block.tail = e;
block->block.tail = &e->next;
auto li = new_listitem (e);
*block->block.tail = li;
block->block.tail = &li->next;
return block;
}
@ -1452,11 +1501,12 @@ prepend_expr (expr_t *block, expr_t *e)
if (e->next)
internal_error (e, "append_expr: expr loop detected");
e->next = block->block.head;
block->block.head = e;
auto li = new_listitem (e);
li->next = block->block.head;
block->block.head = li;
if (block->block.tail == &block->block.head) {
block->block.tail = &e->next;
block->block.tail = &li->next;
}
return block;
@ -1674,8 +1724,9 @@ has_function_call (expr_t *e)
case ex_block:
if (e->block.is_call)
return 1;
for (e = e->block.head; e; e = e->next)
if (has_function_call (e))
case ex_list:
for (auto li = e->block.head; li; li = li->next)
if (has_function_call (li->expr))
return 1;
return 0;
case ex_expr:
@ -1831,6 +1882,7 @@ unary_expr (int op, expr_t *e)
case ex_adjstk:
case ex_with:
case ex_args:
case ex_list:
internal_error (e, "unexpected expression type");
case ex_uexpr:
if (e->expr.op == '-') {
@ -1944,6 +1996,7 @@ unary_expr (int op, expr_t *e)
case ex_adjstk:
case ex_with:
case ex_args:
case ex_list:
internal_error (e, "unexpected expression type");
case ex_bool:
return new_bool_expr (e->boolean.false_list,
@ -2037,6 +2090,7 @@ unary_expr (int op, expr_t *e)
case ex_adjstk:
case ex_with:
case ex_args:
case ex_list:
internal_error (e, "unexpected expression type");
case ex_uexpr:
if (e->expr.op == '~')

View file

@ -146,6 +146,7 @@ is_lvalue (const expr_t *expr)
case ex_swizzle:
case ex_extend:
case ex_multivec:
case ex_list:
break;
case ex_count:
internal_error (expr, "invalid expression");

View file

@ -284,12 +284,7 @@ convert_bool (expr_t *e, int block)
if (b->type == ex_error)
return b;
// insert the assignment into the boolean's block
e->next = b->boolean.e->block.head;
b->boolean.e->block.head = e;
if (b->boolean.e->block.tail == &b->boolean.e->block.head) {
// shouldn't happen, but just in case
b->boolean.e->block.tail = &e->next;
}
prepend_expr (b->boolean.e, e);
return b;
}
@ -321,8 +316,8 @@ convert_bool (expr_t *e, int block)
b = new_block_expr ();
append_expr (b, branch_expr (NE, e, 0));
append_expr (b, goto_expr (0));
e = new_bool_expr (make_list (b->block.head),
make_list (b->block.head->next), b);
e = new_bool_expr (make_list (b->block.head->expr),
make_list (b->block.head->next->expr), b);
}
}
if (block && e->boolean.e->type != ex_block) {

View file

@ -1870,8 +1870,8 @@ identifier_list
classdecl
: CLASS identifier_list ';'
{
expr_t *e;
for (e = $2->block.head; e; e = e->next) {
for (auto li = $2->block.head; li; li = li->next) {
auto e = li->expr;
get_class (e->symbol, 1);
if (!e->symbol->table)
symtab_addsymbol (current_symtab, e->symbol);

View file

@ -725,6 +725,7 @@ static sblock_t *statement_subexpr (sblock_t *sblock, expr_t *e,
operand_t **op);
static sblock_t *expr_symbol (sblock_t *sblock, expr_t *e, operand_t **op);
static sblock_t *expr_def (sblock_t *sblock, expr_t *e, operand_t **op);
static sblock_t *statement_single (sblock_t *sblock, expr_t *e);
static sblock_t *
expr_address (sblock_t *sblock, expr_t *e, operand_t **op)
@ -1056,7 +1057,7 @@ vector_call (sblock_t *sblock, expr_t *earg, expr_t *param, int ind,
param = new_param_expr (get_type (earg), ind);
a->line = earg->line;
a->file = earg->file;
sblock = statement_slist (sblock, a);
sblock = statement_single (sblock, a);
}
sblock = statement_subexpr (sblock, param, op);
return sblock;
@ -1111,7 +1112,7 @@ expr_call_v6p (sblock_t *sblock, expr_t *call, operand_t **op)
expr_t *mov = assign_expr (param, a);
mov->line = a->line;
mov->file = a->file;
sblock = statement_slist (sblock, mov);
sblock = statement_single (sblock, mov);
} else {
operand_t *p = 0;
sblock = statement_subexpr (sblock, param, &p);
@ -1204,7 +1205,7 @@ expr_call (sblock_t *sblock, expr_t *call, operand_t **op)
}
expr_t *assign = assign_expr (def_expr, a);
expr_file_line (assign, call);
sblock = statement_slist (sblock, assign);
sblock = statement_single (sblock, assign);
}
// The call both uses and kills the arguments: use is obvious, but kill
@ -1232,7 +1233,7 @@ expr_call (sblock_t *sblock, expr_t *call, operand_t **op)
count = new_short_expr (num_params);
assign = assign_expr (args_count, count);
expr_file_line (assign, call);
sblock = statement_slist (sblock, assign);
sblock = statement_single (sblock, assign);
if (args_params) {
list = address_expr (args_params, &type_param);
@ -1242,7 +1243,7 @@ expr_call (sblock_t *sblock, expr_t *call, operand_t **op)
expr_file_line (list, call);
assign = assign_expr (args_list, list);
expr_file_line (assign, call);
sblock = statement_slist (sblock, assign);
sblock = statement_single (sblock, assign);
}
statement_t *s = new_statement (st_func, "call", call);
sblock = statement_subexpr (sblock, func, &s->opa);
@ -1513,7 +1514,7 @@ statement_return (sblock_t *sblock, expr_t *e)
operand_t *ret_op = def_operand (ret_ptr, &type_void, e);
ret_ptr->reg = REG;
expr_file_line (with, e);
sblock = statement_slist (sblock, with);
sblock = statement_single (sblock, with);
sblock = statement_subexpr (sblock, call, &ret_op);
}
s->opa = short_operand (0, e);
@ -1635,7 +1636,7 @@ expr_block (sblock_t *sblock, expr_t *e, operand_t **op)
{
if (!e->block.result)
internal_error (e, "block sub-expression without result");
sblock = statement_slist (sblock, e->block.head);
sblock = statement_slist (sblock, &e->block.list);
sblock = statement_subexpr (sblock, e->block.result, op);
return sblock;
}
@ -1932,7 +1933,7 @@ statement_copy_elements (sblock_t **sblock, expr_t *dst, expr_t *src, int base)
expr_t *dst_ele = new_offset_alias_expr (src_type, dst,
size * (index + base));
index += type_width (src_type);
*sblock = statement_slist (*sblock, assign_expr (dst_ele, e));
*sblock = statement_single (*sblock, assign_expr (dst_ele, e));
}
}
return index;
@ -2094,10 +2095,8 @@ build_bool_block (expr_t *block, expr_t *e)
break;
case ex_block:
if (!e->block.result) {
expr_t *t;
for (e = e->block.head; e; e = t) {
t = e->next;
build_bool_block (block, e);
for (auto t = e->block.head; t; t = t->next) {
build_bool_block (block, t->expr);
}
return;
}
@ -2118,69 +2117,69 @@ is_goto_expr (expr_t *e)
static int
is_if_expr (expr_t *e)
{
return e && e->type == ex_branch && e->branch.type == pr_branch_ne;
return e && e->type == ex_branch && e->branch.type != pr_branch_jump
&& e->branch.type != pr_branch_call;;
}
static int
is_ifnot_expr (expr_t *e)
is_label_expr (expr_t *e)
{
return e && e->type == ex_branch && e->branch.type == pr_branch_eq;
return e && e->type == ex_label;
}
static sblock_t *
statement_bool (sblock_t *sblock, expr_t *e)
{
expr_t **s;
expr_t *l;
expr_t *block = new_block_expr ();
build_bool_block (block, e);
s = &block->block.head;
while (*s) {
if (is_if_expr (*s) && is_goto_expr ((*s)->next)) {
l = (*s)->branch.target;
for (e = (*s)->next->next; e && e->type == ex_label; e = e->next) {
if (e == l) {
int num_expr = list_count (&block->block.list);
expr_t *exprs[num_expr + 1];
list_scatter (&block->block.list, exprs);
exprs[num_expr] = 0; // mark end of list
expr_t **d = exprs;
expr_t **s = exprs;
while (s[0]) {
if (is_if_expr (s[0]) && is_goto_expr (s[1])) {
l = s[0]->branch.target;
for (auto e = s + 2; is_label_expr (e[0]); e++) {
if (e[0] == l) {
l->label.used--;
e = *s;
e->branch.type = pr_branch_eq;
e->branch.target = e->next->branch.target;
e->next = e->next->next;
break;
}
}
s = &(*s)->next;
} else if (is_ifnot_expr (*s) && is_goto_expr ((*s)->next)) {
l = (*s)->branch.target;
for (e = (*s)->next->next; e && e->type == ex_label; e = e->next) {
if (e == l) {
l->label.used--;
e = *s;
e->branch.type = pr_branch_ne;
e->branch.target = e->next->branch.target;
e->next = e->next->next;
break;
}
}
s = &(*s)->next;
} else if (is_goto_expr (*s)) {
l = (*s)->branch.target;
for (e = (*s)->next; e && e->type == ex_label; e = e->next) {
if (e == l) {
l->label.used--;
*s = (*s)->next;
// invert logic of if
s[0]->branch.type ^= pr_branch_ne;
// use goto's label in if
s[0]->branch.target = s[1]->branch.target;
l = 0;
break;
}
}
if (l)
s = &(*s)->next;
*d++ = *s++; // copy if
if (!l) {
s++; // skip over goto
}
} else if (is_goto_expr (*s)) {
l = s[0]->branch.target;
for (auto e = s + 1; is_label_expr (e[0]); e++) {
if (e[0] == l) {
l->label.used--;
l = 0;
break;
}
}
if (l) {
*d++ = *s++; // label survived, copy goto
} else {
s++; // skip over goto
}
} else {
s = &(*s)->next;
*d++ = *s++;
}
}
sblock = statement_slist (sblock, block->block.head);
block->block.list = (ex_list_t) {};
list_gather (&block->block.list, exprs, d - exprs);
sblock = statement_slist (sblock, &block->block.list);
return sblock;
}
@ -2212,11 +2211,11 @@ statement_block (sblock_t *sblock, expr_t *e)
sblock->next = new_sblock ();
sblock = sblock->next;
}
sblock = statement_slist (sblock, e->block.head);
sblock = statement_slist (sblock, &e->block.list);
if (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->block.result);
sblock = statement_single (sblock, e->block.result);
}
return sblock;
}
@ -2282,8 +2281,8 @@ statement_nonexec (sblock_t *sblock, expr_t *e)
return sblock;
}
sblock_t *
statement_slist (sblock_t *sblock, expr_t *e)
static sblock_t *
statement_single (sblock_t *sblock, expr_t *e)
{
static statement_f sfuncs[ex_count] = {
[ex_error] = statement_ignore,
@ -2307,10 +2306,19 @@ statement_slist (sblock_t *sblock, expr_t *e)
[ex_with] = statement_with,
};
for (/**/; e; e = e->next) {
if (e->type >= ex_count || !sfuncs[e->type])
internal_error (e, "bad expression type");
sblock = sfuncs[e->type] (sblock, e);
if (e->type >= ex_count || !sfuncs[e->type]) {
internal_error (e, "bad expression type");
}
sblock = sfuncs[e->type] (sblock, e);
return sblock;
}
sblock_t *
statement_slist (sblock_t *sblock, ex_list_t *slist)
{
for (auto s = slist->head; s; s = s->next) {
sblock = statement_single (sblock, s->expr);
}
return sblock;
}
@ -2657,7 +2665,11 @@ make_statements (expr_t *e)
if (options.block_dot.expr)
dump_dot ("expr", e, dump_dot_expr);
statement_slist (sblock, e);
if (e->type != ex_block) {
statement_single (sblock, e);
} else {
statement_slist (sblock, &e->block.list);
}
if (options.block_dot.initial)
dump_dot ("initial", sblock, dump_dot_sblock);
do {