From ee6e38e2f9effafad89339830fcbc01fa5ee7603 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 30 Aug 2024 13:53:31 +0900 Subject: [PATCH] [qfcc] Implement glsl's contructors for math types I don't think this includes bools yet, and matrices aren't supported yet, but float vectors work quite nicely. --- tools/qfcc/include/expr.h | 4 + tools/qfcc/source/Makemodule.am | 1 + tools/qfcc/source/expr.c | 4 + tools/qfcc/source/expr_construct.c | 125 +++++++++++++++++++++++++++++ tools/qfcc/source/expr_vector.c | 29 ++++--- 5 files changed, 153 insertions(+), 10 deletions(-) create mode 100644 tools/qfcc/source/expr_construct.c diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 16145100a..5623906fe 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -658,6 +658,9 @@ float expr_float (const expr_t *e) __attribute__((pure)); const expr_t *new_vector_expr (const float *vector_val); const float *expr_vector (const expr_t *e) __attribute__((pure)); 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); /** Create a new entity constant expression node. @@ -895,6 +898,7 @@ void vararg_integer (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 *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); const expr_t *goto_expr (const expr_t *label); diff --git a/tools/qfcc/source/Makemodule.am b/tools/qfcc/source/Makemodule.am index e264cbd89..ebd7cc642 100644 --- a/tools/qfcc/source/Makemodule.am +++ b/tools/qfcc/source/Makemodule.am @@ -32,6 +32,7 @@ qfcc_SOURCES = \ tools/qfcc/source/expr_bool.c \ tools/qfcc/source/expr_cast.c \ tools/qfcc/source/expr_compound.c \ + tools/qfcc/source/expr_construct.c \ tools/qfcc/source/expr_dag.c \ tools/qfcc/source/expr_obj.c \ tools/qfcc/source/expr_optimize.c \ diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index bd4291dc2..2342ef2d5 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -2341,6 +2341,10 @@ function_expr (const expr_t *fexpr, const expr_t *params) } } + if (fexpr->type == ex_symbol && fexpr->symbol->sy_type == sy_type) { + return constructor_expr (fexpr, params); + } + fexpr = find_function (fexpr, params); fexpr = convert_name (fexpr); if (is_error (fexpr)) { diff --git a/tools/qfcc/source/expr_construct.c b/tools/qfcc/source/expr_construct.c new file mode 100644 index 000000000..eee87282a --- /dev/null +++ b/tools/qfcc/source/expr_construct.c @@ -0,0 +1,125 @@ +/* + expr_construct.c + + type constructor expressions + + Copyright (C) 2024 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include + +#include "tools/qfcc/include/algebra.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/rua-lang.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" +#include "tools/qfcc/include/value.h" + +static const expr_t * +get_value (const expr_t *e, int i, int j) +{ + auto t = get_type (e); + + if (i < 0 || i >= type_cols (t) || j < 0 || j >= type_rows (t)) { + internal_error (e, "invalid index"); + } + if (type_cols (t) > 1) { + auto ind = new_int_expr (i, false); + e = array_expr (e, ind); + } + if (type_rows (t) > 1) { + auto ind = new_int_expr (j, false); + e = array_expr (e, ind); + } + return e; +} + +static const expr_t * +math_constructor (const type_t *type, const expr_t *params, const expr_t *e) +{ + auto base = base_type (type); + int num_comp = type->width; + 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; ) { + if (p < num_param) { + auto pexpr = param_exprs[p++]; + auto ptype = get_type (pexpr); + if (!is_math (ptype)) { + components[c++] = error (pexpr, "invalid type for conversion"); + continue; + } + for (int i = 0; i < type_cols (ptype) && c < num_comp; i++) { + for (int j = 0; j < type_rows (ptype) && c < num_comp; j++) { + auto val = get_value (pexpr, i, j); + all_implicit = all_implicit && val->implicit; + all_constant = all_constant && is_constant (val); + components[c++] = cast_expr (base, val); + } + } + } else { + components[c++] = new_nil_expr (); + } + } + if (p < num_param) { + return error (e, "too may parameters for %s", type->name); + } + if (num_comp == 1) { + return components[0]; + } + if (all_constant) { + return new_vector_value (base, num_comp, num_comp, components, + all_implicit); + } + + auto vec = new_expr (); + vec->type = ex_vector; + vec->vector.type = vector_type (base, num_comp); + list_gather (&vec->vector.list, components, num_comp); + return vec; +} + +const expr_t * +constructor_expr (const expr_t *e, const expr_t *params) +{ + auto type = e->symbol->type; + 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); + } + return error (e, "not implemented"); +} diff --git a/tools/qfcc/source/expr_vector.c b/tools/qfcc/source/expr_vector.c index b97b6b4b0..485eb9af5 100644 --- a/tools/qfcc/source/expr_vector.c +++ b/tools/qfcc/source/expr_vector.c @@ -36,6 +36,23 @@ #include "tools/qfcc/include/type.h" #include "tools/qfcc/include/value.h" +const expr_t * +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)]; + + 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 (vec_type, value), implicit); +} + + const expr_t * new_vector_list (const expr_t *expr_list) { @@ -118,16 +135,8 @@ new_vector_list (const expr_t *expr_list) } if (all_constant) { - const type_t *vec_type = vector_type (ele_type, width); - pr_type_t value[type_size (vec_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 (vec_type, value), all_implicit); + return new_vector_value (ele_type, width, count, elements, + all_implicit); } expr_t *vec = new_expr ();