From a4eefa6204e72a33112a9984e07a2155721d4104 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 25 Nov 2024 12:39:14 +0900 Subject: [PATCH] [qfcc] Implement matrix construction for constants Non-constant matrices are not implemented yet, and it turns out vector-matrix multiplication produces incorrect vector types (for vec4*mat3x4) --- tools/qfcc/include/expr.h | 3 + tools/qfcc/source/expr_construct.c | 118 ++++++++++++++++++++++++++--- tools/qfcc/source/expr_vector.c | 18 ++++- 3 files changed, 127 insertions(+), 12 deletions(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 8dda8ff53..354295989 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -747,6 +747,9 @@ const expr_t *new_vector_list (const expr_t *e); const expr_t *new_vector_value (const type_t *ele_type, int width, int count, const expr_t **elements, bool implicit); +const expr_t *new_matrix_value (const type_t *ele_type, int cols, int rows, + int count, const expr_t **elements, + bool implicit); const expr_t *vector_to_compound (const expr_t *vector); /** Create a new entity constant expression node. diff --git a/tools/qfcc/source/expr_construct.c b/tools/qfcc/source/expr_construct.c index c2101115e..0f8d6f7eb 100644 --- a/tools/qfcc/source/expr_construct.c +++ b/tools/qfcc/source/expr_construct.c @@ -59,20 +59,23 @@ get_value (const expr_t *e, int i, int j) } static const expr_t * -math_constructor (const type_t *type, const expr_t *params, const expr_t *e) +construct_by_components (const type_t *type, const expr_t *params, + const expr_t *e) { auto base = base_type (type); - int num_comp = type->width; + int num_comp = type_rows (type) * type_cols (type); const expr_t *components[num_comp] = {}; int num_param = list_count (¶ms->list); const expr_t *param_exprs[num_param + 1] = {}; list_scatter_rev (¶ms->list, param_exprs); + bool all_constant = true; bool all_implicit = true; - int p = 0; - for (int c = 0; c < num_comp; ) { + int c = 0, p = 0; + int err = -1; + while (c < num_comp) { if (p < num_param) { auto pexpr = param_exprs[p++]; auto ptype = get_type (pexpr); @@ -84,7 +87,8 @@ math_constructor (const type_t *type, const expr_t *params, const expr_t *e) ptype = dereference_type (ptype); } if (!is_math (ptype)) { - components[c++] = error (pexpr, "invalid type for conversion"); + err = c++; + components[err] = error (pexpr, "invalid type for conversion"); continue; } for (int i = 0; i < type_cols (ptype) && c < num_comp; i++) { @@ -96,9 +100,15 @@ math_constructor (const type_t *type, const expr_t *params, const expr_t *e) } } } else { - components[c++] = new_nil_expr (); + break; } } + if (err >= 0) { + return components[err]; + } + if (c < num_comp) { + return error (e, "too few parameters for %s", type->name); + } if (p < num_param) { return error (e, "too may parameters for %s", type->name); } @@ -106,8 +116,13 @@ math_constructor (const type_t *type, const expr_t *params, const expr_t *e) return components[0]; } if (all_constant) { - return new_vector_value (base, num_comp, num_comp, components, - all_implicit); + if (is_matrix (type)) { + return new_matrix_value (base, type_cols (type), type_rows (type), + num_comp, components, all_implicit); + } else { + return new_vector_value (base, type_width (type), + num_comp, components, all_implicit); + } } auto vec = new_expr (); @@ -117,6 +132,90 @@ math_constructor (const type_t *type, const expr_t *params, const expr_t *e) return vec; } +static const expr_t * +construct_diagonal (const type_t *type, const expr_t *scalar, const expr_t *e) +{ + scoped_src_loc (scalar); + int cols = type_cols (type); + int rows = type_rows (type); + const expr_t *components[cols * rows + 1] = {}; + auto zero = new_nil_expr (); + + for (int i = 0; i < cols; i++) { + for (int j = 0; j < rows; j++) { + components[i * rows + j] = i == j ? scalar : zero; + } + } + auto params = new_list_expr (nullptr); + list_gather (¶ms->list, components, cols * rows); + return construct_by_components (type, params, e); +} + +static const expr_t * +construct_matrix (const type_t *type, const expr_t *matrix, const expr_t *e) +{ + scoped_src_loc (matrix); + int cols = type_cols (type); + int rows = type_rows (type); + int src_cols = type_cols (get_type (matrix)); + int src_rows = type_rows (get_type (matrix)); + const expr_t *components[cols * rows + 1] = {}; + auto zero = new_nil_expr (); + + for (int i = 0; i < cols; i++) { + for (int j = 0; j < rows; j++) { + const expr_t *val; + if (i < src_cols && j < src_rows) { + val = get_value (matrix, i, j); + } else { + val = zero; + } + components[i * rows + j] = val; + } + } + auto params = new_list_expr (nullptr); + list_gather (¶ms->list, components, cols * rows); + return construct_by_components (type, params, e); +} + +static const expr_t * +construct_broadcast (const type_t *type, const expr_t *scalar, const expr_t *e) +{ + scoped_src_loc (scalar); + int width = type_width (type); + const expr_t *components[width + 1] = {}; + + for (int i = 0; i < width; i++) { + components[i] = scalar; + } + auto params = new_list_expr (nullptr); + list_gather (¶ms->list, components, width); + return construct_by_components (type, params, e); +} + +static const expr_t * +math_constructor (const type_t *type, const expr_t *params, const expr_t *e) +{ + int num_param = list_count (¶ms->list); + const expr_t *param_exprs[num_param + 1] = {}; + list_scatter_rev (¶ms->list, param_exprs); + + if (num_param == 1 && is_scalar (get_type (param_exprs[0]))) { + if (is_matrix (type)) { + return construct_diagonal (type, param_exprs[0], e); + } + if (is_vector (type)) { + return construct_broadcast (type, param_exprs[0], e); + } + } + if (num_param == 1 && is_matrix (get_type (param_exprs[0]))) { + if (is_matrix (type)) { + return construct_matrix (type, param_exprs[0], e); + } + } + return construct_by_components (type, params, e); +} + const expr_t * constructor_expr (const expr_t *e, const expr_t *params) { @@ -124,9 +223,6 @@ constructor_expr (const expr_t *e, const expr_t *params) if (is_algebra (type)) { return error (e, "algebra not implemented"); } - if (is_matrix (type)) { - return error (e, "matrix not implemented"); - } if (is_math (type)) { return math_constructor (type, params, e); } diff --git a/tools/qfcc/source/expr_vector.c b/tools/qfcc/source/expr_vector.c index ad0004e4a..f91f72f86 100644 --- a/tools/qfcc/source/expr_vector.c +++ b/tools/qfcc/source/expr_vector.c @@ -41,7 +41,7 @@ new_vector_value (const type_t *ele_type, int width, int count, const expr_t **elements, bool implicit) { const type_t *vec_type = vector_type (ele_type, width); - pr_type_t value[type_size (vec_type)]; + pr_type_t value[type_size (vec_type)] = {}; for (int i = 0, offs = 0; i < count; i++) { auto src_type = get_type (elements[i]); @@ -52,6 +52,22 @@ new_vector_value (const type_t *ele_type, int width, int count, return new_value_expr (new_type_value (vec_type, value), implicit); } +const expr_t * +new_matrix_value (const type_t *ele_type, int cols, int rows, int count, + const expr_t **elements, bool implicit) +{ + const type_t *mat_type = matrix_type (ele_type, cols, rows); + pr_type_t value[type_size (mat_type)] = {}; + + for (int i = 0, offs = 0; i < count; i++) { + auto src_type = get_type (elements[i]); + value_store (value + offs, src_type, elements[i]); + offs += type_size (src_type); + } + + return new_value_expr (new_type_value (mat_type, value), implicit); +} + const expr_t * new_vector_list (const expr_t *expr_list)