0
0
Fork 0
mirror of https://git.code.sf.net/p/quake/quakeforge synced 2025-04-11 11:51:50 +00:00

[qfcc] Allow demotion of implicit literals

This fixes the modulo test.
This commit is contained in:
Bill Currie 2024-11-24 16:57:19 +09:00
parent 98d122f122
commit b0207f4dc9
3 changed files with 88 additions and 42 deletions
tools/qfcc

View file

@ -257,6 +257,7 @@ bool is_structural (const type_t *type) __attribute__((pure));
bool type_compatible (const type_t *dst, const type_t *src) __attribute__((pure));
bool type_assignable (const type_t *dst, const type_t *src);
bool type_promotes (const type_t *dst, const type_t *src) __attribute__((pure));
bool type_demotes (const type_t *dst, const type_t *src) __attribute__((pure));
bool type_same (const type_t *dst, const type_t *src) __attribute__((pure));
int type_size (const type_t *type) __attribute__((pure));
int type_count (const type_t *type) __attribute__((pure));

View file

@ -547,47 +547,60 @@ set_func_attrs (const type_t *func_type, attribute_t *attr_list)
}
}
typedef struct {
const type_t *type;
bool implicit;
} callparm_t;
typedef struct {
int num_params;
callparm_t *params;
} calltype_t;
static bool
check_type (const type_t *type, const type_t *param_type, unsigned *cost,
bool promote)
check_type (const type_t *type, callparm_t param, unsigned *cost, bool promote)
{
if (!type) {
return false;
}
if (type == param_type) {
if (type == param.type) {
return true;
}
if (is_reference (type)) {
// pass by references is a free conversion, but no promotion
return dereference_type (type) == param_type;
return dereference_type (type) == param.type;
}
if (is_reference (param_type)) {
if (is_reference (param.type)) {
// dereferencing a reference is free so long as there's no
// promotion, otherwise there's the promotion cost
param_type = dereference_type (param_type);
param.type = dereference_type (param.type);
}
if (type == param_type) {
if (type == param.type) {
return true;
}
if (!promote || !type_promotes (type, param_type)) {
if (!promote) {
// want exact match
return false;
}
if (!type_promotes (type, param.type)) {
return param.implicit && type_demotes (type, param.type);
}
*cost += 1;
return true;
}
static const type_t * __attribute__((pure))
select_type (gentype_t *gentype, const type_t *param_type)
select_type (gentype_t *gentype, callparm_t param)
{
for (auto t = gentype->valid_types; t && *t; t++) {
if (*t == param_type) {
if (*t == param.type) {
return *t;
}
if (is_reference (*t) && dereference_type (*t) == param_type) {
if (is_reference (*t) && dereference_type (*t) == param.type) {
// pass value by reference: no promotion
return *t;
}
auto pt = param_type;
auto pt = param.type;
if (is_reference (pt)) {
// pass reference by value: promotion ok
pt = dereference_type (pt);
@ -604,14 +617,14 @@ select_type (gentype_t *gentype, const type_t *param_type)
static genfunc_t *
find_generic_function (genfunc_t **genfuncs, const expr_t *fexpr,
const type_t *call_type, bool promote)
calltype_t *calltype, bool promote)
{
int num_funcs = 0;
for (auto gf = genfuncs; *gf; gf++, num_funcs++) continue;
unsigned costs[num_funcs] = {};
int num_params = call_type->func.num_params;
auto call_params = call_type->func.param_types;
int num_params = calltype->num_params;
auto call_params = calltype->params;
for (int j = 0; j < num_funcs; j++) {
auto g = genfuncs[j];
if (g->num_params != num_params) {
@ -660,10 +673,10 @@ find_generic_function (genfunc_t **genfuncs, const expr_t *fexpr,
}
static symbol_t *
create_generic_sym (genfunc_t *g, const expr_t *fexpr, const type_t *call_type)
create_generic_sym (genfunc_t *g, const expr_t *fexpr, calltype_t *calltype)
{
int num_params = call_type->func.num_params;
auto call_params = call_type->func.param_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];
@ -738,12 +751,23 @@ get_function (const char *name, specifier_t spec)
spec.sym->type = find_type (spec.sym->type);
}
auto type = unalias_type (spec.sym->type);
int num_params = type->func.num_params;
if (num_params < 0) {
num_params = ~num_params;
}
callparm_t call_params[num_params + 1] = {};
calltype_t calltype = {
.num_params = type->func.num_params,
.params = call_params,
};
for (int i = 0; i < num_params; i++) {
call_params[i].type = type->func.param_types[i];
}
bool overload = spec.is_overload | current_language.always_override;
metafunc_t *func = Hash_Find (function_map, name);
if (func && func->meta_type == mf_generic) {
auto genfuncs = (genfunc_t **) Hash_FindList (generic_functions, name);
auto type = spec.sym->type;
expr_t fexpr = {
.loc = pr.loc,
.type = ex_symbol,
@ -753,9 +777,9 @@ get_function (const char *name, specifier_t spec)
|| !fexpr.symbol->metafunc) {
internal_error (0, "genfunc oops");
}
auto gen = find_generic_function (genfuncs, &fexpr, type, false);
auto gen = find_generic_function (genfuncs, &fexpr, &calltype, false);
if (gen) {
auto sym = create_generic_sym (gen, &fexpr, type);
auto sym = create_generic_sym (gen, &fexpr, &calltype);
if (sym == fexpr.symbol
|| sym->metafunc == fexpr.symbol->metafunc) {
internal_error (0, "genfunc oops");
@ -869,41 +893,35 @@ find_function (const expr_t *fexpr, const expr_t *params)
}
int num_params = params ? list_count (&params->list) : 0;
const type_t *arg_types[num_params + 1];
param_qual_t arg_quals[num_params + 1];
const expr_t *args[num_params + 1];
if (params) {
list_scatter_rev (&params->list, args);
}
callparm_t call_params[num_params] = {};
for (int i = 0; i < num_params; i++) {
auto e = args[i];
if (e->type == ex_error) {
return e;
}
arg_types[i] = get_type (e);
arg_quals[i] = pq_in;
call_params[i] = (callparm_t) {
.type = get_type (e),
.implicit = e->implicit,
};
}
type_t call_type = {
.type = ev_func,
.alignment = 1,
.width = 1,
.columns = 1,
.func = {
.num_params = num_params,
.param_types = arg_types,
.param_quals = arg_quals,
},
calltype_t calltype = {
.num_params = num_params,
.params = call_params,
};
const char *fname = fexpr->symbol->name;
auto genfuncs = (genfunc_t **) Hash_FindList (generic_functions, fname);
if (genfuncs) {
auto gen = find_generic_function (genfuncs, fexpr, &call_type, true);
auto gen = find_generic_function (genfuncs, fexpr, &calltype, true);
if (!gen) {
return new_error_expr ();
}
auto sym = create_generic_sym (gen, fexpr, &call_type);
auto sym = create_generic_sym (gen, fexpr, &calltype);
return new_symbol_expr (sym);
}
@ -923,8 +941,8 @@ find_function (const expr_t *fexpr, const expr_t *params)
for (int i = 0; i < num_funcs; i++) {
auto f = (metafunc_t *) funcs[i];
int num_params = f->type->func.num_params;
if ((num_params >= 0 && num_params != call_type.func.num_params)
|| (num_params < 0 && ~num_params > call_type.func.num_params)) {
if ((num_params >= 0 && num_params != calltype.num_params)
|| (num_params < 0 && ~num_params > calltype.num_params)) {
costs[i] = ~0u;
continue;
}
@ -934,8 +952,8 @@ find_function (const expr_t *fexpr, const expr_t *params)
bool ok = true;
for (int j = 0; ok && j < num_params; j++) {
auto fptype = f->type->func.param_types[j];
auto cptype = call_type.func.param_types[j];
ok &= check_type (fptype, cptype, costs + i, true);
auto cparam = calltype.params[j];
ok &= check_type (fptype, cparam, costs + i, true);
}
if (!ok) {
costs[i] = ~0u;

View file

@ -1749,6 +1749,33 @@ type_promotes (const type_t *dst, const type_t *src)
return false;
}
bool
type_demotes (const type_t *dst, const type_t *src)
{
if (!dst || !src) {
return false;
}
dst = unalias_type (dst);
src = unalias_type (src);
if (type_rows (dst) != type_rows (src)
|| type_cols (dst) != type_cols (src)) {
return false;
}
if (is_float (dst) && is_double (src)) {
return true;
}
if ((is_boolean (dst) || is_int (dst) || is_uint (dst))
&& is_lbool (src)) {
return true;
}
if (is_bool (dst) && (is_lbool (src) || is_long (src))) {
return true;
}
return false;
}
bool
type_same (const type_t *dst, const type_t *src)
{