[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:
Bill Currie 2024-12-11 03:16:15 +09:00
parent 36cf1f948e
commit 6840a208b9
10 changed files with 378 additions and 38 deletions

View file

@ -402,6 +402,10 @@ typedef struct {
bool lvalue; ///< rvalue if false bool lvalue; ///< rvalue if false
} ex_xvalue_t; } ex_xvalue_t;
typedef struct {
const expr_t *expr;
} ex_process_t;
typedef struct expr_s { typedef struct expr_s {
expr_t *next; expr_t *next;
rua_loc_t loc; ///< source location of expression rua_loc_t loc; ///< source location of expression
@ -455,6 +459,7 @@ typedef struct expr_s {
ex_switch_t switchblock; ///< switch block expression ex_switch_t switchblock; ///< switch block expression
ex_caselabel_t caselabel; ///< case label expression ex_caselabel_t caselabel; ///< case label expression
ex_xvalue_t xvalue; ///< lvalue/rvalue specific expression ex_xvalue_t xvalue; ///< lvalue/rvalue specific expression
ex_process_t process; ///< expression than needs processing
}; };
} expr_t; } expr_t;
@ -1022,6 +1027,7 @@ expr_t *new_switch_expr (const expr_t *test, const expr_t *body,
const expr_t *break_label); const expr_t *break_label);
expr_t *new_caselabel_expr (const expr_t *value, const expr_t *end_value); 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_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 /** Create an expression of the correct type that references the specified
parameter slot. 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; typedef struct rua_ctx_s rua_ctx_t;
const expr_t *expr_process (const expr_t *expr, rua_ctx_t *ctx); const expr_t *expr_process (const expr_t *expr, rua_ctx_t *ctx);
bool can_inline (const expr_t *expr, symbol_t *fsym);
///@} ///@}

View file

@ -81,6 +81,7 @@ EX_EXPR(intrinsic) ///< intrinsic instruction expression (::ex_intrinsic_t)
EX_EXPR(switch) ///< switch expression (::ex_switch_t) EX_EXPR(switch) ///< switch expression (::ex_switch_t)
EX_EXPR(caselabel) ///< case expression (::ex_caselabel_t) EX_EXPR(caselabel) ///< case expression (::ex_caselabel_t)
EX_EXPR(xvalue) ///< xvalue expression (::ex_xvalue_t) EX_EXPR(xvalue) ///< xvalue expression (::ex_xvalue_t)
EX_EXPR(process) ///< expression that needs processing (::ex_process_t)
#undef EX_EXPR #undef EX_EXPR

View file

@ -77,6 +77,7 @@ typedef struct genfunc_s {
genparam_t *params; genparam_t *params;
genparam_t *ret_type; genparam_t *ret_type;
const expr_t *expr; ///< inline or intrinsic const expr_t *expr; ///< inline or intrinsic
bool can_inline;
} genfunc_t; } genfunc_t;
typedef enum { typedef enum {
@ -169,7 +170,9 @@ typedef struct metafunc_s {
rua_loc_t loc; ///< source location of the function rua_loc_t loc; ///< source location of the function
mf_type_e meta_type; ///< is this function overloaded mf_type_e meta_type; ///< is this function overloaded
function_t *func; function_t *func;
genfunc_t *genfunc;
const expr_t *expr; ///< inline or intrinsic const expr_t *expr; ///< inline or intrinsic
bool can_inline;
} metafunc_t; } metafunc_t;
extern function_t *current_func; extern function_t *current_func;

View file

@ -100,6 +100,7 @@ get_type (const expr_t *e)
case ex_loop: case ex_loop:
case ex_select: case ex_select:
case ex_message: case ex_message:
case ex_process:
internal_error (e, "unexpected expression type: %s", internal_error (e, "unexpected expression type: %s",
expr_names[e->type]); expr_names[e->type]);
case ex_label: case ex_label:
@ -1997,6 +1998,8 @@ has_function_call (const expr_t *e)
case ex_xvalue: case ex_xvalue:
bug (e, "should xvalue happen here?"); bug (e, "should xvalue happen here?");
return has_function_call (e->xvalue.expr); return has_function_call (e->xvalue.expr);
case ex_process:
internal_error (e, "unexpected expression type");
case ex_count: case ex_count:
break; break;
} }
@ -2322,6 +2325,17 @@ new_xvalue_expr (const expr_t *expr, bool lvalue)
return xv; 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 * expr_t *
new_decl (symbol_t *sym, const expr_t *init) 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; 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);
}

View file

@ -140,6 +140,7 @@ is_lvalue (const expr_t *expr)
case ex_intrinsic: case ex_intrinsic:
case ex_switch: case ex_switch:
case ex_caselabel: case ex_caselabel:
case ex_process:
break; break;
case ex_cond: case ex_cond:
return (is_lvalue (expr->cond.true_expr) return (is_lvalue (expr->cond.true_expr)

View file

@ -37,11 +37,13 @@
#include <stdlib.h> #include <stdlib.h>
#include "tools/qfcc/include/algebra.h" #include "tools/qfcc/include/algebra.h"
#include "tools/qfcc/include/defspace.h"
#include "tools/qfcc/include/diagnostic.h" #include "tools/qfcc/include/diagnostic.h"
#include "tools/qfcc/include/expr.h" #include "tools/qfcc/include/expr.h"
#include "tools/qfcc/include/function.h" #include "tools/qfcc/include/function.h"
#include "tools/qfcc/include/idstuff.h" #include "tools/qfcc/include/idstuff.h"
#include "tools/qfcc/include/options.h" #include "tools/qfcc/include/options.h"
#include "tools/qfcc/include/shared.h"
#include "tools/qfcc/include/symtab.h" #include "tools/qfcc/include/symtab.h"
#include "tools/qfcc/include/target.h" #include "tools/qfcc/include/target.h"
#include "tools/qfcc/include/type.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; 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 * static expr_t *
build_args (const expr_t *(*arg_exprs)[2], int *arg_expr_count, build_args (const expr_t *(*arg_exprs)[2], int *arg_expr_count,
const expr_t **arguments, const type_t **arg_types, 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; return err;
} }
expr_t *call = nullptr;
scoped_src_loc (fexpr); scoped_src_loc (fexpr);
if (fexpr->type == ex_symbol && fexpr->symbol->sy_type == sy_func if (fexpr->type == ex_symbol && fexpr->symbol->sy_type == sy_func
&& fexpr->symbol->metafunc->expr) { && 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) { if (expr->type == ex_intrinsic) {
for (int i = 0; i < arg_count; i++) { return build_intrinsic_call (expr, ftype, arguments, arg_count);
if (is_reference (get_type (arguments[i]))) {
arguments[i] = pointer_deref (arguments[i]);
} }
if (metafunc->can_inline) {
return build_inline_call (fsym, ftype, arguments, arg_count);
} }
call = new_intrinsic_expr (nullptr); internal_error (fexpr, "calls to inline functions that cannot be "
call->intrinsic.opcode = expr->intrinsic.opcode; "inlined not implemented");
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);
}
} else { } else {
call = new_block_expr (0); auto call = new_block_expr (nullptr);
call->block.is_call = 1; call->block.is_call = 1;
int num_args = 0; int num_args = 0;
const expr_t *arg_exprs[arg_count + 1][2]; const expr_t *arg_exprs[arg_count + 1][2];
@ -333,9 +409,9 @@ build_function_call (const expr_t *fexpr, const type_t *ftype,
} }
auto ret_type = ftype->func.ret_type; auto ret_type = ftype->func.ret_type;
call->block.result = new_call_expr (fexpr, arg_list, ret_type); call->block.result = new_call_expr (fexpr, arg_list, ret_type);
}
return call; return call;
} }
}
const expr_t * const expr_t *
function_expr (const expr_t *fexpr, const expr_t *args) function_expr (const expr_t *fexpr, const expr_t *args)

View file

@ -86,6 +86,7 @@ edag_add_expr (const expr_t *expr)
case ex_intrinsic: case ex_intrinsic:
case ex_switch: case ex_switch:
case ex_caselabel: case ex_caselabel:
case ex_process:
// these are never put in the dag // these are never put in the dag
return expr; return expr;
case ex_list: case ex_list:

View file

@ -249,11 +249,16 @@ proc_block (const expr_t *expr, rua_ctx_t *ctx)
const expr_t *result = nullptr; const expr_t *result = nullptr;
const expr_t *in[count + 1]; const expr_t *in[count + 1];
const expr_t *out[count + 1]; const expr_t *out[count + 1];
const expr_t *err = nullptr;
list_scatter (&expr->block.list, in); list_scatter (&expr->block.list, in);
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
edag_flush (); edag_flush ();
auto e = expr_process (in[i], ctx); 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; out[num_out++] = e;
if (expr->block.result == in[i]) { if (expr->block.result == in[i]) {
result = e; result = e;
@ -261,6 +266,10 @@ proc_block (const expr_t *expr, rua_ctx_t *ctx)
} }
} }
edag_flush (); edag_flush ();
if (err) {
current_symtab = old_scope;
return err;
}
scoped_src_loc (expr); scoped_src_loc (expr);
auto block = new_block_expr (nullptr); auto block = new_block_expr (nullptr);
@ -706,5 +715,9 @@ expr_process (const expr_t *expr, rua_ctx_t *ctx)
expr_names[expr->type]); 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;
} }

View file

@ -41,6 +41,7 @@
#include "tools/qfcc/include/function.h" #include "tools/qfcc/include/function.h"
#include "tools/qfcc/include/opcodes.h" #include "tools/qfcc/include/opcodes.h"
#include "tools/qfcc/include/rua-lang.h" #include "tools/qfcc/include/rua-lang.h"
#include "tools/qfcc/include/shared.h"
#include "tools/qfcc/include/statements.h" #include "tools/qfcc/include/statements.h"
#include "tools/qfcc/include/symtab.h" #include "tools/qfcc/include/symtab.h"
#include "tools/qfcc/include/type.h" #include "tools/qfcc/include/type.h"
@ -706,6 +707,17 @@ type_parameter (symbol_t *sym, const expr_t *type)
const type_t * const type_t *
resolve_type (const expr_t *te) 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) { if (te->type != ex_type) {
internal_error (te, "not a type expression"); internal_error (te, "not a type expression");
} }

View file

@ -58,6 +58,7 @@
#include "tools/qfcc/include/expr.h" #include "tools/qfcc/include/expr.h"
#include "tools/qfcc/include/flow.h" #include "tools/qfcc/include/flow.h"
#include "tools/qfcc/include/function.h" #include "tools/qfcc/include/function.h"
#include "tools/qfcc/include/method.h"
#include "tools/qfcc/include/opcodes.h" #include "tools/qfcc/include/opcodes.h"
#include "tools/qfcc/include/options.h" #include "tools/qfcc/include/options.h"
#include "tools/qfcc/include/reloc.h" #include "tools/qfcc/include/reloc.h"
@ -682,11 +683,11 @@ find_generic_function (genfunc_t **genfuncs, const expr_t *fexpr,
} }
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; auto call_params = calltype->params;
const type_t *types[g->num_types] = {};
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;
@ -746,6 +747,7 @@ create_generic_sym (genfunc_t *g, const expr_t *fexpr, calltype_t *calltype)
sym->metafunc = new_metafunc (); sym->metafunc = new_metafunc ();
*sym->metafunc = *fsym->metafunc; *sym->metafunc = *fsym->metafunc;
sym->metafunc->expr = g->expr; sym->metafunc->expr = g->expr;
sym->metafunc->can_inline = g->can_inline;
symtab_addsymbol (fsym->table, sym); symtab_addsymbol (fsym->table, sym);
} }
return sym; return sym;
@ -789,7 +791,8 @@ get_function (const char *name, specifier_t spec)
} }
auto gen = find_generic_function (genfuncs, &fexpr, &calltype, false); auto gen = find_generic_function (genfuncs, &fexpr, &calltype, false);
if (gen) { 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 if (sym == fexpr.symbol
|| sym->metafunc == fexpr.symbol->metafunc) { || sym->metafunc == fexpr.symbol->metafunc) {
internal_error (0, "genfunc oops"); internal_error (0, "genfunc oops");
@ -859,6 +862,7 @@ function_symbol (specifier_t spec)
.full_name = name, .full_name = name,
.loc = pr.loc, .loc = pr.loc,
.meta_type = mf_generic, .meta_type = mf_generic,
.genfunc = genfunc,
}; };
Hash_Add (metafuncs, func); Hash_Add (metafuncs, func);
Hash_Add (function_map, func); Hash_Add (function_map, func);
@ -895,6 +899,46 @@ set_func_symbol (const expr_t *fexpr, metafunc_t *f)
return nf; 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 * const expr_t *
find_function (const expr_t *fexpr, const expr_t *params) 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) { if (!gen) {
return new_error_expr (); 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); return new_symbol_expr (sym);
} }
@ -1069,20 +1120,6 @@ build_scope (symbol_t *fsym, symtab_t *parent)
current_target.build_scope (fsym); 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 * function_t *
make_function (symbol_t *sym, const char *nice_name, defspace_t *space, make_function (symbol_t *sym, const char *nice_name, defspace_t *space,
storage_class_t storage) 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; defspace_t *space = spec.is_far ? pr.far_data : sym->table->space;
func = make_function (sym, nicename, space, spec.storage); 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) expr_t *statements, rua_ctx_t *ctx)
{ {
auto fsym = spec.sym; 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) { if (ctx) {
statements = (expr_t *) expr_process (statements, ctx); statements = (expr_t *) expr_process (statements, ctx);
} }
@ -1271,9 +1327,7 @@ build_intrinsic_function (specifier_t spec, const expr_t *intrinsic)
return; return;
} }
if (sym->metafunc->meta_type == mf_generic) { if (sym->metafunc->meta_type == mf_generic) {
//FIXME find a better way to find the specific genfunc auto genfunc = sym->metafunc->genfunc;
auto genfunc = parse_generic_function (sym->name, spec);
genfunc = add_generic_function (genfunc);
if (genfunc->expr) { if (genfunc->expr) {
error (intrinsic, "%s already defined", sym->name); error (intrinsic, "%s already defined", sym->name);
return; return;