From 3f389b602a4b987dfb2b8b68f26be323c7f3e919 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 30 Jan 2022 10:56:15 +0900 Subject: [PATCH] [qfcc] Add support for horizontal vector ops And reimplement vector comparison for Ruamoko. --- tools/qfcc/include/expr.h | 24 ++++++++++++-- tools/qfcc/include/expr_names.h | 1 + tools/qfcc/source/expr.c | 34 ++++++++++++++++++++ tools/qfcc/source/expr_assign.c | 1 + tools/qfcc/source/expr_binary.c | 21 +++++++++++-- tools/qfcc/source/qc-parse.y | 1 + tools/qfcc/source/qp-parse.y | 1 + tools/qfcc/source/statements.c | 56 ++++++++++++++++++++++++++++++++- 8 files changed, 134 insertions(+), 5 deletions(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index f2b934324..5181dfbc6 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -249,6 +249,12 @@ typedef struct { struct expr_s *with; ///< value to load } ex_with_t; +typedef struct { + int op; ///< operation to perform + struct expr_s *vec; ///< vector expression on which to operate + struct type_s *type; ///< result type +} ex_horizontal_t; + #define POINTER_VAL(p) (((p).def ? (p).def->offset : 0) + (p).val) typedef struct expr_s { @@ -283,6 +289,7 @@ typedef struct expr_s { ex_adjstk_t adjstk; ///< stack adjust param ex_with_t with; ///< with expr param struct type_s *nil; ///< type for nil if known + ex_horizontal_t hop; ///< horizontal vector operation } e; } expr_t; @@ -432,7 +439,7 @@ void build_element_chain (element_chain_t *element_chain, expr_t *eles, int base_offset); void free_element_chain (element_chain_t *element_chain); -/** Create a new binary expression node node. +/** Create a new binary expression node. If either \a e1 or \a e2 are error expressions, then that expression will be returned instead of a new binary expression. @@ -446,7 +453,7 @@ void free_element_chain (element_chain_t *element_chain); */ expr_t *new_binary_expr (int op, expr_t *e1, expr_t *e2); -/** Create a new unary expression node node. +/** Create a new unary expression node. If \a e1 is an error expression, then it will be returned instead of a new unary expression. @@ -458,6 +465,19 @@ expr_t *new_binary_expr (int op, expr_t *e1, expr_t *e2); */ expr_t *new_unary_expr (int op, expr_t *e1); +/** Create a new horizontal vector operantion node. + + If \a vec is an error expression, then it will be returned instead of a + new unary expression. + + \param op The op-code of the horizontal operation. + \param vec The expression (must be a vector type) on which to operate. + \param type The result type (must be scalar type) + \return The new unary expression node (::ex_expr_t) if \a e1 + is not an error expression, otherwise \a e1. +*/ +expr_t *new_horizontal_expr (int op, expr_t *vec, struct type_s *type); + /** Create a new def reference (non-temporary variable) expression node. \return The new def reference expression node (::def_t). diff --git a/tools/qfcc/include/expr_names.h b/tools/qfcc/include/expr_names.h index 820ba9826..05d1f197a 100644 --- a/tools/qfcc/include/expr_names.h +++ b/tools/qfcc/include/expr_names.h @@ -62,5 +62,6 @@ EX_EXPR(return) ///< return expression (::ex_return_t) EX_EXPR(adjstk) ///< stack adjust expression (::ex_adjstk_t) EX_EXPR(with) ///< with expression (::ex_with_t) EX_EXPR(args) ///< @args marker in parameter list. no data +EX_EXPR(horizontal) ///< horizontal vector operation (::ex_horzontal_t) ///@} diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 66140bc52..7af72d5a1 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -276,6 +276,8 @@ get_type (expr_t *e) return get_type (e->e.assign.dst); case ex_args: return &type_va_list; + case ex_horizontal: + return e->e.hop.type; case ex_count: internal_error (e, "invalid expression"); } @@ -531,6 +533,11 @@ copy_expr (expr_t *e) n = new_expr (); *n = *e; return n; + case ex_horizontal: + n = new_expr (); + *n = *e; + e->e.hop.vec = copy_expr (e->e.hop.vec); + return n; case ex_count: break; } @@ -695,6 +702,28 @@ new_unary_expr (int op, expr_t *e1) return e; } +expr_t * +new_horizontal_expr (int op, expr_t *vec, type_t *type) +{ + type_t *vec_type = get_type (vec); + if (!vec_type) { + return vec; + } + if (!is_math (vec_type) || is_scalar (vec_type)) { + internal_error (vec, "horizontal operand not a vector type"); + } + if (!is_scalar (type)) { + internal_error (vec, "horizontal result not a scalar type"); + } + + expr_t *e = new_expr (); + e->type = ex_horizontal; + e->e.hop.op = op; + e->e.hop.vec = vec; + e->e.hop.type = type; + return e; +} + expr_t * new_def_expr (def_t *def) { @@ -1733,6 +1762,8 @@ has_function_call (expr_t *e) return has_function_call (e->e.branch.test); case ex_return: return has_function_call (e->e.retrn.ret_val); + case ex_horizontal: + return has_function_call (e->e.hop.vec); case ex_error: case ex_state: case ex_label: @@ -1873,6 +1904,7 @@ unary_expr (int op, expr_t *e) case ex_vector: case ex_alias: case ex_assign: + case ex_horizontal: { expr_t *n = new_unary_expr (op, e); @@ -1965,6 +1997,7 @@ unary_expr (int op, expr_t *e) case ex_alias: case ex_address: case ex_assign: + case ex_horizontal: if (options.code.progsversion == PROG_VERSION) { return binary_expr (EQ, e, new_nil_expr ()); } else { @@ -2053,6 +2086,7 @@ unary_expr (int op, expr_t *e) case ex_vector: case ex_alias: case ex_assign: + case ex_horizontal: bitnot_expr: if (options.code.progsversion == PROG_ID_VERSION) { expr_t *n1 = new_int_expr (-1); diff --git a/tools/qfcc/source/expr_assign.c b/tools/qfcc/source/expr_assign.c index f9a66b1be..e193de6aa 100644 --- a/tools/qfcc/source/expr_assign.c +++ b/tools/qfcc/source/expr_assign.c @@ -141,6 +141,7 @@ is_lvalue (const expr_t *expr) case ex_adjstk: case ex_with: case ex_args: + case ex_horizontal: break; case ex_count: internal_error (expr, "invalid expression"); diff --git a/tools/qfcc/source/expr_binary.c b/tools/qfcc/source/expr_binary.c index c2acf4028..f533b38cd 100644 --- a/tools/qfcc/source/expr_binary.c +++ b/tools/qfcc/source/expr_binary.c @@ -51,6 +51,7 @@ static expr_t *pointer_compare (int op, expr_t *e1, expr_t *e2); static expr_t *func_compare (int op, expr_t *e1, expr_t *e2); static expr_t *inverse_multiply (int op, expr_t *e1, expr_t *e2); static expr_t *double_compare (int op, expr_t *e1, expr_t *e2); +static expr_t *vector_compare (int op, expr_t *e1, expr_t *e2); static expr_type_t string_string[] = { {'+', &type_string}, @@ -145,8 +146,8 @@ static expr_type_t vector_vector[] = { {'+', &type_vector}, {'-', &type_vector}, {'*', &type_float}, - {EQ, &type_int}, - {NE, &type_int}, + {EQ, 0, 0, 0, vector_compare}, + {NE, 0, 0, 0, vector_compare}, {0, 0} }; @@ -721,6 +722,22 @@ inverse_multiply (int op, expr_t *e1, expr_t *e2) return binary_expr ('*', e1, binary_expr ('/', one, e2)); } +static expr_t * +vector_compare (int op, expr_t *e1, expr_t *e2) +{ + if (options.code.progsversion < PROG_VERSION) { + expr_t *e = new_binary_expr (op, e1, e2); + e->e.expr.type = &type_int; + return e; + } + int hop = op == EQ ? '&' : '|'; + e1 = new_alias_expr (&type_vec3, e1); + e2 = new_alias_expr (&type_vec3, e2); + expr_t *e = new_binary_expr (op, e1, e2); + e->e.expr.type = &type_ivec3; + return new_horizontal_expr (hop, e, &type_int); +} + static expr_t * double_compare (int op, expr_t *e1, expr_t *e2) { diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 282f501ae..0e23c1eb2 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -133,6 +133,7 @@ int yylex (void); %left '&' %left EQ NE %left LT GT GE LE +%token NAND NOR XNOR // end of tokens common between qc and qp %left SHL SHR diff --git a/tools/qfcc/source/qp-parse.y b/tools/qfcc/source/qp-parse.y index db0274ce4..550f8e3f8 100644 --- a/tools/qfcc/source/qp-parse.y +++ b/tools/qfcc/source/qp-parse.y @@ -114,6 +114,7 @@ int yylex (void); %left '&' %left EQ NE %left LT GT GE LE +%token NAND NOR XNOR // end of tokens common between qc and qp %left RELOP diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 2ade73a9f..3de08e449 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -1666,6 +1666,59 @@ expr_uexpr (sblock_t *sblock, expr_t *e, operand_t **op) return sblock; } +static sblock_t * +expr_horizontal (sblock_t *sblock, expr_t *e, operand_t **op) +{ + const char *opcode = "hops"; + statement_t *s; + int hop; + type_t *res_type = e->e.hop.type; + type_t *vec_type = get_type (e->e.hop.vec); + + switch (e->e.hop.op) { + case '&': + hop = 0; + break; + case '|': + hop = 1; + break; + case '^': + hop = 2; + break; + case '+': + if (is_integral (vec_type)) { + hop = 3; + } else { + hop = 7; + } + break; + case NAND: + hop = 4; + break; + case NOR: + hop = 5; + break; + case XNOR: + hop = 6; + break; + default: + internal_error (e, "invalid horizontal op"); + } + hop |= (type_width (vec_type) - 1) << 3; + hop |= (pr_type_size[vec_type->type] - 1) << 5; + + s = new_statement (st_expr, opcode, e); + sblock = statement_subexpr (sblock, e->e.hop.vec, &s->opa); + s->opb = short_operand (hop, e); + if (!*op) { + *op = temp_operand (res_type, e); + } + s->opc = *op; + sblock_add_statement (sblock, s); + + return sblock; +} + static sblock_t * expr_def (sblock_t *sblock, expr_t *e, operand_t **op) { @@ -1826,6 +1879,7 @@ statement_subexpr (sblock_t *sblock, expr_t *e, operand_t **op) [ex_block] = expr_block, [ex_expr] = expr_expr, [ex_uexpr] = expr_uexpr, + [ex_horizontal] = expr_horizontal, [ex_def] = expr_def, [ex_symbol] = expr_symbol, [ex_temp] = expr_temp, @@ -1844,7 +1898,7 @@ statement_subexpr (sblock_t *sblock, expr_t *e, operand_t **op) } if (e->type >= ex_count) - internal_error (e, "bad sub-expression type"); + internal_error (e, "bad sub-expression type: %d", e->type); if (!sfuncs[e->type]) internal_error (e, "unexpected sub-expression type: %s", expr_names[e->type]);