[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)
This commit is contained in:
Bill Currie 2024-11-25 12:39:14 +09:00
parent 1e5d500f8b
commit a4eefa6204
3 changed files with 127 additions and 12 deletions

View file

@ -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, const expr_t *new_vector_value (const type_t *ele_type, int width,
int count, const expr_t **elements, int count, const expr_t **elements,
bool implicit); 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); const expr_t *vector_to_compound (const expr_t *vector);
/** Create a new entity constant expression node. /** Create a new entity constant expression node.

View file

@ -59,20 +59,23 @@ get_value (const expr_t *e, int i, int j)
} }
static const expr_t * 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); 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] = {}; const expr_t *components[num_comp] = {};
int num_param = list_count (&params->list); int num_param = list_count (&params->list);
const expr_t *param_exprs[num_param + 1] = {}; const expr_t *param_exprs[num_param + 1] = {};
list_scatter_rev (&params->list, param_exprs); list_scatter_rev (&params->list, param_exprs);
bool all_constant = true; bool all_constant = true;
bool all_implicit = true; bool all_implicit = true;
int p = 0; int c = 0, p = 0;
for (int c = 0; c < num_comp; ) { int err = -1;
while (c < num_comp) {
if (p < num_param) { if (p < num_param) {
auto pexpr = param_exprs[p++]; auto pexpr = param_exprs[p++];
auto ptype = get_type (pexpr); 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); ptype = dereference_type (ptype);
} }
if (!is_math (ptype)) { if (!is_math (ptype)) {
components[c++] = error (pexpr, "invalid type for conversion"); err = c++;
components[err] = error (pexpr, "invalid type for conversion");
continue; continue;
} }
for (int i = 0; i < type_cols (ptype) && c < num_comp; i++) { 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 { } 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) { if (p < num_param) {
return error (e, "too may parameters for %s", type->name); 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]; return components[0];
} }
if (all_constant) { if (all_constant) {
return new_vector_value (base, num_comp, num_comp, components, if (is_matrix (type)) {
all_implicit); 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 (); auto vec = new_expr ();
@ -117,6 +132,90 @@ math_constructor (const type_t *type, const expr_t *params, const expr_t *e)
return vec; 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 (&params->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 (&params->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 (&params->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 (&params->list);
const expr_t *param_exprs[num_param + 1] = {};
list_scatter_rev (&params->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 * const expr_t *
constructor_expr (const expr_t *e, const expr_t *params) 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)) { if (is_algebra (type)) {
return error (e, "algebra not implemented"); return error (e, "algebra not implemented");
} }
if (is_matrix (type)) {
return error (e, "matrix not implemented");
}
if (is_math (type)) { if (is_math (type)) {
return math_constructor (type, params, e); return math_constructor (type, params, e);
} }

View file

@ -41,7 +41,7 @@ new_vector_value (const type_t *ele_type, int width, int count,
const expr_t **elements, bool implicit) const expr_t **elements, bool implicit)
{ {
const type_t *vec_type = vector_type (ele_type, width); 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++) { for (int i = 0, offs = 0; i < count; i++) {
auto src_type = get_type (elements[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); 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 * const expr_t *
new_vector_list (const expr_t *expr_list) new_vector_list (const expr_t *expr_list)