[qfcc] Use structs for multi-vector type layouts

Simple k-vectors don't use structs for their layout since they're just
an array of scalars, but having the structs for group sets or full
multi-vectors makes the system alignment agnostic.
This commit is contained in:
Bill Currie 2023-08-29 16:17:07 +09:00
parent 09cdf87f67
commit 33295a8ad9
5 changed files with 213 additions and 61 deletions

View File

@ -68,6 +68,7 @@ typedef struct algebra_s {
basis_layout_t layout; basis_layout_t layout;
basis_group_t *groups; basis_group_t *groups;
struct type_s **mvec_types; struct type_s **mvec_types;
struct symbol_s *mvec_sym;
int num_components; ///< number of componets (2^d) int num_components; ///< number of componets (2^d)
int dimension; ///< number of dimensions (plus + minus + zero) int dimension; ///< number of dimensions (plus + minus + zero)
int plus; ///< number of elements squaring to +1 int plus; ///< number of elements squaring to +1
@ -79,6 +80,7 @@ typedef struct multivector_s {
int num_components; int num_components;
int group_mask; int group_mask;
algebra_t *algebra; algebra_t *algebra;
struct symbol_s *mvec_sym; ///< null if single group
} multivector_t; } multivector_t;
struct expr_s; struct expr_s;

View File

