From 027ad12c7244a3fa19df5c679b3cef3f7db971e4 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 13 Jan 2025 12:52:12 +0900 Subject: [PATCH] [qfcc] Support add/sub for matrix/vector and scalar operands GLSL needs it, and it's not entirely unreasonable (though I'll probably add some flags to control it since it doesn't always make sense). --- tools/qfcc/include/expr.h | 1 + tools/qfcc/source/expr_binary.c | 84 +++++++++++++++++++++++++++--- tools/qfcc/source/expr_construct.c | 2 +- 3 files changed, 78 insertions(+), 9 deletions(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 4e3702916..5f146de82 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -1076,6 +1076,7 @@ const expr_t *unary_expr (int op, const expr_t *e); const expr_t *build_function_call (const expr_t *fexpr, const type_t *ftype, const expr_t *params); const expr_t *function_expr (const expr_t *e1, const expr_t *e2); +const expr_t *get_column (const expr_t *e, int i); const expr_t *constructor_expr (const expr_t *e, const expr_t *params); struct function_s; const expr_t *branch_expr (int op, const expr_t *test, const expr_t *label); diff --git a/tools/qfcc/source/expr_binary.c b/tools/qfcc/source/expr_binary.c index 3d89c768e..97a37c9e3 100644 --- a/tools/qfcc/source/expr_binary.c +++ b/tools/qfcc/source/expr_binary.c @@ -249,7 +249,7 @@ matrix_binary_expr (int op, const expr_t *a, const expr_t *b) } static const expr_t * -matrix_scalar_expr (int op, const expr_t *a, const expr_t *b) +matrix_scalar_mul (int op, const expr_t *a, const expr_t *b) { auto ta = get_type (a); auto tb = get_type (b); @@ -272,6 +272,8 @@ convert_scalar (const expr_t *scalar, const expr_t *vec) { // expand the scalar to a vector of the same width as vec auto vec_type = get_type (vec); + // vec might actually be a matrix, so get its column "width" + vec_type = vector_type (base_type (vec_type), type_width (vec_type)); if (is_constant (scalar)) { int width = type_width (get_type (vec)); @@ -279,7 +281,7 @@ convert_scalar (const expr_t *scalar, const expr_t *vec) for (int i = 0; i < width; i++) { elements[i] = scalar; } - auto scalar_list = new_list_expr (0); + auto scalar_list = new_list_expr (nullptr); list_gather (&scalar_list->list, elements, width); return new_vector_list (scalar_list); } @@ -287,6 +289,35 @@ convert_scalar (const expr_t *scalar, const expr_t *vec) return new_extend_expr (scalar, vec_type, 2, false);//2 = copy } +static const expr_t * +matrix_scalar_expr (int op, const expr_t *a, const expr_t *b) +{ + scoped_src_loc (a); + bool left = is_scalar (get_type (a)); + auto mat_type = get_type (left ? b : a); + int count = type_cols (mat_type); + const expr_t *a_cols[count]; + const expr_t *b_cols[count]; + if (left) { + a_cols[0] = convert_scalar (a, b); + for (int i = 0; i < count; i++) { + a_cols[i] = a_cols[0]; + b_cols[i] = get_column (b, i); + } + } else { + b_cols[0] = convert_scalar (b, a); + for (int i = 0; i < count; i++) { + a_cols[i] = get_column (a, i); + b_cols[i] = b_cols[0]; + } + } + auto params = new_list_expr (nullptr); + for (int i = 0; i < count; i++) { + expr_append_expr (params, binary_expr (op, a_cols[i], b_cols[i])); + } + return constructor_expr (new_type_expr (mat_type), params); +} + static const expr_t * matrix_scalar_div (int op, const expr_t *a, const expr_t *b) { @@ -305,7 +336,20 @@ matrix_scalar_div (int op, const expr_t *a, const expr_t *b) } static const expr_t * -vector_vector_expr (int op, const expr_t *a, const expr_t *b) +vector_scalar_expr (int op, const expr_t *a, const expr_t *b) +{ + scoped_src_loc (a); + bool left = is_scalar (get_type (a)); + if (left) { + a = convert_scalar (a, b); + } else { + b = convert_scalar (b, a); + } + return binary_expr (op, a, b); +} + +static const expr_t * +vector_vector_mul (int op, const expr_t *a, const expr_t *b) { expr_t *e = new_binary_expr ('*', a, b); if (options.math.vector_mult == QC_DOT) { @@ -458,6 +502,18 @@ static expr_type_t add_ops[] = { { .match_a = is_integral, .match_b = is_ptr, .process = pointer_arithmetic, }, { .match_a = is_string, .match_b = is_string, }, + { .match_a = is_matrix, .match_b = is_scalar, + .match_shape = shape_always, + .process = matrix_scalar_expr, }, + { .match_a = is_scalar, .match_b = is_matrix, + .match_shape = shape_always, + .process = matrix_scalar_expr, }, + { .match_a = is_nonscalar,.match_b = is_scalar, + .match_shape = shape_always, + .process = vector_scalar_expr, }, + { .match_a = is_scalar, .match_b = is_nonscalar, + .match_shape = shape_always, + .process = vector_scalar_expr, }, { .match_a = is_math, .match_b = is_math, .promote = true }, @@ -469,6 +525,18 @@ static expr_type_t sub_ops[] = { .process = pointer_arithmetic, }, { .match_a = is_ptr, .match_b = is_ptr, .process = pointer_arithmetic, }, + { .match_a = is_matrix, .match_b = is_scalar, + .match_shape = shape_always, + .process = matrix_scalar_expr, }, + { .match_a = is_scalar, .match_b = is_matrix, + .match_shape = shape_always, + .process = matrix_scalar_expr, }, + { .match_a = is_nonscalar,.match_b = is_scalar, + .match_shape = shape_always, + .process = vector_scalar_expr, }, + { .match_a = is_scalar, .match_b = is_nonscalar, + .match_shape = shape_always, + .process = vector_scalar_expr, }, { .match_a = is_math, .match_b = is_math, .promote = true }, @@ -487,18 +555,18 @@ static expr_type_t mul_ops[] = { .process = matrix_binary_expr, }, { .match_a = is_matrix, .match_b = is_scalar, .match_shape = shape_always, - .promote = true, .process = matrix_scalar_expr, }, + .promote = true, .process = matrix_scalar_mul, }, { .match_a = is_scalar, .match_b = is_matrix, .match_shape = shape_always, - .promote = true, .process = matrix_scalar_expr, }, + .promote = true, .process = matrix_scalar_mul, }, { .match_a = is_nonscalar, .match_b = is_scalar, .match_shape = shape_always, - .promote = true, .process = matrix_scalar_expr, }, + .promote = true, .process = matrix_scalar_mul, }, { .match_a = is_scalar, .match_b = is_nonscalar, .match_shape = shape_always, - .promote = true, .process = matrix_scalar_expr, }, + .promote = true, .process = matrix_scalar_mul, }, { .match_a = is_vector, .match_b = is_vector, - .process = vector_vector_expr, }, + .process = vector_vector_mul, }, { .match_a = is_quaternion, .match_b = is_quaternion, .process = quaternion_quaternion_expr, }, { .match_a = is_quaternion, .match_b = is_vector, diff --git a/tools/qfcc/source/expr_construct.c b/tools/qfcc/source/expr_construct.c index 2213f0554..20aa93fd9 100644 --- a/tools/qfcc/source/expr_construct.c +++ b/tools/qfcc/source/expr_construct.c @@ -37,7 +37,7 @@ #include "tools/qfcc/include/type.h" #include "tools/qfcc/include/value.h" -static const expr_t * +const expr_t * get_column (const expr_t *e, int i) { auto t = get_type (e);