[qfcc] Rework vector expression handling

Use with quaternions and vectors is a little broken in that
vec4/quaternion and vec3/vector are not the same types (by design) and
thus a cast is needed (not what I want, though). However, creating
vectors (that happen to be int due to int constants) does seem to be
working nicely otherwise.
This commit is contained in:
Bill Currie 2022-04-27 21:45:05 +09:00
parent 85d851572f
commit 04f60e5ff1
7 changed files with 138 additions and 289 deletions

View file

@ -761,8 +761,6 @@ expr_t *new_param_expr (struct type_s *type, int num);
*/
void convert_name (expr_t *e);
expr_t *convert_vector (expr_t *e);
expr_t *append_expr (expr_t *block, expr_t *e);
expr_t *prepend_expr (expr_t *block, expr_t *e);

View file

@ -461,39 +461,9 @@ print_vector (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
{
int indent = level * 2 + 2;
if (is_vector(e->e.vector.type)) {
expr_t *x = e->e.vector.list;
expr_t *y = x->next;
expr_t *z = y->next;
_print_expr (dstr, x, level, id, next);
_print_expr (dstr, y, level, id, next);
_print_expr (dstr, z, level, id, next);
dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, x);
dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, y);
dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, z);
}
if (is_quaternion(e->e.vector.type)) {
if (e->e.vector.list->next->next) {
expr_t *x = e->e.vector.list;
expr_t *y = x->next;
expr_t *z = y->next;
expr_t *w = z->next;
_print_expr (dstr, x, level, id, next);
_print_expr (dstr, y, level, id, next);
_print_expr (dstr, z, level, id, next);
_print_expr (dstr, w, level, id, next);
dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, x);
dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, y);
dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, z);
dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, w);
} else {
expr_t *v = e->e.vector.list;
expr_t *s = v->next;
_print_expr (dstr, v, level, id, next);
_print_expr (dstr, s, level, id, next);
dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, v);
dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, s);
}
for (expr_t *ele = e->e.vector.list; ele; ele = ele->next) {
_print_expr (dstr, ele, level, id, next);
dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, ele);
}
dasprintf (dstr, "%*se_%p [label=\"vector %d\"];\n", indent, "", e,
e->line);

View file

@ -2104,15 +2104,14 @@ build_function_call (expr_t *fexpr, const type_t *ftype, expr_t *params)
// expression tree
// That, or always use a temp, since it should get optimized out
if (has_function_call (e)) {
expr_t *cast = cast_expr (arg_types[i], convert_vector (e));
expr_t *cast = cast_expr (arg_types[i], e);
expr_t *tmp = new_temp_def_expr (arg_types[i]);
*a = expr_file_line (tmp, e);
arg_exprs[arg_expr_count][0] = expr_file_line (cast, e);
arg_exprs[arg_expr_count][1] = *a;
arg_expr_count++;
} else {
*a = expr_file_line (cast_expr (arg_types[i], convert_vector (e)),
e);
*a = expr_file_line (cast_expr (arg_types[i], e), e);
}
a = &(*a)->next;
}

View file

