mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-26 22:31:05 +00:00
1eb8b61b83
I'd created new_value_expr some time ago, but never used it... Also, replace convert_* with cast_expr to the appropriate type (removes a pile of value check and create code).
168 lines
4.4 KiB
C
168 lines
4.4 KiB
C
/*
|
|
expr_vector.c
|
|
|
|
vector expressions
|
|
|
|
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 <strings.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "QF/alloc.h"
|
|
#include "QF/dstring.h"
|
|
#include "QF/mathlib.h"
|
|
#include "QF/sys.h"
|
|
#include "QF/va.h"
|
|
|
|
#include "tools/qfcc/include/qfcc.h"
|
|
#include "tools/qfcc/include/class.h"
|
|
#include "tools/qfcc/include/def.h"
|
|
#include "tools/qfcc/include/defspace.h"
|
|
#include "tools/qfcc/include/diagnostic.h"
|
|
#include "tools/qfcc/include/emit.h"
|
|
#include "tools/qfcc/include/expr.h"
|
|
#include "tools/qfcc/include/function.h"
|
|
#include "tools/qfcc/include/idstuff.h"
|
|
#include "tools/qfcc/include/method.h"
|
|
#include "tools/qfcc/include/options.h"
|
|
#include "tools/qfcc/include/reloc.h"
|
|
#include "tools/qfcc/include/shared.h"
|
|
#include "tools/qfcc/include/strpool.h"
|
|
#include "tools/qfcc/include/struct.h"
|
|
#include "tools/qfcc/include/symtab.h"
|
|
#include "tools/qfcc/include/type.h"
|
|
#include "tools/qfcc/include/value.h"
|
|
|
|
#include "tools/qfcc/source/qc-parse.h"
|
|
|
|
expr_t *
|
|
new_vector_list (expr_t *expr_list)
|
|
{
|
|
type_t *ele_type = type_default;
|
|
|
|
// lists are built in reverse order
|
|
expr_list = reverse_expr_list (expr_list);
|
|
|
|
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:
|
|
// all scalars (otherwise width would be too large)
|
|
break;
|
|
case 3:
|
|
// 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;
|
|
}
|
|
}
|
|
break;
|
|
case 2:
|
|
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;
|
|
}
|
|
break;
|
|
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);
|
|
}
|
|
|
|
return new_value_expr (new_type_value (vec_type, value));
|
|
}
|
|
|
|
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;
|
|
}
|