[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
} 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).

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(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)
///@}

View file

@ -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);

View file

@ -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");

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 *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)
{

View file

@ -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

View file

@ -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 <op> RELOP

View file

@ -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]);