mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-22 20:41:20 +00:00
[qfcc] Start work on implementing geometric algebra
This gets only some very basics working: * Algebra (multi-vector) types: eg @algebra(float(3,0,1)). * Algebra scopes (using either the above or @algebra(TYPE_NAME) where the above was used in a typedef. * Basis blades (eg, e12) done via procedural symbols that evaluate to suitable constants based on the basis group for the blade. * Addition and subtraction of multi-vectors (only partially tested). * Assignment of sub-algebra multi-vectors to full-algebra multi-vectors (missing elements zeroed). There's still much work to be done, but I thought it time to get something into git.
This commit is contained in:
parent
cb9a82e74c
commit
2e91b29580
27 changed files with 1339 additions and 43 deletions
|
@ -49,6 +49,7 @@ typedef enum {
|
|||
ty_class,
|
||||
ty_alias,
|
||||
ty_handle,
|
||||
ty_algebra,
|
||||
} ty_meta_e;
|
||||
|
||||
typedef struct qfot_alias_s {
|
||||
|
@ -105,6 +106,13 @@ typedef struct qfot_array_s {
|
|||
pr_int_t size; ///< number of elements in array
|
||||
} qfot_array_t;
|
||||
|
||||
typedef struct qfot_algebra_s {
|
||||
etype_t type; ///< always ev_float or ev_double
|
||||
pr_int_t width; ///< components in multivector
|
||||
pr_ptr_t algebra; ///< algebra descriptor
|
||||
pr_int_t element; ///< element within algebra
|
||||
} qfot_algebra_t;
|
||||
|
||||
/** QFO type encoding.
|
||||
|
||||
\note As this holds a union of all type representations, and those
|
||||
|
@ -126,6 +134,7 @@ typedef struct qfot_type_s {
|
|||
pr_string_t class; ///< ty_class
|
||||
qfot_alias_t alias; ///< ty_alias
|
||||
qfot_handle_t handle; ///< ty_handle
|
||||
qfot_algebra_t algebra; ///< ty_algebra
|
||||
};
|
||||
} qfot_type_t;
|
||||
|
||||
|
|
|
@ -260,6 +260,8 @@ pr_debug_type_size (const progs_t *pr, const qfot_type_t *type)
|
|||
case ty_alias:
|
||||
aux_type = &G_STRUCT (pr, qfot_type_t, type->alias.aux_type);
|
||||
return pr_debug_type_size (pr, aux_type);
|
||||
case ty_algebra:
|
||||
return 1; //FIXME wip
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -1053,6 +1055,12 @@ static void
|
|||
value_string (pr_debug_data_t *data, qfot_type_t *type, pr_type_t *value)
|
||||
{
|
||||
switch (type->meta) {
|
||||
case ty_algebra:
|
||||
if (type->type == ev_invalid) {
|
||||
dstring_appendstr (data->dstr, "<?""?>");
|
||||
break;
|
||||
}
|
||||
// fall through
|
||||
case ty_handle:
|
||||
case ty_basic:
|
||||
switch (type->type) {
|
||||
|
|
|
@ -2562,7 +2562,7 @@ pr_exec_ruamoko (progs_t *pr, int exitdepth)
|
|||
startprofile = profile;
|
||||
PR_LeaveFunction (pr, pr->pr_depth == exitdepth);
|
||||
st = pr->pr_statements + pr->pr_xstatement;
|
||||
if (pr->pr_depth== exitdepth) {
|
||||
if (pr->pr_depth == exitdepth) {
|
||||
if (pr->pr_trace && pr->pr_depth <= pr->pr_trace_depth) {
|
||||
pr->pr_trace = false;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
EXTRA_DIST += \
|
||||
tools/qfcc/include/algebra.h \
|
||||
tools/qfcc/include/attribute.h \
|
||||
tools/qfcc/include/class.h \
|
||||
tools/qfcc/include/codespace.h \
|
||||
|
|
107
tools/qfcc/include/algebra.h
Normal file
107
tools/qfcc/include/algebra.h
Normal file
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
algebra.h
|
||||
|
||||
QC geometric algebra support code
|
||||
|
||||
Copyright (C) 2023 Bill Currie <bill@taniwha.org>
|
||||
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __algebra_h
|
||||
#define __algebra_h
|
||||
|
||||
#include "QF/set.h"
|
||||
#include "QF/progs/pr_comp.h"
|
||||
|
||||
typedef struct basis_blade_s {
|
||||
pr_uint_t mask; ///< bit-mask of basis vectors
|
||||
int scale; ///< 1, 0, or -1
|
||||
} basis_blade_t;
|
||||
|
||||
typedef struct basis_group_s {
|
||||
int count;
|
||||
pr_uivec2_t range;
|
||||
basis_blade_t *blades;
|
||||
int *map;
|
||||
set_t *set;
|
||||
struct type_s *type;
|
||||
} basis_group_t;
|
||||
|
||||
typedef struct basis_layout_s {
|
||||
int count;
|
||||
pr_uivec2_t range;
|
||||
basis_group_t *groups;
|
||||
pr_ivec3_t *group_map;
|
||||
int *mask_map;
|
||||
int blade_count;
|
||||
set_t *set;
|
||||
} basis_layout_t;
|
||||
|
||||
typedef struct metric_s {
|
||||
pr_uint_t plus; ///< mask of elements that square to +1
|
||||
pr_uint_t minus; ///< mask of elements that square to -1
|
||||
pr_uint_t zero; ///< mask of elements that square to 0
|
||||
} metric_t;
|
||||
|
||||
typedef struct algebra_s {
|
||||
struct type_s *type; ///< underlying type (float or double)
|
||||
struct type_s *algebra_type;///< type for algebra
|
||||
metric_t metric;
|
||||
basis_layout_t layout;
|
||||
basis_group_t *groups;
|
||||
int num_components; ///< number of componets (2^d)
|
||||
int dimension; ///< number of dimensions (plus + minus + zero)
|
||||
int plus; ///< number of elements squaring to +1
|
||||
int minus; ///< number of elements squaring to -1
|
||||
int zero; ///< number of elements squaring to 0
|
||||
} algebra_t;
|
||||
|
||||
typedef struct multivector_s {
|
||||
int num_components;
|
||||
int element;
|
||||
algebra_t *algebra;
|
||||
} multivector_t;
|
||||
|
||||
struct expr_s;
|
||||
bool is_algebra (const struct type_s *type) __attribute__((pure));
|
||||
struct type_s *algebra_type (struct type_s *type, struct expr_s *params);
|
||||
struct symtab_s *algebra_scope (struct type_s *type, struct symtab_s *curscope);
|
||||
void algebra_print_type_str (struct dstring_s *str, const struct type_s *type);
|
||||
void algebra_encode_type (struct dstring_s *encoding,
|
||||
const struct type_s *type);
|
||||
int algebra_type_size (const struct type_s *type) __attribute__((pure));
|
||||
int algebra_type_width (const struct type_s *type) __attribute__((pure));
|
||||
|
||||
int metric_apply (const metric_t *metric, pr_uint_t a, pr_uint_t b) __attribute__((pure));
|
||||
|
||||
algebra_t *algebra_get (const struct type_s *type) __attribute__((pure));
|
||||
int algebra_type_assignable (const struct type_s *dst,
|
||||
const struct type_s *src) __attribute__((pure));
|
||||
|
||||
struct expr_s *algebra_binary_expr (int op, struct expr_s *e1,
|
||||
struct expr_s *e2);
|
||||
struct expr_s *algebra_negate (struct expr_s *e);
|
||||
struct expr_s *algebra_dual (struct expr_s *e);
|
||||
struct expr_s *algebra_reverse (struct expr_s *e);
|
||||
struct expr_s *algebra_cast_expr (struct type_s *dstType, struct expr_s *e);
|
||||
struct expr_s *algebra_assign_expr (struct expr_s *dst, struct expr_s *src);
|
||||
|
||||
#endif//__algebra_h
|
|
@ -280,6 +280,12 @@ typedef struct {
|
|||
struct type_s *type; ///< result type;
|
||||
} ex_extend_t;
|
||||
|
||||
typedef struct {
|
||||
struct algebra_s *algebra; ///< owning algebra
|
||||
int count; ///< number of component expressions
|
||||
struct expr_s *components; ///< multivector components
|
||||
} ex_multivec_t;
|
||||
|
||||
#define POINTER_VAL(p) (((p).def ? (p).def->offset : 0) + (p).val)
|
||||
|
||||
typedef struct expr_s {
|
||||
|
@ -317,6 +323,7 @@ typedef struct expr_s {
|
|||
ex_horizontal_t hop; ///< horizontal vector operation
|
||||
ex_swizzle_t swizzle; ///< vector swizzle operation
|
||||
ex_extend_t extend; ///< vector extend operation
|
||||
ex_multivec_t multivec; ///< geometric algebra multivector
|
||||
} e;
|
||||
} expr_t;
|
||||
|
||||
|
@ -844,6 +851,7 @@ expr_t *think_expr (struct symbol_s *think_sym);
|
|||
int is_lvalue (const expr_t *expr) __attribute__((pure));
|
||||
expr_t *assign_expr (expr_t *dst, expr_t *src);
|
||||
expr_t *cast_expr (struct type_s *t, expr_t *e);
|
||||
expr_t *cast_error (expr_t *e, struct type_s *t1, struct type_s *t2);
|
||||
|
||||
const char *get_op_string (int op) __attribute__((const));
|
||||
|
||||
|
|
|
@ -65,5 +65,6 @@ EX_EXPR(args) ///< @args marker in parameter list. no data
|
|||
EX_EXPR(horizontal) ///< horizontal vector operation (::ex_horzontal_t)
|
||||
EX_EXPR(swizzle) ///< vector swizzle operation (::ex_swizzle_t)
|
||||
EX_EXPR(extend) ///< vector extend operation (::ex_extend_t)
|
||||
EX_EXPR(multivec) ///< geometric algebra multivector (::ex_multivec_t)
|
||||
|
||||
///@}
|
||||
|
|
|
@ -62,6 +62,7 @@ int enum_as_bool (struct type_s *enm, struct expr_s **zero,
|
|||
|
||||
struct symbol_s *make_structure (const char *name, int su, struct_def_t *defs,
|
||||
struct type_s *type);
|
||||
struct defspace_s;
|
||||
struct def_s * emit_structure (const char *name, int su, struct_def_t *defs,
|
||||
struct type_s *type, void *data,
|
||||
struct defspace_s *space,
|
||||
|
|
|
@ -79,6 +79,8 @@ typedef struct type_s {
|
|||
ty_array_t array;
|
||||
struct symtab_s *symtab;
|
||||
struct class_s *class;
|
||||
struct algebra_s *algebra;
|
||||
struct multivector_s *multivec;
|
||||
ty_alias_t alias;
|
||||
} t;
|
||||
struct type_s *next;
|
||||
|
|
|
@ -7,6 +7,7 @@ bin_PROGRAMS += @QFCC_TARGETS@
|
|||
bin_SCRIPTS += tools/qfcc/source/qfpreqcc
|
||||
|
||||
qfcc_SOURCES = \
|
||||
tools/qfcc/source/algebra.c \
|
||||
tools/qfcc/source/attribute.c \
|
||||
tools/qfcc/source/class.c \
|
||||
tools/qfcc/source/codespace.c \
|
||||
|
@ -25,6 +26,7 @@ qfcc_SOURCES = \
|
|||
tools/qfcc/source/dot_type.c \
|
||||
tools/qfcc/source/emit.c \
|
||||
tools/qfcc/source/expr.c \
|
||||
tools/qfcc/source/expr_algebra.c \
|
||||
tools/qfcc/source/expr_assign.c \
|
||||
tools/qfcc/source/expr_binary.c \
|
||||
tools/qfcc/source/expr_bool.c \
|
||||
|
|
611
tools/qfcc/source/algebra.c
Normal file
611
tools/qfcc/source/algebra.c
Normal file
|
@ -0,0 +1,611 @@
|
|||
/*
|
||||
algebra.c
|
||||
|
||||
QC geometric algebra support code
|
||||
|
||||
Copyright (C) 2023 Bill Currie <bill@taniwha.org>
|
||||
|
||||
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 <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "QF/darray.h"
|
||||
#include "QF/dstring.h"
|
||||
#include "QF/mathlib.h"
|
||||
#include "QF/va.h"
|
||||
|
||||
#include "tools/qfcc/include/algebra.h"
|
||||
#include "tools/qfcc/include/diagnostic.h"
|
||||
#include "tools/qfcc/include/expr.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"
|
||||
|
||||
static struct DARRAY_TYPE (algebra_t *) algebras = DARRAY_STATIC_INIT (16);
|
||||
|
||||
static void
|
||||
binomial (int *coef, int n)
|
||||
{
|
||||
int c = 1;
|
||||
for (int i = 0; i < n + 1; i++) {
|
||||
coef[i] = c;
|
||||
c = (c * (n - i)) / (i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
count_bits (uint32_t v)
|
||||
{
|
||||
int c = 0;
|
||||
for (; v; c++) {
|
||||
v &= v - 1;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
static int
|
||||
count_flips (uint32_t a, uint32_t b)
|
||||
{
|
||||
int c = 0;
|
||||
a >>= 1;
|
||||
while (a) {
|
||||
c += count_bits (a & b);
|
||||
a >>= 1;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
static int
|
||||
count_minus (uint32_t minus)
|
||||
{
|
||||
return count_bits (minus) & 1 ? -1 : 1;
|
||||
}
|
||||
#if 0
|
||||
static struct_def_t mvec_1d_struct[] = {
|
||||
{"vec", &type_vec2},
|
||||
{}
|
||||
};
|
||||
|
||||
static struct_def_t mvec_2d_struct[] = {
|
||||
{"vec", &type_vec4},
|
||||
{}
|
||||
};
|
||||
|
||||
static struct_def_t mvec_3d_struct[] = {
|
||||
{"vec", &type_vec4},
|
||||
{"bvec", &type_vec4},
|
||||
{}
|
||||
};
|
||||
|
||||
static struct_def_t mvec_4d_struct[] = {
|
||||
{"vec", &type_vec4},
|
||||
{"bvecv", &type_vec4},
|
||||
{"bvecm", &type_vec4},
|
||||
{"tvec", &type_vec4},
|
||||
{}
|
||||
};
|
||||
|
||||
static struct_def_t *mvec_struct[] = {
|
||||
[1] = mvec_1d_struct,
|
||||
[2] = mvec_2d_struct,
|
||||
[3] = mvec_3d_struct,
|
||||
[4] = mvec_4d_struct,
|
||||
};
|
||||
|
||||
static symbol_t *
|
||||
build_algebra_types (algebra_t *a)
|
||||
{
|
||||
auto name = save_string (va (0, "multivector.%s.%d.%d.%d",
|
||||
a->type->encoding,
|
||||
a->plus, a->minus, a->zero));
|
||||
int dim = a->plus + a->minus + a->zero;
|
||||
symbol_t *mvsym;
|
||||
if (dim > 4) {
|
||||
auto mvec = new_symtab (0, stab_struct);
|
||||
int counts[dim + 1];
|
||||
binomial (counts, dim);
|
||||
auto sym = new_symbol ("scalar");
|
||||
sym->type = a->type;
|
||||
sym->sy_type = sy_var;
|
||||
sym->visibility = vis_public;
|
||||
symtab_addsymbol (mvec, sym);
|
||||
// skip 0 because the scalar doesn't need a special type
|
||||
for (int i = 1; i < dim + 1; i++) {
|
||||
sym = new_symbol (va (0, "vec_%d", i));
|
||||
sym->type = array_type (a->type, counts[i]);
|
||||
sym->sy_type = sy_var;
|
||||
sym->visibility = vis_public;
|
||||
symtab_addsymbol (mvec, sym);
|
||||
}
|
||||
mvsym = build_struct ('s', new_symbol (name), mvec, 0, 0);
|
||||
if (mvsym->type->alignment < 4) {
|
||||
mvsym->type->alignment = 4;
|
||||
}
|
||||
} else if (dim > 0) {
|
||||
mvsym = make_structure (name, 's', mvec_struct[dim], 0);
|
||||
} else {
|
||||
internal_error (0, "invalid number of dimensions");
|
||||
}
|
||||
return mvsym;
|
||||
}
|
||||
#endif
|
||||
static void
|
||||
basis_blade_init (basis_blade_t *blade, pr_uint_t mask)
|
||||
{
|
||||
*blade = (basis_blade_t) {
|
||||
.mask = mask,
|
||||
.scale = 1,
|
||||
};
|
||||
}
|
||||
|
||||
static void
|
||||
basis_group_init (basis_group_t *group, int count, basis_blade_t *blades,
|
||||
algebra_t *a, int element)
|
||||
{
|
||||
*group = (basis_group_t) {
|
||||
.count = count,
|
||||
.range = { ~0u, 0 },
|
||||
.blades = malloc (sizeof (basis_blade_t[count])),
|
||||
.set = set_new (),
|
||||
};
|
||||
memcpy (group->blades, blades, sizeof (basis_blade_t[count]));
|
||||
for (int i = 0; i < count; i++) {
|
||||
pr_uint_t m = blades[i].mask;
|
||||
group->range[0] = min (m, group->range[0]);
|
||||
group->range[1] = max (m, group->range[1]);
|
||||
set_add (group->set, m);
|
||||
}
|
||||
int num = group->range[1] - group->range[0] + 1;
|
||||
group->map = malloc (sizeof (int[num]));
|
||||
for (int i = 0; i < count; i++) {
|
||||
group->map[blades[i].mask - group->range[0]] = i;
|
||||
}
|
||||
|
||||
if (count == 1 && blades[0].mask == 0) {
|
||||
group->type = a->type;
|
||||
} else {
|
||||
multivector_t *mvec = malloc (sizeof (multivector_t));
|
||||
*mvec = (multivector_t) {
|
||||
.num_components = count,
|
||||
.element = element,
|
||||
.algebra = a,
|
||||
};
|
||||
group->type = new_type ();
|
||||
*group->type = (type_t) {
|
||||
.type = a->type->type,
|
||||
.name = "basis group",
|
||||
.alignment = 4, //FIXME
|
||||
.width = count,
|
||||
.meta = ty_algebra,
|
||||
.t.algebra = (algebra_t *) mvec,
|
||||
.freeable = true,
|
||||
.allocated = true,
|
||||
};
|
||||
chain_type (group->type);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
basis_layout_init (basis_layout_t *layout, int count, basis_group_t *groups)
|
||||
{
|
||||
*layout = (basis_layout_t) {
|
||||
.count = count,
|
||||
.range = { ~0u, 0 },
|
||||
.groups = groups,
|
||||
.set = set_new (),
|
||||
};
|
||||
int group_base[count + 1];
|
||||
group_base[0] = 0;
|
||||
int num_blades = 0;
|
||||
for (int i = 0; i < count; i++) {
|
||||
set_union (layout->set, groups[i].set);
|
||||
group_base[i + 1] = group_base[i] + groups[i].count;
|
||||
num_blades += groups[i].count;
|
||||
layout->range[0] = min (groups[i].range[0], layout->range[0]);
|
||||
layout->range[1] = max (groups[i].range[1], layout->range[1]);
|
||||
}
|
||||
layout->blade_count = num_blades;
|
||||
layout->group_map = malloc (sizeof (pr_ivec3_t[num_blades]));
|
||||
|
||||
int num = layout->range[1] - layout->range[0] + 1;
|
||||
layout->mask_map = calloc (1, sizeof (int[num]));
|
||||
int group_inds[count + 1] = {};
|
||||
for (int i = 0; i < count; i++) {
|
||||
auto g = &groups[i];
|
||||
group_inds[i] = 0;
|
||||
for (int j = 0; j < g->count; j++) {
|
||||
auto b = g->blades[j];
|
||||
layout->mask_map[b.mask - layout->range[0]] = group_inds[count];
|
||||
layout->group_map[group_inds[count]][0] = i;
|
||||
layout->group_map[group_inds[count]][1] = group_inds[i]++;
|
||||
layout->group_map[group_inds[count]][2] = group_base[i];
|
||||
group_inds[count]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
metric_init (metric_t *metric, int p, int m, int z)
|
||||
{
|
||||
metric->plus = ((1 << p) - 1) << z;
|
||||
metric->minus = ((1 << m) - 1) << (z + p);
|
||||
metric->zero = (1 << z) - 1;
|
||||
}
|
||||
|
||||
int
|
||||
metric_apply (const metric_t *metric, pr_uint_t a, pr_uint_t b)
|
||||
{
|
||||
// find all the squared elements
|
||||
pr_uint_t c = a & b;
|
||||
// any elements that square to 0 result in 0
|
||||
if (c & metric->zero) {
|
||||
return 0;
|
||||
}
|
||||
return count_minus (c & metric->minus);
|
||||
}
|
||||
|
||||
static void
|
||||
algebra_init (algebra_t *a)
|
||||
{
|
||||
int p = a->plus;
|
||||
int m = a->minus;
|
||||
int z = a->zero;
|
||||
int d = p + m + z;
|
||||
metric_init (&a->metric, p, m, z);
|
||||
a->dimension = d;
|
||||
a->num_components = 1 << d;
|
||||
|
||||
basis_blade_t blades[a->num_components];
|
||||
int indices[d + 1];
|
||||
int counts[d + 1];
|
||||
binomial (counts, d);
|
||||
|
||||
indices[0] = 0;
|
||||
for (int i = 0; i < d; i++) {
|
||||
indices[i + 1] = indices[i] + counts[i];
|
||||
}
|
||||
|
||||
for (int i = 0; i < a->num_components; i++) {
|
||||
int grade = count_bits (i);
|
||||
int ind = indices[grade]++;
|
||||
pr_uint_t mask = i;
|
||||
basis_blade_init (&blades[ind], mask);
|
||||
}
|
||||
|
||||
if (p == 3 && m == 0 && z == 1) {
|
||||
// 3d PGA (w squares to 0, x y z square to +1):
|
||||
// : x y z w
|
||||
// : yz zx xy 1
|
||||
// : wx wy wz wxyz
|
||||
// : wzy wxz wyx xyz
|
||||
basis_blade_t pga_blades[16] = {
|
||||
blades[2], blades[3], blades[4], blades[1],
|
||||
blades[10], blades[9], blades[7], blades[0],
|
||||
blades[5], blades[6], blades[8], blades[15],
|
||||
blades[13], blades[12], blades[11], blades[14],
|
||||
};
|
||||
a->groups = malloc (sizeof (basis_group_t[6]));
|
||||
basis_group_init (&a->groups[0], 4, pga_blades + 0, a, 0);
|
||||
basis_group_init (&a->groups[1], 3, pga_blades + 4, a, 1);
|
||||
basis_group_init (&a->groups[2], 1, pga_blades + 7, a, 2);
|
||||
basis_group_init (&a->groups[3], 3, pga_blades + 8, a, 3);
|
||||
basis_group_init (&a->groups[4], 1, pga_blades + 11, a, 4);
|
||||
basis_group_init (&a->groups[5], 4, pga_blades + 12, a, 5);
|
||||
basis_layout_init (&a->layout, 6, a->groups);
|
||||
} else if (p == 2 && m == 0 && z == 1) {
|
||||
// 2d PGA (w squares to 0, x y square to +1):
|
||||
// : 1 xy wx wy
|
||||
// : x y w wxy
|
||||
basis_blade_t pga_blades[8] = {
|
||||
blades[0], blades[6], blades[4], blades[5],
|
||||
blades[2], blades[3], blades[1], blades[7],
|
||||
};
|
||||
a->groups = malloc (sizeof (basis_group_t[4]));
|
||||
basis_group_init (&a->groups[0], 1, pga_blades + 0, a, 0);
|
||||
basis_group_init (&a->groups[1], 3, pga_blades + 1, a, 1);
|
||||
basis_group_init (&a->groups[2], 3, pga_blades + 4, a, 2);
|
||||
basis_group_init (&a->groups[3], 1, pga_blades + 7, a, 3);
|
||||
basis_layout_init (&a->layout, 4, a->groups);
|
||||
} else {
|
||||
// just use the grades as the default layout
|
||||
a->groups = malloc (sizeof (basis_group_t[d + 1]));
|
||||
for (int i = 0; i < d + 1; i++) {
|
||||
int c = counts[i];
|
||||
int ind = indices[i];
|
||||
basis_group_init (&a->groups[i], c, &blades[ind - c], a, i);
|
||||
}
|
||||
basis_layout_init (&a->layout, d + 1, a->groups);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
is_algebra (const type_t *type)
|
||||
{
|
||||
type = unalias_type (type);
|
||||
return type->meta == ty_algebra;
|
||||
}
|
||||
|
||||
type_t *
|
||||
algebra_type (type_t *type, expr_t *params)
|
||||
{
|
||||
if (!is_float (type) && !is_double (type)) {
|
||||
error (0, "algebra type must be float or double");
|
||||
return type_default;
|
||||
}
|
||||
params = reverse_expr_list (params);
|
||||
auto plus = params;
|
||||
auto minus = plus ? plus->next : 0;
|
||||
auto zero = minus ? minus->next : 0;
|
||||
|
||||
expr_t *err = 0;
|
||||
if ((plus && !is_integral_val (err = plus))
|
||||
|| (minus && !is_integral_val (err = minus))
|
||||
|| (zero && !is_integral_val (err = zero))) {
|
||||
error (err, "signature must be integral constant");
|
||||
return type_default;
|
||||
}
|
||||
|
||||
algebra_t search_algebra = {
|
||||
.type = type,
|
||||
// default to 3,0,1 (plane-based PGA)
|
||||
.plus = plus ? expr_integral (plus) : 3,
|
||||
.minus = minus ? expr_integral (minus) : 0,
|
||||
.zero = zero ? expr_integral (zero) : plus ? 0 : 1,
|
||||
};
|
||||
int dim = search_algebra.plus + search_algebra.minus + search_algebra.zero;
|
||||
if (search_algebra.plus < 0
|
||||
|| search_algebra.minus < 0
|
||||
|| search_algebra.zero < 0
|
||||
|| dim < 1) {
|
||||
error (err, "signature must be positive");
|
||||
return type_default;
|
||||
}
|
||||
if (dim > 16) {
|
||||
error (err, "signature too large (that's %zd components!)",
|
||||
((size_t) 1) << dim);
|
||||
return type_default;
|
||||
}
|
||||
algebra_t *algebra = 0;
|
||||
for (size_t i = 0; i < algebras.size; i++) {
|
||||
auto a = algebras.a[i];
|
||||
if (a->type == search_algebra.type
|
||||
&& a->plus == search_algebra.plus
|
||||
&& a->minus == search_algebra.minus
|
||||
&& a->zero == search_algebra.zero) {
|
||||
algebra = a;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!algebra) {
|
||||
algebra = malloc (sizeof (algebra_t));
|
||||
*algebra = search_algebra;
|
||||
DARRAY_APPEND (&algebras, algebra);
|
||||
algebra_init (algebra);
|
||||
}
|
||||
auto t = new_type ();
|
||||
t->meta = ty_algebra;
|
||||
t->type = ev_invalid;
|
||||
t->alignment = (dim > 1 ? 4 : 2) * type->alignment;
|
||||
t->t.algebra = algebra;
|
||||
algebra->algebra_type = t;
|
||||
return find_type (t);
|
||||
}
|
||||
|
||||
static int pga_swaps_2d[8] = {
|
||||
[0x5] = 1, // e20
|
||||
};
|
||||
static int pga_swaps_3d[16] = {
|
||||
[0x7] = 1, // e021
|
||||
[0xa] = 1, // e31
|
||||
[0xd] = 1, // e032
|
||||
};
|
||||
|
||||
static symbol_t *
|
||||
algebra_symbol (const char *name, symtab_t *symtab)
|
||||
{
|
||||
algebra_t *alg = symtab->procsymbol_data;
|
||||
symbol_t *sym = 0;
|
||||
uint32_t dimension = alg->plus + alg->minus + alg->zero;
|
||||
bool pga_2d = (alg->plus == 2 && alg->minus == 0 && alg->zero == 1);
|
||||
bool pga_3d = (alg->plus == 3 && alg->minus == 0 && alg->zero == 1);
|
||||
|
||||
//FIXME supports only 0-9 (ie, up to 10d)
|
||||
if (name[0] == 'e' && isdigit(name[1])) {
|
||||
int ind = 1;
|
||||
while (name[ind] && isdigit ((byte) name[ind])) {
|
||||
ind++;
|
||||
}
|
||||
if (name[ind]) {
|
||||
// not a valid basis blade name
|
||||
return 0;
|
||||
}
|
||||
char indices[ind--];
|
||||
strcpy (indices, name + 1);
|
||||
int swaps = 0;
|
||||
uint32_t blade = 0;
|
||||
for (int i = 0; i < ind; i++) {
|
||||
uint32_t c = indices[i] - '0';
|
||||
c -= alg->zero != 1;
|
||||
if (c >= dimension) {
|
||||
error (0, "basis %c not in algebra %d", indices[i], c);
|
||||
continue;
|
||||
}
|
||||
uint32_t mask = 1u << c;
|
||||
if (blade & mask) {
|
||||
warning (0, "duplicate index in basis blade");
|
||||
}
|
||||
swaps += count_flips (blade, mask);
|
||||
blade |= mask;
|
||||
}
|
||||
if (pga_2d) {
|
||||
swaps += pga_swaps_2d[blade];
|
||||
}
|
||||
if (pga_3d) {
|
||||
swaps += pga_swaps_3d[blade];
|
||||
}
|
||||
int sign = 1 - 2 * (swaps & 1);
|
||||
auto g = alg->layout.group_map[alg->layout.mask_map[blade]];
|
||||
auto group = &alg->layout.groups[g[0]];
|
||||
ex_value_t *blade_val = 0;
|
||||
if (is_float (alg->type)) {
|
||||
float components[group->count] = {};
|
||||
components[g[1]] = sign;
|
||||
blade_val = new_type_value (group->type, (pr_type_t *)components);
|
||||
} else {
|
||||
double components[group->count] = {};
|
||||
components[g[1]] = sign;
|
||||
blade_val = new_type_value (group->type, (pr_type_t *)components);
|
||||
}
|
||||
sym = new_symbol_type (name, group->type);
|
||||
sym->sy_type = sy_const;
|
||||
sym->s.value = blade_val;
|
||||
symtab_addsymbol (symtab, sym);
|
||||
}
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
symtab_t *
|
||||
algebra_scope (type_t *type, symtab_t *curscope)
|
||||
{
|
||||
auto scope = new_symtab (curscope, stab_local);
|
||||
scope->space = curscope->space;
|
||||
|
||||
if (!is_algebra (type)) {
|
||||
error (0, "algebra type required for algebra scope");
|
||||
return scope;
|
||||
}
|
||||
scope->procsymbol = algebra_symbol;
|
||||
scope->procsymbol_data = unalias_type (type)->t.algebra;
|
||||
return scope;
|
||||
}
|
||||
|
||||
algebra_t *
|
||||
algebra_get (const type_t *type)
|
||||
{
|
||||
if (type->type == ev_invalid) {
|
||||
return type->t.algebra;
|
||||
} else {
|
||||
return type->t.multivec->algebra;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
algebra_print_type_str (dstring_t *str, const type_t *type)
|
||||
{
|
||||
if (type->type == ev_invalid) {
|
||||
auto a = type->t.algebra;
|
||||
dasprintf (str, " algebra(%s(%d,%d,%d))", a->type->name,
|
||||
a->plus, a->minus, a->zero);
|
||||
} else if (type->type == ev_float || type->type == ev_double) {
|
||||
auto m = type->t.multivec;
|
||||
auto a = m->algebra;
|
||||
dasprintf (str, " algebra(%s(%d,%d,%d):%d)", a->type->name,
|
||||
a->plus, a->minus, a->zero, m->element);
|
||||
} else {
|
||||
internal_error (0, "invalid algebra type");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
algebra_encode_type (dstring_t *encoding, const type_t *type)
|
||||
{
|
||||
if (type->type == ev_invalid) {
|
||||
auto a = type->t.algebra;
|
||||
dasprintf (encoding, "{∧");
|
||||
encode_type (encoding, a->type);
|
||||
dasprintf (encoding, "(%d,%d,%d)}", a->plus, a->minus, a->zero);
|
||||
} else if (type->type == ev_float || type->type == ev_double) {
|
||||
auto m = type->t.multivec;
|
||||
auto a = m->algebra;
|
||||
dasprintf (encoding, "{∧");
|
||||
encode_type (encoding, a->type);
|
||||
dasprintf (encoding, "(%d,%d,%d):%d}", a->plus, a->minus, a->zero,
|
||||
m->element);
|
||||
} else {
|
||||
internal_error (0, "invalid algebra type");
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
algebra_type_size (const type_t *type)
|
||||
{
|
||||
if (type->type == ev_invalid) {
|
||||
auto a = type->t.algebra;
|
||||
return a->num_components * type_size (a->type);
|
||||
} else if (type->type == ev_float || type->type == ev_double) {
|
||||
auto m = type->t.multivec;
|
||||
return m->num_components * type_size (m->algebra->type);
|
||||
} else {
|
||||
internal_error (0, "invalid algebra type");
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
algebra_type_width (const type_t *type)
|
||||
{
|
||||
if (type->type == ev_invalid) {
|
||||
return 0;
|
||||
} else if (type->type == ev_float || type->type == ev_double) {
|
||||
auto m = type->t.multivec;
|
||||
return m->num_components;
|
||||
} else {
|
||||
internal_error (0, "invalid algebra type");
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
algebra_type_assignable (const type_t *dst, const type_t *src)
|
||||
{
|
||||
if (src->meta == ty_algebra && src->type == ev_invalid) {
|
||||
// full algebra types cannot be assigned to anything but the same
|
||||
// full algebra type (type represents a full multivector, so the two
|
||||
// types are fundametally different), and cannot be assigned to
|
||||
// elements of even the same algebra (to get here, the two types
|
||||
// had to be different)
|
||||
return 0;
|
||||
}
|
||||
if (dst->meta == ty_algebra && dst->type == ev_invalid) {
|
||||
if (is_scalar (src)) {
|
||||
// scalars can always be assigned to a full algebra type (sets
|
||||
// the scalar element and zeros the other elements)
|
||||
return 1;
|
||||
}
|
||||
if (src->meta != ty_algebra) {
|
||||
return 0;
|
||||
}
|
||||
if (src->t.multivec->algebra != dst->t.algebra) {
|
||||
return 0;
|
||||
}
|
||||
// the multivec is a member of the destination algebra
|
||||
return 1;
|
||||
}
|
||||
if (dst->meta != ty_algebra || src->meta != ty_algebra) {
|
||||
return 0;
|
||||
}
|
||||
return dst->t.multivec == src->t.multivec;
|
||||
}
|
|
@ -445,6 +445,7 @@ static const char *ty_meta_names[] = {
|
|||
"ty_class",
|
||||
"ty_alias",
|
||||
"ty_handle",
|
||||
"ty_algebra",
|
||||
};
|
||||
#define NUM_META ((int)(sizeof (ty_meta_names) / sizeof (ty_meta_names[0])))
|
||||
const int vector_types = (1 << ev_float)
|
||||
|
@ -454,6 +455,14 @@ const int vector_types = (1 << ev_float)
|
|||
| (1 << ev_long)
|
||||
| (1 << ev_ulong);
|
||||
|
||||
static const char *
|
||||
get_ev_type_name (etype_t type)
|
||||
{
|
||||
return ((unsigned) type >= ev_type_count)
|
||||
? "invalid type"
|
||||
: pr_type_name[type];
|
||||
}
|
||||
|
||||
static void
|
||||
dump_qfo_types (qfo_t *qfo, int base_address)
|
||||
{
|
||||
|
@ -489,9 +498,7 @@ dump_qfo_types (qfo_t *qfo, int base_address)
|
|||
}
|
||||
switch ((ty_meta_e) type->meta) {
|
||||
case ty_basic:
|
||||
printf (" %-10s", ((unsigned) type->type >= ev_type_count)
|
||||
? "invalid type"
|
||||
: pr_type_name[type->type]);
|
||||
printf (" %-10s", get_ev_type_name (type->type));
|
||||
if (type->type == ev_func) {
|
||||
printf (" %4x %d", type->func.return_type,
|
||||
count = type->func.num_params);
|
||||
|
@ -535,6 +542,10 @@ dump_qfo_types (qfo_t *qfo, int base_address)
|
|||
case ty_handle:
|
||||
printf (" %-5x\n", type->handle.tag);
|
||||
break;
|
||||
case ty_algebra:
|
||||
printf (" %s[%d] %5x %d\n",
|
||||
get_ev_type_name (type->type), type->algebra.width,
|
||||
type->algebra.algebra, type->algebra.element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "QF/va.h"
|
||||
|
||||
#include "tools/qfcc/include/qfcc.h"
|
||||
#include "tools/qfcc/include/algebra.h"
|
||||
#include "tools/qfcc/include/class.h"
|
||||
#include "tools/qfcc/include/def.h"
|
||||
#include "tools/qfcc/include/defspace.h"
|
||||
|
@ -199,6 +200,8 @@ get_type (expr_t *e)
|
|||
return e->e.swizzle.type;
|
||||
case ex_extend:
|
||||
return e->e.extend.type;
|
||||
case ex_multivec:
|
||||
return e->e.multivec.algebra->algebra_type;
|
||||
case ex_count:
|
||||
internal_error (e, "invalid expression");
|
||||
}
|
||||
|
@ -439,6 +442,20 @@ copy_expr (expr_t *e)
|
|||
*n = *e;
|
||||
e->e.extend.src = copy_expr (e->e.extend.src);
|
||||
return n;
|
||||
case ex_multivec:
|
||||
n = new_expr ();
|
||||
*n = *e;
|
||||
n->e.multivec.algebra = e->e.multivec.algebra;
|
||||
n->e.multivec.count = e->e.multivec.count;
|
||||
n->e.multivec.components = copy_expr (e->e.multivec.components);
|
||||
t = e->e.multivec.components;
|
||||
e = n->e.multivec.components;
|
||||
while (t->next) {
|
||||
e->next = copy_expr (t->next);
|
||||
e = e->next;
|
||||
t = t->next;
|
||||
}
|
||||
return n;
|
||||
case ex_count:
|
||||
break;
|
||||
}
|
||||
|
@ -1685,6 +1702,13 @@ has_function_call (expr_t *e)
|
|||
case ex_with:
|
||||
case ex_args:
|
||||
return 0;
|
||||
case ex_multivec:
|
||||
for (auto c = e->e.multivec.components; c; c = c->next) {
|
||||
if (has_function_call (c)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
case ex_count:
|
||||
break;
|
||||
}
|
||||
|
@ -1835,6 +1859,8 @@ unary_expr (int op, expr_t *e)
|
|||
n->e.expr.type = e->e.symbol->type;
|
||||
return n;
|
||||
}
|
||||
case ex_multivec:
|
||||
return algebra_negate (e);
|
||||
case ex_nil:
|
||||
case ex_address:
|
||||
return error (e, "invalid type for unary -");
|
||||
|
@ -1921,6 +1947,8 @@ unary_expr (int op, expr_t *e)
|
|||
n->e.expr.type = &type_float;
|
||||
return n;
|
||||
}
|
||||
case ex_multivec:
|
||||
return algebra_dual (e);
|
||||
case ex_branch:
|
||||
case ex_nil:
|
||||
return error (e, "invalid type for unary !");
|
||||
|
@ -2015,6 +2043,8 @@ bitnot_expr:
|
|||
n->e.expr.type = t;
|
||||
return n;
|
||||
}
|
||||
case ex_multivec:
|
||||
return algebra_reverse (e);
|
||||
case ex_nil:
|
||||
case ex_address:
|
||||
return error (e, "invalid type for unary ~");
|
||||
|
|
354
tools/qfcc/source/expr_algebra.c
Normal file
354
tools/qfcc/source/expr_algebra.c
Normal file
|
@ -0,0 +1,354 @@
|
|||
/*
|
||||
expr_algebra.c
|
||||
|
||||
goemetric algebra expressions
|
||||
|
||||
Copyright (C) 2023 Bill Currie <bill@taniwha.org>
|
||||
|
||||
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 "tools/qfcc/include/algebra.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"
|
||||
|
||||
#include "tools/qfcc/source/qc-parse.h"
|
||||
|
||||
static expr_t *
|
||||
promote_scalar (type_t *dst_type, expr_t *scalar)
|
||||
{
|
||||
auto scalar_type = get_type (scalar);
|
||||
if (scalar_type != dst_type) {
|
||||
if (!type_promotes (dst_type, scalar_type)) {
|
||||
warning (scalar, "demoting %s to %s (use a cast)",
|
||||
get_type_string (scalar_type),
|
||||
get_type_string (dst_type));
|
||||
}
|
||||
scalar = cast_expr (dst_type, scalar);
|
||||
}
|
||||
return scalar;
|
||||
}
|
||||
|
||||
static expr_t *
|
||||
scalar_product (expr_t *e1, expr_t *e2)
|
||||
{
|
||||
auto scalar = is_scalar (get_type (e1)) ? e1 : e2;
|
||||
auto vector = is_scalar (get_type (e1)) ? e2 : e1;
|
||||
if (vector->type == ex_vector) {
|
||||
internal_error (vector, "multiproduce scale not implemented");
|
||||
auto comp = vector->e.vector.list;
|
||||
auto prod = scalar_product (scalar, comp);
|
||||
while (comp->next) {
|
||||
comp = comp->next;
|
||||
auto p = scalar_product (scalar, comp);
|
||||
p->next = prod;
|
||||
prod = p;
|
||||
}
|
||||
return fold_constants (prod);
|
||||
} else {
|
||||
auto vector_type = get_type (vector);
|
||||
auto scalar_type = base_type (vector_type);
|
||||
scalar = promote_scalar (scalar_type, scalar);
|
||||
if (type_width (vector_type) > 4) {
|
||||
internal_error (vector, "scalar * %d-vector not implemented",
|
||||
type_width (vector_type));
|
||||
}
|
||||
auto prod = new_binary_expr (SCALE, vector, scalar);
|
||||
prod->e.expr.type = vector_type;
|
||||
return fold_constants (prod);
|
||||
}
|
||||
}
|
||||
|
||||
static expr_t *
|
||||
inner_product (expr_t *e1, expr_t *e2)
|
||||
{
|
||||
if (is_scalar (get_type (e1)) || is_scalar (get_type (e2))) {
|
||||
auto scalar = is_scalar (get_type (e1)) ? e1 : e2;
|
||||
notice (scalar,
|
||||
"the inner product of a scalar with any other grade is 0");
|
||||
pr_type_t zero[type_size (get_type (scalar))] = {};
|
||||
return new_value_expr (new_type_value (get_type (scalar), zero));
|
||||
}
|
||||
internal_error (e1, "not implemented");
|
||||
}
|
||||
|
||||
static expr_t *
|
||||
outer_product (expr_t *e1, expr_t *e2)
|
||||
{
|
||||
if (is_scalar (get_type (e1)) || is_scalar (get_type (e2))) {
|
||||
return scalar_product (e1, e2);
|
||||
}
|
||||
internal_error (e1, "not implemented");
|
||||
}
|
||||
|
||||
static expr_t *
|
||||
regressive_product (expr_t *e1, expr_t *e2)
|
||||
{
|
||||
internal_error (e1, "not implemented");
|
||||
}
|
||||
|
||||
static void
|
||||
component_sum (int op, expr_t **components, expr_t *e,
|
||||
const basis_layout_t *layout)
|
||||
{
|
||||
int group;
|
||||
auto t = get_type (e);
|
||||
if (is_scalar (t)) {
|
||||
group = layout->group_map[layout->mask_map[0]][0];
|
||||
} else {
|
||||
group = t->t.multivec->element;
|
||||
}
|
||||
if (components[group]) {
|
||||
if (t != get_type (components[group])) {
|
||||
internal_error (e, "tangled multivec types");
|
||||
}
|
||||
components[group] = new_binary_expr (op, components[group], e);
|
||||
components[group]->e.expr.type = t;
|
||||
} else {
|
||||
components[group] = scalar_product (new_float_expr (-1), e);
|
||||
}
|
||||
components[group] = fold_constants (components[group]);
|
||||
}
|
||||
|
||||
static expr_t *
|
||||
multivector_sum (int op, expr_t *e1, expr_t *e2)
|
||||
{
|
||||
auto t1 = get_type (e1);
|
||||
auto t2 = get_type (e2);
|
||||
auto alg = is_algebra (t1) ? algebra_get (t1) : algebra_get (t2);
|
||||
auto layout = &alg->layout;
|
||||
expr_t *components[layout->count] = {};
|
||||
if (e1->type == ex_multivec) {
|
||||
for (auto c = e1->e.multivec.components; c; c = c->next) {
|
||||
auto ct = get_type (c);
|
||||
int group;
|
||||
if (is_scalar (ct)) {
|
||||
group = layout->group_map[layout->mask_map[0]][0];
|
||||
} else {
|
||||
group = ct->t.multivec->element;
|
||||
}
|
||||
components[group] = c;
|
||||
}
|
||||
} else {
|
||||
int group;
|
||||
if (is_scalar (t1)) {
|
||||
group = layout->group_map[layout->mask_map[0]][0];
|
||||
} else {
|
||||
group = t1->t.multivec->element;
|
||||
}
|
||||
components[group] = e1;
|
||||
}
|
||||
if (e2->type == ex_multivec) {
|
||||
for (auto c = e1->e.multivec.components; c; c = c->next) {
|
||||
component_sum (op, components, c, layout);
|
||||
}
|
||||
} else {
|
||||
component_sum (op, components, e2, layout);
|
||||
}
|
||||
int count = 0;
|
||||
expr_t *sum = 0;
|
||||
for (int i = 0; i < layout->count; i++) {
|
||||
if (components[i]) {
|
||||
count++;
|
||||
sum = components[i];
|
||||
}
|
||||
}
|
||||
if (count == 1) {
|
||||
return sum;
|
||||
}
|
||||
|
||||
sum = new_expr ();
|
||||
sum->type = ex_multivec;
|
||||
sum->e.multivec.algebra = alg;
|
||||
for (int i = layout->count; i-- > 0; ) {
|
||||
if (components[i]) {
|
||||
components[i]->next = sum->e.multivec.components;
|
||||
sum->e.multivec.components = components[i];
|
||||
sum->e.multivec.count++;
|
||||
}
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
static expr_t *
|
||||
geometric_product (expr_t *e1, expr_t *e2)
|
||||
{
|
||||
if (is_scalar (get_type (e1)) || is_scalar (get_type (e2))) {
|
||||
return scalar_product (e1, e2);
|
||||
}
|
||||
internal_error (e1, "not implemented");
|
||||
}
|
||||
|
||||
static expr_t *
|
||||
commutator_product (expr_t *e1, expr_t *e2)
|
||||
{
|
||||
auto ab = geometric_product (e1, e2);
|
||||
auto ba = geometric_product (e2, e1);
|
||||
return multivector_sum ('-', ab, ba);
|
||||
}
|
||||
|
||||
static expr_t *
|
||||
multivector_divide (expr_t *e1, expr_t *e2)
|
||||
{
|
||||
internal_error (e1, "not implemented");
|
||||
}
|
||||
|
||||
expr_t *
|
||||
algebra_binary_expr (int op, expr_t *e1, expr_t *e2)
|
||||
{
|
||||
switch (op) {
|
||||
case DOT:
|
||||
return inner_product (e1, e2);
|
||||
case WEDGE:
|
||||
return outer_product (e1, e2);
|
||||
case REGRESSIVE:
|
||||
return regressive_product (e1, e2);
|
||||
case CROSS:
|
||||
return commutator_product (e1, e2);
|
||||
case '+':
|
||||
case '-':
|
||||
return multivector_sum (op, e1, e2);
|
||||
case '/':
|
||||
return multivector_divide (e1, e2);
|
||||
case '*':
|
||||
case GEOMETRIC:
|
||||
return geometric_product (e1, e2);
|
||||
}
|
||||
return error (e1, "invalid operator");
|
||||
}
|
||||
|
||||
expr_t *
|
||||
algebra_negate (expr_t *e)
|
||||
{
|
||||
if (e) {
|
||||
internal_error (e, "not implemented");
|
||||
}
|
||||
notice (e, "not implemented");
|
||||
return 0;
|
||||
}
|
||||
|
||||
expr_t *
|
||||
algebra_dual (expr_t *e)
|
||||
{
|
||||
if (e) {
|
||||
internal_error (e, "not implemented");
|
||||
}
|
||||
notice (e, "not implemented");
|
||||
return 0;
|
||||
}
|
||||
|
||||
expr_t *
|
||||
algebra_reverse (expr_t *e)
|
||||
{
|
||||
if (e) {
|
||||
internal_error (e, "not implemented");
|
||||
}
|
||||
notice (e, "not implemented");
|
||||
return 0;
|
||||
}
|
||||
|
||||
expr_t *
|
||||
algebra_cast_expr (type_t *dstType, expr_t *e)
|
||||
{
|
||||
type_t *srcType = get_type (e);
|
||||
if (dstType->type == ev_invalid
|
||||
|| srcType->type == ev_invalid
|
||||
|| type_size (dstType) != type_size (srcType)
|
||||
|| type_width (dstType) != type_width (srcType)) {
|
||||
return cast_error (e, srcType, dstType);
|
||||
}
|
||||
return new_alias_expr (dstType, e);
|
||||
}
|
||||
|
||||
static void
|
||||
zero_components (expr_t *block, expr_t *dst, int memset_base, int memset_size)
|
||||
{
|
||||
auto base = new_offset_alias_expr (&type_int, dst, memset_base);
|
||||
auto zero = new_int_expr (0);
|
||||
auto size = new_int_expr (memset_size);
|
||||
append_expr (block, new_memset_expr (base, zero, size));
|
||||
}
|
||||
|
||||
expr_t *
|
||||
algebra_assign_expr (expr_t *dst, expr_t *src)
|
||||
{
|
||||
type_t *srcType = get_type (src);
|
||||
type_t *dstType = get_type (dst);
|
||||
|
||||
if (type_size (srcType) == type_size (dstType)) {
|
||||
return new_assign_expr (dst, src);
|
||||
}
|
||||
|
||||
if (dstType->meta != ty_algebra && dstType->type != ev_invalid) {
|
||||
return 0;
|
||||
}
|
||||
auto layout = &dstType->t.algebra->layout;
|
||||
expr_t *components[layout->count] = {};
|
||||
if (src->type == ex_multivec) {
|
||||
for (auto c = src->e.multivec.components; c; c = c->next) {
|
||||
auto ct = get_type (c);
|
||||
int group;
|
||||
if (is_scalar (ct)) {
|
||||
group = layout->group_map[layout->mask_map[0]][0];
|
||||
} else {
|
||||
group = ct->t.multivec->element;
|
||||
}
|
||||
components[group] = c;
|
||||
}
|
||||
} else {
|
||||
int group;
|
||||
if (is_scalar (srcType)) {
|
||||
group = layout->group_map[layout->mask_map[0]][0];
|
||||
} else {
|
||||
group = srcType->t.multivec->element;
|
||||
}
|
||||
components[group] = src;
|
||||
}
|
||||
auto block = new_block_expr ();
|
||||
int memset_base = 0;
|
||||
int memset_size = 0;
|
||||
int offset = 0;
|
||||
for (int i = 0; i < layout->count; i++) {
|
||||
if (components[i]) {
|
||||
if (memset_size) {
|
||||
zero_components (block, dst, memset_base, memset_size);
|
||||
memset_size = 0;
|
||||
}
|
||||
auto dst_type = layout->groups[i].type;
|
||||
auto dst_alias = new_offset_alias_expr (dst_type, dst, offset);
|
||||
append_expr (block, new_assign_expr (dst_alias, components[i]));
|
||||
offset += type_size (dst_type);
|
||||
memset_base = offset;
|
||||
} else {
|
||||
offset += type_size (layout->groups[i].type);
|
||||
memset_size += type_size (layout->groups[i].type);
|
||||
}
|
||||
}
|
||||
if (memset_size) {
|
||||
zero_components (block, dst, memset_base, memset_size);
|
||||
}
|
||||
return block;
|
||||
}
|
|
@ -46,6 +46,7 @@
|
|||
#include "QF/va.h"
|
||||
|
||||
#include "tools/qfcc/include/qfcc.h"
|
||||
#include "tools/qfcc/include/algebra.h"
|
||||
#include "tools/qfcc/include/class.h"
|
||||
#include "tools/qfcc/include/def.h"
|
||||
#include "tools/qfcc/include/defspace.h"
|
||||
|
@ -144,6 +145,7 @@ is_lvalue (const expr_t *expr)
|
|||
case ex_horizontal:
|
||||
case ex_swizzle:
|
||||
case ex_extend:
|
||||
case ex_multivec:
|
||||
break;
|
||||
case ex_count:
|
||||
internal_error (expr, "invalid expression");
|
||||
|
@ -175,6 +177,9 @@ check_types_compatible (expr_t *dst, expr_t *src)
|
|||
}
|
||||
|
||||
if (type_assignable (dst_type, src_type)) {
|
||||
if (is_algebra (dst_type) || is_algebra (src_type)) {
|
||||
return algebra_assign_expr (dst, src);
|
||||
}
|
||||
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)) {
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include "tools/qfcc/include/algebra.h"
|
||||
#include "tools/qfcc/include/diagnostic.h"
|
||||
#include "tools/qfcc/include/expr.h"
|
||||
#include "tools/qfcc/include/options.h"
|
||||
|
@ -1112,6 +1113,10 @@ binary_expr (int op, expr_t *e1, expr_t *e2)
|
|||
if (!t1 || !t2)
|
||||
internal_error (e1, "expr with no type");
|
||||
|
||||
if (is_algebra (t1) || is_algebra (t2)) {
|
||||
return algebra_binary_expr (op, e1, e2);
|
||||
}
|
||||
|
||||
if (op == EQ || op == NE) {
|
||||
if (e1->type == ex_nil) {
|
||||
t1 = t2;
|
||||
|
|
|
@ -37,13 +37,14 @@
|
|||
#include "QF/mathlib.h"
|
||||
|
||||
#include "tools/qfcc/include/qfcc.h"
|
||||
#include "tools/qfcc/include/algebra.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 *
|
||||
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),
|
||||
|
@ -106,6 +107,13 @@ cast_expr (type_t *dstType, expr_t *e)
|
|||
c = new_alias_expr (dstType, e);
|
||||
return c;
|
||||
}
|
||||
if (is_algebra (dstType) || is_algebra (srcType)) {
|
||||
if ((c = algebra_cast_expr (dstType, e))) {
|
||||
return c;
|
||||
}
|
||||
return cast_error (e, srcType, dstType);
|
||||
}
|
||||
|
||||
if (!(is_ptr (dstType) && (is_ptr (srcType) || is_integral (srcType)
|
||||
|| is_array (srcType)))
|
||||
&& !(is_integral (dstType) && is_ptr (srcType))
|
||||
|
|
|
@ -31,36 +31,11 @@
|
|||
# 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)
|
||||
{
|
||||
|
|
|
@ -699,6 +699,7 @@ get_def_type (qfo_t *qfo, pr_ptr_t type)
|
|||
case ty_alias: //XXX
|
||||
case ty_basic:
|
||||
case ty_handle: //XXX
|
||||
case ty_algebra:
|
||||
// field, pointer and function types store their basic type in
|
||||
// the same location.
|
||||
return type_def->type;
|
||||
|
@ -750,6 +751,7 @@ get_type_size (qfo_t *qfo, pr_ptr_t type)
|
|||
return type_def->array.size
|
||||
* get_type_size (qfo, type_def->array.type);
|
||||
case ty_class:
|
||||
case ty_algebra:
|
||||
return 0; // FIXME
|
||||
}
|
||||
return 0;
|
||||
|
@ -799,6 +801,7 @@ get_type_alignment_log (qfo_t *qfo, pr_ptr_t type)
|
|||
case ty_array:
|
||||
return get_type_alignment_log (qfo, type_def->array.type);
|
||||
case ty_class:
|
||||
case ty_algebra:
|
||||
return 0; // FIXME
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
|
||||
#include "compat.h"
|
||||
|
||||
#include "tools/qfcc/include/algebra.h"
|
||||
#include "tools/qfcc/include/class.h"
|
||||
#include "tools/qfcc/include/def.h"
|
||||
#include "tools/qfcc/include/defspace.h"
|
||||
|
@ -290,20 +291,45 @@ qfo_encode_handle (type_t *type, defspace_t *space)
|
|||
return def;
|
||||
}
|
||||
|
||||
static def_t *
|
||||
qfo_encode_algebra (type_t *type, defspace_t *space)
|
||||
{
|
||||
qfot_type_t *enc;
|
||||
def_t *def;
|
||||
def_t *algebra_type_def = 0;
|
||||
|
||||
if (type->type != ev_invalid) {
|
||||
auto m = (multivector_t *) type->t.algebra;
|
||||
algebra_type_def = qfo_encode_type (m->algebra->type, space);
|
||||
}
|
||||
|
||||
def = qfo_new_encoding (type, sizeof (enc->algebra), space);
|
||||
enc = D_POINTER (qfot_type_t, def);
|
||||
enc->algebra = (qfot_algebra_t) {
|
||||
.type = type->type,
|
||||
.width = type->width,
|
||||
};
|
||||
if (algebra_type_def) {
|
||||
ENC_DEF (enc->algebra.algebra, algebra_type_def);
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
def_t *
|
||||
qfo_encode_type (type_t *type, defspace_t *space)
|
||||
{
|
||||
reloc_t *relocs = 0;
|
||||
|
||||
static encode_f funcs[] = {
|
||||
qfo_encode_basic, // ty_basic
|
||||
qfo_encode_struct, // ty_struct
|
||||
qfo_encode_struct, // ty_union
|
||||
qfo_encode_struct, // ty_enum
|
||||
qfo_encode_array, // ty_array
|
||||
qfo_encode_class, // ty_class
|
||||
qfo_encode_alias, // ty_alias
|
||||
qfo_encode_handle, // ty_handle
|
||||
[ty_basic] = qfo_encode_basic,
|
||||
[ty_struct] = qfo_encode_struct,
|
||||
[ty_union] = qfo_encode_struct,
|
||||
[ty_enum] = qfo_encode_struct,
|
||||
[ty_array] = qfo_encode_array,
|
||||
[ty_class] = qfo_encode_class,
|
||||
[ty_alias] = qfo_encode_alias,
|
||||
[ty_handle] = qfo_encode_handle,
|
||||
[ty_algebra] = qfo_encode_algebra,
|
||||
};
|
||||
|
||||
if (type->type_def && type->type_def->external) {
|
||||
|
|
|
@ -269,9 +269,10 @@ STRING \"(\\.|[^"\\])*\"
|
|||
}
|
||||
|
||||
"·" { return DOT; }
|
||||
"⋀" { return WEDGE; }
|
||||
"•" { return DOT; }
|
||||
"∧" { return WEDGE; }
|
||||
"∨" { return REGRESSIVE; }
|
||||
"⋀" { return WEDGE; }
|
||||
"†" { return DAGGER; }
|
||||
"∗" { return STAR; }
|
||||
"×" { return CROSS; }
|
||||
|
@ -440,6 +441,7 @@ static keyword_t qf_keywords[] = {
|
|||
{"@dot", DOT, },
|
||||
{"@wedge", WEDGE, },
|
||||
{"@geometric", GEOMETRIC, },
|
||||
{"@algebra", ALGEBRA, },
|
||||
};
|
||||
|
||||
// These keywors are always available. Other than the @ keywords, they
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include <QF/sys.h>
|
||||
#include <QF/va.h>
|
||||
|
||||
#include "tools/qfcc/include/algebra.h"
|
||||
#include "tools/qfcc/include/attribute.h"
|
||||
#include "tools/qfcc/include/class.h"
|
||||
#include "tools/qfcc/include/debug.h"
|
||||
|
@ -152,7 +153,7 @@ int yylex (void);
|
|||
|
||||
%token LOCAL WHILE DO IF ELSE FOR BREAK CONTINUE
|
||||
%token RETURN AT_RETURN ELLIPSIS
|
||||
%token NIL GOTO SWITCH CASE DEFAULT ENUM
|
||||
%token NIL GOTO SWITCH CASE DEFAULT ENUM ALGEBRA
|
||||
%token ARGS TYPEDEF EXTERN STATIC SYSTEM OVERLOAD NOT ATTRIBUTE
|
||||
%token <op> STRUCT HANDLE
|
||||
%token <spec> TYPE_SPEC TYPE_NAME TYPE_QUAL
|
||||
|
@ -179,7 +180,7 @@ int yylex (void);
|
|||
|
||||
%type <symbol> tag
|
||||
%type <spec> struct_specifier struct_list
|
||||
%type <spec> enum_specifier
|
||||
%type <spec> enum_specifier algebra_specifier
|
||||
%type <symbol> optional_enum_list enum_list enumerator_list enumerator
|
||||
%type <symbol> enum_init
|
||||
%type <size> array_decl
|
||||
|
@ -893,6 +894,7 @@ typespec
|
|||
|
||||
typespec_reserved
|
||||
: TYPE_SPEC
|
||||
| algebra_specifier
|
||||
| enum_specifier
|
||||
| struct_specifier
|
||||
// NOTE: fields don't parse the way they should. This is not a problem
|
||||
|
@ -1019,6 +1021,19 @@ attribute
|
|||
|
||||
tag : NAME ;
|
||||
|
||||
algebra_specifier
|
||||
: ALGEBRA '(' TYPE_SPEC '(' expr_list ')' ')'
|
||||
{
|
||||
auto spec = make_spec (algebra_type ($3.type, $5), 0, 0, 0);
|
||||
$$ = spec;
|
||||
}
|
||||
| ALGEBRA '(' TYPE_SPEC ')'
|
||||
{
|
||||
auto spec = make_spec (algebra_type ($3.type, 0), 0, 0, 0);
|
||||
$$ = spec;
|
||||
}
|
||||
;
|
||||
|
||||
enum_specifier
|
||||
: ENUM tag optional_enum_list
|
||||
{
|
||||
|
@ -1558,6 +1573,36 @@ statement
|
|||
break_label = $2;
|
||||
continue_label = $3;
|
||||
}
|
||||
| ALGEBRA '(' TYPE_SPEC '(' expr_list ')' ')'
|
||||
{
|
||||
auto algebra = algebra_type ($3.type, $5);
|
||||
current_symtab = algebra_scope (algebra, current_symtab);
|
||||
}
|
||||
compound_statement
|
||||
{
|
||||
current_symtab = current_symtab->parent;
|
||||
$$ = $9;
|
||||
}
|
||||
| ALGEBRA '(' TYPE_SPEC ')'
|
||||
{
|
||||
auto algebra = algebra_type ($3.type, 0);
|
||||
current_symtab = algebra_scope (algebra, current_symtab);
|
||||
}
|
||||
compound_statement
|
||||
{
|
||||
current_symtab = current_symtab->parent;
|
||||
$$ = $6;
|
||||
}
|
||||
| ALGEBRA '(' TYPE_NAME ')'
|
||||
{
|
||||
auto algebra = $3.type;
|
||||
current_symtab = algebra_scope (algebra, current_symtab);
|
||||
}
|
||||
compound_statement
|
||||
{
|
||||
current_symtab = current_symtab->parent;
|
||||
$$ = $6;
|
||||
}
|
||||
| comma_expr ';'
|
||||
{
|
||||
$$ = $1;
|
||||
|
|
|
@ -32,6 +32,21 @@ pr_info_t pr;
|
|||
type_t type_Class;
|
||||
type_t type_SEL;
|
||||
type_t type_id;
|
||||
void algebra_print_type_str (struct dstring_s *str, const struct type_s *type);
|
||||
void algebra_print_type_str (struct dstring_s *str, const struct type_s *type){}
|
||||
void algebra_encode_type (struct dstring_s *encoding,
|
||||
const struct type_s *type);
|
||||
void algebra_encode_type (struct dstring_s *encoding,
|
||||
const struct type_s *type){}
|
||||
__attribute__((const)) int algebra_type_size (const struct type_s *type);
|
||||
int algebra_type_size (const struct type_s *type){return 0;}
|
||||
__attribute__((const)) int algebra_type_width (const struct type_s *type);
|
||||
int algebra_type_width (const struct type_s *type){return 0;}
|
||||
__attribute__((const)) int algebra_type_assignable (const type_t *dst, const type_t *src);
|
||||
int algebra_type_assignable (const type_t *dst, const type_t *src){return 0;}
|
||||
__attribute__((const)) int is_algebra (const type_t *type);
|
||||
int is_algebra (const type_t *type){return 0;}
|
||||
|
||||
__attribute__((const)) pr_string_t ReuseString (const char *str) {return 0;}
|
||||
__attribute__((const)) codespace_t *codespace_new (void) {return 0;}
|
||||
void codespace_addcode (codespace_t *codespace, struct dstatement_s *code, int size) {}
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "QF/sys.h"
|
||||
#include "QF/va.h"
|
||||
|
||||
#include "tools/qfcc/include/algebra.h"
|
||||
#include "tools/qfcc/include/class.h"
|
||||
#include "tools/qfcc/include/def.h"
|
||||
#include "tools/qfcc/include/diagnostic.h"
|
||||
|
@ -312,6 +313,7 @@ copy_chain (type_t *type, type_t *append)
|
|||
case ty_class:
|
||||
case ty_alias: //XXX is this correct?
|
||||
case ty_handle:
|
||||
case ty_algebra:
|
||||
internal_error (0, "copy object type %d", type->meta);
|
||||
}
|
||||
}
|
||||
|
@ -370,6 +372,7 @@ append_type (type_t *type, type_t *new)
|
|||
case ty_class:
|
||||
case ty_alias: //XXX is this correct?
|
||||
case ty_handle:
|
||||
case ty_algebra:
|
||||
internal_error (0, "append to object type");
|
||||
}
|
||||
}
|
||||
|
@ -440,6 +443,8 @@ types_same (type_t *a, type_t *b)
|
|||
case ty_handle:
|
||||
// names have gone through save_string
|
||||
return a->name == b->name;
|
||||
case ty_algebra:
|
||||
return a->t.algebra == b->t.algebra;
|
||||
}
|
||||
internal_error (0, "we be broke");
|
||||
}
|
||||
|
@ -571,6 +576,8 @@ find_type (type_t *type)
|
|||
break;
|
||||
case ty_handle:
|
||||
break;
|
||||
case ty_algebra:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -596,7 +603,7 @@ find_type (type_t *type)
|
|||
}
|
||||
}
|
||||
}
|
||||
check->freeable = 0;
|
||||
check->freeable = false;
|
||||
|
||||
chain_type (check);
|
||||
|
||||
|
@ -819,6 +826,9 @@ print_type_str (dstring_t *str, const type_t *type)
|
|||
return;
|
||||
}
|
||||
switch (type->meta) {
|
||||
case ty_algebra:
|
||||
algebra_print_type_str (str, type);
|
||||
return;
|
||||
case ty_handle:
|
||||
dasprintf (str, " handle %s", type->name);
|
||||
return;
|
||||
|
@ -1011,6 +1021,9 @@ encode_type (dstring_t *encoding, const type_t *type)
|
|||
if (!type)
|
||||
return;
|
||||
switch (type->meta) {
|
||||
case ty_algebra:
|
||||
algebra_encode_type (encoding, type);
|
||||
return;
|
||||
case ty_handle:
|
||||
dasprintf (encoding, "{%s$}", type->name);
|
||||
return;
|
||||
|
@ -1285,6 +1298,9 @@ type_assignable (const type_t *dst, const type_t *src)
|
|||
return 0;
|
||||
}
|
||||
if (!is_ptr (dst) || !is_ptr (src)) {
|
||||
if (is_algebra (dst) || is_algebra (src)) {
|
||||
return algebra_type_assignable (dst, src);
|
||||
}
|
||||
if (is_scalar (dst) && is_scalar (src)) {
|
||||
return 1;
|
||||
}
|
||||
|
@ -1384,6 +1400,8 @@ type_size (const type_t *type)
|
|||
}
|
||||
case ty_alias:
|
||||
return type_size (type->t.alias.aux_type);
|
||||
case ty_algebra:
|
||||
return algebra_type_size (type);
|
||||
}
|
||||
internal_error (0, "invalid type meta: %d", type->meta);
|
||||
}
|
||||
|
@ -1414,6 +1432,8 @@ type_width (const type_t *type)
|
|||
return 1;
|
||||
case ty_alias:
|
||||
return type_width (type->t.alias.aux_type);
|
||||
case ty_algebra:
|
||||
return algebra_type_width (type);
|
||||
}
|
||||
internal_error (0, "invalid type meta: %d", type->meta);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ fail_bins=
|
|||
|
||||
test_progs_dat=\
|
||||
tools/qfcc/test/address-cast.dat \
|
||||
tools/qfcc/test/algtypes.dat \
|
||||
tools/qfcc/test/alignment.dat \
|
||||
tools/qfcc/test/arraylife.dat \
|
||||
tools/qfcc/test/arraylife2.dat \
|
||||
|
@ -141,6 +142,16 @@ tools/qfcc/test/address-cast.run: $(qfcc_test_run_deps)
|
|||
include $(address_cast_dep) # am--include-marker
|
||||
r_depfiles_remade += $(address_cast_dep)
|
||||
|
||||
tools_qfcc_test_algtypes_dat_SOURCES=tools/qfcc/test/algtypes.r
|
||||
algtypes_obj=$(tools_qfcc_test_algtypes_dat_SOURCES:.r=.o)
|
||||
algtypes_dep=$(call qcautodep,$(tools_qfcc_test_algtypes_dat_SOURCES))
|
||||
tools/qfcc/test/algtypes.dat$(EXEEXT): $(algtypes_obj) $(QFCC_DEP)
|
||||
$(V_QFCCLD)$(QLINK) -o $@ $(algtypes_obj)
|
||||
tools/qfcc/test/algtypes.run: $(qfcc_test_run_deps)
|
||||
@$(top_srcdir)/tools/qfcc/test/build-run $@
|
||||
include $(algtypes_dep) # am--include-marker
|
||||
r_depfiles_remade += $(algtypes_dep)
|
||||
|
||||
tools_qfcc_test_alignment_dat_SOURCES=tools/qfcc/test/alignment.r
|
||||
alignment_obj=$(tools_qfcc_test_alignment_dat_SOURCES:.r=.o)
|
||||
alignment_dep=$(call qcautodep,$(tools_qfcc_test_alignment_dat_SOURCES))
|
||||
|
|
36
tools/qfcc/test/algtypes.r
Normal file
36
tools/qfcc/test/algtypes.r
Normal file
|
@ -0,0 +1,36 @@
|
|||
@algebra(float) pgaf1;
|
||||
//@algebra(double) pgad1;
|
||||
//@algebra(float(3)) vgaf;
|
||||
//@algebra(double(3)) vgad;
|
||||
//@algebra(float(3,0,1)) pgaf2;
|
||||
//@algebra(double(3,0,1)) pgad2;
|
||||
//@algebra(float(0,1)) complexf;
|
||||
//@algebra(double(0,1)) complexd;
|
||||
typedef @algebra(float(3,0,1)) PGA;
|
||||
typedef @algebra(float(4,1)) CGA;
|
||||
|
||||
float sin(float x) = #0;
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
@algebra (PGA) {
|
||||
auto p1 = 3*e1 + e2 - e3 + e0;
|
||||
auto p2 = e1 + 3*e2 + e3 - e0;
|
||||
pgaf1 = p1 * p2;
|
||||
#if 0
|
||||
auto rx = e23;
|
||||
auto ry = e31;
|
||||
auto rz = e12;
|
||||
auto tx = e01;
|
||||
auto ty = e02;
|
||||
auto tz = e03;
|
||||
auto x = e032;
|
||||
auto y = e013;
|
||||
auto z = e021;
|
||||
auto w = e123;
|
||||
auto mvec = rx + ry;
|
||||
#endif
|
||||
}
|
||||
return 0; // to survive and prevail :)
|
||||
}
|
|
@ -12,7 +12,7 @@ main ()
|
|||
printf ("cross product failed\n");
|
||||
return 1;
|
||||
};
|
||||
if (v · c != [1, 1, 1]) {
|
||||
if (v • c != [1, 1, 1]) {
|
||||
printf ("dot product failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue