[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;
typeeval_t *build_type_function (const expr_t *te, int num_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

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 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 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 *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 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 typeset_t type_registry;
extern const type_t *ev_types[];
extern int type_cast_map[];

View file

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

View file

@ -50,6 +50,9 @@
#include "tools/qfcc/include/type.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 {
const type_t **types;
int num_types;
@ -57,74 +60,158 @@ typedef struct typectx_s {
sys_jmpbuf jmpbuf;
} 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
tf_function_func (progs_t *pr, void *data)
{
auto ctx = *(typectx_t **) data;
internal_error (ctx->expr, "not implemented");
}
static void
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
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
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
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
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
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
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
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
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
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
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
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
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
@ -140,8 +227,7 @@ tf_gentype_func (progs_t *pr, void *data)
error (ctx->expr, "refernce to unresolved type");
Sys_longjmp (ctx->jmpbuf);
}
auto type_def = type_encodings.a[type->id];
R_POINTER (pr) = type_def->offset;
R_UINT (pr) = type->id;
}
#define BASE(b, base) (((base) & 3) << OP_##b##_SHIFT)
@ -213,3 +299,26 @@ setup_type_progs (void)
PR_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)
{
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);
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);
return res;
}
@ -810,7 +810,7 @@ expand_type (const expr_t *te, rua_ctx_t *ctx)
}
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) {
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");
}
auto val = compute_tmp (ctx);
auto type_def = type_encodings.a[arg->typ.type->id];
D_INT (val) = type_def->offset;
D_INT (val) = arg->typ.type->id;
return val;
}
int op = arg->typ.op;

View file

@ -564,6 +564,7 @@ typedef struct {
typedef struct {
int num_params;
callparm_t *params;
const type_t **types;
} calltype_t;
static bool
@ -687,36 +688,43 @@ find_generic_function (genfunc_t **genfuncs, const expr_t *fexpr,
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 *
create_generic_sym (genfunc_t *g, const expr_t *fexpr, calltype_t *calltype,
const type_t **types)
create_generic_sym (genfunc_t *g, const expr_t *fexpr, calltype_t *calltype)
{
int num_params = calltype->num_params;
auto call_params = calltype->params;
const type_t *param_types[num_params];
param_qual_t param_quals[num_params];
const type_t *return_type;
for (int i = 0; i < num_params; i++) {
auto p = &g->params[i];
if (!p->fixed_type) {
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_types[i] = compute_param_type (p, i, g, calltype, fexpr);
param_quals[i] = p->qual;
}
if (!g->ret_type->fixed_type) {
int ind = g->ret_type->gentype;
if (!types[ind]) {
internal_error (0, "return type not determined");
}
return_type = types[ind];
} else {
return_type = g->ret_type->fixed_type;
return_type = compute_param_type (g->ret_type, -1, g, calltype, fexpr);
if (!return_type) {
internal_error (0, "return type not determined");
}
param_t *params = nullptr;
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);
if (gen) {
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
|| sym->metafunc == fexpr.symbol->metafunc) {
internal_error (0, "genfunc oops");
}
func = sym->metafunc;
overload = true;
calltype.types = nullptr;
} else {
func = nullptr;
}
@ -1004,7 +1014,8 @@ find_function (const expr_t *fexpr, const expr_t *params)
return new_error_expr ();
}
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) {
// the call will be inlined, so a new scope is needed every
// time

View file

@ -481,10 +481,10 @@ SRC_LINE
"genBType isnan(genDType x);" "\n"
"genBType isinf(genFType x);" "\n"
"genBType isinf(genDType x);" "\n"
"genIType floatBitsToInt(highp genFType value);" "\n"
"genUType floatBitsToUint(highp genFType value);" "\n"
"genFType intBitsToFloat(highp genIType value);" "\n"
"genFType uintBitsToFloat(highp genUType value);" "\n"
"@vector(int,@width(genFType)) floatBitsToInt(highp genFType value) = " SPV(124) ";" "\n"
"@vector(uint,@width(genFType)) floatBitsToUint(highp genFType value) = " SPV(124) ";" "\n"
"@vector(float,@width(genIType)) intBitsToFloat(highp genIType value) = " SPV(124) ";" "\n"
"@vector(float,@width(genUType)) uintBitsToFloat(highp genUType value) = " SPV(124) ";" "\n"
"genFType fma(genFType a, genFType b, genFType c);" "\n"
"genDType fma(genDType a, genDType b, genDType c);" "\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,
};
typeset_t type_registry = DARRAY_STATIC_INIT (64);
defset_t type_encodings = DARRAY_STATIC_INIT (64);
ALLOC_STATE (type_t, types);
@ -309,7 +310,8 @@ chain_type (type_t *type)
if (type->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);
type->next = pr.types;
pr.types = type;
@ -2027,7 +2029,9 @@ type_aligned_size (const type_t *type)
static void
chain_basic_types (void)
{
type_registry.size = 0;
type_encodings.size = 0;
DARRAY_APPEND (&type_registry, nullptr);
DARRAY_APPEND (&type_encodings, nullptr);
type_entity.symtab = pr.entity_fields;