[qfcc] Add a code generator for type expressions

Allows the parsing of the return type in the following:

    @generic(vec=[vec2,vec3,vec4]) {
    @vector(bool,@width(vec)) lessThan(vec x, vec y);
    }

Unfortunately, can't use math in int value parameters just yet, the
processing of expressions needs to be delayed (it's currently done
immediately so type-checking happens to early).

It's not connected up yet, but does produce what looks like the correct
code.
This commit is contained in:
Bill Currie 2024-09-06 01:00:25 +09:00
parent 55d7d1f069
commit b59a8fb66a
7 changed files with 662 additions and 11 deletions

View file

@ -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,

View file

@ -0,0 +1,75 @@
/*
evaluate_type.h
type evaluation
Copyright (C) 2024 Bill Currie <bill@taniwha.org>
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

View file

@ -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 \

View file

@ -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);

View file

@ -0,0 +1,214 @@
/*
evaluate_type.c
type evaluation
Copyright (C) 2024 Bill Currie <bill@taniwha.org>
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 <string.h>
#include <stdlib.h>
#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);
}

View file

@ -29,18 +29,39 @@
#endif
#include <string.h>
#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;
}

View file

@ -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);