@ -87,42 +87,49 @@ count_minus (uint32_t minus)
{ {
return count_bits (minus) & 1 ? -1 : 1; return count_bits (minus) & 1 ? -1 : 1;
} }
#if 0
static struct_def_t mvec_1d_struct[] = { static const char *mvec_1d_names[] = {
{"vec", &type_vec2}, "vec",
{} "scalar",
0
}; };
static struct_def_t mvec_2d_struct[] = { static const char *mvec_2d_names[] = {
{"vec", &type_vec4}, "vec",
{} "scalar",
"bvec",
0
}; };
static struct_def_t mvec_3d_struct[] = { static const char *mvec_3d_names[] = {
{"vec", &type_vec4}, "vec",
{"bvec", &type_vec4}, "scalar"
{} "bvec",
"tvec",
0
}; };
static struct_def_t mvec_4d_struct[] = { static const char *mvec_4d_names[] = {
{"vec", &type_vec4}, "vec",
{"bvecv", &type_vec4}, "bvecv",
{"bvecm", &type_vec4}, "scalar",
{"tvec", &type_vec4}, "bvecm",
{} "qvec",
"tvec",
0
}; };
static struct_def_t *mvec_struct[] = { static const char **mvec_names[] = {
[1] = mvec_1d_struct, [1] = mvec_1d_names,
[2] = mvec_2d_struct, [2] = mvec_2d_names,
[3] = mvec_3d_struct, [3] = mvec_3d_names,
[4] = mvec_4d_struct, [4] = mvec_4d_names,
}; };
static symbol_t * 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->type->encoding,
a->plus, a->minus, a->zero)); a->plus, a->minus, a->zero));
int dim = 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; mvsym->type->alignment = 4;
} }
} else if (dim > 0) { } 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 { } else {
internal_error (0, "invalid number of dimensions"); internal_error (0, "invalid number of dimensions");
} }
return mvsym; return mvsym;
} }
#endif
static void static void
basis_blade_init (basis_blade_t *blade, pr_uint_t mask) 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); 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 bool
@ -461,23 +480,41 @@ algebra_mvec_type (algebra_t *algebra, pr_uint_t group_mask)
} }
if (!algebra->mvec_types[group_mask]) { if (!algebra->mvec_types[group_mask]) {
int count = 0; int count = 0;
int components = 0;
for (int i = 0; i < algebra->layout.count; i++) { for (int i = 0; i < algebra->layout.count; i++) {
if (group_mask & (1 << 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)); multivector_t *mvec = malloc (sizeof (multivector_t));
*mvec = (multivector_t) { *mvec = (multivector_t) {
.num_components = count, .num_components = components,
.group_mask = group_mask, .group_mask = group_mask,
.algebra = algebra, .algebra = algebra,
.mvec_sym = mvec_sym,
}; };
algebra->mvec_types[group_mask] = new_type (); algebra->mvec_types[group_mask] = new_type ();
*algebra->mvec_types[group_mask] = (type_t) { *algebra->mvec_types[group_mask] = (type_t) {
.type = algebra->type->type, .type = algebra->type->type,
.name = "basis group", .name = "basis group",
.alignment = algebra_alignment (algebra->type, count), .alignment = algebra_alignment (algebra->type, components),
.width = count, .width = components,
.meta = ty_algebra, .meta = ty_algebra,
.t.algebra = (algebra_t *) mvec, .t.algebra = (algebra_t *) mvec,
.freeable = true, .freeable = true,

View File

@ -33,6 +33,7 @@
#include "tools/qfcc/include/algebra.h" #include "tools/qfcc/include/algebra.h"
#include "tools/qfcc/include/diagnostic.h" #include "tools/qfcc/include/diagnostic.h"
#include "tools/qfcc/include/expr.h" #include "tools/qfcc/include/expr.h"
#include "tools/qfcc/include/symtab.h"
#include "tools/qfcc/include/type.h" #include "tools/qfcc/include/type.h"
#include "tools/qfcc/include/value.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); 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 * static expr_t *
mvec_expr (expr_t *expr, algebra_t *algebra) mvec_expr (expr_t *expr, algebra_t *algebra)
{ {
@ -91,16 +104,10 @@ mvec_expr (expr_t *expr, algebra_t *algebra)
.algebra = algebra, .algebra = algebra,
}; };
expr_t **c = &mvec->e.multivec.components; expr_t **c = &mvec->e.multivec.components;
int comp_offset = 0; for (auto sym = get_mvec_sym (mvtype); sym; sym = sym->next) {
for (int i = 0; i < layout->count; i++) { *c = new_offset_alias_expr (sym->type, expr, sym->s.offset);
pr_uint_t mask = 1u << i; c = &(*c)->next;
if (mask & group_mask) { mvec->e.multivec.count++;
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;
}
} }
return mvec; return mvec;
@ -1580,7 +1587,7 @@ algebra_assign_expr (expr_t *dst, expr_t *src)
type_t *dstType = get_type (dst); type_t *dstType = get_type (dst);
if (src->type != ex_multivec) { if (src->type != ex_multivec) {
if (type_size (srcType) == type_size (dstType)) { if (srcType == dstType) {
return new_assign_expr (dst, src); return new_assign_expr (dst, src);
} }
} }
@ -1594,31 +1601,27 @@ algebra_assign_expr (expr_t *dst, expr_t *src)
src = mvec_expr (src, algebra); src = mvec_expr (src, algebra);
mvec_scatter (components, src, algebra); mvec_scatter (components, src, algebra);
auto sym = get_mvec_sym (dstType);
auto block = new_block_expr (); auto block = new_block_expr ();
int memset_base = 0; int memset_base = 0;
int memset_size = 0;
int offset = 0;
for (int i = 0; i < layout->count; i++) { for (int i = 0; i < layout->count; i++) {
if (components[i]) { if (!components[i]) {
if (memset_size) { continue;
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);
}
} }
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) { if (type_size (dstType) - memset_base) {
zero_components (block, dst, memset_base, memset_size); zero_components (block, dst, memset_base,
type_size (dstType) - memset_base);
} }
return block; return block;
} }

View File

@ -45,6 +45,7 @@ test_progs_dat=\
tools/qfcc/test/overload.dat \ tools/qfcc/test/overload.dat \
tools/qfcc/test/paramret.dat \ tools/qfcc/test/paramret.dat \
tools/qfcc/test/pga2d.dat \ tools/qfcc/test/pga2d.dat \
tools/qfcc/test/pga3d.dat \
tools/qfcc/test/postop.dat \ tools/qfcc/test/postop.dat \
tools/qfcc/test/ptraliasenc.dat \ tools/qfcc/test/ptraliasenc.dat \
tools/qfcc/test/ptrfunc.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 include $(pga2d_dep) # am--include-marker
r_depfiles_remade += $(pga2d_dep) 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 tools_qfcc_test_postop_dat_SOURCES=tools/qfcc/test/postop.r
postop_obj=$(tools_qfcc_test_postop_dat_SOURCES:.r=.o) postop_obj=$(tools_qfcc_test_postop_dat_SOURCES:.r=.o)
postop_dep=$(call qcautodep,$(tools_qfcc_test_postop_dat_SOURCES)) postop_dep=$(call qcautodep,$(tools_qfcc_test_postop_dat_SOURCES))

99
tools/qfcc/test/pga3d.r Normal file
View File

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