[qfcc] Add some utility functions for working with vector types

Finding vector types from base type and width, and getting the base type
for a vector type, as well as basic promotion rules for math types.
This commit is contained in:
Bill Currie 2022-04-27 21:32:41 +09:00
parent c120bf2940
commit ae0b3a5870
3 changed files with 85 additions and 14 deletions

View file

@ -160,6 +160,8 @@ type_t *find_type (type_t *new);
void new_typedef (const char *name, type_t *type);
type_t *field_type (type_t *aux);
type_t *pointer_type (type_t *aux);
type_t *vector_type (const type_t *ele_type, int width) __attribute__((pure));
type_t *base_type (const type_t *vec_type) __attribute__((pure));
type_t *array_type (type_t *aux, int size);
type_t *based_array_type (type_t *aux, int base, int top);
type_t *alias_type (type_t *type, type_t *alias_chain, const char *name);
@ -187,6 +189,7 @@ int is_array (const type_t *type) __attribute__((pure));
int is_structural (const type_t *type) __attribute__((pure));
int type_compatible (const type_t *dst, const type_t *src) __attribute__((pure));
int type_assignable (const type_t *dst, const type_t *src);
int type_promotes (const type_t *dst, const type_t *src) __attribute__((pure));
int type_same (const type_t *dst, const type_t *src) __attribute__((pure));
int type_size (const type_t *type) __attribute__((pure));
int type_width (const type_t *type) __attribute__((pure));
@ -197,5 +200,7 @@ void chain_initial_types (void);
void clear_typedefs (void);
extern type_t *ev_types[];
extern int type_cast_map[];
#define TYPE_CAST_CODE(from, to, width) (((width) << 6) | ((from) << 3) | (to))
#endif//__type_h

View file

@ -1760,17 +1760,6 @@ expr_expr (sblock_t *sblock, expr_t *e, operand_t **op)
return sblock;
}
static int type_map[ev_type_count] = {
[ev_int] = 0,
[ev_float] = 1,
[ev_long] = 2,
[ev_double] = 3,
[ev_uint] = 4,
//[ev_bool32] = 5,
[ev_ulong] = 6,
//[ev_bool64] = 7,
};
static sblock_t *
expr_cast (sblock_t *sblock, expr_t *e, operand_t **op)
{
@ -1786,10 +1775,10 @@ expr_cast (sblock_t *sblock, expr_t *e, operand_t **op)
s = new_statement (st_expr, "conv", e);
s->opa = src;
if (options.code.progsversion == PROG_VERSION) {
int from = type_map[src_type->type];
int to = type_map[type->type];
int from = type_cast_map[src_type->type];
int to = type_cast_map[type->type];
int width = type_width (src_type) - 1;
int conv = (width << 6) | (from << 3) | to;
int conv = TYPE_CAST_CODE (from, to, width);
s->opb = short_operand (conv, e);
}
s->opc = *op;

View file

@ -89,6 +89,11 @@ type_t type_invalid = {
};
#include "tools/qfcc/include/vec_types.h"
#define VEC_TYPE(type_name, base_type) &type_##type_name,
static type_t *vec_types[] = {
#include "tools/qfcc/include/vec_types.h"
0
};
type_t *type_nil;
type_t *type_default;
type_t *type_long_int;
@ -145,6 +150,17 @@ type_t *ev_types[ev_type_count] = {
&type_invalid,
};
int type_cast_map[ev_type_count] = {
[ev_int] = 0,
[ev_float] = 1,
[ev_long] = 2,
[ev_double] = 3,
[ev_uint] = 4,
//[ev_bool32] = 5,
[ev_ulong] = 6,
//[ev_bool64] = 7,
};
static type_t *types_freelist;
etype_t
@ -524,6 +540,38 @@ pointer_type (type_t *aux)
return new;
}
type_t *
vector_type (const type_t *ele_type, int width)
{
if (width == 1) {
for (type_t **t = ev_types; t - ev_types < ev_type_count; t++) {
if ((*t)->type == ele_type->type && (*t)->width == 1) {
return *t;
}
}
}
for (type_t **vtype = vec_types; *vtype; vtype++) {
if ((*vtype)->type == ele_type->type
&& (*vtype)->width == width) {
return *vtype;
}
}
return 0;
}
type_t *
base_type (const type_t *vec_type)
{
if (!is_math (vec_type)) {
return 0;
}
// vec_type->type for quaternion and vector points back to itself
if (is_quaternion (vec_type) || is_vector (vec_type)) {
return &type_float;
}
return ev_types[vec_type->type];
}
type_t *
array_type (type_t *aux, int size)
{
@ -1097,6 +1145,35 @@ type_assignable (const type_t *dst, const type_t *src)
return 0;
}
int
type_promotes (const type_t *dst, const type_t *src)
{
dst = unalias_type (dst);
src = unalias_type (src);
// nothing promotes to int
if (is_int (dst)) {
return 0;
}
if (is_uint (dst) && is_int (src)) {
return 1;
}
if (is_long (dst) && (is_int (src) || is_uint (src))) {
return 1;
}
if (is_ulong (dst) && (is_int (src) || is_uint (src) || is_long (src))) {
return 1;
}
if (is_float (dst) && (is_int (src) || is_uint (src))) {
return 1;
}
//XXX what to do with (u)long<->float?
// everything promotes to double
if (is_double (dst)) {
return 1;
}
return 0;
}
int
type_same (const type_t *dst, const type_t *src)
{