From 85d851572ffecf46b1a800229d013dd2e62d43d2 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 27 Apr 2022 21:36:15 +0900 Subject: [PATCH] [qfcc] Implement constant casts for the new vector types Nicely, I was able to reuse the generated conversion code used by the progs engine to do the work in qfcc, just needed appropriate definitions for the operand macros, and to set up the conversion code. Helped greatly by the new value load/store functions. --- tools/qfcc/include/expr.h | 4 +- tools/qfcc/source/Makemodule.am | 1 + tools/qfcc/source/expr.c | 119 ++++--------------------- tools/qfcc/source/expr_cast.c | 148 ++++++++++++++++++++++++++++++++ 4 files changed, 170 insertions(+), 102 deletions(-) create mode 100644 tools/qfcc/source/expr_cast.c diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 2b3887ae1..3c2f2a555 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -205,6 +205,8 @@ typedef struct ex_value_s { unsigned uint_val; ///< unsigned int constant int16_t short_val; ///< short constant uint16_t ushort_val; ///< unsigned short constant +#define VEC_TYPE(type_name, base_type) pr_##type_name##_t type_name##_val; +#include "tools/qfcc/include/vec_types.h" } v; } ex_value_t; @@ -309,7 +311,6 @@ expr_t *type_mismatch (expr_t *e1, expr_t *e2, int op); expr_t *param_mismatch (expr_t *e, int param, const char *fn, struct type_s *t1, struct type_s *t2); -expr_t *cast_error (expr_t *e, struct type_s *t1, struct type_s *t2); expr_t *test_error (expr_t *e, struct type_s *t); extern expr_t *local_expr; @@ -640,6 +641,7 @@ unsigned expr_uint (expr_t *e) __attribute__((pure)); */ expr_t *new_short_expr (short short_val); short expr_short (expr_t *e) __attribute__((pure)); +unsigned short expr_ushort (expr_t *e) __attribute__((pure)); int expr_integral (expr_t *e) __attribute__((pure)); diff --git a/tools/qfcc/source/Makemodule.am b/tools/qfcc/source/Makemodule.am index 0406cea3e..a070fad67 100644 --- a/tools/qfcc/source/Makemodule.am +++ b/tools/qfcc/source/Makemodule.am @@ -28,6 +28,7 @@ qfcc_SOURCES = \ tools/qfcc/source/expr_assign.c \ tools/qfcc/source/expr_binary.c \ tools/qfcc/source/expr_bool.c \ + tools/qfcc/source/expr_cast.c \ tools/qfcc/source/expr_compound.c \ tools/qfcc/source/expr_obj.c \ tools/qfcc/source/expr_vector.c \ diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 8033d6435..388ab8e14 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -214,16 +214,9 @@ extract_type (expr_t *e) expr_t * type_mismatch (expr_t *e1, expr_t *e2, int op) { - dstring_t *t1 = dstring_newstr (); - dstring_t *t2 = dstring_newstr (); - - print_type_str (t1, get_type (e1)); - print_type_str (t2, get_type (e2)); - e1 = error (e1, "type mismatch: %s %s %s", - t1->str, get_op_string (op), t2->str); - dstring_delete (t1); - dstring_delete (t2); + get_type_string (get_type (e1)), get_op_string (op), + get_type_string (get_type (e2))); return e1; } @@ -243,21 +236,6 @@ param_mismatch (expr_t *e, int param, const char *fn, type_t *t1, type_t *t2) return e; } -expr_t * -cast_error (expr_t *e, type_t *t1, type_t *t2) -{ - dstring_t *s1 = dstring_newstr (); - dstring_t *s2 = dstring_newstr (); - - print_type_str (s1, t1); - print_type_str (s2, t2); - - e = error (e, "cannot cast from %s to %s", s1->str, s2->str); - dstring_delete (s1); - dstring_delete (s2); - return e; -} - expr_t * test_error (expr_t *e, type_t *t) { @@ -1145,6 +1123,22 @@ expr_short (expr_t *e) internal_error (e, "not a short constant"); } +unsigned short +expr_ushort (expr_t *e) +{ + if (e->type == ex_nil) { + return 0; + } + if (e->type == ex_value && e->e.value->lltype == ev_ushort) { + return e->e.value->v.ushort_val; + } + if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const + && e->e.symbol->type->type == ev_ushort) { + return e->e.symbol->s.value->v.ushort_val; + } + internal_error (e, "not a ushort constant"); +} + int is_integral_val (expr_t *e) { @@ -2872,83 +2866,6 @@ think_expr (symbol_t *think_sym) return new_symbol_expr (think_sym); } -expr_t * -cast_expr (type_t *dstType, expr_t *e) -{ - expr_t *c; - type_t *srcType; - - convert_name (e); - - if (e->type == ex_error) - return e; - - dstType = (type_t *) unalias_type (dstType); //FIXME cast - srcType = get_type (e); - - if (dstType == srcType) - return e; - - if ((dstType == type_default && is_enum (srcType)) - || (is_enum (dstType) && srcType == type_default)) - return e; - if ((is_ptr (dstType) && is_string (srcType)) - || (is_string (dstType) && is_ptr (srcType))) { - c = new_alias_expr (dstType, e); - return c; - } - if (!(is_ptr (dstType) && (is_ptr (srcType) || is_integral (srcType) - || is_array (srcType))) - && !(is_integral (dstType) && is_ptr (srcType)) - && !(is_func (dstType) && is_func (srcType)) - && !(is_scalar (dstType) && is_scalar (srcType))) { - return cast_error (e, srcType, dstType); - } - if (is_array (srcType)) { - return address_expr (e, dstType->t.fldptr.type); - } - if (is_constant (e) && is_scalar (dstType) && is_scalar (srcType)) { - ex_value_t *val = 0; - if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const) { - val = e->e.symbol->s.value; - } else if (e->type == ex_symbol - && e->e.symbol->sy_type == sy_var) { - // initialized global def treated as a constant - // from the tests above, the def is known to be constant - // and of one of the three storable scalar types - def_t *def = e->e.symbol->s.def; - if (is_float (def->type)) { - val = new_float_val (D_FLOAT (def)); - } else if (is_double (def->type)) { - val = new_double_val (D_DOUBLE (def)); - } else if (is_integral (def->type)) { - val = new_int_val (D_INT (def)); - } - } else if (e->type == ex_value) { - val = e->e.value; - } else if (e->type == ex_nil) { - convert_nil (e, dstType); - return e; - } - if (!val) - internal_error (e, "unexpected constant expression type"); - e->e.value = convert_value (val, dstType); - e->type = ex_value; - c = e; - } else if (is_integral (dstType) && is_integral (srcType)) { - c = new_alias_expr (dstType, e); - } else if (is_scalar (dstType) && is_scalar (srcType)) { - c = new_unary_expr ('C', e); - c->e.expr.type = dstType; - } else if (e->type == ex_uexpr && e->e.expr.op == '.') { - e->e.expr.type = dstType; - c = e; - } else { - c = new_alias_expr (dstType, e); - } - return c; -} - expr_t * encode_expr (type_t *type) { diff --git a/tools/qfcc/source/expr_cast.c b/tools/qfcc/source/expr_cast.c new file mode 100644 index 000000000..9ec9e9d1a --- /dev/null +++ b/tools/qfcc/source/expr_cast.c @@ -0,0 +1,148 @@ +/* + expr_cast.c + + expression casting + + Copyright (C) 2022 Bill Currie + + Author: Bill Currie + Date: 2022/04/27 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include "QF/mathlib.h" + +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/def.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/type.h" +#include "tools/qfcc/include/value.h" + +static expr_t * +cast_error (expr_t *e, type_t *t1, type_t *t2) +{ + e = error (e, "cannot cast from %s to %s", get_type_string (t1), + get_type_string (t2)); + return e; +} + +static void +do_conversion (pr_type_t *dst_value, type_t *dstType, + pr_type_t *src_value, type_t *srcType, expr_t *expr) +{ + int from = type_cast_map[base_type (srcType)->type]; + int to = type_cast_map[base_type (dstType)->type]; + int width = type_width (srcType) - 1; + int conversion = TYPE_CAST_CODE (from, to, width); +#define OPA(type) (*((pr_##type##_t *) (src_value))) +#define OPC(type) (*((pr_##type##_t *) (dst_value))) + switch (conversion) { +#include "libs/gamecode/pr_convert.cinc" + default: + internal_error (expr, "invalid conversion code: %04o", conversion); + } +} + +static expr_t * +cast_math (type_t *dstType, type_t *srcType, expr_t *expr) +{ + pr_type_t src_value[type_size (srcType)]; + pr_type_t dst_value[type_size (dstType)]; + + value_store (src_value, srcType, expr); + + do_conversion (dst_value, dstType, src_value, srcType, expr); + + expr_t *val = new_expr (); + val->type = ex_value; + val->e.value = new_type_value (dstType, dst_value); + return val; +} + +expr_t * +cast_expr (type_t *dstType, expr_t *e) +{ + expr_t *c; + type_t *srcType; + + convert_name (e); + + if (e->type == ex_error) + return e; + + dstType = (type_t *) unalias_type (dstType); //FIXME cast + srcType = get_type (e); + + if (dstType == srcType) + return e; + + if ((dstType == type_default && is_enum (srcType)) + || (is_enum (dstType) && srcType == type_default)) + return e; + if ((is_ptr (dstType) && is_string (srcType)) + || (is_string (dstType) && is_ptr (srcType))) { + c = new_alias_expr (dstType, e); + return c; + } + if (!(is_ptr (dstType) && (is_ptr (srcType) || is_integral (srcType) + || is_array (srcType))) + && !(is_integral (dstType) && is_ptr (srcType)) + && !(is_func (dstType) && is_func (srcType)) + && !(is_math (dstType) && is_math (srcType) + && type_width (dstType) == type_width (srcType)) + && !((is_int (dstType) || is_uint (dstType)) + && (is_short (srcType) || is_ushort (srcType)) + // [u]short is always width 0 + && type_width (dstType) == 1)) { + return cast_error (e, srcType, dstType); + } + if (is_array (srcType)) { + return address_expr (e, dstType->t.fldptr.type); + } + if (is_short (srcType)) { + e = new_int_expr (expr_short (e)); + srcType = &type_int; + } else if (is_ushort (srcType)) { + e = new_int_expr (expr_ushort (e)); + srcType = &type_int; + } + if (is_constant (e) && is_math (dstType) && is_math (srcType)) { + return cast_math (dstType, srcType, e); + } else if (is_integral (dstType) && is_integral (srcType)) { + c = new_alias_expr (dstType, e); + } else if (is_scalar (dstType) && is_scalar (srcType)) { + c = new_unary_expr ('C', e); + c->e.expr.type = dstType; + } else if (e->type == ex_uexpr && e->e.expr.op == '.') { + e->e.expr.type = dstType; + c = e; + } else { + c = new_alias_expr (dstType, e); + } + return c; +}