[qfcc] Implement generic type computation

I had already implemented the code generation side (though using type
ids instead of encodings is a nice change), but I hadn't implemented the
actual evaluation or even called it. Now return types can be computed
from generic parameters (eg, ivecN from vecN).
This commit is contained in:
Bill Currie 2025-01-10 00:56:02 +09:00
parent 4db018ee47
commit 6e004e9baa
9 changed files with 163 additions and 37 deletions

View file

@ -69,7 +69,8 @@ typedef struct expr_s expr_t;
typedef struct gentype_s gentype_t; typedef struct gentype_s gentype_t;
typeeval_t *build_type_function (const expr_t *te, int num_types, typeeval_t *build_type_function (const expr_t *te, int num_types,
gentype_t *types); gentype_t *types);
const type_t *evaluate_type (const typeeval_t *typeeval, int num_types,
const type_t **types, const expr_t *expr);
///@} ///@}
#endif//__evaluate_type_h #endif//__evaluate_type_h

View file

@ -1052,7 +1052,7 @@ symbol_t *type_parameter (symbol_t *sym, const expr_t *type);
const type_t *resolve_type (const expr_t *te, rua_ctx_t *ctx); const type_t *resolve_type (const expr_t *te, rua_ctx_t *ctx);
const expr_t *process_type (const expr_t *te, rua_ctx_t *ctx); const expr_t *process_type (const expr_t *te, rua_ctx_t *ctx);
const type_t **expand_type (const expr_t *te, rua_ctx_t *ctx); const type_t **expand_type (const expr_t *te, rua_ctx_t *ctx);
const expr_t *evaluate_type (const expr_t *te, rua_ctx_t *ctx); const expr_t *eval_type (const expr_t *te, rua_ctx_t *ctx);
expr_t *append_expr (expr_t *block, const expr_t *e); expr_t *append_expr (expr_t *block, const expr_t *e);
expr_t *prepend_expr (expr_t *block, const expr_t *e); expr_t *prepend_expr (expr_t *block, const expr_t *e);

View file

@ -276,7 +276,9 @@ void clear_typedefs (void);
typedef struct def_s def_t; typedef struct def_s def_t;
typedef struct defset_s DARRAY_TYPE (def_t *) defset_t; typedef struct defset_s DARRAY_TYPE (def_t *) defset_t;
typedef struct typeset_s DARRAY_TYPE (const type_t *) typeset_t;
extern defset_t type_encodings; ///< qfo encodoing extern defset_t type_encodings; ///< qfo encodoing
extern typeset_t type_registry;
extern const type_t *ev_types[]; extern const type_t *ev_types[];
extern int type_cast_map[]; extern int type_cast_map[];

View file

