diff --git a/tools/qfcc/include/evaluate.h b/tools/qfcc/include/evaluate.h index e9855c581..1027c977c 100644 --- a/tools/qfcc/include/evaluate.h +++ b/tools/qfcc/include/evaluate.h @@ -31,11 +31,15 @@ #ifndef __evaluate_h #define __evaluate_h +#include "QF/progs.h" + /** \defgroup qfcc_evaluate Constant evaluation. \ingroup qfcc_expr */ ///@{ +void evaluate_debug_handler (prdebug_t event, void *param, void *data); + struct type_s; struct ex_value_s; struct ex_value_s *convert_value (struct ex_value_s *value, diff --git a/tools/qfcc/include/evaluate_type.h b/tools/qfcc/include/evaluate_type.h new file mode 100644 index 000000000..3460cf231 --- /dev/null +++ b/tools/qfcc/include/evaluate_type.h @@ -0,0 +1,75 @@ +/* + evaluate_type.h + + type evaluation + + 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 + +*/ + +#ifndef __evaluate_type_h +#define __evaluate_type_h + +/** \defgroup qfcc_evaluate_type Computed type expression evaluation. + \ingroup qfcc_expr +*/ +///@{ + +enum { + tf_null, + tf_eval, + tf_function, + tf_field, + tf_pointer, + tf_array, + tf_base, + tf_width, + tf_vector, + tf_rows, + tf_cols, + tf_matrix, + tf_int, + tf_uint, + tf_bool, + tf_float, + tf_gentype, + + tf_num_functions +}; + +typedef struct typeeval_s { + struct typeeval_s *next; + struct dstatement_s *code; + struct pr_type_s *data; + int code_size; + int data_size; +} typeeval_t; + +void setup_type_progs (void); + +typedef struct expr_s expr_t; +typedef struct gentype_s gentype_t; +typeeval_t *build_type_function (const expr_t *te, int num_types, + gentype_t *types); + +///@} + +#endif//__evaluate_type_h diff --git a/tools/qfcc/source/Makemodule.am b/tools/qfcc/source/Makemodule.am index dcc3346d6..b87cae83b 100644 --- a/tools/qfcc/source/Makemodule.am +++ b/tools/qfcc/source/Makemodule.am @@ -39,6 +39,7 @@ qfcc_SOURCES = \ tools/qfcc/source/expr_type.c \ tools/qfcc/source/expr_vector.c \ tools/qfcc/source/evaluate.c \ + tools/qfcc/source/evaluate_type.c \ tools/qfcc/source/flow.c \ tools/qfcc/source/function.c \ tools/qfcc/source/glsl-block.c \ diff --git a/tools/qfcc/source/evaluate.c b/tools/qfcc/source/evaluate.c index 5493ed7fc..79731cce8 100644 --- a/tools/qfcc/source/evaluate.c +++ b/tools/qfcc/source/evaluate.c @@ -53,8 +53,8 @@ //FIXME this (to setup_value_progs) should be in its own file and more //general (good for constant folding, too, and maybe some others). -static void -value_debug_handler (prdebug_t event, void *param, void *data) +void +evaluate_debug_handler (prdebug_t event, void *param, void *data) { progs_t *pr = data; dstatement_t *st = 0; @@ -89,7 +89,7 @@ enum { static bfunction_t value_functions[] = { {}, // null function - [vf_convert] = { .first_statement = vf_convert * 16 }, + [vf_convert] = { .first_statement = vf_convert * 16 }, [vf_foldconst] = { .first_statement = vf_foldconst * 16 }, }; @@ -112,13 +112,13 @@ static codespace_t value_codespace = { #define num_globals 16384 #define stack_size 8192 static __attribute__((aligned(64))) -pr_type_t value_globals[num_globals + 128] = { +pr_type_t evaluate_globals[num_globals + 128] = { [num_globals - stack_size] = { .uint_value = num_globals }, }; static defspace_t value_defspace = { .type = ds_backed, .def_tail = &value_defspace.defs, - .data = value_globals, + .data = evaluate_globals, .max_size = num_globals - stack_size, .grow = 0, }; @@ -131,19 +131,19 @@ static dprograms_t value_progs = { }; static progs_t value_pr = { .progs = &value_progs, - .debug_handler = value_debug_handler, + .debug_handler = evaluate_debug_handler, .debug_data = &value_pr, .pr_trace = 1, .pr_trace_depth = -1, .function_table = value_functions, .pr_statements = value_statements, .globals_size = num_globals, - .pr_globals = value_globals, + .pr_globals = evaluate_globals, .stack_bottom = num_globals - stack_size + 4, - .pr_return_buffer = value_globals + num_globals, - .pr_return = value_globals + num_globals, + .pr_return_buffer = evaluate_globals + num_globals, + .pr_return = evaluate_globals + num_globals, .globals = { - .stack = (pr_ptr_t *) (value_globals + num_globals - stack_size), + .stack = (pr_ptr_t *) (evaluate_globals + num_globals - stack_size), } }; @@ -172,7 +172,7 @@ convert_value (ex_value_t *value, const type_t *type) int addr = value_functions[vf_convert].first_statement; value_statements[addr + 0].b = conv; value_statements[addr + 1].c = type_size (type) - 1; - memcpy (value_globals, &value->raw_value, + memcpy (evaluate_globals, &value->raw_value, type_size (value->type) * sizeof (pr_type_t)); value_pr.pr_trace = options.verbosity > 1; PR_ExecuteProgram (&value_pr, vf_convert); diff --git a/tools/qfcc/source/evaluate_type.c b/tools/qfcc/source/evaluate_type.c new file mode 100644 index 000000000..aaecf2500 --- /dev/null +++ b/tools/qfcc/source/evaluate_type.c @@ -0,0 +1,214 @@ +/* + evaluate_type.c + + type evaluation + + 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 + +#include "QF/progs.h" +#include "QF/sys.h" + +#include "QF/simd/types.h" + +#include "tools/qfcc/include/codespace.h" +#include "tools/qfcc/include/def.h" +#include "tools/qfcc/include/defspace.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/dot.h" +#include "tools/qfcc/include/evaluate.h" +#include "tools/qfcc/include/evaluate_type.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/opcodes.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/statements.h" +#include "tools/qfcc/include/type.h" +#include "tools/qfcc/include/value.h" + +typedef struct typectx_s { + const type_t **types; + int num_types; + const expr_t *expr; + sys_jmpbuf jmpbuf; +} typectx_t; + +static void +tf_function_func (progs_t *pr, void *data) +{ +} + +static void +tf_field_func (progs_t *pr, void *data) +{ +} + +static void +tf_pointer_func (progs_t *pr, void *data) +{ +} + +static void +tf_array_func (progs_t *pr, void *data) +{ +} + +static void +tf_base_func (progs_t *pr, void *data) +{ +} + +static void +tf_width_func (progs_t *pr, void *data) +{ +} + +static void +tf_vector_func (progs_t *pr, void *data) +{ +} + +static void +tf_rows_func (progs_t *pr, void *data) +{ +} + +static void +tf_cols_func (progs_t *pr, void *data) +{ +} + +static void +tf_matrix_func (progs_t *pr, void *data) +{ +} + +static void +tf_int_func (progs_t *pr, void *data) +{ +} + +static void +tf_uint_func (progs_t *pr, void *data) +{ +} + +static void +tf_bool_func (progs_t *pr, void *data) +{ +} + +static void +tf_float_func (progs_t *pr, void *data) +{ +} + +static void +tf_gentype_func (progs_t *pr, void *data) +{ + auto ctx = *(typectx_t **) data; + int ind = P_INT (pr, 0); + if (ind < 0 || ind >= ctx->num_types) { + internal_error (ctx->expr, "invalid type index"); + } + auto type = ctx->types[ind]; + if (!type) { + error (ctx->expr, "refernce to unresolved type"); + Sys_longjmp (ctx->jmpbuf); + } + R_POINTER (pr) = type->type_def->offset; +} + +#define BASE(b, base) (((base) & 3) << OP_##b##_SHIFT) +#define OP(a, b, c, op) ((op) | BASE(A, a) | BASE(B, b) | BASE(C, c)) + +static typectx_t *type_genfunc; +#define TF_FUNC(tf) \ + [tf] = { .first_statement = -1, .func = tf##_func, .data = &type_genfunc } +static bfunction_t type_functions[] = { + {}, // null function + [tf_eval] = { .first_statement = 1 }, + TF_FUNC(tf_function), + TF_FUNC(tf_field), + TF_FUNC(tf_pointer), + TF_FUNC(tf_array), + TF_FUNC(tf_base), + TF_FUNC(tf_width), + TF_FUNC(tf_vector), + TF_FUNC(tf_rows), + TF_FUNC(tf_cols), + TF_FUNC(tf_matrix), + TF_FUNC(tf_int), + TF_FUNC(tf_uint), + TF_FUNC(tf_bool), + TF_FUNC(tf_float), + TF_FUNC(tf_gentype), +}; +#undef TF_FUNC + +#define num_globals 16384 +#define stack_size 8192 +static __attribute__((aligned(64))) +pr_type_t type_globals[num_globals + 128] = { + [num_globals - stack_size] = { .uint_value = num_globals }, +}; +static defspace_t type_defspace = { + .type = ds_backed, + .def_tail = &type_defspace.defs, + .data = type_globals, + .max_size = num_globals - stack_size, + .grow = 0, +}; + +static dprograms_t type_progs = { + .version = PROG_VERSION, + //.statements.count filled in at runtime +}; +static progs_t type_pr = { + .progs = &type_progs, + .debug_handler = evaluate_debug_handler, + .debug_data = &type_pr, + .pr_trace = 1, + .pr_trace_depth = -1, + .function_table = type_functions, + //.pr_statements filled in at runtime + .globals_size = num_globals, + .pr_globals = type_globals, + .stack_bottom = num_globals - stack_size + 4, + .pr_return_buffer = type_globals + num_globals, + .pr_return = type_globals + num_globals, + .globals = { + .stack = (pr_ptr_t *) (type_globals + num_globals - stack_size), + } +}; + +void +setup_type_progs (void) +{ + PR_Init (&type_pr); + PR_Debug_Init (&type_pr); +} diff --git a/tools/qfcc/source/expr_type.c b/tools/qfcc/source/expr_type.c index bd4221fab..b364cbb53 100644 --- a/tools/qfcc/source/expr_type.c +++ b/tools/qfcc/source/expr_type.c @@ -29,18 +29,39 @@ #endif #include +#include "QF/progs.h" +#include "QF/sys.h" + +#include "tools/qfcc/include/def.h" +#include "tools/qfcc/include/defspace.h" +#include "tools/qfcc/include/codespace.h" #include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/evaluate_type.h" #include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/function.h" +#include "tools/qfcc/include/opcodes.h" #include "tools/qfcc/include/rua-lang.h" +#include "tools/qfcc/include/statements.h" #include "tools/qfcc/include/symtab.h" #include "tools/qfcc/include/type.h" +typedef struct { + gentype_t *types; + int num_types; + codespace_t *code; + defspace_t *data; + sys_jmpbuf jmpbuf; + def_t *args[3]; + def_t *funcs[tf_num_functions]; +} comp_ctx_t; + typedef struct { const char *name; const char *(*check_params) (int arg_count, const expr_t **args); const type_t *(*resolve) (int arg_count, const expr_t **args); const type_t **(*expand) (int arg_count, const expr_t **args); const expr_t *(*evaluate) (int arg_count, const expr_t **args); + def_t *(*compute) (int arg_count, const expr_t **args, comp_ctx_t *ctx); } type_func_t; static type_func_t type_funcs[]; @@ -393,78 +414,256 @@ expand_matrix (int arg_count, const expr_t **args) } } +static def_t *compute_tmp (comp_ctx_t *ctx); +static def_t *compute_type (const expr_t *arg, comp_ctx_t *ctx); +static def_t *compute_val (const expr_t *arg, comp_ctx_t *ctx); + +#define BASE(b, base) (((base) & 3) << OP_##b##_SHIFT) +#define DBASE(b, d) ((d) ? BASE(b, ((def_t*)(d))->reg) : 0) +#define DOFFSET(d) ((d) ? ((def_t*)(d))->offset : 0) +#define OP(a, b, c, op) ((op) | DBASE(A, a) | DBASE(B, b) | DBASE(C, c)) +#define I(_op, _a, _b, _c) &(dstatement_t){ \ + .op = OP(_a,_b,_c,_op), \ + .a = DOFFSET(_a), \ + .b = DOFFSET(_b), \ + .c = DOFFSET(_c), \ +} +#define C(op, a, b, c) codespace_addcode (ctx->code, I(op, a, b, c), 1) + +static def_t * +compute_function (int arg_count, const expr_t **args, comp_ctx_t *ctx) +{ + auto type = compute_type (args[0], ctx); + auto res = compute_tmp (ctx); + C (OP_STORE_A_1, ctx->args[0], nullptr, type); + C (OP_CALL_B, ctx->funcs[tf_function], nullptr, res); + return res; +} + +static def_t * +compute_field (int arg_count, const expr_t **args, comp_ctx_t *ctx) +{ + auto type = compute_type (args[0], ctx); + auto res = compute_tmp (ctx); + C (OP_STORE_A_1, ctx->args[0], nullptr, type); + C (OP_CALL_B, ctx->funcs[tf_field], nullptr, res); + return res; +} + +static def_t * +compute_pointer (int arg_count, const expr_t **args, comp_ctx_t *ctx) +{ + auto type = compute_type (args[0], ctx); + auto res = compute_tmp (ctx); + C (OP_STORE_A_1, ctx->args[0], nullptr, type); + C (OP_CALL_B, ctx->funcs[tf_pointer], nullptr, res); + return res; +} + +static def_t * +compute_base (int arg_count, const expr_t **args, comp_ctx_t *ctx) +{ + auto type = compute_type (args[0], ctx); + auto res = compute_tmp (ctx); + C (OP_STORE_A_1, ctx->args[0], nullptr, type); + C (OP_CALL_B, ctx->funcs[tf_base], nullptr, res); + return res; +} + +static def_t * +compute_int (int arg_count, const expr_t **args, comp_ctx_t *ctx) +{ + auto type = compute_type (args[0], ctx); + auto res = compute_tmp (ctx); + C (OP_STORE_A_1, ctx->args[0], nullptr, type); + C (OP_CALL_B, ctx->funcs[tf_int], nullptr, res); + return res; +} + +static def_t * +compute_uint (int arg_count, const expr_t **args, comp_ctx_t *ctx) +{ + auto type = compute_type (args[0], ctx); + auto res = compute_tmp (ctx); + C (OP_STORE_A_1, ctx->args[0], nullptr, type); + C (OP_CALL_B, ctx->funcs[tf_uint], nullptr, res); + return res; +} + +static def_t * +compute_bool (int arg_count, const expr_t **args, comp_ctx_t *ctx) +{ + auto type = compute_type (args[0], ctx); + auto res = compute_tmp (ctx); + C (OP_STORE_A_1, ctx->args[0], nullptr, type); + C (OP_CALL_B, ctx->funcs[tf_bool], nullptr, res); + return res; +} + +static def_t * +compute_float (int arg_count, const expr_t **args, comp_ctx_t *ctx) +{ + auto type = compute_type (args[0], ctx); + auto res = compute_tmp (ctx); + C (OP_STORE_A_1, ctx->args[0], nullptr, type); + C (OP_CALL_B, ctx->funcs[tf_float], nullptr, res); + return res; +} + +static def_t * +compute_type_array (int arg_count, const expr_t **args, comp_ctx_t *ctx) +{ + auto type = compute_type (args[0], ctx); + auto size = compute_val (args[1], ctx); + auto res = compute_tmp (ctx); + C (OP_STORE_A_1, ctx->args[0], nullptr, type); + C (OP_STORE_A_1, ctx->args[1], nullptr, size); + C (OP_CALL_B, ctx->funcs[tf_array], nullptr, res); + return res; +} + +static def_t * +compute_type_vector (int arg_count, const expr_t **args, comp_ctx_t *ctx) +{ + auto type = compute_type (args[0], ctx); + auto width = compute_val (args[1], ctx); + auto res = compute_tmp (ctx); + C (OP_STORE_A_1, ctx->args[0], nullptr, type); + C (OP_STORE_A_1, ctx->args[1], nullptr, width); + C (OP_CALL_B, ctx->funcs[tf_vector], nullptr, res); + return res; +} + +static def_t * +compute_matrix (int arg_count, const expr_t **args, comp_ctx_t *ctx) +{ + auto type = compute_type (args[0], ctx); + auto cols = compute_val (args[1], ctx); + auto rows = compute_val (args[2], ctx); + auto res = compute_tmp (ctx); + C (OP_STORE_A_1, ctx->args[0], nullptr, type); + C (OP_STORE_A_1, ctx->args[1], nullptr, cols); + C (OP_STORE_A_1, ctx->args[2], nullptr, rows); + C (OP_CALL_B, ctx->funcs[tf_matrix], nullptr, res); + return res; +} + +static def_t * +compute_width (int arg_count, const expr_t **args, comp_ctx_t *ctx) +{ + auto type = compute_type (args[0], ctx); + auto res = compute_tmp (ctx); + C (OP_STORE_A_1, ctx->args[0], nullptr, type); + C (OP_CALL_B, ctx->funcs[tf_width], nullptr, res); + return res; +} + +static def_t * +compute_rows (int arg_count, const expr_t **args, comp_ctx_t *ctx) +{ + auto type = compute_type (args[0], ctx); + auto res = compute_tmp (ctx); + C (OP_STORE_A_1, ctx->args[0], nullptr, type); + C (OP_CALL_B, ctx->funcs[tf_rows], nullptr, res); + return res; +} + +static def_t * +compute_cols (int arg_count, const expr_t **args, comp_ctx_t *ctx) +{ + auto type = compute_type (args[0], ctx); + auto res = compute_tmp (ctx); + C (OP_STORE_A_1, ctx->args[0], nullptr, type); + C (OP_CALL_B, ctx->funcs[tf_cols], nullptr, res); + return res; +} + static type_func_t type_funcs[] = { [QC_AT_FUNCTION - QC_GENERIC] = { .name = "@function", .check_params = single_type, .resolve = resolve_function, + .compute = compute_function, }, [QC_AT_FIELD - QC_GENERIC] = { .name = "@field", .check_params = single_type, .resolve = resolve_field, + .compute = compute_field, }, [QC_AT_POINTER - QC_GENERIC] = { .name = "@pointer", .check_params = single_type, .resolve = resolve_pointer, + .compute = compute_pointer, }, [QC_AT_ARRAY - QC_GENERIC] = { .name = "@array", .check_params = single_type_opt_int, .resolve = resolve_array, + .compute = compute_type_array, }, [QC_AT_BASE - QC_GENERIC] = { .name = "@base", .check_params = single_type, .resolve = resolve_base, + .compute = compute_base, }, [QC_AT_WIDTH - QC_GENERIC] = { .name = "@width", .check_params = single_type, .evaluate = evaluate_int_op, + .compute = compute_width, }, [QC_AT_VECTOR - QC_GENERIC] = { .name = "@vector", .check_params = single_type_opt_int, .resolve = resolve_vector, .expand = expand_vector, + .compute = compute_type_vector, }, [QC_AT_ROWS - QC_GENERIC] = { .name = "@rows", .check_params = single_type, .evaluate = evaluate_int_op, + .compute = compute_rows, }, [QC_AT_COLS - QC_GENERIC] = { .name = "@cols", .check_params = single_type, .evaluate = evaluate_int_op, + .compute = compute_cols, }, [QC_AT_MATRIX - QC_GENERIC] = { .name = "@matrix", .check_params = single_type_opt_int_pair, .resolve = resolve_matrix, .expand = expand_matrix, + .compute = compute_matrix, }, [QC_AT_INT - QC_GENERIC] = { .name = "@int", .check_params = single_type, .resolve = resolve_int, + .compute = compute_int, }, [QC_AT_UINT - QC_GENERIC] = { .name = "@uint", .check_params = single_type, .resolve = resolve_uint, + .compute = compute_uint, }, [QC_AT_BOOL - QC_GENERIC] = { .name = "@bool", .check_params = single_type, .resolve = resolve_bool, + .compute = compute_bool, }, [QC_AT_FLOAT - QC_GENERIC] = { .name = "@float", .check_params = single_type, .resolve = resolve_float, + .compute = compute_float, }, }; @@ -576,3 +775,159 @@ evaluate_type (const expr_t *te) list_scatter (&te->typ.params->list, args); return type_funcs[ind].evaluate (arg_count, args); } + +static def_t * +compute_tmp (comp_ctx_t *ctx) +{ + return new_def (0, &type_int, ctx->data, sc_static); +} + +static def_t * +compute_val (const expr_t *arg, comp_ctx_t *ctx) +{ + auto val = compute_tmp (ctx); + if (arg->type == ex_expr || arg->type == ex_uexpr) { + def_t *d1 = compute_val (arg->expr.e1, ctx); + def_t *d2 = nullptr; + statement_t s = { + .opcode = convert_op (arg->expr.op), + .opa = def_operand (d1, d1->type, arg->expr.e1), + .opc = def_operand (val, val->type, arg), + }; + if (arg->type == ex_uexpr) { + d2 = compute_val (arg->expr.e2, ctx); + s.opb = def_operand (d2, d2->type, arg->expr.e2); + } + auto inst = opcode_find (s.opcode, s.opa, s.opb, s.opc); + if (!inst) { + print_statement (&s); + internal_error (arg, "no such instruction"); + } + C (opcode_get (inst), d1, d2, val); + } else if (is_integral_val (arg)) { + D_INT (val) = expr_integral (arg); + } else if (arg->type == ex_type) { + int op = arg->typ.op; + int ind = op - QC_GENERIC; + if (arg->typ.type) { + auto type = arg->typ.type; + if (op == QC_AT_WIDTH) { + D_INT (val) = type_width (type); + } else if (op == QC_AT_ROWS) { + D_INT (val) = type_rows (type); + } else if (op == QC_AT_COLS) { + D_INT (val) = type_cols (type); + } else { + internal_error (arg, "invalid type op"); + } + } else if (arg->typ.params) { + auto params = arg->typ.params; + if (params->type != ex_list || !params->list.head + || params->list.head->next) { + internal_error (arg, "invalid type params"); + } + auto type = compute_type (params->list.head->expr, ctx); + if (op == QC_AT_WIDTH) { + op = tf_width; + } else if (op == QC_AT_ROWS) { + op = tf_rows; + } else if (op == QC_AT_COLS) { + op = tf_cols; + } else { + internal_error (arg, "invalid type op"); + } + C (OP_STORE_A_1, ctx->args[0], nullptr, type); + C (OP_CALL_B, ctx->funcs[op], nullptr, val); + } else { + error (arg, "invalid type passed to %s", type_funcs[ind].name); + } + } + return val; +} + +static def_t * +compute_type (const expr_t *arg, comp_ctx_t *ctx) +{ + if (arg->type == ex_symbol) { + auto sym = arg->symbol; + auto gen = compute_tmp (ctx); + auto res = compute_tmp (ctx); + int ind = -1; + for (int i = 0; i < ctx->num_types; i++) { + if (strcmp (ctx->types[i].name, sym->name) == 0) { + ind = i; + break; + } + } + if (ind < 0) { + error (arg, "%s cannot be resolved here", sym->name); + Sys_longjmp (ctx->jmpbuf); + } + D_INT (gen) = ind; + C (OP_STORE_A_1, ctx->args[0], nullptr, gen); + C (OP_CALL_B, ctx->funcs[tf_gentype], nullptr, res); + return res; + } + if (arg->type != ex_type) { + internal_error (arg, "not a type expression"); + } + if (!arg->typ.op) { + if (!arg->typ.type) { + internal_error (arg, "no type in reference"); + } + auto val = compute_tmp (ctx); + D_INT (val) = arg->typ.type->type_def->offset; + return val; + } + int op = arg->typ.op; + unsigned ind = op - QC_GENERIC; + if (ind >= sizeof (type_funcs) / sizeof (type_funcs[0]) + || !type_funcs[ind].name) { + internal_error (arg, "invalid type op: %d", op); + } + int arg_count = list_count (&arg->typ.params->list); + const expr_t *args[arg_count]; + list_scatter (&arg->typ.params->list, args); + return type_funcs[ind].compute (arg_count, args, ctx); +} + +typeeval_t * +build_type_function (const expr_t *te, int num_types, gentype_t *types) +{ + auto code = codespace_new (); + auto data = defspace_new (ds_backed); + comp_ctx_t *ctx = &(comp_ctx_t) { + .types = types, + .num_types = num_types, + .code = code, + .data = data, + }; + compute_tmp (ctx); + for (int i = 0; i < 3; i++) { + ctx->args[i] = compute_tmp (ctx); + } + for (int i = tf_null + 1; i < tf_num_functions; i++) { + ctx->funcs[i] = compute_tmp (ctx); + D_FUNCTION (ctx->funcs[i]) = i; + } + C (OP_NOP, nullptr, nullptr, nullptr); + def_t *res = nullptr; + if (!Sys_setjmp (ctx->jmpbuf)) { + res = compute_type (te, ctx); + } else { + res = compute_tmp (ctx); + } + C (OP_RETURN, res, nullptr, 0); + typeeval_t *func = malloc (sizeof (typeeval_t)); + *func = (typeeval_t) { + .code = code->code, + .data = data->data, + .code_size = code->size, + .data_size = data->size, + }; + code->code = nullptr; + data->data = nullptr; + codespace_delete (code); + defspace_delete (data); + return func; +} diff --git a/tools/qfcc/source/function.c b/tools/qfcc/source/function.c index bc89f9b6a..f4df5a965 100644 --- a/tools/qfcc/source/function.c +++ b/tools/qfcc/source/function.c @@ -52,6 +52,7 @@ #include "tools/qfcc/include/def.h" #include "tools/qfcc/include/defspace.h" #include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/evaluate_type.h" #include "tools/qfcc/include/emit.h" #include "tools/qfcc/include/expr.h" #include "tools/qfcc/include/flow.h" @@ -1424,6 +1425,7 @@ clear_functions (void) Hash_FlushTable (metafuncs); Hash_FlushTable (function_map); } else { + setup_type_progs (); generic_functions = Hash_NewTable (1021, gen_func_get_key, 0, 0, 0); metafuncs = Hash_NewTable (1021, metafunc_get_full_name, 0, 0, 0); function_map = Hash_NewTable (1021, metafunc_get_name, 0, 0, 0);