mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-25 13:11:00 +00:00
[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:
parent
4db018ee47
commit
6e004e9baa
9 changed files with 163 additions and 37 deletions
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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[];
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -564,6 +564,7 @@ typedef struct {
|
|||
typedef struct {
|
||||
int num_params;
|
||||
callparm_t *params;
|
||||
const type_t **types;
|
||||
} calltype_t;
|
||||
|
||||
static bool
|
||||
|
@ -687,37 +688,44 @@ 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]) {
|
||||
return_type = compute_param_type (g->ret_type, -1, g, calltype, fexpr);
|
||||
if (!return_type) {
|
||||
internal_error (0, "return type not determined");
|
||||
}
|
||||
return_type = types[ind];
|
||||
} else {
|
||||
return_type = g->ret_type->fixed_type;
|
||||
}
|
||||
param_t *params = nullptr;
|
||||
for (int i = 0; i < num_params; i++) {
|
||||
param_types[i] = unalias_type (param_types[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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue