mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-05-10 17:50:54 +00:00
[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:
parent
09cdf87f67
commit
33295a8ad9
5 changed files with 213 additions and 61 deletions
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
99
tools/qfcc/test/pga3d.r
Normal 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 :)
|
||||||
|
}
|
Loading…
Reference in a new issue