diff --git a/tools/qfcc/source/constfold.c b/tools/qfcc/source/constfold.c index ae36079b3..6b01bc7f4 100644 --- a/tools/qfcc/source/constfold.c +++ b/tools/qfcc/source/constfold.c @@ -446,7 +446,7 @@ do_op_vector (int op, expr_t *e, expr_t *e1, expr_t *e2) { const float *v1, *v2; vec3_t v, float_vec; - static int valid[] = {'+', '-', '*', EQ, NE, 0}; + static int valid[] = {'+', '-', '*', SCALE, EQ, NE, 0}; expr_t *t; if (!is_vector(get_type (e1))) { @@ -460,7 +460,7 @@ do_op_vector (int op, expr_t *e, expr_t *e1, expr_t *e2) } if (!is_vector(get_type (e2))) { e->e.expr.e2 = e2 = convert_to_float (e2); - if (op != '*' && op != '/') + if (op != SCALE && op != '/') return error (e1, "invalid operator for vector"); } else { if (!valid_op (op, valid)) diff --git a/tools/qfcc/source/expr_binary.c b/tools/qfcc/source/expr_binary.c index 47dc3ae5c..5bd004d42 100644 --- a/tools/qfcc/source/expr_binary.c +++ b/tools/qfcc/source/expr_binary.c @@ -53,6 +53,7 @@ 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_t *vector_multiply (int op, expr_t *e1, expr_t *e2); +static expr_t *vector_scale (int op, expr_t *e1, expr_t *e2); static expr_type_t string_string[] = { {'+', &type_string}, @@ -89,7 +90,7 @@ static expr_type_t float_float[] = { }; static expr_type_t float_vector[] = { - {'*', &type_vector}, + {'*', .process = vector_scale }, {0, 0} }; @@ -138,7 +139,7 @@ static expr_type_t float_double[] = { }; static expr_type_t vector_float[] = { - {'*', &type_vector}, + {'*', .process = vector_scale }, {'/', 0, 0, 0, inverse_multiply}, {0, 0} }; @@ -755,6 +756,21 @@ static expr_t *vector_multiply (int op, expr_t *e1, expr_t *e2) return e; } +static expr_t *vector_scale (int op, expr_t *e1, expr_t *e2) +{ + // Ensure the expression is always vector * scalar. The operation is + // always commutative, and the Ruamoko ISA supports only vector * scalar + // (though v6 does support scalar * vector, one less if). + if (is_scalar (get_type (e1))) { + expr_t *t = e1; + e1 = e2; + e2 = t; + } + expr_t *e = new_binary_expr (SCALE, e1, e2); + e->e.expr.type = get_type (e1); + return e; +} + 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 7d294db13..3ab14cbe2 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -138,7 +138,7 @@ int yylex (void); %left SHL SHR %left '+' '-' -%left '*' '/' '%' MOD +%left '*' '/' '%' MOD SCALE %left CROSS DOT %right SIZEOF UNARY INCOP %left HYPERUNARY diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index bce46f8cd..e9b375aba 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -606,6 +606,7 @@ convert_op (int op) case '.': return "load"; case CROSS: return "cross"; case DOT: return "dot"; + case SCALE: return "scale"; default: return 0; }