From 8e2fe83c2719d78e3c40a628efd07f542624b028 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 Dec 2024 00:06:17 +0900 Subject: [PATCH] [qfcc] Add a function for checking type comparisons It returns true if the comparison is valid without a diagnostic (usually a warning), false otherwise. --- tools/qfcc/include/type.h | 1 + tools/qfcc/source/type.c | 49 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) 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) {