diff --git a/tools/qfcc/include/algebra.h b/tools/qfcc/include/algebra.h index c1e0c5640..36d641495 100644 --- a/tools/qfcc/include/algebra.h +++ b/tools/qfcc/include/algebra.h @@ -38,11 +38,11 @@ typedef struct basis_blade_s { typedef struct basis_group_s { int count; + pr_uint_t group_mask; 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 { @@ -67,6 +67,7 @@ typedef struct algebra_s { metric_t metric; basis_layout_t layout; basis_group_t *groups; + struct type_s **mvec_types; int num_components; ///< number of componets (2^d) int dimension; ///< number of dimensions (plus + minus + zero) int plus; ///< number of elements squaring to +1 @@ -76,13 +77,14 @@ typedef struct algebra_s { typedef struct multivector_s { int num_components; - int element; + int group_mask; 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 type_s *algebra_mvec_type (algebra_t *algebra, pr_uint_t group_mask); 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, @@ -95,6 +97,7 @@ int metric_apply (const metric_t *metric, pr_uint_t a, pr_uint_t b) __attribute_ 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 type_s *algebra_base_type (const struct type_s *type) __attribute__((pure)); struct expr_s *algebra_binary_expr (int op, struct expr_s *e1, struct expr_s *e2); diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 89081fd94..993304c24 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -281,6 +281,7 @@ typedef struct { } ex_extend_t; typedef struct { + struct type_s *type; ///< overall type of multivector struct algebra_s *algebra; ///< owning algebra int count; ///< number of component expressions struct expr_s *components; ///< multivector components diff --git a/tools/qfcc/source/algebra.c b/tools/qfcc/source/algebra.c index 4f17239e3..b856080d8 100644 --- a/tools/qfcc/source/algebra.c +++ b/tools/qfcc/source/algebra.c @@ -164,10 +164,12 @@ basis_blade_init (basis_blade_t *blade, pr_uint_t mask) static void basis_group_init (basis_group_t *group, int count, basis_blade_t *blades, - algebra_t *a, int element) + algebra_t *a, int group_id) { + pr_uint_t group_mask = 1 << group_id; *group = (basis_group_t) { .count = count, + .group_mask = group_mask, .range = { ~0u, 0 }, .blades = malloc (sizeof (basis_blade_t[count])), .set = set_new (), @@ -184,29 +186,6 @@ basis_group_init (basis_group_t *group, int count, basis_blade_t *blades, 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 @@ -268,6 +247,12 @@ metric_apply (const metric_t *metric, pr_uint_t a, pr_uint_t b) return count_minus (c & metric->minus); } +static type_t ** +alloc_mvec_types (int num_groups) +{ + return calloc (1 << num_groups, sizeof (type_t *)); +} + static void algebra_init (algebra_t *a) { @@ -309,6 +294,7 @@ algebra_init (algebra_t *a) blades[13], blades[12], blades[11], blades[14], }; a->groups = malloc (sizeof (basis_group_t[6])); + a->mvec_types = alloc_mvec_types (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); @@ -325,6 +311,7 @@ algebra_init (algebra_t *a) blades[2], blades[3], blades[1], blades[7], }; a->groups = malloc (sizeof (basis_group_t[4])); + a->mvec_types = alloc_mvec_types (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); @@ -333,6 +320,7 @@ algebra_init (algebra_t *a) } else { // just use the grades as the default layout a->groups = malloc (sizeof (basis_group_t[d + 1])); + a->mvec_types = alloc_mvec_types (d + 1); for (int i = 0; i < d + 1; i++) { int c = counts[i]; int ind = indices[i]; @@ -340,6 +328,15 @@ algebra_init (algebra_t *a) } basis_layout_init (&a->layout, d + 1, a->groups); } + + for (int i = 0; i < a->layout.count; i++) { + auto g = &a->layout.groups[i]; + if (g->count == 1 && g->blades[0].mask == 0) { + a->mvec_types[g->group_mask] = a->type; + } else { + algebra_mvec_type (a, g->group_mask); + } + } } bool @@ -415,6 +412,41 @@ algebra_type (type_t *type, expr_t *params) return find_type (t); } +type_t * +algebra_mvec_type (algebra_t *algebra, pr_uint_t group_mask) +{ + if (!group_mask) { + return 0; + } + if (!algebra->mvec_types[group_mask]) { + int count = 0; + for (int i = 0; i < algebra->layout.count; i++) { + if (group_mask & (1 << i)) { + count += algebra->layout.groups[i].count; + } + } + multivector_t *mvec = malloc (sizeof (multivector_t)); + *mvec = (multivector_t) { + .num_components = count, + .group_mask = group_mask, + .algebra = algebra, + }; + algebra->mvec_types[group_mask] = new_type (); + *algebra->mvec_types[group_mask] = (type_t) { + .type = algebra->type->type, + .name = "basis group", + .alignment = 4, //FIXME + .width = count, + .meta = ty_algebra, + .t.algebra = (algebra_t *) mvec, + .freeable = true, + .allocated = true, + }; + chain_type (algebra->mvec_types[group_mask]); + } + return algebra->mvec_types[group_mask]; +} + static int pga_swaps_2d[8] = { [0x5] = 1, // e20 }; @@ -470,17 +502,18 @@ algebra_symbol (const char *name, symtab_t *symtab) int sign = 1 - 2 * (swaps & 1); auto g = alg->layout.group_map[alg->layout.mask_map[blade]]; auto group = &alg->layout.groups[g[0]]; + auto group_type = alg->mvec_types[group->group_mask]; 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); + 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); + blade_val = new_type_value (group_type, (pr_type_t *)components); } - sym = new_symbol_type (name, group->type); + sym = new_symbol_type (name, group_type); sym->sy_type = sy_const; sym->s.value = blade_val; symtab_addsymbol (symtab, sym); @@ -524,8 +557,8 @@ algebra_print_type_str (dstring_t *str, const type_t *type) } 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); + dasprintf (str, " algebra(%s(%d,%d,%d):%04x)", a->type->name, + a->plus, a->minus, a->zero, m->group_mask); } else { internal_error (0, "invalid algebra type"); } @@ -544,8 +577,8 @@ algebra_encode_type (dstring_t *encoding, const type_t *type) 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); + dasprintf (encoding, "(%d,%d,%d):%04x}", a->plus, a->minus, a->zero, + m->group_mask); } else { internal_error (0, "invalid algebra type"); } @@ -609,3 +642,12 @@ algebra_type_assignable (const type_t *dst, const type_t *src) } return dst->t.multivec == src->t.multivec; } + +type_t * +algebra_base_type (const type_t *type) +{ + if (type->type == ev_invalid) { + return type->t.algebra->type; + } + return ev_types[type->type]; +} diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index ce04a151f..4b1cf0a14 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -201,7 +201,7 @@ get_type (expr_t *e) case ex_extend: return e->e.extend.type; case ex_multivec: - return e->e.multivec.algebra->algebra_type; + return e->e.multivec.type; case ex_count: internal_error (e, "invalid expression"); } @@ -445,8 +445,6 @@ copy_expr (expr_t *e) 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; diff --git a/tools/qfcc/source/expr_algebra.c b/tools/qfcc/source/expr_algebra.c index 4ec685f7b..5b7ad0bf2 100644 --- a/tools/qfcc/source/expr_algebra.c +++ b/tools/qfcc/source/expr_algebra.c @@ -28,6 +28,8 @@ # include "config.h" #endif +#include "QF/math/bitop.h" + #include "tools/qfcc/include/algebra.h" #include "tools/qfcc/include/diagnostic.h" #include "tools/qfcc/include/expr.h" @@ -36,6 +38,121 @@ #include "tools/qfcc/source/qc-parse.h" +static expr_t * +mvec_expr (expr_t *expr, algebra_t *algebra) +{ + auto mvtype = get_type (expr); + if (expr->type == ex_multivec || is_scalar (mvtype)) { + return expr; + } + if (!is_algebra (mvtype)) { + return error (expr, "invalid operand for GA"); + } + + auto layout = &algebra->layout; + pr_uint_t group_mask = (1u << (layout->count + 1)) - 1; + if (mvtype->type != ev_invalid) { + group_mask = mvtype->t.multivec->group_mask; + } + if (!(group_mask & (group_mask - 1))) { + return expr; + } + auto mvec = new_expr (); + mvec->type = ex_multivec; + mvec->e.multivec = (ex_multivec_t) { + .type = algebra_mvec_type (algebra, group_mask), + .algebra = algebra, + }; + expr_t **c = &mvec->e.multivec.components; + for (int i = 0; i < layout->count; i++) { + pr_uint_t mask = 1u << i; + if (mask & group_mask) { + auto comp_type = algebra_mvec_type (algebra, mask); + int comp_offset = algebra->layout.group_map[i][1]; + *c = new_offset_alias_expr (comp_type, expr, comp_offset); + mvec->e.multivec.count++; + } + } + + return mvec; +} + +static void +mvec_scatter (expr_t **components, expr_t *mvec, algebra_t *algebra) +{ + auto layout = &algebra->layout; + int group; + + if (mvec->type != ex_multivec) { + auto type = get_type (mvec); + if (!is_algebra (type)) { + group = layout->group_map[layout->mask_map[0]][0]; + } else { + if (type->type == ev_invalid) { + internal_error (mvec, "full algebra in mvec_scatter"); + } + pr_uint_t mask = type->t.multivec->group_mask; + if (mask & (mask - 1)) { + internal_error (mvec, "bare multivector in mvec_scatter"); + } + group = BITOP_LOG2 (mask); + } + components[group] = mvec; + return; + } + for (auto c = mvec->e.multivec.components; c; c = c->next) { + auto ct = get_type (c); + if (is_scalar (ct)) { + group = layout->group_map[layout->mask_map[0]][0]; + components[group] = mvec; + } else if (ct->meta == ty_algebra && ct->type != ev_invalid) { + pr_uint_t mask = ct->t.multivec->group_mask; + if (mask & (mask - 1)) { + internal_error (mvec, "multivector in multivec expression"); + } + group = BITOP_LOG2 (mask); + } else { + internal_error (mvec, "invalid type in multivec expression"); + } + components[group] = c; + } +} + +static expr_t * +mvec_gather (expr_t **components, algebra_t *algebra) +{ + auto layout = &algebra->layout; + + pr_uint_t group_mask = 0; + int count = 0; + expr_t *mvec = 0; + for (int i = 0; i < layout->count; i++) { + if (components[i]) { + count++; + mvec = components[i]; + group_mask |= 1 << i; + } + } + if (count == 1) { + return mvec; + } + + mvec = new_expr (); + mvec->type = ex_multivec; + mvec->e.multivec = (ex_multivec_t) { + .type = algebra_mvec_type (algebra, group_mask), + .algebra = algebra, + }; + for (int i = layout->count; i-- > 0; ) { + if (components[i]) { + components[i]->next = mvec->e.multivec.components; + mvec->e.multivec.components = components[i]; + mvec->e.multivec.count++; + } + } + return mvec; +} + static expr_t * promote_scalar (type_t *dst_type, expr_t *scalar) { @@ -56,29 +173,34 @@ 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_multivec) { - auto comp = vector->e.multivec.components; - auto prod = scalar_product (scalar, comp); - while (comp->next) { - comp = comp->next; - auto p = scalar_product (scalar, comp); - p = fold_constants (p); - p->next = prod; - prod = p; + auto algebra = algebra_get (get_type (vector)); + auto layout = &algebra->layout; + + scalar = promote_scalar (algebra->type, scalar); + + expr_t *components[layout->count] = {}; + vector = mvec_expr (vector, algebra); + mvec_scatter (components, vector, algebra); + + for (int i = 0; i < layout->count; i++) { + if (!components[i]) { + continue; } - return 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) { + auto comp_type = get_type (components[i]); + if (type_width (comp_type) == 1) { + auto prod = new_binary_expr ('*', components[i], scalar); + prod->e.expr.type = comp_type; + components[i] = fold_constants (prod); + } else if (type_width (comp_type) > 4) { internal_error (vector, "scalar * %d-vector not implemented", - type_width (vector_type)); + type_width (comp_type)); + } else { + auto prod = new_binary_expr (SCALE, components[i], scalar); + prod->e.expr.type = comp_type; + components[i] = fold_constants (prod); } - auto prod = new_binary_expr (SCALE, vector, scalar); - prod->e.expr.type = vector_type; - return fold_constants (prod); } + return mvec_gather (components, algebra); } static expr_t * @@ -110,30 +232,31 @@ regressive_product (expr_t *e1, expr_t *e2) } static void -component_sum (int op, expr_t **components, expr_t *e, - const basis_layout_t *layout) +component_sum (int op, expr_t **c, expr_t **a, expr_t **b, + algebra_t *algebra) { - 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 { - if (op == '+') { - components[group] = e; + auto layout = &algebra->layout; + for (int i = 0; i < layout->count; i++) { + if (a[i] && b[i]) { + if (get_type (a[i]) != get_type (b[i])) { + internal_error (a[i], "tangled multivec types"); + } + c[i] = new_binary_expr (op, a[i], b[i]); + c[i]->e.expr.type = get_type (a[i]); + c[i] = fold_constants (c[i]); + } else if (a[i]) { + c[i] = a[i]; + } else if (b[i]) { + if (op == '+') { + c[i] = b[i]; + } else { + c[i] = scalar_product (new_float_expr (-1), b[i]); + c[i] = fold_constants (c[i]); + } } else { - components[group] = scalar_product (new_float_expr (-1), e); + c[i] = 0; } } - components[group] = fold_constants (components[group]); } static expr_t * @@ -141,60 +264,17 @@ 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; + auto algebra = is_algebra (t1) ? algebra_get (t1) : algebra_get (t2); + auto layout = &algebra->layout; + expr_t *a[layout->count] = {}; + expr_t *b[layout->count] = {}; + expr_t *c[layout->count]; + e1 = mvec_expr (e1, algebra); + e2 = mvec_expr (e2, algebra); + mvec_scatter (a, e1, algebra); + mvec_scatter (b, e2, algebra); + component_sum (op, c, a, b, algebra); + return mvec_gather (c, algebra); } static expr_t * @@ -302,35 +382,21 @@ 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 (src->type != ex_multivec) { + if (type_size (srcType) == type_size (dstType)) { + return new_assign_expr (dst, src); + } } - if (dstType->meta != ty_algebra && dstType->type != ev_invalid) { + if (dstType->meta != ty_algebra && dstType != srcType) { return 0; } - auto layout = &dstType->t.algebra->layout; + auto algebra = algebra_get (dstType); + auto layout = &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; - } + src = mvec_expr (src, algebra); + mvec_scatter (components, src, algebra); + auto block = new_block_expr (); int memset_base = 0; int memset_size = 0; @@ -341,14 +407,17 @@ algebra_assign_expr (expr_t *dst, expr_t *src) zero_components (block, dst, memset_base, memset_size); memset_size = 0; } - auto dst_type = layout->groups[i].type; + auto dst_type = algebra_mvec_type (algebra, 1 << i); 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 (dstType->type == ev_invalid) { + auto dst_type = algebra_mvec_type (algebra, 1 << i); + offset += type_size (dst_type); + memset_size += type_size (dst_type); + } } } if (memset_size) { diff --git a/tools/qfcc/source/expr_assign.c b/tools/qfcc/source/expr_assign.c index a9258937f..bdfe77ad6 100644 --- a/tools/qfcc/source/expr_assign.c +++ b/tools/qfcc/source/expr_assign.c @@ -173,6 +173,9 @@ check_types_compatible (expr_t *dst, expr_t *src) type_t *src_type = get_type (src); if (dst_type == src_type) { + if (is_algebra (dst_type) || is_algebra (src_type)) { + return algebra_assign_expr (dst, src); + } return 0; } diff --git a/tools/qfcc/source/stub.c b/tools/qfcc/source/stub.c index 0eba17fd7..97cc063c2 100644 --- a/tools/qfcc/source/stub.c +++ b/tools/qfcc/source/stub.c @@ -46,6 +46,8 @@ __attribute__((const)) int algebra_type_assignable (const type_t *dst, const typ 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)) int algebra_base_type (const type_t *type); +int algebra_base_type (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;} diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index 991bf0f9c..b83042c09 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -678,6 +678,9 @@ vector_type (const type_t *ele_type, int width) type_t * base_type (const type_t *vec_type) { + if (is_algebra (vec_type)) { + return algebra_base_type (vec_type); + } if (!is_math (vec_type)) { return 0; } @@ -1221,6 +1224,9 @@ is_math (const type_t *type) if (is_vector (type) || is_quaternion (type)) { return 1; } + if (is_algebra (type)) { + return 1; + } return is_scalar (type) || is_nonscalar (type); } diff --git a/tools/qfcc/test/algtypes.r b/tools/qfcc/test/algtypes.r index 805b17d5a..96ec81678 100644 --- a/tools/qfcc/test/algtypes.r +++ b/tools/qfcc/test/algtypes.r @@ -17,7 +17,8 @@ main (void) @algebra (PGA) { auto p1 = 3*e1 + e2 - e3 + e0; auto p2 = e1 + 3*e2 + e3 - e0; - pgaf1 = p1 * p2; + auto v = 4*(e1 + e032 + e123); + pgaf1 = p1 + v;// * p2; #if 0 auto rx = e23; auto ry = e31;