mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-20 18:52:28 +00:00
[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:
parent
ae0b3a5870
commit
85d851572f
4 changed files with 170 additions and 102 deletions
|
@ -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));
|
||||
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
148
tools/qfcc/source/expr_cast.c
Normal file
148
tools/qfcc/source/expr_cast.c
Normal 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;
|
||||
}
|
Loading…
Reference in a new issue