mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-16 17:01:53 +00:00
[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:
parent
85d851572f
commit
04f60e5ff1
7 changed files with 138 additions and 289 deletions
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue