[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:
Bill Currie 2023-08-21 17:37:56 +09:00
parent cb9a82e74c
commit 2e91b29580
27 changed files with 1339 additions and 43 deletions

View file

@ -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;

View file

@ -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) {

View file

@ -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;
}

View file

@ -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 \

View 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

View file

@ -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));

View file

@ -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)
///@}

View file

@ -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,

View file

@ -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;

View file

@ -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
View 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;
}

View file

@ -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);
}
}
}

View file

@ -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 ~");

View 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;
}

View file

@ -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)) {

View file

@ -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;

View file

@ -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))

View file

@ -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)
{

View file

@ -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;

View file

@ -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) {

View file

@ -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

View file

@ -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;

View file

@ -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) {}

View file

@ -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);
}

View file

@ -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))

View 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 :)
}

View file

@ -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;
}