[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.
This commit is contained in:
Bill Currie 2022-04-27 21:36:15 +09:00
parent ae0b3a5870
commit 85d851572f
4 changed files with 170 additions and 102 deletions

View File

@ -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));

View File

@ -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 \

View File

@ -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)
{

View File

@ -0,0 +1,148 @@
/*
expr_cast.c
expression casting
Copyright (C) 2022 Bill Currie <bill@taniwha.org>
Author: Bill Currie <bill@taniwha.org>
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 <string.h>
#include <stdlib.h>
#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;
}