diff --git a/tools/qfcc/include/target.h b/tools/qfcc/include/target.h index 68a8cd4ea..2e9de6ce1 100644 --- a/tools/qfcc/include/target.h +++ b/tools/qfcc/include/target.h @@ -49,6 +49,8 @@ typedef struct { const expr_t *(*proc_switch) (const expr_t *expr, rua_ctx_t *ctx); const expr_t *(*proc_caselabel) (const expr_t *expr, rua_ctx_t *ctx); const expr_t *(*proc_address) (const expr_t *expr, rua_ctx_t *ctx); + // for both vector and quaternion types + const expr_t *(*vector_compare)(int op, const expr_t *e1, const expr_t *e2); bool (*setup_intrinsic_symtab) (symtab_t *symtab); diff --git a/tools/qfcc/source/expr_binary.c b/tools/qfcc/source/expr_binary.c index 97a37c9e3..8d06748f4 100644 --- a/tools/qfcc/source/expr_binary.c +++ b/tools/qfcc/source/expr_binary.c @@ -36,6 +36,7 @@ #include "tools/qfcc/include/expr.h" #include "tools/qfcc/include/options.h" #include "tools/qfcc/include/rua-lang.h" +#include "tools/qfcc/include/target.h" #include "tools/qfcc/include/type.h" typedef struct { @@ -213,13 +214,12 @@ math_compare (int op, const expr_t *e1, const expr_t *e2) t1 = get_type (e1); t2 = get_type (e2); } + if (is_vector (t1) || is_quaternion (t1)) { + return current_target.vector_compare (op, e1, e2); + } + auto e = new_binary_expr (op, e1, e2); e->expr.type = bool_type (t1); - if (is_vector (t1) || is_quaternion (t1)) { - //FIXME operators other than just == and != ? - int hop = op == QC_EQ ? '&' : '|'; - e = new_horizontal_expr (hop, e, &type_int); - } return e; } diff --git a/tools/qfcc/source/target_rua.c b/tools/qfcc/source/target_rua.c index 17d51e03e..b83dfe5fc 100644 --- a/tools/qfcc/source/target_rua.c +++ b/tools/qfcc/source/target_rua.c @@ -355,6 +355,21 @@ ruamoko_proc_address (const expr_t *expr, rua_ctx_t *ctx) return address_expr (e, nullptr); } +static const expr_t * +ruamoko_vector_compare (int op, const expr_t *e1, const expr_t *e2) +{ + // both e1 and e2 should have the same types here + auto type = get_type (e1); + if (op != QC_EQ && op != QC_NE) { + return error (e2, "invalid comparison for %s", type->name); + } + int hop = op == QC_EQ ? '&' : '|'; + auto e = new_binary_expr (op, e1, e2); + e->expr.type = bool_type (type); + e = new_horizontal_expr (hop, e, &type_int); + return e; +} + target_t ruamoko_target = { .value_too_large = ruamoko_value_too_large, .build_scope = ruamoko_build_scope, @@ -365,4 +380,5 @@ target_t ruamoko_target = { .proc_switch = ruamoko_proc_switch, .proc_caselabel = ruamoko_proc_caselabel, .proc_address = ruamoko_proc_address, + .vector_compare = ruamoko_vector_compare, }; diff --git a/tools/qfcc/source/target_spirv.c b/tools/qfcc/source/target_spirv.c index 8960bb2b5..1447a5e31 100644 --- a/tools/qfcc/source/target_spirv.c +++ b/tools/qfcc/source/target_spirv.c @@ -2201,6 +2201,21 @@ spirv_assign_vector (const expr_t *dst, const expr_t *src) return new_assign_expr (dst, new);; } +static const expr_t * +spirv_vector_compare (int op, const expr_t *e1, const expr_t *e2) +{ + // both e1 and e2 should have the same types here + auto type = get_type (e1); + if (op != QC_EQ && op != QC_NE) { + return error (e2, "invalid comparison for %s", type->name); + } + int hop = op == QC_EQ ? '&' : '|'; + auto e = new_binary_expr (op, e1, e2); + e->expr.type = bool_type (type); + e = new_horizontal_expr (hop, e, &type_int); + return e; +} + target_t spirv_target = { .value_too_large = spirv_value_too_large, .build_scope = spirv_build_scope, @@ -2209,4 +2224,5 @@ target_t spirv_target = { .initialized_temp = spirv_initialized_temp, .assign_vector = spirv_assign_vector, .setup_intrinsic_symtab = spirv_setup_intrinsic_symtab, + .vector_compare = spirv_vector_compare, }; diff --git a/tools/qfcc/source/target_v6.c b/tools/qfcc/source/target_v6.c index 3c7b05455..74fd63f64 100644 --- a/tools/qfcc/source/target_v6.c +++ b/tools/qfcc/source/target_v6.c @@ -193,6 +193,32 @@ v6p_assign_vector (const expr_t *dst, const expr_t *src) return block; } +static const expr_t * +do_vector_compare (int op, const expr_t *e1, const expr_t *e2, + const type_t *res_type) +{ + // both e1 and e2 should have the same types here + auto type = get_type (e1); + if (op != QC_EQ && op != QC_NE) { + return error (e2, "invalid comparison for %s", type->name); + } + auto e = new_binary_expr (op, e1, e2); + e->expr.type = res_type; + return e; +} + +static const expr_t * +v6_vector_compare (int op, const expr_t *e1, const expr_t *e2) +{ + return do_vector_compare (op, e1, e2, &type_float); +} + +static const expr_t * +v6p_vector_compare (int op, const expr_t *e1, const expr_t *e2) +{ + return do_vector_compare (op, e1, e2, &type_int); +} + target_t v6_target = { .value_too_large = v6_value_too_large, .build_scope = v6p_build_scope, @@ -204,6 +230,7 @@ target_t v6_target = { .proc_switch = ruamoko_proc_switch, .proc_caselabel = ruamoko_proc_caselabel, .proc_address = ruamoko_proc_address, + .vector_compare = v6_vector_compare, }; target_t v6p_target = { @@ -217,4 +244,5 @@ target_t v6p_target = { .proc_switch = ruamoko_proc_switch, .proc_caselabel = ruamoko_proc_caselabel, .proc_address = ruamoko_proc_address, + .vector_compare = v6p_vector_compare, };