@ -211,73 +211,31 @@ check_types_compatible (expr_t *dst, expr_t *src)
return type_mismatch (dst, src, '=');
}
static int
copy_elements (expr_t *block, expr_t *dst, expr_t *src, int base)
{
int index = 0;
for (expr_t *e = src->e.vector.list; e; e = e->next) {
if (e->type == ex_vector) {
index += copy_elements (block, dst, e, index + base);
} else {
expr_t *dst_ele = array_expr (dst, new_int_expr (index + base));
append_expr (block, assign_expr (dst_ele, e));
index += type_width (get_type (e));
}
}
return index;
}
static expr_t *
assign_vector_expr (expr_t *dst, expr_t *src)
{
expr_t *dx, *sx;
expr_t *dy, *sy;
expr_t *dz, *sz;
expr_t *dw, *sw;
expr_t *ds, *ss;
expr_t *dv, *sv;
expr_t *block;
if (src->type == ex_vector) {
src = convert_vector (src);
if (src->type != ex_vector) {
// src was constant and thus converted
return assign_expr (dst, src);
}
}
if (src->type == ex_vector && dst->type != ex_vector) {
if (is_vector(src->e.vector.type)) {
// guaranteed to have three elements
sx = src->e.vector.list;
sy = sx->next;
sz = sy->next;
dx = field_expr (dst, new_name_expr ("x"));
dy = field_expr (dst, new_name_expr ("y"));
dz = field_expr (dst, new_name_expr ("z"));
block = new_block_expr ();
append_expr (block, assign_expr (dx, sx));
append_expr (block, assign_expr (dy, sy));
append_expr (block, assign_expr (dz, sz));
block->e.block.result = dst;
return block;
}
if (is_quaternion(src->e.vector.type)) {
// guaranteed to have two or four elements
if (src->e.vector.list->next->next) {
// four vals: x, y, z, w
sx = src->e.vector.list;
sy = sx->next;
sz = sy->next;
sw = sz->next;
dx = field_expr (dst, new_name_expr ("x"));
dy = field_expr (dst, new_name_expr ("y"));
dz = field_expr (dst, new_name_expr ("z"));
dw = field_expr (dst, new_name_expr ("w"));
block = new_block_expr ();
append_expr (block, assign_expr (dx, sx));
append_expr (block, assign_expr (dy, sy));
append_expr (block, assign_expr (dz, sz));
append_expr (block, assign_expr (dw, sw));
block->e.block.result = dst;
return block;
} else {
// v, s
sv = src->e.vector.list;
ss = sv->next;
dv = field_expr (dst, new_name_expr ("v"));
ds = field_expr (dst, new_name_expr ("s"));
block = new_block_expr ();
append_expr (block, assign_expr (dv, sv));
append_expr (block, assign_expr (ds, ss));
block->e.block.result = dst;
return block;
}
}
internal_error (src, "bogus vector expression");
expr_t *block = new_block_expr ();
copy_elements (block, dst, src, 0);
block->e.block.result = dst;
return block;
}
return 0;
}

View file