@ -62,7 +62,7 @@ evaluate_debug_handler (prdebug_t event, void *param, void *data)
switch (event) { switch (event) {
case prd_trace: case prd_trace:
st = pr->pr_statements + pr->pr_xstatement; st = pr->pr_statements + pr->pr_xstatement;
PR_PrintStatement (pr, st, 0); PR_PrintStatement (pr, st, 3);
break; break;
case prd_breakpoint: case prd_breakpoint:
case prd_subenter: case prd_subenter:

View file

@ -50,6 +50,9 @@
#include "tools/qfcc/include/type.h" #include "tools/qfcc/include/type.h"
#include "tools/qfcc/include/value.h" #include "tools/qfcc/include/value.h"
#undef P_PACKED
#define P_PACKED(p,t,n) (*(t *) &(p)->pr_globals[1+n])
typedef struct typectx_s { typedef struct typectx_s {
const type_t **types; const type_t **types;
int num_types; int num_types;
@ -57,74 +60,158 @@ typedef struct typectx_s {
sys_jmpbuf jmpbuf; sys_jmpbuf jmpbuf;
} typectx_t; } typectx_t;
static const type_t *
fetch_type (unsigned id, typectx_t *ctx)
{
const type_t *type = nullptr;
if (id < type_registry.size) {
type = type_registry.a[id];
}
if (!type) {
internal_error (ctx->expr, "invalid type id");
}
return type;
}
static void static void
tf_function_func (progs_t *pr, void *data) tf_function_func (progs_t *pr, void *data)
{ {
auto ctx = *(typectx_t **) data;
internal_error (ctx->expr, "not implemented");
} }
static void static void
tf_field_func (progs_t *pr, void *data) tf_field_func (progs_t *pr, void *data)
{ {
auto ctx = *(typectx_t **) data;
unsigned id = P_UINT (pr, 0);
auto type = fetch_type (id, ctx);
type = pointer_type (type);
type = find_type (type);
R_UINT (pr) = type->id;
} }
static void static void
tf_pointer_func (progs_t *pr, void *data) tf_pointer_func (progs_t *pr, void *data)
{ {
auto ctx = *(typectx_t **) data;
unsigned id = P_UINT (pr, 0);
auto type = fetch_type (id, ctx);
type = pointer_type (type);
type = find_type (type);
R_UINT (pr) = type->id;
} }
static void static void
tf_array_func (progs_t *pr, void *data) tf_array_func (progs_t *pr, void *data)
{ {
auto ctx = *(typectx_t **) data;
unsigned id = P_UINT (pr, 0);
unsigned count = P_UINT (pr, 1);
auto type = fetch_type (id, ctx);
type = array_type (type, count);
type = find_type (type);
R_UINT (pr) = type->id;
} }
static void static void
tf_base_func (progs_t *pr, void *data) tf_base_func (progs_t *pr, void *data)
{ {
auto ctx = *(typectx_t **) data;
unsigned id = P_UINT (pr, 0);
auto type = fetch_type (id, ctx);
type = base_type (type);
R_UINT (pr) = type->id;
} }
static void static void
tf_width_func (progs_t *pr, void *data) tf_width_func (progs_t *pr, void *data)
{ {
auto ctx = *(typectx_t **) data;
unsigned id = P_UINT (pr, 0);
auto type = fetch_type (id, ctx);
R_UINT (pr) = type_width (type);
} }
static void static void
tf_vector_func (progs_t *pr, void *data) tf_vector_func (progs_t *pr, void *data)
{ {
auto ctx = *(typectx_t **) data;
unsigned id = P_UINT (pr, 0);
unsigned width = P_UINT (pr, 1);
auto base = fetch_type (id, ctx);
auto type = vector_type (base, width);
R_UINT (pr) = type->id;
} }
static void static void
tf_rows_func (progs_t *pr, void *data) tf_rows_func (progs_t *pr, void *data)
{ {
auto ctx = *(typectx_t **) data;
unsigned id = P_UINT (pr, 0);
auto type = fetch_type (id, ctx);
R_UINT (pr) = type_rows (type);
} }
static void static void
tf_cols_func (progs_t *pr, void *data) tf_cols_func (progs_t *pr, void *data)
{ {
auto ctx = *(typectx_t **) data;
unsigned id = P_UINT (pr, 0);
auto type = fetch_type (id, ctx);
R_UINT (pr) = type_cols (type);
} }
static void static void
tf_matrix_func (progs_t *pr, void *data) tf_matrix_func (progs_t *pr, void *data)
{ {
auto ctx = *(typectx_t **) data;
unsigned id = P_UINT (pr, 0);
unsigned cols = P_UINT (pr, 1);
unsigned rows = P_UINT (pr, 2);
auto base = fetch_type (id, ctx);
auto type = matrix_type (base, cols, rows);
R_UINT (pr) = type->id;
} }
static void static void
tf_int_func (progs_t *pr, void *data) tf_int_func (progs_t *pr, void *data)
{ {
auto ctx = *(typectx_t **) data;
unsigned id = P_UINT (pr, 0);
auto type = fetch_type (id, ctx);
type = int_type (type);
R_UINT (pr) = type->id;
} }
static void static void
tf_uint_func (progs_t *pr, void *data) tf_uint_func (progs_t *pr, void *data)
{ {
auto ctx = *(typectx_t **) data;
unsigned id = P_UINT (pr, 0);
auto type = fetch_type (id, ctx);
type = uint_type (type);
R_UINT (pr) = type->id;
} }
static void static void
tf_bool_func (progs_t *pr, void *data) tf_bool_func (progs_t *pr, void *data)
{ {
auto ctx = *(typectx_t **) data;
unsigned id = P_UINT (pr, 0);
auto type = fetch_type (id, ctx);
type = bool_type (type);
R_UINT (pr) = type->id;
} }
static void static void
tf_float_func (progs_t *pr, void *data) tf_float_func (progs_t *pr, void *data)
{ {
auto ctx = *(typectx_t **) data;
unsigned id = P_UINT (pr, 0);
auto type = fetch_type (id, ctx);
type = float_type (type);
R_UINT (pr) = type->id;
} }
static void static void
@ -140,8 +227,7 @@ tf_gentype_func (progs_t *pr, void *data)
error (ctx->expr, "refernce to unresolved type"); error (ctx->expr, "refernce to unresolved type");
Sys_longjmp (ctx->jmpbuf); Sys_longjmp (ctx->jmpbuf);
} }
auto type_def = type_encodings.a[type->id]; R_UINT (pr) = type->id;
R_POINTER (pr) = type_def->offset;
} }
#define BASE(b, base) (((base) & 3) << OP_##b##_SHIFT) #define BASE(b, base) (((base) & 3) << OP_##b##_SHIFT)
@ -213,3 +299,26 @@ setup_type_progs (void)
PR_Init (&type_pr); PR_Init (&type_pr);
PR_Debug_Init (&type_pr); PR_Debug_Init (&type_pr);
} }
const type_t *
evaluate_type (const typeeval_t *typeeval, int num_types, const type_t **types,
const expr_t *expr)
{
typectx_t ctx = {
types = types,
num_types = num_types,
expr = expr,
};
int err;
if ((err = Sys_setjmp (ctx.jmpbuf))) {
return nullptr;
}
type_genfunc = &ctx;
type_pr.pr_statements = typeeval->code;
type_pr.pr_globals = typeeval->data;
type_pr.globals_size = typeeval->data_size;
type_pr.pr_trace = options.verbosity > 1;
PR_ExecuteProgram (&type_pr, tf_eval);
unsigned id = R_UINT (&type_pr);
return fetch_type (id, &ctx);
}

