mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-16 17:01:53 +00:00
[qfcc] Implement automatic casting between same-width vectors
This allows all the tests to build and pass. I'll need to add tests to ensure warnings happen when they should and that all vec operations are correct (ouch, that'll be a lot of work), but vectors and quaternions are working again.
This commit is contained in:
parent
bf53edf5e3
commit
9c8e13aa4c
6 changed files with 102 additions and 24 deletions
|
@ -2231,8 +2231,9 @@ return_expr (function_t *f, expr_t *e)
|
|||
}
|
||||
if (!type_assignable (ret_type, t)) {
|
||||
if (!options.traditional)
|
||||
return error (e, "type mismatch for return value of %s",
|
||||
f->sym->name);
|
||||
return error (e, "type mismatch for return value of %s: %s -> %s",
|
||||
f->sym->name, get_type_string (t),
|
||||
get_type_string (ret_type));
|
||||
if (options.warnings.traditional)
|
||||
warning (e, "type mismatch for return value of %s",
|
||||
f->sym->name);
|
||||
|
|
|
@ -173,21 +173,20 @@ check_types_compatible (expr_t *dst, expr_t *src)
|
|||
}
|
||||
|
||||
if (type_assignable (dst_type, src_type)) {
|
||||
if (is_scalar (dst_type) && is_scalar (src_type)) {
|
||||
if (!src->implicit) {
|
||||
if (is_double (src_type)) {
|
||||
warning (dst, "assignment of double to %s (use a cast)\n",
|
||||
dst_type->name);
|
||||
}
|
||||
}
|
||||
// the types are different but cast-compatible
|
||||
expr_t *new = cast_expr (dst_type, src);
|
||||
// the cast was a no-op, so the types are compatible at the
|
||||
// low level (very true for default type <-> enum)
|
||||
if (new != src) {
|
||||
return assign_expr (dst, new);
|
||||
debug (dst, "casting %s to %s", src_type->name, dst_type->name);
|
||||
if (!src->implicit && !type_promotes (dst_type, src_type)) {
|
||||
if (is_double (src_type)) {
|
||||
warning (dst, "assignment of %s to %s (use a cast)\n",
|
||||
src_type->name, dst_type->name);
|
||||
}
|
||||
}
|
||||
// the types are different but cast-compatible
|
||||
expr_t *new = cast_expr (dst_type, src);
|
||||
// the cast was a no-op, so the types are compatible at the
|
||||
// low level (very true for default type <-> enum)
|
||||
if (new != src) {
|
||||
return assign_expr (dst, new);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
// traditional qcc is a little sloppy
|
||||
|
|
|
@ -642,6 +642,27 @@ static expr_type_t **binary_expr_types[ev_type_count] = {
|
|||
[ev_double] = double_x
|
||||
};
|
||||
|
||||
// supported operators for scalar-vector expressions
|
||||
static int scalar_vec_ops[] = { '*', '/', '%', MOD, 0 };
|
||||
static expr_t *
|
||||
convert_scalar (expr_t *scalar, int op, expr_t *vec)
|
||||
{
|
||||
int *s_op = scalar_vec_ops;
|
||||
while (*s_op && *s_op != op) {
|
||||
s_op++;
|
||||
}
|
||||
if (!*s_op) {
|
||||
return 0;
|
||||
}
|
||||
// expand the scalar to a vector of the same width as vec
|
||||
for (int i = 1; i < type_width (get_type (vec)); i++) {
|
||||
expr_t *s = copy_expr (scalar);
|
||||
s->next = scalar;
|
||||
scalar = s;
|
||||
}
|
||||
return new_vector_list (scalar);
|
||||
}
|
||||
|
||||
static expr_t *
|
||||
pointer_arithmetic (int op, expr_t *e1, expr_t *e2)
|
||||
{
|
||||
|
@ -1025,12 +1046,55 @@ binary_expr (int op, expr_t *e1, expr_t *e2)
|
|||
return invalid_binary_expr(op, e1, e2);
|
||||
|
||||
if ((t1->width > 1 || t2->width > 1)) {
|
||||
if (t1 != t2) {
|
||||
// vector/quaternion and scalar won't get here as vector and quaternion
|
||||
// are distict types with type.width == 1, but vector and vec3 WILL get
|
||||
// here because of vec3 being float{3}
|
||||
if (type_width (t1) == 1) {
|
||||
// scalar op vec
|
||||
if (!(e = convert_scalar (e1, op, e2))) {
|
||||
return invalid_binary_expr (op, e1, e2);
|
||||
}
|
||||
e1 = e;
|
||||
t1 = get_type (e1);
|
||||
}
|
||||
if (type_width (t2) == 1) {
|
||||
// vec op scalar
|
||||
if (!(e = convert_scalar (e2, op, e1))) {
|
||||
return invalid_binary_expr (op, e1, e2);
|
||||
}
|
||||
e2 = e;
|
||||
t2 = get_type (e2);
|
||||
}
|
||||
if (type_width (t1) != type_width (t2)) {
|
||||
// vec op vec of different widths
|
||||
return invalid_binary_expr (op, e1, e2);
|
||||
}
|
||||
e = new_binary_expr (op, e1, e2);
|
||||
e->e.expr.type = t1;
|
||||
return e;
|
||||
if (t1 != t2) {
|
||||
if (is_float (base_type (t1)) && is_double (base_type (t2))
|
||||
&& e2->implicit) {
|
||||
e2 = cast_expr (t1, e2);
|
||||
} else if (is_double (base_type (t1)) && is_float (base_type (t2))
|
||||
&& e1->implicit) {
|
||||
e1 = cast_expr (t2, e1);
|
||||
} else if (type_promotes (base_type (t1), base_type (t2))) {
|
||||
e2 = cast_expr (t1, e2);
|
||||
} else if (type_promotes (base_type (t2), base_type (t1))) {
|
||||
e1 = cast_expr (t2, e1);
|
||||
} else {
|
||||
debug (e1, "%d %d\n", e1->implicit, e2->implicit);
|
||||
return invalid_binary_expr (op, e1, e2);
|
||||
}
|
||||
}
|
||||
t1 = get_type (e1);
|
||||
t2 = get_type (e2);
|
||||
et1 = low_level_type (t1);
|
||||
et2 = low_level_type (t2);
|
||||
// both widths are the same at this point
|
||||
if (t1->width > 1) {
|
||||
e = new_binary_expr (op, e1, e2);
|
||||
e->e.expr.type = t1;
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
expr_type = binary_expr_types[et1][et2];
|
||||
|
|
|
@ -97,12 +97,14 @@ new_vector_list (expr_t *expr_list)
|
|||
}
|
||||
|
||||
int all_constant = 1;
|
||||
int all_implicit = 1;
|
||||
expr_t *elements[count + 1];
|
||||
elements[count] = 0;
|
||||
count = 0;
|
||||
for (expr_t *e = expr_list; e; e = e->next) {
|
||||
int cast_width = type_width (get_type (e));
|
||||
type_t *cast_type = vector_type (ele_type, cast_width);
|
||||
all_implicit = all_implicit && e->implicit;
|
||||
elements[count] = cast_expr (cast_type, fold_constants (e));
|
||||
all_constant = all_constant && is_constant (elements[count]);
|
||||
count++;
|
||||
|
@ -153,7 +155,9 @@ new_vector_list (expr_t *expr_list)
|
|||
offs += type_size (src_type);
|
||||
}
|
||||
|
||||
return new_value_expr (new_type_value (vec_type, value));
|
||||
expr_t *vec = new_value_expr (new_type_value (vec_type, value));
|
||||
vec->implicit = all_implicit;
|
||||
return vec;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
|
|
|
@ -137,10 +137,12 @@ STRING \"(\\.|[^"\\])*\"
|
|||
i = strtol (yytext + 2, 0, 2);
|
||||
else
|
||||
i = strtol (yytext, 0, 0);
|
||||
if (*c == 'u' || *c == 'U')
|
||||
if (*c == 'u' || *c == 'U') {
|
||||
qc_yylval.expr = new_int_expr (i);//FIXME
|
||||
else
|
||||
} else {
|
||||
qc_yylval.expr = new_int_expr (i);
|
||||
qc_yylval.expr->implicit = 1;
|
||||
}
|
||||
return VALUE;
|
||||
}
|
||||
|
||||
|
|
|
@ -1124,8 +1124,16 @@ type_assignable (const type_t *dst, const type_t *src)
|
|||
return 1;
|
||||
return 0;
|
||||
}
|
||||
if (!is_ptr (dst) || !is_ptr (src))
|
||||
return is_scalar (dst) && is_scalar (src);
|
||||
if (!is_ptr (dst) || !is_ptr (src)) {
|
||||
if (is_scalar (dst) && is_scalar (src)) {
|
||||
return 1;
|
||||
}
|
||||
if (is_nonscalar (dst) && is_nonscalar (src)
|
||||
&& type_width (dst) == type_width (src)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// pointer = pointer
|
||||
// give the object system first shot because the pointee types might have
|
||||
|
|
Loading…
Reference in a new issue