@ -958,7 +958,6 @@ binary_expr (int op, expr_t *e1, expr_t *e2)
expr_type_t *expr_type;
convert_name (e1);
e1 = convert_vector (e1);
// FIXME this is target-specific info and should not be in the
// expression tree
if (e1->type == ex_alias && is_call (e1->e.alias.expr)) {
@ -982,7 +981,6 @@ binary_expr (int op, expr_t *e1, expr_t *e2)
return e1;
convert_name (e2);
e2 = convert_vector (e2);
if (e2->type == ex_error)
return e2;

View file

@ -62,155 +62,110 @@
#include "tools/qfcc/source/qc-parse.h"
expr_t *
convert_vector (expr_t *e)
new_vector_list (expr_t *expr_list)
{
float val[4];
type_t *ele_type = type_default;
if (e->type != ex_vector)
return e;
if (is_vector(e->e.vector.type)) {
// guaranteed to have three elements
expr_t *x = e->e.vector.list;
expr_t *y = x->next;
expr_t *z = y->next;
x = fold_constants (cast_expr (&type_float, x));
y = fold_constants (cast_expr (&type_float, y));
z = fold_constants (cast_expr (&type_float, z));
if (is_constant (x) && is_constant (y) && is_constant (z)) {
val[0] = expr_float(x);
val[1] = expr_float(y);
val[2] = expr_float(z);
return new_vector_expr (val);
}
// at least one of x, y, z is not constant, so rebuild the
// list incase any of them are new expressions
z->next = 0;
y->next = z;
x->next = y;
e->e.vector.list = x;
return e;
}
if (is_quaternion(e->e.vector.type)) {
// guaranteed to have two or four elements
if (e->e.vector.list->next->next) {
// four vals: x, y, z, w
expr_t *x = e->e.vector.list;
expr_t *y = x->next;
expr_t *z = y->next;
expr_t *w = z->next;
x = fold_constants (cast_expr (&type_float, x));
y = fold_constants (cast_expr (&type_float, y));
z = fold_constants (cast_expr (&type_float, z));
w = fold_constants (cast_expr (&type_float, w));
if (is_constant (x) && is_constant (y) && is_constant (z)
&& is_constant (w)) {
val[0] = expr_float(x);
val[1] = expr_float(y);
val[2] = expr_float(z);
val[3] = expr_float(w);
return new_quaternion_expr (val);
}
// at least one of x, y, z, w is not constant, so rebuild the
// list incase any of them are new expressions
w->next = 0;
z->next = w;
y->next = z;
x->next = y;
e->e.vector.list = x;
return e;
} else {
// v, s
expr_t *v = e->e.vector.list;
expr_t *s = v->next;
// lists are built in reverse order
expr_list = reverse_expr_list (expr_list);
v = convert_vector (v);
s = fold_constants (cast_expr (&type_float, s));
if (is_constant (v) && is_constant (s)) {
memcpy (val, expr_vector (v), 3 * sizeof (float));
val[3] = expr_float (s);
return new_quaternion_expr (val);
}
// Either v or s is not constant, so can't convert to a quaternion
// constant.
// Rebuild the list in case v or s is a new expression
// the list will always be v, s
s->next = 0;
v->next = s;
e->e.vector.list = v;
return e;
}
}
internal_error (e, "bogus vector expression");
}
expr_t *
new_vector_list (expr_t *e)
{
expr_t *t;
int count;
type_t *type = &type_vector;
expr_t *vec;
e = reverse_expr_list (e); // put the elements in the right order
for (t = e, count = 0; t; t = t->next)
int width = 0;
int count = 0;
for (expr_t *e = expr_list; e; e = e->next) {
count++;
type_t *t = get_type (e);
if (!t) {
return e;
}
if (!is_math (t)) {
return error (e, "invalid type for vector element");
}
width += type_width (t);
if (is_nonscalar (t)) {
t = base_type (t);
}
if (type_promotes (t, ele_type)) {
ele_type = t;
}
}
if (width < 2) {
return error (expr_list, "not a vector");
}
if (width > 4) {
return error (expr_list, "resulting vector is too large: %d elements",
width);
}
int all_constant = 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);
elements[count] = cast_expr (cast_type, fold_constants (e));
all_constant = all_constant && is_constant (elements[count]);
count++;
}
switch (count) {
case 4:
type = &type_quaternion;
// all scalars (otherwise width would be too large)
break;
case 3:
// quaternion or vector. all expressions must be compatible with
// a float (ie, a scalar)
for (t = e; t; t = t->next) {
if (t->type == ex_error) {
return t;
}
if (!is_scalar (get_type (t))) {
return error (t, "invalid type for vector element");
// shuffle any vectors to the beginning of the list (there should
// be only one, but futhre...)
for (int i = 1; i < count; i++) {
if (is_nonscalar (get_type (elements[i]))) {
expr_t *t = elements[i];
int j = i;
for (; j > 0 && is_scalar (get_type (elements[j])); j--) {
elements[j] = elements[j - 1];
}
elements[j] = t;
}
}
vec = new_expr ();
vec->type = ex_vector;
vec->e.vector.type = type;
vec->e.vector.list = e;
break;
case 2:
if (e->type == ex_error || e->next->type == ex_error) {
return e;
if (is_scalar (get_type (elements[0]))
&& is_nonscalar (get_type (elements[1]))) {
// swap s, v to be v, s (ie, vector always comes before scalar)
expr_t *t = elements[0];
elements[0] = elements[1];
elements[1] = t;
}
if (is_scalar (get_type (e)) && is_scalar (get_type (e->next))) {
// scalar, scalar
// expand [x, y] to [x, y, 0]
e->next->next = new_float_expr (0);
vec = new_expr ();
vec->type = ex_vector;
vec->e.vector.type = type;
vec->e.vector.list = e;
break;
}
// quaternion. either scalar, vector or vector, scalar
if (is_scalar (get_type (e))
&& is_vector (get_type (e->next))) {
// scalar, vector
// swap expressions
t = e;
e = e->next;
e->next = t;
t->next = 0;
} else if (is_vector (get_type (e))
&& is_scalar (get_type (e->next))) {
// vector, scalar
// do nothing
} else {
return error (t, "invalid types for vector elements");
}
// v, s
vec = new_expr ();
vec->type = ex_vector;
vec->e.vector.type = &type_quaternion;
vec->e.vector.list = e;
break;
default:
return error (e, "invalid number of elements in vector exprssion");
case 1:
if (is_scalar (get_type (elements[0]))) {
internal_error (expr_list, "confused about vectors");
}
// it's already a vector
return elements[0];
}
if (all_constant) {
type_t *vec_type = vector_type (ele_type, width);
pr_type_t value[type_size (vec_type)];
for (int i = 0, offs = 0; i < count; i++) {
type_t *src_type = get_type (elements[i]);
value_store (value + offs, src_type, elements[i]);
offs += type_size (src_type);
}
expr_t *vec = new_expr ();
vec->type = ex_value;
vec->e.value = new_type_value (vec_type, value);
return vec;
}
for (int i = 0; i < count; i++) {
elements[i]->next = elements[i + 1];
}
expr_t *vec = new_expr ();
vec->type = ex_vector;
vec->e.vector.type = vector_type (ele_type, width);
vec->e.vector.list = elements[0];
return vec;
}

View file

@ -1926,13 +1926,28 @@ expr_temp (sblock_t *sblock, expr_t *e, operand_t **op)
return sblock;
}
static int
statement_copy_elements (sblock_t **sblock, expr_t *dst, expr_t *src, int base)
{
int index = 0;
for (expr_t *e = src->e.vector.list; e; e = e->next) {
if (e->type == ex_vector) {
index += statement_copy_elements (sblock, dst, e, index + base);
} else {
int size = type_size (base_type (get_type (dst)));
type_t *src_type = get_type (e);
expr_t *dst_ele = new_offset_alias_expr (src_type, dst,
size * (index + base));
index += type_width (src_type);
*sblock = statement_slist (*sblock, assign_expr (dst_ele, e));
}
}
return index;
}
static sblock_t *
expr_vector_e (sblock_t *sblock, expr_t *e, operand_t **op)
{
expr_t *x, *y, *z, *w;
expr_t *s, *v;
expr_t *ax, *ay, *az, *aw;
expr_t *as, *av;
expr_t *tmp;
type_t *vec_type = get_type (e);
int file = pr.source_file;
@ -1942,52 +1957,8 @@ expr_vector_e (sblock_t *sblock, expr_t *e, operand_t **op)
pr.source_line = e->line;
tmp = new_temp_def_expr (vec_type);
if (is_vector(vec_type)) {
// guaranteed to have three elements
x = e->e.vector.list;
y = x->next;
z = y->next;
ax = new_name_expr ("x");
ay = new_name_expr ("y");
az = new_name_expr ("z");
ax = assign_expr (field_expr (tmp, ax), x);
ay = assign_expr (field_expr (tmp, ay), y);
az = assign_expr (field_expr (tmp, az), z);
sblock = statement_slist (sblock, ax);
sblock = statement_slist (sblock, ay);
sblock = statement_slist (sblock, az);
} else {
// guaranteed to have two or four elements
if (e->e.vector.list->next->next) {
// four vals: x, y, z, w
x = e->e.vector.list;
y = x->next;
z = y->next;
w = z->next;
ax = new_name_expr ("x");
ay = new_name_expr ("y");
az = new_name_expr ("z");
aw = new_name_expr ("w");
ax = assign_expr (field_expr (tmp, ax), x);
ay = assign_expr (field_expr (tmp, ay), y);
az = assign_expr (field_expr (tmp, az), z);
aw = assign_expr (field_expr (tmp, aw), w);
sblock = statement_slist (sblock, ax);
sblock = statement_slist (sblock, ay);
sblock = statement_slist (sblock, az);
sblock = statement_slist (sblock, aw);
} else {
// v, s
v = e->e.vector.list;
s = v->next;
av = new_name_expr ("v");
as = new_name_expr ("s");
av = assign_expr (field_expr (tmp, av), v);
as = assign_expr (field_expr (tmp, as), s);
sblock = statement_slist (sblock, av);
sblock = statement_slist (sblock, as);
}
}
statement_copy_elements (&sblock, tmp, e, 0);
pr.source_file = file;
pr.source_line = line;
sblock = statement_subexpr (sblock, tmp, op);