diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 42fc798d0..508aac907 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -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 diff --git a/tools/qfcc/include/expr_names.h b/tools/qfcc/include/expr_names.h index 9eda07130..a6169350e 100644 --- a/tools/qfcc/include/expr_names.h +++ b/tools/qfcc/include/expr_names.h @@ -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) ///@} diff --git a/tools/qfcc/include/statements.h b/tools/qfcc/include/statements.h index 9e25a694e..4b7013346 100644 --- a/tools/qfcc/include/statements.h +++ b/tools/qfcc/include/statements.h @@ -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); diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index c401e93fb..41d93cd2d 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -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; diff --git a/tools/qfcc/source/dot_expr.c b/tools/qfcc/source/dot_expr.c index 3a690595b..9274dece8 100644 --- a/tools/qfcc/source/dot_expr.c +++ b/tools/qfcc/source/dot_expr.c @@ -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\n", indent + 2, ""); - dasprintf (dstr, "%*s" - "\n", indent + 4, "", e->line, + dasprintf (dstr, "%*s" + "\n", indent + 4, "", num_exprs, e->line, e->block.is_call ? "c" : ""); if (e->block.result) - dasprintf (dstr, "%*s" - "\n", indent + 4, ""); - for (se = e->block.head, i = 0; se; se = se->next, i++) - dasprintf (dstr, "%*s\n", - indent + 4, "", se->line, i, expr_names[se->type]); + dasprintf (dstr, "%*s" + "\n", indent + 4, "", num_exprs); + dasprintf (dstr, "%*s\n", indent + 4, ""); + for (int i = 0; i < num_exprs; i++) { + dasprintf (dstr, "%*s\n", indent + 8, "", exprs[i]->line); + } + dasprintf (dstr, "%*s\n", indent + 4, ""); + dasprintf (dstr, "%*s\n", indent + 4, ""); + for (int i = 0; i < num_exprs; i++) { + dasprintf (dstr, "%*s\n", indent + 8, "", + i, expr_names[exprs[i]->type]); + } + dasprintf (dstr, "%*s\n", indent + 4, ""); dasprintf (dstr, "%*s
<block>(%d)%s
<block>(%d)%s
=
%d%s
=
%d
%s
\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]); } } diff --git a/tools/qfcc/source/evaluate.c b/tools/qfcc/source/evaluate.c index 171539a16..469a8611d 100644 --- a/tools/qfcc/source/evaluate.c +++ b/tools/qfcc/source/evaluate.c @@ -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"); } diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 7083b0385..c6d306c11 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -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 == '~') diff --git a/tools/qfcc/source/expr_assign.c b/tools/qfcc/source/expr_assign.c index d38b0aa0e..c9c373a8a 100644 --- a/tools/qfcc/source/expr_assign.c +++ b/tools/qfcc/source/expr_assign.c @@ -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"); diff --git a/tools/qfcc/source/expr_bool.c b/tools/qfcc/source/expr_bool.c index e866ab040..910430e88 100644 --- a/tools/qfcc/source/expr_bool.c +++ b/tools/qfcc/source/expr_bool.c @@ -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) { diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 0f20b67cf..8e144b883 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -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); diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 756548836..f5287c98c 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -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 {