View file

@ -517,10 +517,10 @@ static def_t *
compute_type_array (int arg_count, const expr_t **args, comp_ctx_t *ctx) compute_type_array (int arg_count, const expr_t **args, comp_ctx_t *ctx)
{ {
auto type = compute_type (args[0], ctx); auto type = compute_type (args[0], ctx);
auto size = compute_val (args[1], ctx); auto count = compute_val (args[1], ctx);
auto res = compute_tmp (ctx); auto res = compute_tmp (ctx);
C (OP_STORE_A_1, ctx->args[0], nullptr, type); C (OP_STORE_A_1, ctx->args[0], nullptr, type);
C (OP_STORE_A_1, ctx->args[1], nullptr, size); C (OP_STORE_A_1, ctx->args[1], nullptr, count);
C (OP_CALL_B, ctx->funcs[tf_array], nullptr, res); C (OP_CALL_B, ctx->funcs[tf_array], nullptr, res);
return res; return res;
} }
@ -810,7 +810,7 @@ expand_type (const expr_t *te, rua_ctx_t *ctx)
} }
const expr_t * const expr_t *
evaluate_type (const expr_t *te, rua_ctx_t *ctx) eval_type (const expr_t *te, rua_ctx_t *ctx)
{ {
if (te->type != ex_type) { if (te->type != ex_type) {
internal_error (te, "not a type expression"); internal_error (te, "not a type expression");
@ -927,8 +927,7 @@ compute_type (const expr_t *arg, comp_ctx_t *ctx)
internal_error (arg, "no type in reference"); internal_error (arg, "no type in reference");
} }
auto val = compute_tmp (ctx); auto val = compute_tmp (ctx);
auto type_def = type_encodings.a[arg->typ.type->id]; D_INT (val) = arg->typ.type->id;
D_INT (val) = type_def->offset;
return val; return val;
} }
int op = arg->typ.op; int op = arg->typ.op;

