mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 15:22:04 +00:00
[qfcc] Add support for horizontal vector ops
And reimplement vector comparison for Ruamoko.
This commit is contained in:
parent
feb3be4e6b
commit
3f389b602a
8 changed files with 134 additions and 5 deletions
|
@ -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).
|
||||
|
|
|
@ -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)
|
||||
|
||||
///@}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]);
|
||||
|
|
Loading…
Reference in a new issue