[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_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;

View File

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

View File

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

View File

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

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