From c185d2463b58e77e1eb88591ec7ec26bfc67d5b6 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 Dec 2024 00:26:07 +0900 Subject: [PATCH] [qfcc] Support matrices in spirv output With a few more fixes, iqm.vert builds nicely. --- tools/qfcc/include/type.h | 1 + tools/qfcc/source/expr.c | 2 +- tools/qfcc/source/expr_construct.c | 6 ++-- tools/qfcc/source/expr_process.c | 16 ++++++++-- tools/qfcc/source/target_spirv.c | 51 ++++++++++++++++++++++-------- tools/qfcc/source/type.c | 9 +++++- 6 files changed, 66 insertions(+), 19 deletions(-) diff --git a/tools/qfcc/include/type.h b/tools/qfcc/include/type.h index 479ab5f08..af06aa405 100644 --- a/tools/qfcc/include/type.h +++ b/tools/qfcc/include/type.h @@ -171,6 +171,7 @@ const type_t *reference_type (const type_t *aux); const type_t *tagged_reference_type (unsigned tag, const type_t *aux); const type_t *vector_type (const type_t *ele_type, int width) __attribute__((pure)); const type_t *matrix_type (const type_t *ele_type, int cols, int rows) __attribute__((pure)); +const type_t *column_type (const type_t *mat_type) __attribute__((pure)); const type_t *base_type (const type_t *vec_type) __attribute__((pure)); /** Return an integral type of same size as the provided type. diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index df54681ff..b8df2466f 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -2372,7 +2372,7 @@ array_expr (const expr_t *array, const expr_t *index) return index; if (!is_pointer (array_type) && !is_array (array_type) - && !is_nonscalar (array_type)) + && !is_nonscalar (array_type) && !is_matrix (array_type)) return error (array, "not an array"); if (!is_integral (index_type)) return error (index, "invalid array index type"); diff --git a/tools/qfcc/source/expr_construct.c b/tools/qfcc/source/expr_construct.c index 0f8d6f7eb..850c30cc0 100644 --- a/tools/qfcc/source/expr_construct.c +++ b/tools/qfcc/source/expr_construct.c @@ -47,7 +47,9 @@ get_value (const expr_t *e, int i, int j) } if (type_cols (t) > 1) { auto ind = new_int_expr (i, false); - e = array_expr (e, ind); + auto a = new_array_expr (e, ind); + a->array.type = column_type (t); + e = a; } if (type_rows (t) > 1) { auto ind = new_int_expr (j, false); @@ -127,7 +129,7 @@ construct_by_components (const type_t *type, const expr_t *params, auto vec = new_expr (); vec->type = ex_vector; - vec->vector.type = vector_type (base, num_comp); + vec->vector.type = type; list_gather (&vec->vector.list, components, num_comp); return vec; } diff --git a/tools/qfcc/source/expr_process.c b/tools/qfcc/source/expr_process.c index d1e1bc354..91ef19ac7 100644 --- a/tools/qfcc/source/expr_process.c +++ b/tools/qfcc/source/expr_process.c @@ -170,7 +170,19 @@ proc_array (const expr_t *expr) } scoped_src_loc (expr); auto e = new_array_expr (base, index); - e->array.type = dereference_type (get_type (base)); + auto bt = get_type (base); + if (is_reference (bt)) { + bt = dereference_type (bt); + } + const type_t *type; + if (is_matrix (bt)) { + type = column_type (bt); + } else if (is_nonscalar (bt)) { + type = base_type (bt); + } else { + type = dereference_type (bt); + } + e->array.type = type; return e; } @@ -230,7 +242,7 @@ static bool proc_do_list (ex_list_t *out, const ex_list_t *in) { int count = list_count (in); - const expr_t *exprs[count + 1]; + const expr_t *exprs[count + 1] = {}; list_scatter (in, exprs); bool ok = true; for (int i = 0; i < count; i++) { diff --git a/tools/qfcc/source/target_spirv.c b/tools/qfcc/source/target_spirv.c index 90b1b22a2..c81d80309 100644 --- a/tools/qfcc/source/target_spirv.c +++ b/tools/qfcc/source/target_spirv.c @@ -482,8 +482,8 @@ type_id (const type_t *type, spirvctx_t *ctx) // quaternion as vec4 auto qtype = vector_type (&type_float, 4); id = type_id (qtype, ctx); - } else if (type_cols (type) > 1) { - auto ctype = vector_type (base_type (type), type_rows (type)); + } else if (is_matrix (type)) { + auto ctype = column_type (type); unsigned cid = type_id (ctype, ctx); id = spirv_TypeMatrix (cid, type_cols (type), ctx); } else if (type_width (type) > 1) { @@ -1109,17 +1109,14 @@ spirv_vector_value (const ex_value_t *value, spirvctx_t *ctx) auto base = base_type (value->type); int width = type_width (value->type); ex_value_t *comp_vals[width]; - if (type_size (base) == 1) { - for (int i = 0; i < width; i++) { - comp_vals[i] = new_type_value (base, &value->raw_value + i); - } - } else if (type_size (base) == 2) { - for (int i = 0; i < width; i++) { - comp_vals[i] = new_type_value (base, &value->raw_value + i * 2); - } - } else { + auto val = &value->raw_value; + if (type_size (base) < 1 || type_size (base) > 2) { internal_error (nullptr, "invalid vector component size"); } + for (int i = 0; i < width; i++) { + comp_vals[i] = new_type_value (base, val); + val += type_size (base); + } unsigned comp_ids[width]; for (int i = 0; i < width; i++) { auto e = new_value_expr (comp_vals[i], false); @@ -1138,12 +1135,40 @@ spirv_vector_value (const ex_value_t *value, spirvctx_t *ctx) return id; } +static unsigned +spirv_matrix_value (const ex_value_t *value, spirvctx_t *ctx) +{ + auto ctype = column_type (value->type); + int count = type_cols (value->type); + ex_value_t *columns[count]; + auto val = &value->raw_value; + for (int i = 0; i < count; i++) { + columns[i] = new_type_value (ctype, val); + val += type_size (ctype); + columns[i]->id = spirv_vector_value (columns[i], ctx); + } + + auto space = ctx->module->globals; + int tid = type_id (value->type, ctx); + int id = spirv_id (ctx); + auto insn = spirv_new_insn (SpvOpConstantComposite, 3 + count, space); + INSN (insn, 1) = tid; + INSN (insn, 2) = id; + for (int i = 0; i < count; i++) { + INSN (insn, 3 + i) = columns[i]->id; + } + return id; +} + static unsigned spirv_value (const expr_t *e, spirvctx_t *ctx) { auto value = e->value; if (!value->id) { - if (is_nonscalar (value->type) && type_cols (value->type) == 1) { + if (is_matrix (value->type)) { + return spirv_matrix_value (value, ctx); + } + if (is_nonscalar (value->type)) { return spirv_vector_value (value, ctx); } unsigned tid = type_id (value->type, ctx); @@ -1887,7 +1912,7 @@ spirv_build_element_chain (element_chain_t *element_chain, const type_t *type, state.offset = state.field->id; } } else if (is_matrix (type)) { - state.type = vector_type (base_type (type), type_rows (type)); + state.type = column_type (type); } else if (is_nonscalar (type)) { state.type = base_type (type); } else if (is_array (type)) { diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index f0ab6881c..d10f42960 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -855,6 +855,12 @@ matrix_type (const type_t *ele_type, int cols, int rows) return nullptr; } +const type_t * +column_type (const type_t *mat_type) +{ + return vector_type (base_type (mat_type), type_rows (mat_type)); +} + const type_t * vector_type (const type_t *ele_type, int width) { @@ -1040,6 +1046,7 @@ unalias_type (const type_t *type) const type_t * dereference_type (const type_t *type) { + // is_ptr is used to catch both pointer and reference if (!is_ptr (type) && !is_field (type) && !is_array (type)) { internal_error (0, "dereference non pointer/field/array type"); } @@ -1575,7 +1582,7 @@ is_math (const type_t *type) if (is_algebra (type)) { return true; } - return is_scalar (type) || is_nonscalar (type); + return is_scalar (type) || is_nonscalar (type) || is_matrix (type); } bool