[qfcc] Add support for horizontal vector ops

And reimplement vector comparison for Ruamoko.
This commit is contained in:
Bill Currie 2022-01-30 10:56:15 +09:00
parent feb3be4e6b
commit 3f389b602a
8 changed files with 134 additions and 5 deletions

View file

@ -249,6 +249,12 @@ typedef struct {
struct expr_s *with; ///< value to load struct expr_s *with; ///< value to load
} ex_with_t; } 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) #define POINTER_VAL(p) (((p).def ? (p).def->offset : 0) + (p).val)
typedef struct expr_s { typedef struct expr_s {
@ -283,6 +289,7 @@ typedef struct expr_s {
ex_adjstk_t adjstk; ///< stack adjust param ex_adjstk_t adjstk; ///< stack adjust param
ex_with_t with; ///< with expr param ex_with_t with; ///< with expr param
struct type_s *nil; ///< type for nil if known struct type_s *nil; ///< type for nil if known
ex_horizontal_t hop; ///< horizontal vector operation
} e; } e;
} expr_t; } expr_t;
@ -432,7 +439,7 @@ void build_element_chain (element_chain_t *element_chain,
expr_t *eles, int base_offset); expr_t *eles, int base_offset);
void free_element_chain (element_chain_t *element_chain); 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 If either \a e1 or \a e2 are error expressions, then that expression will
be returned instead of a new binary expression. 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); 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 If \a e1 is an error expression, then it will be returned instead of a
new unary expression. 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); 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. /** Create a new def reference (non-temporary variable) expression node.
\return The new def reference expression node (::def_t). \return The new def reference expression node (::def_t).

View file

@ -62,5 +62,6 @@ EX_EXPR(return) ///< return expression (::ex_return_t)
EX_EXPR(adjstk) ///< stack adjust expression (::ex_adjstk_t) EX_EXPR(adjstk) ///< stack adjust expression (::ex_adjstk_t)
EX_EXPR(with) ///< with expression (::ex_with_t) EX_EXPR(with) ///< with expression (::ex_with_t)
EX_EXPR(args) ///< @args marker in parameter list. no data EX_EXPR(args) ///< @args marker in parameter list. no data
EX_EXPR(horizontal) ///< horizontal vector operation (::ex_horzontal_t)
///@} ///@}

View file

@ -276,6 +276,8 @@ get_type (expr_t *e)
return get_type (e->e.assign.dst); return get_type (e->e.assign.dst);
case ex_args: case ex_args:
return &type_va_list; return &type_va_list;
case ex_horizontal:
return e->e.hop.type;
case ex_count: case ex_count:
internal_error (e, "invalid expression"); internal_error (e, "invalid expression");
} }
@ -531,6 +533,11 @@ copy_expr (expr_t *e)
n = new_expr (); n = new_expr ();
*n = *e; *n = *e;
return n; 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: case ex_count:
break; break;
} }
@ -695,6 +702,28 @@ new_unary_expr (int op, expr_t *e1)
return e; 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 * expr_t *
new_def_expr (def_t *def) new_def_expr (def_t *def)
{ {
@ -1733,6 +1762,8 @@ has_function_call (expr_t *e)
return has_function_call (e->e.branch.test); return has_function_call (e->e.branch.test);
case ex_return: case ex_return:
return has_function_call (e->e.retrn.ret_val); 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_error:
case ex_state: case ex_state:
case ex_label: case ex_label:
@ -1873,6 +1904,7 @@ unary_expr (int op, expr_t *e)
case ex_vector: case ex_vector:
case ex_alias: case ex_alias:
case ex_assign: case ex_assign:
case ex_horizontal:
{ {
expr_t *n = new_unary_expr (op, e); expr_t *n = new_unary_expr (op, e);
@ -1965,6 +1997,7 @@ unary_expr (int op, expr_t *e)
case ex_alias: case ex_alias:
case ex_address: case ex_address:
case ex_assign: case ex_assign:
case ex_horizontal:
if (options.code.progsversion == PROG_VERSION) { if (options.code.progsversion == PROG_VERSION) {
return binary_expr (EQ, e, new_nil_expr ()); return binary_expr (EQ, e, new_nil_expr ());
} else { } else {
@ -2053,6 +2086,7 @@ unary_expr (int op, expr_t *e)
case ex_vector: case ex_vector:
case ex_alias: case ex_alias:
case ex_assign: case ex_assign:
case ex_horizontal:
bitnot_expr: bitnot_expr:
if (options.code.progsversion == PROG_ID_VERSION) { if (options.code.progsversion == PROG_ID_VERSION) {
expr_t *n1 = new_int_expr (-1); expr_t *n1 = new_int_expr (-1);

View file

@ -141,6 +141,7 @@ is_lvalue (const expr_t *expr)
case ex_adjstk: case ex_adjstk:
case ex_with: case ex_with:
case ex_args: case ex_args:
case ex_horizontal:
break; break;
case ex_count: case ex_count:
internal_error (expr, "invalid expression"); internal_error (expr, "invalid expression");

View file

@ -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 *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 *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 *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[] = { static expr_type_t string_string[] = {
{'+', &type_string}, {'+', &type_string},
@ -145,8 +146,8 @@ static expr_type_t vector_vector[] = {
{'+', &type_vector}, {'+', &type_vector},
{'-', &type_vector}, {'-', &type_vector},
{'*', &type_float}, {'*', &type_float},
{EQ, &type_int}, {EQ, 0, 0, 0, vector_compare},
{NE, &type_int}, {NE, 0, 0, 0, vector_compare},
{0, 0} {0, 0}
}; };
@ -721,6 +722,22 @@ inverse_multiply (int op, expr_t *e1, expr_t *e2)
return binary_expr ('*', e1, binary_expr ('/', one, 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 * static expr_t *
double_compare (int op, expr_t *e1, expr_t *e2) double_compare (int op, expr_t *e1, expr_t *e2)
{ {

View file

@ -133,6 +133,7 @@ int yylex (void);
%left '&' %left '&'
%left EQ NE %left EQ NE
%left LT GT GE LE %left LT GT GE LE
%token NAND NOR XNOR
// end of tokens common between qc and qp // end of tokens common between qc and qp
%left SHL SHR %left SHL SHR

View file

@ -114,6 +114,7 @@ int yylex (void);
%left '&' %left '&'
%left EQ NE %left EQ NE
%left LT GT GE LE %left LT GT GE LE
%token NAND NOR XNOR
// end of tokens common between qc and qp // end of tokens common between qc and qp
%left <op> RELOP %left <op> RELOP

View file

@ -1666,6 +1666,59 @@ expr_uexpr (sblock_t *sblock, expr_t *e, operand_t **op)
return sblock; 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 * static sblock_t *
expr_def (sblock_t *sblock, expr_t *e, operand_t **op) 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_block] = expr_block,
[ex_expr] = expr_expr, [ex_expr] = expr_expr,
[ex_uexpr] = expr_uexpr, [ex_uexpr] = expr_uexpr,
[ex_horizontal] = expr_horizontal,
[ex_def] = expr_def, [ex_def] = expr_def,
[ex_symbol] = expr_symbol, [ex_symbol] = expr_symbol,
[ex_temp] = expr_temp, [ex_temp] = expr_temp,
@ -1844,7 +1898,7 @@ statement_subexpr (sblock_t *sblock, expr_t *e, operand_t **op)
} }
if (e->type >= ex_count) 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]) if (!sfuncs[e->type])
internal_error (e, "unexpected sub-expression type: %s", internal_error (e, "unexpected sub-expression type: %s",
expr_names[e->type]); expr_names[e->type]);