diff --git a/tools/qfcc/include/algebra.h b/tools/qfcc/include/algebra.h index 83f5013b5..72030caf7 100644 --- a/tools/qfcc/include/algebra.h +++ b/tools/qfcc/include/algebra.h @@ -68,6 +68,7 @@ typedef struct algebra_s { basis_layout_t layout; basis_group_t *groups; struct type_s **mvec_types; + struct symbol_s *mvec_sym; int num_components; ///< number of componets (2^d) int dimension; ///< number of dimensions (plus + minus + zero) int plus; ///< number of elements squaring to +1 @@ -79,6 +80,7 @@ typedef struct multivector_s { int num_components; int group_mask; algebra_t *algebra; + struct symbol_s *mvec_sym; ///< null if single group } multivector_t; struct expr_s; diff --git a/tools/qfcc/source/algebra.c b/tools/qfcc/source/algebra.c index e0447a0bf..b3babbd23 100644 --- a/tools/qfcc/source/algebra.c +++ b/tools/qfcc/source/algebra.c @@ -87,42 +87,49 @@ 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 const char *mvec_1d_names[] = { + "vec", + "scalar", + 0 }; -static struct_def_t mvec_2d_struct[] = { - {"vec", &type_vec4}, - {} +static const char *mvec_2d_names[] = { + "vec", + "scalar", + "bvec", + 0 }; -static struct_def_t mvec_3d_struct[] = { - {"vec", &type_vec4}, - {"bvec", &type_vec4}, - {} +static const char *mvec_3d_names[] = { + "vec", + "scalar" + "bvec", + "tvec", + 0 }; -static struct_def_t mvec_4d_struct[] = { - {"vec", &type_vec4}, - {"bvecv", &type_vec4}, - {"bvecm", &type_vec4}, - {"tvec", &type_vec4}, - {} +static const char *mvec_4d_names[] = { + "vec", + "bvecv", + "scalar", + "bvecm", + "qvec", + "tvec", + 0 }; -static struct_def_t *mvec_struct[] = { - [1] = mvec_1d_struct, - [2] = mvec_2d_struct, - [3] = mvec_3d_struct, - [4] = mvec_4d_struct, +static const char **mvec_names[] = { + [1] = mvec_1d_names, + [2] = mvec_2d_names, + [3] = mvec_3d_names, + [4] = mvec_4d_names, }; static symbol_t * -build_algebra_types (algebra_t *a) +build_algebra_type (algebra_t *a) { - auto name = save_string (va (0, "multivector.%s.%d.%d.%d", + auto name = save_string (va (0, "multivec.%s(%d.%d.%d)", a->type->encoding, a->plus, a->minus, a->zero)); int dim = a->plus + a->minus + a->zero; @@ -149,13 +156,23 @@ build_algebra_types (algebra_t *a) mvsym->type->alignment = 4; } } else if (dim > 0) { - mvsym = make_structure (name, 's', mvec_struct[dim], 0); + const char **names = mvec_names[dim]; + int count = 0; + for (auto n = names; *n; n++, count++) continue; + struct_def_t fields[count + 1] = {}; + for (int i = 0; i < count; i++) { + fields[i] = (struct_def_t) { + .name = names[i], + .type = algebra_mvec_type (a, 1u << i), + }; + }; + mvsym = make_structure (name, 's', fields, 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) { @@ -340,6 +357,8 @@ algebra_init (algebra_t *a) algebra_mvec_type (a, g->group_mask); } } + a->mvec_sym = build_algebra_type (a); + a->mvec_types[(1 << a->dimension) - 1] = a->mvec_sym->type; } bool @@ -461,23 +480,41 @@ algebra_mvec_type (algebra_t *algebra, pr_uint_t group_mask) } if (!algebra->mvec_types[group_mask]) { int count = 0; + int components = 0; for (int i = 0; i < algebra->layout.count; i++) { if (group_mask & (1 << i)) { - count += algebra->layout.groups[i].count; + components += algebra->layout.groups[i].count; + count++; } } + symbol_t *mvec_sym = 0; + if (group_mask & (group_mask - 1)) { + struct_def_t fields[count + 1] = {}; + for (int i = 0, c = 0; i < algebra->layout.count; i++) { + pr_uint_t mask = 1 << i; + if (group_mask & mask) { + fields[c] = (struct_def_t) { + .name = save_string (va (0, "group_%d", i)), + .type = algebra_mvec_type (algebra, mask), + }; + c++; + }; + }; + mvec_sym = make_structure (0, 's', fields, 0); + } multivector_t *mvec = malloc (sizeof (multivector_t)); *mvec = (multivector_t) { - .num_components = count, + .num_components = components, .group_mask = group_mask, .algebra = algebra, + .mvec_sym = mvec_sym, }; algebra->mvec_types[group_mask] = new_type (); *algebra->mvec_types[group_mask] = (type_t) { .type = algebra->type->type, .name = "basis group", - .alignment = algebra_alignment (algebra->type, count), - .width = count, + .alignment = algebra_alignment (algebra->type, components), + .width = components, .meta = ty_algebra, .t.algebra = (algebra_t *) mvec, .freeable = true, diff --git a/tools/qfcc/source/expr_algebra.c b/tools/qfcc/source/expr_algebra.c index 977fcb29c..33a1a9950 100644 --- a/tools/qfcc/source/expr_algebra.c +++ b/tools/qfcc/source/expr_algebra.c @@ -33,6 +33,7 @@ #include "tools/qfcc/include/algebra.h" #include "tools/qfcc/include/diagnostic.h" #include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/symtab.h" #include "tools/qfcc/include/type.h" #include "tools/qfcc/include/value.h" @@ -65,6 +66,18 @@ offset_cast (type_t *type, expr_t *expr, int offset) return new_offset_alias_expr (type, expr, offset); } +static symbol_t * +get_mvec_sym (type_t *type) +{ + symbol_t *sym = 0; + if (type->type == ev_invalid) { + sym = type->t.algebra->mvec_sym; + } else { + sym = type->t.multivec->mvec_sym; + } + return sym->type->t.symtab->symbols; +} + static expr_t * mvec_expr (expr_t *expr, algebra_t *algebra) { @@ -91,16 +104,10 @@ mvec_expr (expr_t *expr, algebra_t *algebra) .algebra = algebra, }; expr_t **c = &mvec->e.multivec.components; - int comp_offset = 0; - 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); - *c = offset_cast (comp_type, expr, comp_offset); - c = &(*c)->next; - mvec->e.multivec.count++; - comp_offset += algebra->layout.groups[i].count; - } + for (auto sym = get_mvec_sym (mvtype); sym; sym = sym->next) { + *c = new_offset_alias_expr (sym->type, expr, sym->s.offset); + c = &(*c)->next; + mvec->e.multivec.count++; } return mvec; @@ -1580,7 +1587,7 @@ algebra_assign_expr (expr_t *dst, expr_t *src) type_t *dstType = get_type (dst); if (src->type != ex_multivec) { - if (type_size (srcType) == type_size (dstType)) { + if (srcType == dstType) { return new_assign_expr (dst, src); } } @@ -1594,31 +1601,27 @@ algebra_assign_expr (expr_t *dst, expr_t *src) src = mvec_expr (src, algebra); mvec_scatter (components, src, algebra); + auto sym = get_mvec_sym (dstType); 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 = 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 { - 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 (!components[i]) { + continue; } + while (sym->type != get_type (components[i])) { + sym = sym->next; + } + int size = sym->s.offset - memset_base; + if (size) { + zero_components (block, dst, memset_base, size); + } + auto dst_alias = new_offset_alias_expr (sym->type, dst, sym->s.offset); + append_expr (block, new_assign_expr (dst_alias, components[i])); + memset_base = sym->s.offset + type_size (sym->type); } - if (memset_size) { - zero_components (block, dst, memset_base, memset_size); + if (type_size (dstType) - memset_base) { + zero_components (block, dst, memset_base, + type_size (dstType) - memset_base); } return block; } diff --git a/tools/qfcc/test/Makemodule.am b/tools/qfcc/test/Makemodule.am index 7d8455446..ab161b953 100644 --- a/tools/qfcc/test/Makemodule.am +++ b/tools/qfcc/test/Makemodule.am @@ -45,6 +45,7 @@ test_progs_dat=\ tools/qfcc/test/overload.dat \ tools/qfcc/test/paramret.dat \ tools/qfcc/test/pga2d.dat \ + tools/qfcc/test/pga3d.dat \ tools/qfcc/test/postop.dat \ tools/qfcc/test/ptraliasenc.dat \ tools/qfcc/test/ptrfunc.dat \ @@ -554,6 +555,16 @@ tools/qfcc/test/pga2d.run: $(qfcc_test_run_deps) include $(pga2d_dep) # am--include-marker r_depfiles_remade += $(pga2d_dep) +tools_qfcc_test_pga3d_dat_SOURCES=tools/qfcc/test/pga3d.r +pga3d_obj=$(tools_qfcc_test_pga3d_dat_SOURCES:.r=.o) +pga3d_dep=$(call qcautodep,$(tools_qfcc_test_pga3d_dat_SOURCES)) +tools/qfcc/test/pga3d.dat$(EXEEXT): $(pga3d_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(pga3d_obj) +tools/qfcc/test/pga3d.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(pga3d_dep) # am--include-marker +r_depfiles_remade += $(pga3d_dep) + tools_qfcc_test_postop_dat_SOURCES=tools/qfcc/test/postop.r postop_obj=$(tools_qfcc_test_postop_dat_SOURCES:.r=.o) postop_dep=$(call qcautodep,$(tools_qfcc_test_postop_dat_SOURCES)) diff --git a/tools/qfcc/test/pga3d.r b/tools/qfcc/test/pga3d.r new file mode 100644 index 000000000..e42bcad88 --- /dev/null +++ b/tools/qfcc/test/pga3d.r @@ -0,0 +1,99 @@ +#include "test-harness.h" +#pragma warn no-vararg-integer +typedef @algebra(float(3,0,1)) PGA; +typedef PGA.group_mask(0x04) scalar_t; +typedef PGA.group_mask(0x01) vector_t; +typedef PGA.group_mask(0x20) trivector_t; +typedef PGA.group_mask(0x10) quadvector_t; +typedef union { + PGA.group_mask(0x0a) bvec; + struct { + PGA.group_mask(0x02) dir; + PGA.group_mask(0x08) mom; + }; +} bivector_t; +typedef union { + PGA.group_mask(0x1e) mvec; + struct { + bivector_t bvec; + scalar_t scalar; + }; +} evengrades_t; +typedef union { + PGA.group_mask(0x21) mvec; + struct { + vector_t vec; + trivector_t tvec; + }; +} oddgrades_t; + +int +main (void) +{ + if (sizeof (scalar_t) != sizeof (float)) { + printf ("scalar has wrong size: %d\n", sizeof (scalar_t)); + return 1; + } + if (sizeof (vector_t) != 4 * sizeof (scalar_t)) { + printf ("bivector has wrong size: %d\n", sizeof (vector_t)); + return 1; + } + // the pair of vec3s in a bivector have an alignment of 4 + if (sizeof (bivector_t) != 8 * sizeof (scalar_t)) { + printf ("bivector has wrong size: %d\n", sizeof (bivector_t)); + return 1; + } + if (sizeof (bivector_t) != sizeof (PGA.group_mask(0x0a))) { + printf ("bivector group has wrong size: %d\n", + sizeof (PGA.group_mask(0x0a))); + return 1; + } + if (sizeof (trivector_t) != 4 * sizeof (scalar_t)) { + printf ("trivector has wrong size: %d\n", sizeof (trivector_t)); + return 1; + } + if (sizeof (quadvector_t) != sizeof (scalar_t)) { + printf ("quadvector has wrong size: %d\n", sizeof (quadvector_t)); + return 1; + } + + scalar_t scalar; + vector_t vec, vecb; + bivector_t bvec, bvecb; + trivector_t tvec, tvecb; + quadvector_t qvec, qvecb; + @algebra (PGA) { + scalar = 42; + vec = 3*e1 - 2*e2 + e0; + bvec.bvec = 4*e20 - 3*e01 + 2*e12; + tvec = 7*e012; + qvec = 8*e0123; + + vecb = 5*e1 + 12*e2 - 13*e0; + bvecb.bvec = 6*e20 + 4*e01 + 1*e12; + tvecb = 3*e032; + qvecb = 1*e0123; + } + + if (scalar != 42) { + printf ("scalar != 42: %g\n", scalar); + return 1; + } + if ((vec4)vec != '3 -2 0 1') { + printf ("vec != '3 -2 0 1': %q\n", vec); + return 1; + } + if ((vec3)bvec.dir != '0 0 2' || (vec3)bvec.mom != '-3 -4 0') { + printf ("bvec != '0 0 2' '-3 -4 0': %v %v\n", bvec.dir, bvec.mom); + return 1; + } + if ((vec4)tvec != '0 0 -7 0') { + printf ("tvec != '0 0 -7': %g\n", tvec); + return 1; + } + if ((scalar_t)qvec != 8) { + printf ("tvec != 8: %g\n", (scalar_t) qvec); + return 1; + } + return 0; // to survive and prevail :) +}