mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-25 05:01:24 +00:00
[qfcc] Implement inline function calls
They're buggy in that the defspaces for parameters and locals are incorrect (they need to point to the calling scope's space). Also, parameters are not yet hooked up correctly. However, errors (because I need to allow casts from scalars to vectors) do get handled.
This commit is contained in:
parent
36cf1f948e
commit
6840a208b9
10 changed files with 378 additions and 38 deletions
|
@ -402,6 +402,10 @@ typedef struct {
|
|||
bool lvalue; ///< rvalue if false
|
||||
} ex_xvalue_t;
|
||||
|
||||
typedef struct {
|
||||
const expr_t *expr;
|
||||
} ex_process_t;
|
||||
|
||||
typedef struct expr_s {
|
||||
expr_t *next;
|
||||
rua_loc_t loc; ///< source location of expression
|
||||
|
@ -455,6 +459,7 @@ typedef struct expr_s {
|
|||
ex_switch_t switchblock; ///< switch block expression
|
||||
ex_caselabel_t caselabel; ///< case label expression
|
||||
ex_xvalue_t xvalue; ///< lvalue/rvalue specific expression
|
||||
ex_process_t process; ///< expression than needs processing
|
||||
};
|
||||
} expr_t;
|
||||
|
||||
|
@ -1022,6 +1027,7 @@ expr_t *new_switch_expr (const expr_t *test, const expr_t *body,
|
|||
const expr_t *break_label);
|
||||
expr_t *new_caselabel_expr (const expr_t *value, const expr_t *end_value);
|
||||
expr_t *new_xvalue_expr (const expr_t *expr, bool lvalue);
|
||||
expr_t *new_process_expr (const expr_t *expr);
|
||||
|
||||
/** Create an expression of the correct type that references the specified
|
||||
parameter slot.
|
||||
|
@ -1147,6 +1153,7 @@ const expr_t *gather_factors (const type_t *type, int op,
|
|||
|
||||
typedef struct rua_ctx_s rua_ctx_t;
|
||||
const expr_t *expr_process (const expr_t *expr, rua_ctx_t *ctx);
|
||||
bool can_inline (const expr_t *expr, symbol_t *fsym);
|
||||
|
||||
///@}
|
||||
|
||||
|
|
|
@ -81,6 +81,7 @@ EX_EXPR(intrinsic) ///< intrinsic instruction expression (::ex_intrinsic_t)
|
|||
EX_EXPR(switch) ///< switch expression (::ex_switch_t)
|
||||
EX_EXPR(caselabel) ///< case expression (::ex_caselabel_t)
|
||||
EX_EXPR(xvalue) ///< xvalue expression (::ex_xvalue_t)
|
||||
EX_EXPR(process) ///< expression that needs processing (::ex_process_t)
|
||||
|
||||
#undef EX_EXPR
|
||||
|
||||
|
|
|
@ -77,6 +77,7 @@ typedef struct genfunc_s {
|
|||
genparam_t *params;
|
||||
genparam_t *ret_type;
|
||||
const expr_t *expr; ///< inline or intrinsic
|
||||
bool can_inline;
|
||||
} genfunc_t;
|
||||
|
||||
typedef enum {
|
||||
|
@ -169,7 +170,9 @@ typedef struct metafunc_s {
|
|||
rua_loc_t loc; ///< source location of the function
|
||||
mf_type_e meta_type; ///< is this function overloaded
|
||||
function_t *func;
|
||||
genfunc_t *genfunc;
|
||||
const expr_t *expr; ///< inline or intrinsic
|
||||
bool can_inline;
|
||||
} metafunc_t;
|
||||
|
||||
extern function_t *current_func;
|
||||
|
|
|
@ -100,6 +100,7 @@ get_type (const expr_t *e)
|
|||
case ex_loop:
|
||||
case ex_select:
|
||||
case ex_message:
|
||||
case ex_process:
|
||||
internal_error (e, "unexpected expression type: %s",
|
||||
expr_names[e->type]);
|
||||
case ex_label:
|
||||
|
@ -1997,6 +1998,8 @@ has_function_call (const expr_t *e)
|
|||
case ex_xvalue:
|
||||
bug (e, "should xvalue happen here?");
|
||||
return has_function_call (e->xvalue.expr);
|
||||
case ex_process:
|
||||
internal_error (e, "unexpected expression type");
|
||||
case ex_count:
|
||||
break;
|
||||
}
|
||||
|
@ -2322,6 +2325,17 @@ new_xvalue_expr (const expr_t *expr, bool lvalue)
|
|||
return xv;
|
||||
}
|
||||
|
||||
expr_t *
|
||||
new_process_expr (const expr_t *expr)
|
||||
{
|
||||
auto xv = new_expr ();
|
||||
xv->type = ex_process;
|
||||
xv->process = (ex_process_t) {
|
||||
.expr = expr,
|
||||
};
|
||||
return xv;
|
||||
}
|
||||
|
||||
expr_t *
|
||||
new_decl (symbol_t *sym, const expr_t *init)
|
||||
{
|
||||
|
@ -2855,3 +2869,161 @@ sizeof_expr (const expr_t *expr, const type_t *type)
|
|||
}
|
||||
return expr;
|
||||
}
|
||||
|
||||
static bool
|
||||
can_inline_list (const ex_list_t *list, symbol_t *fsym)
|
||||
{
|
||||
int count = list_count (list);
|
||||
const expr_t *arg_exprs[count + 1] = {};
|
||||
list_scatter (list, arg_exprs);
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (!can_inline (arg_exprs[i], fsym)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
can_inline (const expr_t *expr, symbol_t *fsym)
|
||||
{
|
||||
if (!expr) {
|
||||
return true;
|
||||
}
|
||||
switch (expr->type) {
|
||||
case ex_block:
|
||||
return can_inline_list (&expr->block.list, fsym);
|
||||
case ex_expr:
|
||||
if (expr->expr.op == QC_AND || expr->expr.op == QC_OR) {
|
||||
//FIXME
|
||||
return false;
|
||||
}
|
||||
return (can_inline (expr->expr.e1, fsym)
|
||||
&& can_inline (expr->expr.e2, fsym));
|
||||
case ex_uexpr:
|
||||
return can_inline (expr->expr.e1, fsym);
|
||||
case ex_symbol:
|
||||
auto sym = expr->symbol;
|
||||
if (sym->table == fsym->table
|
||||
&& strcmp (sym->name, fsym->name) == 0) {
|
||||
// recursive function, however to get here, no conditional
|
||||
// expresions were found
|
||||
warning (expr, "infinite recursion in %s", fsym->name);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
case ex_vector:
|
||||
return can_inline_list (&expr->vector.list, fsym);
|
||||
case ex_selector:
|
||||
return can_inline (expr->selector.sel_ref, fsym);
|
||||
case ex_message:
|
||||
if (!can_inline (expr->message.receiver, fsym)) {
|
||||
return false;
|
||||
}
|
||||
for (auto k = expr->message.message; k; k = k->next) {
|
||||
if (!can_inline (k->expr, fsym)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
case ex_compound:
|
||||
for (auto ele = expr->compound.head; ele; ele = ele->next) {
|
||||
if (!can_inline (ele->expr, fsym)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
case ex_memset:
|
||||
return (can_inline (expr->memset.dst, fsym)
|
||||
&& can_inline (expr->memset.val, fsym)
|
||||
&& can_inline (expr->memset.count, fsym));
|
||||
case ex_alias:
|
||||
return (can_inline (expr->alias.expr, fsym)
|
||||
&& can_inline (expr->alias.offset, fsym));
|
||||
case ex_address:
|
||||
return (can_inline (expr->address.lvalue, fsym)
|
||||
&& can_inline (expr->address.offset, fsym));
|
||||
case ex_assign:
|
||||
return (can_inline (expr->assign.dst, fsym)
|
||||
&& can_inline (expr->assign.src, fsym));
|
||||
case ex_branch:
|
||||
if (expr->branch.type != pr_branch_call) {
|
||||
notice (expr, "%s", expr_names[expr->type]);
|
||||
return false;
|
||||
}
|
||||
if (!can_inline (expr->branch.target, fsym)) {
|
||||
notice (expr, "%s", expr_names[expr->type]);
|
||||
return false;
|
||||
}
|
||||
auto args = (expr_t *) expr->branch.args;
|
||||
if (!args) {
|
||||
return true;
|
||||
}
|
||||
return can_inline_list (&args->list, fsym);
|
||||
case ex_return:
|
||||
if (expr->retrn.ret_val) {
|
||||
return can_inline (expr->retrn.ret_val, fsym);
|
||||
}
|
||||
return true;
|
||||
case ex_horizontal:
|
||||
return can_inline (expr->hop.vec, fsym);
|
||||
case ex_swizzle:
|
||||
return can_inline (expr->swizzle.src, fsym);
|
||||
case ex_extend:
|
||||
return can_inline (expr->extend.src, fsym);
|
||||
case ex_incop:
|
||||
return can_inline (expr->incop.expr, fsym);
|
||||
case ex_list:
|
||||
return can_inline_list (&expr->list, fsym);
|
||||
case ex_cond:
|
||||
return (can_inline (expr->cond.test, fsym)
|
||||
&& can_inline (expr->cond.true_expr, fsym)
|
||||
&& can_inline (expr->cond.false_expr, fsym));
|
||||
case ex_field:
|
||||
return (can_inline (expr->field.object, fsym)
|
||||
&& can_inline (expr->field.member, fsym));
|
||||
case ex_array:
|
||||
return (can_inline (expr->array.base, fsym)
|
||||
&& can_inline (expr->array.index, fsym));
|
||||
case ex_decl:
|
||||
return can_inline_list (&expr->decl.list, fsym);
|
||||
case ex_xvalue:
|
||||
auto xvalue = expr->xvalue.expr;
|
||||
if (xvalue->type == ex_symbol
|
||||
&& xvalue->symbol->sy_type == sy_xvalue) {
|
||||
if (expr->xvalue.lvalue) {
|
||||
xvalue = xvalue->symbol->xvalue.lvalue;
|
||||
} else {
|
||||
xvalue = xvalue->symbol->xvalue.rvalue;
|
||||
}
|
||||
}
|
||||
return can_inline (xvalue, fsym);
|
||||
case ex_def:
|
||||
case ex_temp:
|
||||
case ex_nil:
|
||||
case ex_value:
|
||||
case ex_type:
|
||||
case ex_adjstk:
|
||||
case ex_with:
|
||||
case ex_args:
|
||||
return true;
|
||||
case ex_loop://FIXME
|
||||
case ex_state://FIXME
|
||||
case ex_bool://FIXME
|
||||
case ex_label://FIXME
|
||||
case ex_labelref://FIXME
|
||||
case ex_select://FIXME
|
||||
case ex_switch:
|
||||
return false;
|
||||
case ex_error:
|
||||
case ex_inout:
|
||||
case ex_caselabel:
|
||||
case ex_multivec:
|
||||
case ex_intrinsic:
|
||||
case ex_process:
|
||||
case ex_count:
|
||||
internal_error (expr, "unexpected expr %s",
|
||||
expr_names[expr->type]);
|
||||
}
|
||||
internal_error (expr, "invald expr type %d", expr->type);
|
||||
}
|
||||
|
|
|
@ -140,6 +140,7 @@ is_lvalue (const expr_t *expr)
|
|||
case ex_intrinsic:
|
||||
case ex_switch:
|
||||
case ex_caselabel:
|
||||
case ex_process:
|
||||
break;
|
||||
case ex_cond:
|
||||
return (is_lvalue (expr->cond.true_expr)
|
||||
|
|
|
@ -37,11 +37,13 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "tools/qfcc/include/algebra.h"
|
||||
#include "tools/qfcc/include/defspace.h"
|
||||
#include "tools/qfcc/include/diagnostic.h"
|
||||
#include "tools/qfcc/include/expr.h"
|
||||
#include "tools/qfcc/include/function.h"
|
||||
#include "tools/qfcc/include/idstuff.h"
|
||||
#include "tools/qfcc/include/options.h"
|
||||
#include "tools/qfcc/include/shared.h"
|
||||
#include "tools/qfcc/include/symtab.h"
|
||||
#include "tools/qfcc/include/target.h"
|
||||
#include "tools/qfcc/include/type.h"
|
||||
|
@ -203,6 +205,84 @@ check_arg_types (const expr_t **arguments, const type_t **arg_types,
|
|||
return err;
|
||||
}
|
||||
|
||||
static expr_t *
|
||||
build_intrinsic_call (const expr_t *expr, const type_t *ftype,
|
||||
const expr_t **arguments, int arg_count)
|
||||
{
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
if (is_reference (get_type (arguments[i]))) {
|
||||
arguments[i] = pointer_deref (arguments[i]);
|
||||
}
|
||||
}
|
||||
auto call = new_intrinsic_expr (nullptr);
|
||||
call->intrinsic.opcode = expr->intrinsic.opcode;
|
||||
call->intrinsic.res_type = ftype->func.ret_type;
|
||||
list_append_list (&call->intrinsic.operands,
|
||||
&expr->intrinsic.operands);
|
||||
list_gather (&call->intrinsic.operands, arguments, arg_count);
|
||||
return call;
|
||||
}
|
||||
|
||||
static expr_t *
|
||||
build_inline_call (symbol_t *fsym, const type_t *ftype,
|
||||
const expr_t **arguments, int arg_count)
|
||||
{
|
||||
auto metafunc = fsym->metafunc;
|
||||
auto func = metafunc->func;
|
||||
|
||||
auto params = func->parameters;
|
||||
auto locals = func->locals;
|
||||
|
||||
for (auto p = fsym->params; p; p = p->next) {
|
||||
if (!p->selector && !p->type && !p->name) {
|
||||
internal_error (0, "inline variadic not implemented");
|
||||
}
|
||||
if (!p->type) {
|
||||
continue; // non-param selector
|
||||
}
|
||||
if (is_void (p->type)) {
|
||||
if (p->name) {
|
||||
error (0, "invalid parameter type for %s", p->name);
|
||||
} else if (p != fsym->params || p->next) {
|
||||
error (0, "void must be the only parameter");
|
||||
continue;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!p->name) {
|
||||
notice (0, "parameter name omitted");
|
||||
continue;
|
||||
}
|
||||
auto param = new_symbol_type (p->name, p->type);
|
||||
symtab_addsymbol (params, param);
|
||||
}
|
||||
|
||||
auto call = new_block_expr (nullptr);
|
||||
call->block.scope = locals;
|
||||
|
||||
if (!is_void (ftype->func.ret_type)) {
|
||||
auto spec = (specifier_t) {
|
||||
.type = ftype->func.ret_type,
|
||||
.storage = sc_local,
|
||||
};
|
||||
auto decl = new_decl_expr (spec, locals);
|
||||
auto ret = new_symbol (".ret");
|
||||
append_decl (decl, ret, nullptr);
|
||||
append_expr (call, decl);
|
||||
call->block.result = new_symbol_expr (ret);
|
||||
}
|
||||
auto expr = metafunc->expr;
|
||||
if (expr->type == ex_block) {
|
||||
expr->block.scope->parent = locals;
|
||||
}
|
||||
append_expr (call, expr);
|
||||
|
||||
auto proc = new_process_expr (call);
|
||||
|
||||
return proc;
|
||||
}
|
||||
|
||||
static expr_t *
|
||||
build_args (const expr_t *(*arg_exprs)[2], int *arg_expr_count,
|
||||
const expr_t **arguments, const type_t **arg_types,
|
||||
|
@ -301,26 +381,22 @@ build_function_call (const expr_t *fexpr, const type_t *ftype,
|
|||
return err;
|
||||
}
|
||||
|
||||
expr_t *call = nullptr;
|
||||
scoped_src_loc (fexpr);
|
||||
if (fexpr->type == ex_symbol && fexpr->symbol->sy_type == sy_func
|
||||
&& fexpr->symbol->metafunc->expr) {
|
||||
auto expr = fexpr->symbol->metafunc->expr;
|
||||
auto fsym = fexpr->symbol;
|
||||
auto metafunc = fsym->metafunc;
|
||||
auto expr = metafunc->expr;
|
||||
if (expr->type == ex_intrinsic) {
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
if (is_reference (get_type (arguments[i]))) {
|
||||
arguments[i] = pointer_deref (arguments[i]);
|
||||
}
|
||||
}
|
||||
call = new_intrinsic_expr (nullptr);
|
||||
call->intrinsic.opcode = expr->intrinsic.opcode;
|
||||
call->intrinsic.res_type = ftype->func.ret_type;
|
||||
list_append_list (&call->intrinsic.operands,
|
||||
&expr->intrinsic.operands);
|
||||
list_gather (&call->intrinsic.operands, arguments, arg_count);
|
||||
return build_intrinsic_call (expr, ftype, arguments, arg_count);
|
||||
}
|
||||
if (metafunc->can_inline) {
|
||||
return build_inline_call (fsym, ftype, arguments, arg_count);
|
||||
}
|
||||
internal_error (fexpr, "calls to inline functions that cannot be "
|
||||
"inlined not implemented");
|
||||
} else {
|
||||
call = new_block_expr (0);
|
||||
auto call = new_block_expr (nullptr);
|
||||
call->block.is_call = 1;
|
||||
int num_args = 0;
|
||||
const expr_t *arg_exprs[arg_count + 1][2];
|
||||
|
@ -333,8 +409,8 @@ build_function_call (const expr_t *fexpr, const type_t *ftype,
|
|||
}
|
||||
auto ret_type = ftype->func.ret_type;
|
||||
call->block.result = new_call_expr (fexpr, arg_list, ret_type);
|
||||
return call;
|
||||
}
|
||||
return call;
|
||||
}
|
||||
|
||||
const expr_t *
|
||||
|
|
|
@ -86,6 +86,7 @@ edag_add_expr (const expr_t *expr)
|
|||
case ex_intrinsic:
|
||||
case ex_switch:
|
||||
case ex_caselabel:
|
||||
case ex_process:
|
||||
// these are never put in the dag
|
||||
return expr;
|
||||
case ex_list:
|
||||
|
|
|
@ -249,11 +249,16 @@ proc_block (const expr_t *expr, rua_ctx_t *ctx)
|
|||
const expr_t *result = nullptr;
|
||||
const expr_t *in[count + 1];
|
||||
const expr_t *out[count + 1];
|
||||
const expr_t *err = nullptr;
|
||||
list_scatter (&expr->block.list, in);
|
||||
for (int i = 0; i < count; i++) {
|
||||
edag_flush ();
|
||||
auto e = expr_process (in[i], ctx);
|
||||
if (e && !is_error (e)) {
|
||||
if (is_error (e)) {
|
||||
err = e;
|
||||
continue;
|
||||
}
|
||||
if (e) {
|
||||
out[num_out++] = e;
|
||||
if (expr->block.result == in[i]) {
|
||||
result = e;
|
||||
|
@ -261,6 +266,10 @@ proc_block (const expr_t *expr, rua_ctx_t *ctx)
|
|||
}
|
||||
}
|
||||
edag_flush ();
|
||||
if (err) {
|
||||
current_symtab = old_scope;
|
||||
return err;
|
||||
}
|
||||
|
||||
scoped_src_loc (expr);
|
||||
auto block = new_block_expr (nullptr);
|
||||
|
@ -706,5 +715,9 @@ expr_process (const expr_t *expr, rua_ctx_t *ctx)
|
|||
expr_names[expr->type]);
|
||||
}
|
||||
|
||||
return funcs[expr->type] (expr, ctx);
|
||||
auto proc = funcs[expr->type] (expr, ctx);
|
||||
if (proc && proc->type == ex_process) {
|
||||
proc = expr_process (proc->process.expr, ctx);
|
||||
}
|
||||
return proc;
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "tools/qfcc/include/function.h"
|
||||
#include "tools/qfcc/include/opcodes.h"
|
||||
#include "tools/qfcc/include/rua-lang.h"
|
||||
#include "tools/qfcc/include/shared.h"
|
||||
#include "tools/qfcc/include/statements.h"
|
||||
#include "tools/qfcc/include/symtab.h"
|
||||
#include "tools/qfcc/include/type.h"
|
||||
|
@ -706,6 +707,17 @@ type_parameter (symbol_t *sym, const expr_t *type)
|
|||
const type_t *
|
||||
resolve_type (const expr_t *te)
|
||||
{
|
||||
if (te->type == ex_symbol) {
|
||||
auto sym = te->symbol;
|
||||
if (sym->type == sy_name) {
|
||||
sym = symtab_lookup (current_symtab, sym->name);
|
||||
if (sym && sym->sy_type == sy_type_param) {
|
||||
te = sym->expr;
|
||||
}
|
||||
} else if (sym->sy_type == sy_type) {
|
||||
return sym->type;
|
||||
}
|
||||
}
|
||||
if (te->type != ex_type) {
|
||||
internal_error (te, "not a type expression");
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
#include "tools/qfcc/include/expr.h"
|
||||
#include "tools/qfcc/include/flow.h"
|
||||
#include "tools/qfcc/include/function.h"
|
||||
#include "tools/qfcc/include/method.h"
|
||||
#include "tools/qfcc/include/opcodes.h"
|
||||
#include "tools/qfcc/include/options.h"
|
||||
#include "tools/qfcc/include/reloc.h"
|
||||
|
@ -682,11 +683,11 @@ find_generic_function (genfunc_t **genfuncs, const expr_t *fexpr,
|
|||
}
|
||||
|
||||
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;
|
||||
auto call_params = calltype->params;
|
||||
const type_t *types[g->num_types] = {};
|
||||
const type_t *param_types[num_params];
|
||||
param_qual_t param_quals[num_params];
|
||||
const type_t *return_type;
|
||||
|
@ -746,6 +747,7 @@ create_generic_sym (genfunc_t *g, const expr_t *fexpr, calltype_t *calltype)
|
|||
sym->metafunc = new_metafunc ();
|
||||
*sym->metafunc = *fsym->metafunc;
|
||||
sym->metafunc->expr = g->expr;
|
||||
sym->metafunc->can_inline = g->can_inline;
|
||||
symtab_addsymbol (fsym->table, sym);
|
||||
}
|
||||
return sym;
|
||||
|
@ -789,7 +791,8 @@ get_function (const char *name, specifier_t spec)
|
|||
}
|
||||
auto gen = find_generic_function (genfuncs, &fexpr, &calltype, false);
|
||||
if (gen) {
|
||||
auto sym = create_generic_sym (gen, &fexpr, &calltype);
|
||||
const type_t *ref_types[gen->num_types] = {};
|
||||
auto sym = create_generic_sym (gen, &fexpr, &calltype, ref_types);
|
||||
if (sym == fexpr.symbol
|
||||
|| sym->metafunc == fexpr.symbol->metafunc) {
|
||||
internal_error (0, "genfunc oops");
|
||||
|
@ -859,6 +862,7 @@ function_symbol (specifier_t spec)
|
|||
.full_name = name,
|
||||
.loc = pr.loc,
|
||||
.meta_type = mf_generic,
|
||||
.genfunc = genfunc,
|
||||
};
|
||||
Hash_Add (metafuncs, func);
|
||||
Hash_Add (function_map, func);
|
||||
|
@ -895,6 +899,46 @@ set_func_symbol (const expr_t *fexpr, metafunc_t *f)
|
|||
return nf;
|
||||
}
|
||||
|
||||
static void
|
||||
build_generic_scope (symbol_t *fsym, symtab_t *parent, genfunc_t *genfunc,
|
||||
const type_t **ref_types)
|
||||
{
|
||||
auto func = fsym->metafunc->func;
|
||||
func->label_scope = new_symtab (0, stab_label);
|
||||
|
||||
auto parameters = new_symtab (parent, stab_param);
|
||||
parameters->space = parent->space;
|
||||
func->parameters = parameters;
|
||||
|
||||
auto locals = new_symtab (parameters, stab_local);
|
||||
locals->space = parent->space;
|
||||
func->locals = locals;
|
||||
|
||||
for (int i = 0; i < genfunc->num_types; i++) {
|
||||
auto type = &genfunc->types[i];
|
||||
auto sym = new_symbol (type->name);
|
||||
sym->sy_type = sy_type_param;
|
||||
if (ref_types) {
|
||||
sym->expr = new_type_expr (ref_types[i]);
|
||||
}
|
||||
symtab_addsymbol (func->parameters, sym);
|
||||
}
|
||||
}
|
||||
|
||||
static function_t *
|
||||
new_function (const char *name, const char *nice_name)
|
||||
{
|
||||
function_t *f;
|
||||
|
||||
ALLOC (1024, function_t, functions, f);
|
||||
f->o_name = save_string (name);
|
||||
f->s_name = ReuseString (name);
|
||||
f->s_file = pr.loc.file;
|
||||
if (!(f->name = nice_name))
|
||||
f->name = name;
|
||||
return f;
|
||||
}
|
||||
|
||||
const expr_t *
|
||||
find_function (const expr_t *fexpr, const expr_t *params)
|
||||
{
|
||||
|
@ -932,7 +976,14 @@ find_function (const expr_t *fexpr, const expr_t *params)
|
|||
if (!gen) {
|
||||
return new_error_expr ();
|
||||
}
|
||||
auto sym = create_generic_sym (gen, fexpr, &calltype);
|
||||
const type_t *ref_types[gen->num_types] = {};
|
||||
auto sym = create_generic_sym (gen, fexpr, &calltype, ref_types);
|
||||
if (gen->can_inline) {
|
||||
// the call will be inlined, so a new scope is needed every
|
||||
// time
|
||||
sym->metafunc->func = new_function (sym->name, gen->name);
|
||||
build_generic_scope (sym, current_symtab, gen, ref_types);
|
||||
}
|
||||
return new_symbol_expr (sym);
|
||||
}
|
||||
|
||||
|
@ -1069,20 +1120,6 @@ build_scope (symbol_t *fsym, symtab_t *parent)
|
|||
current_target.build_scope (fsym);
|
||||
}
|
||||
|
||||
static function_t *
|
||||
new_function (const char *name, const char *nice_name)
|
||||
{
|
||||
function_t *f;
|
||||
|
||||
ALLOC (1024, function_t, functions, f);
|
||||
f->o_name = save_string (name);
|
||||
f->s_name = ReuseString (name);
|
||||
f->s_file = pr.loc.file;
|
||||
if (!(f->name = nice_name))
|
||||
f->name = name;
|
||||
return f;
|
||||
}
|
||||
|
||||
function_t *
|
||||
make_function (symbol_t *sym, const char *nice_name, defspace_t *space,
|
||||
storage_class_t storage)
|
||||
|
@ -1142,6 +1179,15 @@ begin_function (specifier_t spec, const char *nicename, symtab_t *parent)
|
|||
});
|
||||
}
|
||||
|
||||
if (spec.is_generic) {
|
||||
auto genfunc = sym->metafunc->genfunc;
|
||||
func = new_function (sym->name, nicename);
|
||||
sym->metafunc->func = func;
|
||||
sym->metafunc->genfunc = genfunc;
|
||||
build_generic_scope (sym, parent, genfunc, nullptr);
|
||||
return func;
|
||||
}
|
||||
|
||||
defspace_t *space = spec.is_far ? pr.far_data : sym->table->space;
|
||||
|
||||
func = make_function (sym, nicename, space, spec.storage);
|
||||
|
@ -1183,6 +1229,16 @@ build_code_function (specifier_t spec, const expr_t *state_expr,
|
|||
expr_t *statements, rua_ctx_t *ctx)
|
||||
{
|
||||
auto fsym = spec.sym;
|
||||
if (fsym->metafunc->meta_type == mf_generic) {
|
||||
auto genfunc = fsym->metafunc->genfunc;
|
||||
if (genfunc->expr) {
|
||||
error (statements, "%s already defined", fsym->name);
|
||||
return;
|
||||
}
|
||||
genfunc->expr = statements;
|
||||
genfunc->can_inline = can_inline (statements, fsym);
|
||||
return;
|
||||
}
|
||||
if (ctx) {
|
||||
statements = (expr_t *) expr_process (statements, ctx);
|
||||
}
|
||||
|
@ -1271,9 +1327,7 @@ build_intrinsic_function (specifier_t spec, const expr_t *intrinsic)
|
|||
return;
|
||||
}
|
||||
if (sym->metafunc->meta_type == mf_generic) {
|
||||
//FIXME find a better way to find the specific genfunc
|
||||
auto genfunc = parse_generic_function (sym->name, spec);
|
||||
genfunc = add_generic_function (genfunc);
|
||||
auto genfunc = sym->metafunc->genfunc;
|
||||
if (genfunc->expr) {
|
||||
error (intrinsic, "%s already defined", sym->name);
|
||||
return;
|
||||
|
|
Loading…
Reference in a new issue