View file

@ -564,6 +564,7 @@ typedef struct {
typedef struct { typedef struct {
int num_params; int num_params;
callparm_t *params; callparm_t *params;
const type_t **types;
} calltype_t; } calltype_t;
static bool static bool
@ -687,36 +688,43 @@ find_generic_function (genfunc_t **genfuncs, const expr_t *fexpr,
return genfuncs[best_ind]; return genfuncs[best_ind];
} }
static const type_t *
compute_param_type (const genparam_t *param, int param_ind,
const genfunc_t *genfunc, calltype_t *calltype,
const expr_t *fexpr)
{
auto call_types = calltype->types;
auto call_params = calltype->params;
if (param->fixed_type) {
return param->fixed_type;
}
if (param->compute) {
return evaluate_type (param->compute, genfunc->num_types,
calltype->types, fexpr);
}
int ind = param->gentype;
if (!call_types[ind] && param_ind >= 0) {
call_types[ind] = select_type (&genfunc->types[ind],
call_params[param_ind]);
}
return call_types[ind];
}
static symbol_t * static symbol_t *
create_generic_sym (genfunc_t *g, const expr_t *fexpr, calltype_t *calltype, create_generic_sym (genfunc_t *g, const expr_t *fexpr, calltype_t *calltype)
const type_t **types)
{ {
int num_params = calltype->num_params; int num_params = calltype->num_params;
auto call_params = calltype->params;
const type_t *param_types[num_params]; const type_t *param_types[num_params];
param_qual_t param_quals[num_params]; param_qual_t param_quals[num_params];
const type_t *return_type; const type_t *return_type;
for (int i = 0; i < num_params; i++) { for (int i = 0; i < num_params; i++) {
auto p = &g->params[i]; auto p = &g->params[i];
if (!p->fixed_type) { param_types[i] = compute_param_type (p, i, g, calltype, fexpr);
int ind = p->gentype;
if (!types[ind]) {
types[ind] = select_type (&g->types[ind], call_params[i]);
}
param_types[i] = types[ind];
} else {
param_types[i] = p->fixed_type;
}
param_quals[i] = p->qual; param_quals[i] = p->qual;
} }
if (!g->ret_type->fixed_type) { return_type = compute_param_type (g->ret_type, -1, g, calltype, fexpr);
int ind = g->ret_type->gentype; if (!return_type) {
if (!types[ind]) { internal_error (0, "return type not determined");
internal_error (0, "return type not determined");
}
return_type = types[ind];
} else {
return_type = g->ret_type->fixed_type;
} }
param_t *params = nullptr; param_t *params = nullptr;
for (int i = 0; i < num_params; i++) { for (int i = 0; i < num_params; i++) {
@ -796,13 +804,15 @@ get_function (const char *name, specifier_t spec, rua_ctx_t *ctx)
auto gen = find_generic_function (genfuncs, &fexpr, &calltype, false); auto gen = find_generic_function (genfuncs, &fexpr, &calltype, false);
if (gen) { if (gen) {
const type_t *ref_types[gen->num_types] = {}; const type_t *ref_types[gen->num_types] = {};
auto sym = create_generic_sym (gen, &fexpr, &calltype, ref_types); calltype.types = ref_types;
auto sym = create_generic_sym (gen, &fexpr, &calltype);
if (sym == fexpr.symbol if (sym == fexpr.symbol
|| sym->metafunc == fexpr.symbol->metafunc) { || sym->metafunc == fexpr.symbol->metafunc) {
internal_error (0, "genfunc oops"); internal_error (0, "genfunc oops");
} }
func = sym->metafunc; func = sym->metafunc;
overload = true; overload = true;
calltype.types = nullptr;
} else { } else {
func = nullptr; func = nullptr;
} }
@ -1004,7 +1014,8 @@ find_function (const expr_t *fexpr, const expr_t *params)
return new_error_expr (); return new_error_expr ();
} }
const type_t *ref_types[gen->num_types] = {}; const type_t *ref_types[gen->num_types] = {};
auto sym = create_generic_sym (gen, fexpr, &calltype, ref_types); calltype.types = ref_types;
auto sym = create_generic_sym (gen, fexpr, &calltype);
if (gen->can_inline) { if (gen->can_inline) {
// the call will be inlined, so a new scope is needed every // the call will be inlined, so a new scope is needed every
// time // time

View file

@ -481,10 +481,10 @@ SRC_LINE
"genBType isnan(genDType x);" "\n" "genBType isnan(genDType x);" "\n"
"genBType isinf(genFType x);" "\n" "genBType isinf(genFType x);" "\n"
"genBType isinf(genDType x);" "\n" "genBType isinf(genDType x);" "\n"
"genIType floatBitsToInt(highp genFType value);" "\n" "@vector(int,@width(genFType)) floatBitsToInt(highp genFType value) = " SPV(124) ";" "\n"
"genUType floatBitsToUint(highp genFType value);" "\n" "@vector(uint,@width(genFType)) floatBitsToUint(highp genFType value) = " SPV(124) ";" "\n"
"genFType intBitsToFloat(highp genIType value);" "\n" "@vector(float,@width(genIType)) intBitsToFloat(highp genIType value) = " SPV(124) ";" "\n"
"genFType uintBitsToFloat(highp genUType value);" "\n" "@vector(float,@width(genUType)) uintBitsToFloat(highp genUType value) = " SPV(124) ";" "\n"
"genFType fma(genFType a, genFType b, genFType c);" "\n" "genFType fma(genFType a, genFType b, genFType c);" "\n"
"genDType fma(genDType a, genDType b, genDType c);" "\n" "genDType fma(genDType a, genDType b, genDType c);" "\n"
"genFType frexp(highp genFType x, out highp genIType exp);" "\n" "genFType frexp(highp genFType x, out highp genIType exp);" "\n"

View file

@ -265,6 +265,7 @@ int type_cast_map[ev_type_count] = {
//[ev_bool64] = 7, //[ev_bool64] = 7,
}; };
typeset_t type_registry = DARRAY_STATIC_INIT (64);
defset_t type_encodings = DARRAY_STATIC_INIT (64); defset_t type_encodings = DARRAY_STATIC_INIT (64);
ALLOC_STATE (type_t, types); ALLOC_STATE (type_t, types);
@ -309,7 +310,8 @@ chain_type (type_t *type)
if (type->id) { if (type->id) {
internal_error (0, "type already has id"); internal_error (0, "type already has id");
} }
type->id = type_encodings.size; type->id = type_registry.size;
DARRAY_APPEND (&type_registry, type);
DARRAY_APPEND (&type_encodings, nullptr); DARRAY_APPEND (&type_encodings, nullptr);
type->next = pr.types; type->next = pr.types;
pr.types = type; pr.types = type;
@ -2027,7 +2029,9 @@ type_aligned_size (const type_t *type)
static void static void
chain_basic_types (void) chain_basic_types (void)
{ {
type_registry.size = 0;
type_encodings.size = 0; type_encodings.size = 0;
DARRAY_APPEND (&type_registry, nullptr);
DARRAY_APPEND (&type_encodings, nullptr); DARRAY_APPEND (&type_encodings, nullptr);
type_entity.symtab = pr.entity_fields; type_entity.symtab = pr.entity_fields;