diff --git a/tools/qfcc/include/type.h b/tools/qfcc/include/type.h index 37fcb2d0e..479ab5f08 100644 --- a/tools/qfcc/include/type.h +++ b/tools/qfcc/include/type.h @@ -258,6 +258,7 @@ 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_compares (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)); diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index 2aee7d71f..3bc8d47c5 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -1787,6 +1787,55 @@ type_demotes (const type_t *dst, const type_t *src) return dst_mask & (1 << src->type); } +#define C(type) (1 << ev_##type) +static unsigned compare_masks[ev_type_count] = { + [ev_float] = C(float), + [ev_int] = C(int) | C(long), + [ev_uint] = C(uint) | C(ulong), + [ev_double] = C(double), + [ev_long] = C(long) | C(int), + [ev_ulong] = C(ulong) | C(uint), +}; +#undef C + +bool +type_compares (const type_t *dst, const type_t *src) +{ + if (!dst || !src) { + return false; + } + + dst = unalias_type (dst); + src = unalias_type (src); + if (dst == src) { + return true; + } + if (type_rows (dst) != type_rows (src) + || type_cols (dst) != type_cols (src)) { + return false; + } + if (!is_math (dst) || !is_math (src)) { + return false; + } + + if (is_boolean (dst) || is_boolean (src)) { + // comparison between bool and lbool are ok, but not between either + // bool and any other type + return is_boolean (dst) && is_boolean (src); + } + if (is_enum (src)) { + return is_integral (dst) && !is_enum (dst); + } + if (is_enum (dst)) { + return is_integral (src) && !is_enum (src); + } + + dst = base_type (dst); + src = base_type (src); + int dst_mask = compare_masks[dst->type]; + return dst_mask & (1 << src->type); +} + bool type_same (const type_t *dst, const type_t *src) {