mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-04-11 20:03:11 +00:00
[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:
parent
55d7d1f069
commit
b59a8fb66a
7 changed files with 662 additions and 11 deletions
|
@ -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,
|
||||
|
|
75
tools/qfcc/include/evaluate_type.h
Normal file
75
tools/qfcc/include/evaluate_type.h
Normal 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
|
|
@ -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 \
|
||||
|
|
|
@ -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);
|
||||
|
|
214
tools/qfcc/source/evaluate_type.c
Normal file
214
tools/qfcc/source/evaluate_type.c
Normal 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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue