2023-08-21 08:37:56 +00:00
|
|
|
/*
|
|
|
|
expr_algebra.c
|
|
|
|
|
2023-08-25 08:24:47 +00:00
|
|
|
geometric algebra expressions
|
2023-08-21 08:37:56 +00:00
|
|
|
|
|
|
|
Copyright (C) 2023 Bill Currie <bill@taniwha.org>
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License
|
|
|
|
as published by the Free Software Foundation; either version 2
|
|
|
|
of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to:
|
|
|
|
|
|
|
|
Free Software Foundation, Inc.
|
|
|
|
59 Temple Place - Suite 330
|
|
|
|
Boston, MA 02111-1307, USA
|
|
|
|
|
|
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
2023-09-30 06:13:14 +00:00
|
|
|
#include <string.h>
|
2023-08-21 08:37:56 +00:00
|
|
|
|
2023-09-30 06:13:14 +00:00
|
|
|
#include "QF/fbsearch.h"
|
|
|
|
#include "QF/heapsort.h"
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
#include "QF/math/bitop.h"
|
|
|
|
|
2023-08-21 08:37:56 +00:00
|
|
|
#include "tools/qfcc/include/algebra.h"
|
|
|
|
#include "tools/qfcc/include/diagnostic.h"
|
|
|
|
#include "tools/qfcc/include/expr.h"
|
2024-04-18 03:41:24 +00:00
|
|
|
#include "tools/qfcc/include/rua-lang.h"
|
2023-08-29 07:17:07 +00:00
|
|
|
#include "tools/qfcc/include/symtab.h"
|
2023-08-21 08:37:56 +00:00
|
|
|
#include "tools/qfcc/include/type.h"
|
|
|
|
#include "tools/qfcc/include/value.h"
|
|
|
|
|
2023-08-23 06:31:20 +00:00
|
|
|
static int __attribute__((pure))
|
2024-02-13 14:09:28 +00:00
|
|
|
get_group (const type_t *type, algebra_t *algebra)
|
2023-08-23 06:31:20 +00:00
|
|
|
{
|
|
|
|
auto layout = &algebra->layout;
|
2023-08-26 14:57:37 +00:00
|
|
|
if (is_scalar (type) && !is_algebra (type)) {
|
2023-08-23 06:31:20 +00:00
|
|
|
return layout->group_map[layout->mask_map[0]][0];
|
|
|
|
}
|
|
|
|
if (!is_algebra (type)) {
|
|
|
|
internal_error (0, "non-algebra type");
|
|
|
|
}
|
2023-09-11 01:25:35 +00:00
|
|
|
pr_uint_t group_mask = (1u << layout->count) - 1;
|
2023-08-23 06:31:20 +00:00
|
|
|
if (type->type != ev_invalid) {
|
2024-08-16 08:23:29 +00:00
|
|
|
group_mask = type->multivec->group_mask;
|
2023-08-23 06:31:20 +00:00
|
|
|
}
|
|
|
|
if (group_mask & (group_mask - 1)) {
|
|
|
|
internal_error (0, "multi-group mult-vector");
|
|
|
|
}
|
|
|
|
return BITOP_LOG2 (group_mask);
|
|
|
|
}
|
|
|
|
|
2023-09-27 08:42:44 +00:00
|
|
|
pr_uint_t
|
|
|
|
get_group_mask (const type_t *type, algebra_t *algebra)
|
2023-09-10 04:13:49 +00:00
|
|
|
{
|
|
|
|
auto layout = &algebra->layout;
|
|
|
|
if (!is_algebra (type)) {
|
|
|
|
int group = layout->group_map[layout->mask_map[0]][0];
|
|
|
|
return 1u << group;
|
|
|
|
} else {
|
|
|
|
if (type->type == ev_invalid) {
|
|
|
|
return (1 << algebra->layout.count) - 1;
|
|
|
|
}
|
2024-08-16 08:23:29 +00:00
|
|
|
return type->multivec->group_mask;
|
2023-09-10 04:13:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-01 07:29:14 +00:00
|
|
|
bool
|
2023-09-02 04:43:22 +00:00
|
|
|
is_neg (const expr_t *e)
|
|
|
|
{
|
2023-09-23 09:01:49 +00:00
|
|
|
return e->type == ex_uexpr && e->expr.op == '-';
|
2023-09-02 04:43:22 +00:00
|
|
|
}
|
|
|
|
|
2023-09-02 10:42:33 +00:00
|
|
|
static bool __attribute__((const))
|
|
|
|
anti_com (const expr_t *e)
|
|
|
|
{
|
2023-09-25 08:26:37 +00:00
|
|
|
return e && e->type == ex_expr && e->expr.anticommute;
|
2023-09-02 10:42:33 +00:00
|
|
|
}
|
|
|
|
|
2023-09-29 02:00:44 +00:00
|
|
|
static bool __attribute__((const))
|
|
|
|
op_commute (int op)
|
|
|
|
{
|
2023-10-24 10:50:31 +00:00
|
|
|
return (op == '+' || op == '*' || op == QC_HADAMARD || op == QC_DOT);
|
2023-09-29 02:00:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool __attribute__((const))
|
|
|
|
op_anti_com (int op)
|
|
|
|
{
|
2023-10-24 10:50:31 +00:00
|
|
|
return (op == '-' || op == QC_CROSS || op == QC_WEDGE);
|
2023-09-29 02:00:44 +00:00
|
|
|
}
|
|
|
|
|
2023-10-01 07:29:14 +00:00
|
|
|
const expr_t *
|
2024-02-13 14:09:28 +00:00
|
|
|
typed_binary_expr (const type_t *type, int op, const expr_t *e1, const expr_t *e2)
|
2023-09-27 03:41:31 +00:00
|
|
|
{
|
|
|
|
auto e = new_binary_expr (op, e1, e2);
|
|
|
|
e->expr.type = type;
|
2023-09-29 02:00:44 +00:00
|
|
|
e->expr.commutative = op_commute (op);
|
|
|
|
e->expr.anticommute = op_anti_com (op);
|
2023-09-27 03:41:31 +00:00
|
|
|
return e;
|
|
|
|
}
|
|
|
|
|
2023-10-01 07:29:14 +00:00
|
|
|
const expr_t *
|
2023-09-27 03:41:31 +00:00
|
|
|
neg_expr (const expr_t *e)
|
2023-09-02 04:43:22 +00:00
|
|
|
{
|
2023-09-02 08:21:16 +00:00
|
|
|
if (!e) {
|
|
|
|
// propagated zero
|
|
|
|
return 0;
|
|
|
|
}
|
2023-09-02 04:43:22 +00:00
|
|
|
if (is_neg (e)) {
|
2023-09-23 09:01:49 +00:00
|
|
|
return e->expr.e1;
|
2023-09-02 04:43:22 +00:00
|
|
|
}
|
|
|
|
auto type = get_type (e);
|
2024-09-30 10:15:44 +00:00
|
|
|
if (e->type == ex_alias && !e->alias.offset && anti_com (e->alias.expr)) {
|
|
|
|
auto n = neg_expr (e->alias.expr);
|
|
|
|
n = algebra_cast_expr (type, n);
|
|
|
|
return n;
|
|
|
|
}
|
2023-09-27 03:41:31 +00:00
|
|
|
expr_t *neg;
|
2023-09-02 10:42:33 +00:00
|
|
|
if (anti_com (e)) {
|
2023-09-27 03:41:31 +00:00
|
|
|
neg = new_binary_expr (e->expr.op, e->expr.e2, e->expr.e1);
|
2023-09-02 10:42:33 +00:00
|
|
|
} else {
|
2023-09-27 03:41:31 +00:00
|
|
|
neg = new_unary_expr ('-', e);
|
2023-09-02 10:42:33 +00:00
|
|
|
}
|
2023-09-27 03:41:31 +00:00
|
|
|
neg->expr.type = type;
|
2025-01-02 16:03:28 +00:00
|
|
|
return edag_add_expr (fold_constants (neg));
|
2023-09-02 04:43:22 +00:00
|
|
|
}
|
|
|
|
|
2023-10-01 07:29:14 +00:00
|
|
|
const expr_t *
|
2024-02-13 14:09:28 +00:00
|
|
|
ext_expr (const expr_t *src, const type_t *type, int extend, bool reverse)
|
2023-09-26 05:37:22 +00:00
|
|
|
{
|
|
|
|
if (!src) {
|
2024-04-06 16:10:54 +00:00
|
|
|
return nullptr;
|
2023-09-26 05:37:22 +00:00
|
|
|
}
|
|
|
|
bool neg = false;
|
|
|
|
if (is_neg (src)) {
|
|
|
|
neg = true;
|
|
|
|
src = neg_expr (src);
|
|
|
|
}
|
|
|
|
auto ext = edag_add_expr (new_extend_expr (src, type, extend, reverse));
|
|
|
|
if (neg) {
|
2023-09-27 03:41:31 +00:00
|
|
|
return neg_expr (ext);
|
2023-09-26 05:37:22 +00:00
|
|
|
}
|
|
|
|
return ext;
|
|
|
|
}
|
|
|
|
|
2023-09-28 01:58:25 +00:00
|
|
|
static bool __attribute__((const))
|
|
|
|
ext_compat (const ex_extend_t *a, const ex_extend_t *b)
|
|
|
|
{
|
|
|
|
return (a->extend == b->extend && a->reverse == b->reverse
|
|
|
|
&& a->type == b->type);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool __attribute__((const))
|
|
|
|
is_ext (const expr_t *e)
|
|
|
|
{
|
|
|
|
return e && e->type == ex_extend;
|
|
|
|
}
|
|
|
|
|
2023-09-27 03:41:31 +00:00
|
|
|
static const expr_t *
|
2024-02-13 14:09:28 +00:00
|
|
|
alias_expr (const type_t *type, const expr_t *e, int offset)
|
2023-09-02 04:43:22 +00:00
|
|
|
{
|
2023-09-02 08:21:16 +00:00
|
|
|
if (type == get_type (e)) {
|
|
|
|
if (offset) {
|
|
|
|
internal_error (e, "offset alias to same type");
|
|
|
|
}
|
|
|
|
return e;
|
|
|
|
}
|
2023-09-25 07:09:51 +00:00
|
|
|
e = edag_add_expr (e);
|
2023-09-02 04:43:22 +00:00
|
|
|
bool neg = false;
|
|
|
|
if (is_neg (e)) {
|
|
|
|
neg = true;
|
|
|
|
e = neg_expr (e);
|
|
|
|
}
|
2024-02-19 15:33:34 +00:00
|
|
|
if (e->type == ex_uexpr && e->expr.op == '.') {
|
2024-04-18 00:46:10 +00:00
|
|
|
auto offs = new_int_expr (offset, false);
|
2024-02-19 15:33:34 +00:00
|
|
|
auto ptr = e->expr.e1;
|
|
|
|
ptr = offset_pointer_expr (ptr, edag_add_expr (offs));
|
|
|
|
ptr = cast_expr (pointer_type (type), ptr);
|
|
|
|
e = unary_expr ('.', ptr);
|
|
|
|
} else {
|
|
|
|
e = new_offset_alias_expr (type, e, offset);
|
|
|
|
}
|
2023-09-02 04:43:22 +00:00
|
|
|
if (neg) {
|
2024-02-03 11:56:04 +00:00
|
|
|
e = edag_add_expr (e);
|
2023-09-02 04:43:22 +00:00
|
|
|
e = neg_expr (e);
|
|
|
|
}
|
2023-09-25 07:09:51 +00:00
|
|
|
return edag_add_expr (e);
|
2023-09-02 04:43:22 +00:00
|
|
|
}
|
|
|
|
|
2023-09-27 03:41:31 +00:00
|
|
|
static const expr_t *
|
2024-02-13 14:09:28 +00:00
|
|
|
offset_cast (const type_t *type, const expr_t *expr, int offset)
|
2023-08-26 14:57:37 +00:00
|
|
|
{
|
2023-09-02 08:21:16 +00:00
|
|
|
if (type->meta != ty_basic) {
|
|
|
|
internal_error (expr, "offset cast to non-basic type");
|
|
|
|
}
|
2023-09-18 10:36:15 +00:00
|
|
|
if (expr->type == ex_expr
|
2023-09-23 09:01:49 +00:00
|
|
|
&& (expr->expr.op == '+' || expr->expr.op == '-')) {
|
|
|
|
auto e1 = offset_cast (type, expr->expr.e1, offset);
|
|
|
|
auto e2 = offset_cast (type, expr->expr.e2, offset);
|
|
|
|
int op = expr->expr.op;
|
2023-09-18 10:36:15 +00:00
|
|
|
if (!e1) {
|
|
|
|
if (op == '-') {
|
|
|
|
e2 = neg_expr (e2);
|
2023-09-02 08:21:16 +00:00
|
|
|
}
|
2023-09-18 10:36:15 +00:00
|
|
|
return e2;
|
2023-09-02 08:21:16 +00:00
|
|
|
}
|
2023-09-18 10:36:15 +00:00
|
|
|
if (!e2) {
|
|
|
|
return e1;
|
2023-09-02 08:21:16 +00:00
|
|
|
}
|
2023-09-27 03:41:31 +00:00
|
|
|
auto cast = typed_binary_expr (type, op, e1, e2);
|
2023-09-25 07:09:51 +00:00
|
|
|
return edag_add_expr (cast);
|
2023-09-02 08:21:16 +00:00
|
|
|
}
|
|
|
|
if (expr->type == ex_extend) {
|
2023-09-23 09:01:49 +00:00
|
|
|
auto ext = expr->extend;
|
2023-09-02 08:21:16 +00:00
|
|
|
if (type_width (get_type (ext.src)) == type_width (type)) {
|
|
|
|
return alias_expr (type, ext.src, 0);
|
|
|
|
}
|
2023-09-18 12:43:23 +00:00
|
|
|
bool rev = ext.reverse;
|
|
|
|
int cwidth = type_width (type);
|
|
|
|
int dwidth = type_width (ext.type);
|
|
|
|
int swidth = type_width (get_type (ext.src));
|
|
|
|
|
|
|
|
if ((!rev && offset >= swidth)
|
|
|
|
|| (rev && offset + cwidth <= dwidth - swidth)) {
|
2023-09-02 08:21:16 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2023-09-18 15:47:29 +00:00
|
|
|
if (is_neg (expr)) {
|
2023-09-23 09:01:49 +00:00
|
|
|
auto e = expr->expr.e1;
|
2023-09-18 15:47:29 +00:00
|
|
|
if (e->type == ex_extend) {
|
|
|
|
return neg_expr (offset_cast (type, e, offset));
|
|
|
|
}
|
|
|
|
}
|
2023-08-26 14:57:37 +00:00
|
|
|
offset *= type_size (base_type (get_type (expr)));
|
2023-09-25 07:09:51 +00:00
|
|
|
return edag_add_expr (alias_expr (type, expr, offset));
|
2023-08-26 14:57:37 +00:00
|
|
|
}
|
|
|
|
|
2023-09-10 15:24:50 +00:00
|
|
|
static symtab_t *
|
2024-02-13 14:09:28 +00:00
|
|
|
get_mvec_struct (const type_t *type)
|
2023-08-29 07:17:07 +00:00
|
|
|
{
|
|
|
|
symbol_t *sym = 0;
|
|
|
|
if (type->type == ev_invalid) {
|
2024-08-16 08:23:29 +00:00
|
|
|
sym = type->algebra->mvec_sym;
|
2023-08-29 07:17:07 +00:00
|
|
|
} else {
|
2024-08-16 08:23:29 +00:00
|
|
|
sym = type->multivec->mvec_sym;
|
2023-08-29 07:17:07 +00:00
|
|
|
}
|
2024-08-16 08:23:29 +00:00
|
|
|
return sym ? sym->type->symtab : 0;
|
2023-09-10 15:24:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static symbol_t *
|
2024-02-13 14:09:28 +00:00
|
|
|
get_mvec_sym (const type_t *type)
|
2023-09-10 15:24:50 +00:00
|
|
|
{
|
|
|
|
auto symtab = get_mvec_struct (type);
|
|
|
|
return symtab ? symtab->symbols : 0;
|
2023-08-29 07:17:07 +00:00
|
|
|
}
|
|
|
|
|
2023-08-30 06:45:44 +00:00
|
|
|
static bool
|
2023-09-27 03:41:31 +00:00
|
|
|
check_types (const expr_t **e, algebra_t *algebra)
|
2023-08-30 06:45:44 +00:00
|
|
|
{
|
|
|
|
auto layout = &algebra->layout;
|
|
|
|
for (int i = 0; i < layout->count; i++) {
|
|
|
|
if (!e[i]) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
auto type = algebra_mvec_type (algebra, 1u << i);
|
|
|
|
if (get_type (e[i]) != type) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-09-27 03:41:31 +00:00
|
|
|
static const expr_t *
|
2024-02-13 14:09:28 +00:00
|
|
|
promote_scalar (const type_t *dst_type, const expr_t *scalar)
|
2023-09-04 02:06:28 +00:00
|
|
|
{
|
|
|
|
auto scalar_type = get_type (scalar);
|
|
|
|
if (scalar_type != dst_type) {
|
|
|
|
if (!type_promotes (dst_type, scalar_type)) {
|
|
|
|
warning (scalar, "demoting %s to %s (use a cast)",
|
|
|
|
get_type_string (scalar_type),
|
|
|
|
get_type_string (dst_type));
|
|
|
|
}
|
|
|
|
scalar = cast_expr (dst_type, scalar);
|
|
|
|
}
|
2023-09-25 07:09:51 +00:00
|
|
|
return edag_add_expr (scalar);
|
2023-09-04 02:06:28 +00:00
|
|
|
}
|
|
|
|
|
2023-10-01 07:29:14 +00:00
|
|
|
const expr_t *
|
2023-09-27 03:41:31 +00:00
|
|
|
mvec_expr (const expr_t *expr, algebra_t *algebra)
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
{
|
|
|
|
auto mvtype = get_type (expr);
|
2023-09-25 07:09:51 +00:00
|
|
|
expr = edag_add_expr (expr);
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
if (expr->type == ex_multivec || is_scalar (mvtype)) {
|
2023-09-04 02:06:28 +00:00
|
|
|
if (!is_algebra (mvtype)) {
|
|
|
|
expr = promote_scalar (algebra->type, expr);
|
|
|
|
}
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
return expr;
|
|
|
|
}
|
|
|
|
if (!is_algebra (mvtype)) {
|
|
|
|
return error (expr, "invalid operand for GA");
|
|
|
|
}
|
|
|
|
|
|
|
|
auto layout = &algebra->layout;
|
2023-09-11 01:25:35 +00:00
|
|
|
pr_uint_t group_mask = (1u << layout->count) - 1;
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
if (mvtype->type != ev_invalid) {
|
2024-08-16 08:23:29 +00:00
|
|
|
group_mask = mvtype->multivec->group_mask;
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
}
|
|
|
|
if (!(group_mask & (group_mask - 1))) {
|
|
|
|
return expr;
|
|
|
|
}
|
|
|
|
auto mvec = new_expr ();
|
|
|
|
mvec->type = ex_multivec;
|
2023-09-23 09:01:49 +00:00
|
|
|
mvec->multivec = (ex_multivec_t) {
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
.type = algebra_mvec_type (algebra, group_mask),
|
|
|
|
.algebra = algebra,
|
|
|
|
};
|
2023-09-27 08:42:44 +00:00
|
|
|
const expr_t *components[layout->count];
|
|
|
|
int count = 0;
|
2023-08-29 07:17:07 +00:00
|
|
|
for (auto sym = get_mvec_sym (mvtype); sym; sym = sym->next) {
|
2023-09-27 08:42:44 +00:00
|
|
|
auto c = &components[count++];
|
2024-08-16 07:48:11 +00:00
|
|
|
*c = new_offset_alias_expr (sym->type, expr, sym->offset);
|
2024-02-03 11:56:04 +00:00
|
|
|
*c = edag_add_expr (*c);
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
}
|
2023-09-27 08:42:44 +00:00
|
|
|
list_gather (&mvec->multivec.components, components, count);
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
|
|
|
|
return mvec;
|
|
|
|
}
|
|
|
|
|
2023-10-01 07:29:14 +00:00
|
|
|
void
|
2023-09-27 03:41:31 +00:00
|
|
|
mvec_scatter (const expr_t **components, const expr_t *mvec, algebra_t *algebra)
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
{
|
|
|
|
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");
|
|
|
|
}
|
2024-08-16 08:23:29 +00:00
|
|
|
pr_uint_t mask = type->multivec->group_mask;
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
if (mask & (mask - 1)) {
|
|
|
|
internal_error (mvec, "bare multivector in mvec_scatter");
|
|
|
|
}
|
|
|
|
group = BITOP_LOG2 (mask);
|
|
|
|
}
|
2023-09-25 07:09:51 +00:00
|
|
|
components[group] = edag_add_expr (mvec);
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
return;
|
|
|
|
}
|
2023-09-27 08:42:44 +00:00
|
|
|
for (auto li = mvec->multivec.components.head; li; li = li->next) {
|
|
|
|
auto c = li->expr;
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
auto ct = get_type (c);
|
2023-08-26 14:57:37 +00:00
|
|
|
if (!is_algebra (ct)) {
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
group = layout->group_map[layout->mask_map[0]][0];
|
|
|
|
} else if (ct->meta == ty_algebra && ct->type != ev_invalid) {
|
2024-08-16 08:23:29 +00:00
|
|
|
pr_uint_t mask = ct->multivec->group_mask;
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
if (mask & (mask - 1)) {
|
|
|
|
internal_error (mvec, "multivector in multivec expression");
|
|
|
|
}
|
|
|
|
group = BITOP_LOG2 (mask);
|
|
|
|
} else {
|
|
|
|
internal_error (mvec, "invalid type in multivec expression");
|
|
|
|
}
|
2023-09-27 08:42:44 +00:00
|
|
|
if (components[group]) {
|
|
|
|
internal_error (mvec, "duplicate group in multivec expression");
|
|
|
|
}
|
2023-09-25 07:09:51 +00:00
|
|
|
components[group] = edag_add_expr (c);
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-01 07:29:14 +00:00
|
|
|
const expr_t *
|
2023-09-27 03:41:31 +00:00
|
|
|
mvec_gather (const expr_t **components, algebra_t *algebra)
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
{
|
|
|
|
auto layout = &algebra->layout;
|
|
|
|
|
|
|
|
pr_uint_t group_mask = 0;
|
|
|
|
int count = 0;
|
2023-09-27 03:41:31 +00:00
|
|
|
const expr_t *vec = 0;
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
for (int i = 0; i < layout->count; i++) {
|
|
|
|
if (components[i]) {
|
|
|
|
count++;
|
2023-09-27 03:41:31 +00:00
|
|
|
vec = components[i];
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
group_mask |= 1 << i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (count == 1) {
|
2023-09-27 03:41:31 +00:00
|
|
|
return vec;
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
}
|
2023-08-26 14:57:37 +00:00
|
|
|
if (!count) {
|
|
|
|
return new_zero_expr (algebra->type);
|
|
|
|
}
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
|
2023-09-27 03:41:31 +00:00
|
|
|
auto mvec = new_expr ();
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
mvec->type = ex_multivec;
|
2023-09-23 09:01:49 +00:00
|
|
|
mvec->multivec = (ex_multivec_t) {
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
.type = algebra_mvec_type (algebra, group_mask),
|
|
|
|
.algebra = algebra,
|
|
|
|
};
|
|
|
|
for (int i = layout->count; i-- > 0; ) {
|
|
|
|
if (components[i]) {
|
2023-09-27 08:42:44 +00:00
|
|
|
list_append (&mvec->multivec.components, components[i]);
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return mvec;
|
|
|
|
}
|
2023-09-28 07:36:42 +00:00
|
|
|
|
2023-10-01 07:29:14 +00:00
|
|
|
bool
|
2023-09-28 07:36:42 +00:00
|
|
|
is_scale (const expr_t *expr)
|
2023-09-18 15:47:29 +00:00
|
|
|
{
|
2023-10-24 10:50:31 +00:00
|
|
|
return expr && expr->type == ex_expr && expr->expr.op == QC_SCALE;
|
2023-09-18 15:47:29 +00:00
|
|
|
}
|
2023-09-28 07:36:42 +00:00
|
|
|
|
2023-10-01 07:29:14 +00:00
|
|
|
const expr_t *
|
2023-09-27 03:41:31 +00:00
|
|
|
traverse_scale (const expr_t *expr)
|
2023-09-25 07:21:51 +00:00
|
|
|
{
|
2023-09-28 07:36:42 +00:00
|
|
|
while (is_scale (expr)) {
|
2023-09-25 07:21:51 +00:00
|
|
|
expr = expr->expr.e1;
|
|
|
|
}
|
|
|
|
return expr;
|
|
|
|
}
|
|
|
|
|
2023-10-01 07:29:14 +00:00
|
|
|
bool
|
2023-09-25 10:40:29 +00:00
|
|
|
is_sum (const expr_t *expr)
|
|
|
|
{
|
|
|
|
return (expr && expr->type == ex_expr
|
|
|
|
&& (expr->expr.op == '+' || expr->expr.op == '-'));
|
|
|
|
}
|
|
|
|
|
2023-10-01 12:30:41 +00:00
|
|
|
bool
|
2023-09-30 06:13:14 +00:00
|
|
|
is_mult (const expr_t *expr)
|
|
|
|
{
|
|
|
|
return (expr && expr->type == ex_expr
|
2023-10-24 10:50:31 +00:00
|
|
|
&& (expr->expr.op == '*' || expr->expr.op == QC_HADAMARD));
|
2023-09-30 06:13:14 +00:00
|
|
|
}
|
|
|
|
|
2023-10-01 07:29:14 +00:00
|
|
|
int
|
2023-09-25 10:40:29 +00:00
|
|
|
count_terms (const expr_t *expr)
|
|
|
|
{
|
|
|
|
if (!is_sum (expr)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
auto e1 = expr->expr.e1;
|
|
|
|
auto e2 = expr->expr.e2;
|
2024-08-10 05:19:07 +00:00
|
|
|
int terms = !is_sum (e1) + !is_sum (e2);
|
2024-09-30 04:51:52 +00:00
|
|
|
if (!e1->paren && is_sum (e1)) {
|
2023-09-25 10:40:29 +00:00
|
|
|
terms += count_terms (expr->expr.e1);
|
|
|
|
}
|
2024-09-30 04:51:52 +00:00
|
|
|
if (!e2->paren && is_sum (e2)) {
|
2023-09-25 10:40:29 +00:00
|
|
|
terms += count_terms (expr->expr.e2);
|
|
|
|
}
|
|
|
|
return terms;
|
|
|
|
}
|
|
|
|
|
2023-10-01 12:30:41 +00:00
|
|
|
int __attribute__((pure))
|
2023-09-30 06:13:14 +00:00
|
|
|
count_factors (const expr_t *expr)
|
|
|
|
{
|
|
|
|
if (!is_mult (expr)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
auto e1 = expr->expr.e1;
|
|
|
|
auto e2 = expr->expr.e2;
|
2024-08-10 05:19:07 +00:00
|
|
|
int terms = !is_mult (e1) + !is_mult (e2);
|
2023-09-30 06:13:14 +00:00
|
|
|
if (is_mult (e1)) {
|
|
|
|
terms += count_factors (expr->expr.e1);
|
|
|
|
}
|
|
|
|
if (is_mult (e2)) {
|
|
|
|
terms += count_factors (expr->expr.e2);
|
|
|
|
}
|
|
|
|
return terms;
|
|
|
|
}
|
|
|
|
|
2023-10-01 07:29:14 +00:00
|
|
|
bool __attribute__((pure))
|
2023-09-25 10:40:29 +00:00
|
|
|
is_cross (const expr_t *expr)
|
|
|
|
{
|
2023-10-24 10:50:31 +00:00
|
|
|
return (expr && expr->type == ex_expr && (expr->expr.op == QC_CROSS));
|
2023-09-25 10:40:29 +00:00
|
|
|
}
|
|
|
|
|
2023-09-30 06:13:14 +00:00
|
|
|
static void
|
2023-10-01 12:30:41 +00:00
|
|
|
scatter_factors_core (const expr_t *prod, const expr_t **factors, int *ind)
|
2023-09-30 06:13:14 +00:00
|
|
|
{
|
|
|
|
auto e1 = prod->expr.e1;
|
|
|
|
auto e2 = prod->expr.e2;
|
|
|
|
if (is_mult (e1)) {
|
2023-10-01 12:30:41 +00:00
|
|
|
scatter_factors_core (e1, factors, ind);
|
2023-09-30 06:13:14 +00:00
|
|
|
} else {
|
|
|
|
factors[(*ind)++] = e1;
|
|
|
|
}
|
|
|
|
if (is_mult (e2)) {
|
2023-10-01 12:30:41 +00:00
|
|
|
scatter_factors_core (e2, factors, ind);
|
2023-09-30 06:13:14 +00:00
|
|
|
} else {
|
|
|
|
factors[(*ind)++] = e2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-01 12:30:41 +00:00
|
|
|
void
|
|
|
|
scatter_factors (const expr_t *prod, const expr_t **factors)
|
2023-09-30 06:13:14 +00:00
|
|
|
{
|
|
|
|
if (!is_mult (prod)) {
|
2023-10-01 12:30:41 +00:00
|
|
|
internal_error (prod, "scatter_factors with no product");
|
2023-09-30 06:13:14 +00:00
|
|
|
}
|
|
|
|
int ind = 0;
|
2023-10-01 12:30:41 +00:00
|
|
|
scatter_factors_core (prod, factors, &ind);
|
2023-09-30 06:13:14 +00:00
|
|
|
}
|
|
|
|
|
2023-10-01 12:30:41 +00:00
|
|
|
const expr_t *
|
2024-02-13 14:09:28 +00:00
|
|
|
gather_factors (const type_t *type, int op, const expr_t **factors, int count)
|
2023-09-30 06:13:14 +00:00
|
|
|
{
|
|
|
|
if (!count) {
|
|
|
|
internal_error (0, "no factors to collect");
|
|
|
|
}
|
|
|
|
if (count == 1) {
|
|
|
|
return *factors;
|
|
|
|
}
|
|
|
|
const expr_t *a, *b;
|
|
|
|
if (count == 2) {
|
|
|
|
a = factors[0];
|
|
|
|
b = factors[1];
|
|
|
|
} else {
|
|
|
|
int mid = (count + 1) / 2;
|
2023-10-01 12:30:41 +00:00
|
|
|
a = gather_factors (type, op, factors, mid);
|
|
|
|
b = gather_factors (type, op, factors + mid, count - mid);
|
2023-09-30 06:13:14 +00:00
|
|
|
}
|
|
|
|
auto prod = typed_binary_expr (type, op, a, b);
|
|
|
|
return edag_add_expr (prod);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
expr_ptr_cmp (const void *_a, const void *_b)
|
|
|
|
{
|
|
|
|
auto a = *(const expr_t **) _a;
|
|
|
|
auto b = *(const expr_t **) _b;
|
|
|
|
return a - b;
|
|
|
|
}
|
|
|
|
#if 0
|
|
|
|
static void
|
|
|
|
insert_expr (const expr_t **array, const expr_t *e, int count)
|
|
|
|
{
|
|
|
|
auto dst = array;
|
|
|
|
if (e > *dst) {
|
|
|
|
dst = fbsearch (e, array, count, sizeof (dst[0]), expr_ptr_cmp);
|
|
|
|
}
|
|
|
|
memmove (dst + 1, dst, sizeof (expr_t *[count - (dst - array)]));
|
|
|
|
*dst = e;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
static const expr_t *
|
2024-02-13 14:09:28 +00:00
|
|
|
sort_factors (const type_t *type, const expr_t *e)
|
2023-09-30 06:13:14 +00:00
|
|
|
{
|
|
|
|
if (!is_mult (e)) {
|
|
|
|
internal_error (e, "not a product");
|
|
|
|
}
|
|
|
|
|
|
|
|
int count = count_factors (e);
|
|
|
|
const expr_t *factors[count + 1] = {};
|
2023-10-01 12:30:41 +00:00
|
|
|
scatter_factors (e, factors);
|
2023-09-30 06:13:14 +00:00
|
|
|
heapsort (factors, count, sizeof (factors[0]), expr_ptr_cmp);
|
2023-10-01 12:30:41 +00:00
|
|
|
auto mult = gather_factors (type, '*', factors, count);
|
2023-09-30 06:13:14 +00:00
|
|
|
return mult;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const expr_t *
|
2024-02-13 14:09:28 +00:00
|
|
|
sum_expr_low (const type_t *type, int op, const expr_t *a, const expr_t *b)
|
2023-09-30 06:13:14 +00:00
|
|
|
{
|
|
|
|
if (!a) {
|
|
|
|
return op == '-' ? neg_expr (b) : b;
|
|
|
|
}
|
|
|
|
if (!b) {
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
if (op == '-' && a == b) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto sum = typed_binary_expr (type, op, a, b);
|
2025-01-02 16:03:28 +00:00
|
|
|
sum = fold_constants (sum);
|
2023-09-30 06:13:14 +00:00
|
|
|
sum = edag_add_expr (sum);
|
|
|
|
return sum;
|
|
|
|
}
|
|
|
|
|
2023-09-25 10:40:29 +00:00
|
|
|
static void
|
2023-10-01 07:29:14 +00:00
|
|
|
scatter_terms_core (const expr_t *sum,
|
2023-09-27 03:41:31 +00:00
|
|
|
const expr_t **adds, int *addind,
|
|
|
|
const expr_t **subs, int *subind, bool negative)
|
2023-09-25 10:40:29 +00:00
|
|
|
{
|
|
|
|
bool subtract = (sum->expr.op == '-') ^ negative;
|
|
|
|
auto e1 = sum->expr.e1;
|
|
|
|
auto e2 = sum->expr.e2;
|
2024-09-30 04:51:52 +00:00
|
|
|
if (!e1->paren && is_sum (e1)) {
|
2023-10-01 07:29:14 +00:00
|
|
|
scatter_terms_core (e1, adds, addind, subs, subind, negative);
|
2023-09-25 10:40:29 +00:00
|
|
|
}
|
2024-09-30 04:51:52 +00:00
|
|
|
if (!e2->paren && is_sum (e2)) {
|
2023-10-01 07:29:14 +00:00
|
|
|
scatter_terms_core (e2, adds, addind, subs, subind, subtract);
|
2023-09-25 10:40:29 +00:00
|
|
|
}
|
2024-09-30 04:51:52 +00:00
|
|
|
if (e1->paren || !is_sum (e1)) {
|
2023-09-26 05:37:22 +00:00
|
|
|
auto e = sum->expr.e1;
|
|
|
|
auto arr = negative ^ is_neg (e) ? subs : adds;
|
|
|
|
auto ind = negative ^ is_neg (e) ? subind : addind;
|
|
|
|
if (is_neg (e)) {
|
|
|
|
e = neg_expr (e);
|
2023-09-25 10:40:29 +00:00
|
|
|
}
|
2023-09-26 05:37:22 +00:00
|
|
|
arr[(*ind)++] = e;
|
2023-09-25 10:40:29 +00:00
|
|
|
}
|
2024-09-30 04:51:52 +00:00
|
|
|
if (e2->paren || !is_sum (e2)) {
|
2023-09-26 05:37:22 +00:00
|
|
|
auto e = sum->expr.e2;
|
|
|
|
auto arr = subtract ^ is_neg (e) ? subs : adds;
|
|
|
|
auto ind = subtract ^ is_neg (e) ? subind : addind;
|
|
|
|
if (is_neg (e)) {
|
|
|
|
e = neg_expr (e);
|
2023-09-25 10:40:29 +00:00
|
|
|
}
|
2023-09-26 05:37:22 +00:00
|
|
|
arr[(*ind)++] = e;
|
2023-09-25 10:40:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-01 07:29:14 +00:00
|
|
|
void
|
|
|
|
scatter_terms (const expr_t *sum, const expr_t **adds, const expr_t **subs)
|
2023-09-25 10:40:29 +00:00
|
|
|
{
|
|
|
|
if (!is_sum (sum)) {
|
2023-10-01 07:29:14 +00:00
|
|
|
internal_error (sum, "scatter_terms with no sum");
|
2023-09-25 10:40:29 +00:00
|
|
|
}
|
2023-09-30 06:13:14 +00:00
|
|
|
|
|
|
|
int addind = 0;
|
|
|
|
int subind = 0;
|
2023-10-01 07:29:14 +00:00
|
|
|
scatter_terms_core (sum, adds, &addind, subs, &subind, false);
|
2023-09-25 10:40:29 +00:00
|
|
|
}
|
|
|
|
|
2023-10-01 07:29:14 +00:00
|
|
|
const expr_t *
|
2024-02-13 14:09:28 +00:00
|
|
|
gather_terms (const type_t *type, const expr_t **adds, const expr_t **subs)
|
2023-09-25 10:40:29 +00:00
|
|
|
{
|
2023-09-27 03:41:31 +00:00
|
|
|
const expr_t *a = 0;
|
|
|
|
const expr_t *b = 0;
|
2023-09-25 10:40:29 +00:00
|
|
|
for (auto s = adds; *s; s++) {
|
2023-09-26 05:37:22 +00:00
|
|
|
a = sum_expr_low (type, '+', a, *s);
|
2023-09-25 10:40:29 +00:00
|
|
|
}
|
|
|
|
for (auto s = subs; *s; s++) {
|
2023-09-26 05:37:22 +00:00
|
|
|
b = sum_expr_low (type, '+', b, *s);
|
|
|
|
}
|
|
|
|
auto sum = sum_expr_low (type, '-', a, b);
|
|
|
|
return sum;
|
|
|
|
}
|
|
|
|
|
2024-02-13 14:09:28 +00:00
|
|
|
static const expr_t *sum_expr (const type_t *type,
|
|
|
|
const expr_t *a, const expr_t *b);
|
2023-09-28 01:58:25 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
merge_extends (const expr_t **adds, const expr_t **subs)
|
|
|
|
{
|
|
|
|
for (auto scan = adds; *scan; scan++) {
|
|
|
|
if (!is_ext (*scan)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
auto extend = (*scan)->extend;
|
|
|
|
auto type = get_type (extend.src);
|
|
|
|
auto dst = scan + 1;
|
|
|
|
for (auto src = dst; *src; src++) {
|
|
|
|
if (is_ext (*src) && ext_compat (&extend, &(*src)->extend)) {
|
|
|
|
extend.src = sum_expr (type, extend.src,
|
|
|
|
(*src)->extend.src);
|
|
|
|
} else {
|
|
|
|
*dst++ = *src;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*dst = 0;
|
|
|
|
dst = subs;
|
|
|
|
for (auto src = dst; *src; src++) {
|
|
|
|
if (is_ext (*src) && ext_compat (&extend, &(*src)->extend)) {
|
|
|
|
extend.src = sum_expr (type, extend.src,
|
|
|
|
neg_expr ((*src)->extend.src));
|
|
|
|
} else {
|
|
|
|
*dst++ = *src;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*scan = ext_expr (extend.src, extend.type,
|
|
|
|
extend.extend, extend.reverse);
|
|
|
|
*dst = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-27 03:41:31 +00:00
|
|
|
static const expr_t *
|
2024-02-13 14:09:28 +00:00
|
|
|
sum_expr (const type_t *type, const expr_t *a, const expr_t *b)
|
2023-09-26 05:37:22 +00:00
|
|
|
{
|
|
|
|
if (!a) {
|
2024-02-11 12:47:21 +00:00
|
|
|
return cast_expr (type, b);
|
2023-09-25 10:40:29 +00:00
|
|
|
}
|
2023-09-26 05:37:22 +00:00
|
|
|
if (!b) {
|
2024-02-11 12:47:21 +00:00
|
|
|
return cast_expr (type, a);
|
2023-09-26 05:37:22 +00:00
|
|
|
}
|
|
|
|
|
2023-09-27 03:41:31 +00:00
|
|
|
auto sum = typed_binary_expr (type, '+', a, b);
|
2023-09-26 05:37:22 +00:00
|
|
|
int num_terms = count_terms (sum);
|
2023-09-27 03:41:31 +00:00
|
|
|
const expr_t *adds[num_terms + 1] = {};
|
|
|
|
const expr_t *subs[num_terms + 1] = {};
|
2023-10-01 07:29:14 +00:00
|
|
|
scatter_terms (sum, adds, subs);
|
2023-09-27 03:41:31 +00:00
|
|
|
const expr_t **dstadd, **srcadd;
|
|
|
|
const expr_t **dstsub, **srcsub;
|
2023-09-26 05:37:22 +00:00
|
|
|
|
2023-09-28 01:58:25 +00:00
|
|
|
merge_extends (adds, subs);
|
|
|
|
|
2023-09-30 06:13:14 +00:00
|
|
|
for (auto term = adds; *term; term++) {
|
|
|
|
if (is_mult (*term)) {
|
|
|
|
*term = sort_factors (type, *term);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto term = subs; *term; term++) {
|
|
|
|
if (is_mult (*term)) {
|
|
|
|
*term = sort_factors (type, *term);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-26 05:37:22 +00:00
|
|
|
for (dstadd = adds, srcadd = adds; *srcadd; srcadd++) {
|
|
|
|
for (dstsub = subs, srcsub = subs; *srcsub; srcsub++) {
|
|
|
|
if (*srcadd == *srcsub) {
|
|
|
|
// found a-a
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2023-09-29 12:53:56 +00:00
|
|
|
dstsub = srcsub;
|
2023-09-26 05:37:22 +00:00
|
|
|
if (*srcsub++) {
|
|
|
|
// found a-a
|
|
|
|
while (*srcsub) {
|
|
|
|
*dstsub++ = *srcsub++;
|
|
|
|
}
|
|
|
|
*dstsub = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
*dstadd++ = *srcadd;
|
|
|
|
}
|
|
|
|
*dstadd = 0;
|
2023-10-01 07:29:14 +00:00
|
|
|
sum = gather_terms (type, adds, subs);
|
2023-09-26 05:37:22 +00:00
|
|
|
return sum;
|
2023-09-25 10:40:29 +00:00
|
|
|
}
|
|
|
|
|
2023-08-21 08:37:56 +00:00
|
|
|
static void
|
2023-09-27 03:41:31 +00:00
|
|
|
component_sum (int op, const expr_t **c, const expr_t **a, const expr_t **b,
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
algebra_t *algebra)
|
2023-08-21 08:37:56 +00:00
|
|
|
{
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
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");
|
|
|
|
}
|
2023-08-25 08:26:09 +00:00
|
|
|
auto sum_type = get_type (a[i]);
|
2023-09-02 08:21:16 +00:00
|
|
|
if (op == '+') {
|
|
|
|
c[i] = sum_expr (sum_type, a[i], b[i]);
|
|
|
|
} else {
|
|
|
|
c[i] = sum_expr (sum_type, a[i], neg_expr (b[i]));
|
|
|
|
}
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
} else if (a[i]) {
|
|
|
|
c[i] = a[i];
|
|
|
|
} else if (b[i]) {
|
|
|
|
if (op == '+') {
|
|
|
|
c[i] = b[i];
|
|
|
|
} else {
|
2023-09-02 08:21:16 +00:00
|
|
|
c[i] = neg_expr (b[i]);
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
}
|
2023-08-21 11:10:13 +00:00
|
|
|
} else {
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
c[i] = 0;
|
2023-08-21 11:10:13 +00:00
|
|
|
}
|
2023-08-21 08:37:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-28 15:44:09 +00:00
|
|
|
static const expr_t *
|
2024-02-13 14:09:28 +00:00
|
|
|
distribute_product (const type_t *type, const expr_t *a, const expr_t *b,
|
|
|
|
const expr_t *(*product) (const type_t *type,
|
2023-09-29 04:29:19 +00:00
|
|
|
const expr_t *a, const expr_t *b),
|
|
|
|
bool anti_com)
|
2023-09-28 15:44:09 +00:00
|
|
|
{
|
2023-09-29 02:00:44 +00:00
|
|
|
bool neg = false;
|
|
|
|
if (is_neg (a)) {
|
|
|
|
neg = !neg;
|
|
|
|
a = neg_expr (a);
|
|
|
|
}
|
|
|
|
if (is_neg (b)) {
|
|
|
|
neg = !neg;
|
|
|
|
b = neg_expr (b);
|
|
|
|
}
|
2023-09-29 04:29:19 +00:00
|
|
|
if (anti_com && neg) {
|
2023-09-29 02:00:44 +00:00
|
|
|
auto t = a;
|
|
|
|
a = b;
|
|
|
|
b = t;
|
|
|
|
neg = false;
|
|
|
|
}
|
|
|
|
|
2023-09-28 15:44:09 +00:00
|
|
|
int a_terms = count_terms (a);
|
|
|
|
int b_terms = count_terms (b);
|
|
|
|
|
|
|
|
const expr_t *a_adds[a_terms + 2] = {};
|
|
|
|
const expr_t *a_subs[a_terms + 2] = {};
|
|
|
|
const expr_t *b_adds[b_terms + 2] = {};
|
|
|
|
const expr_t *b_subs[a_terms + 2] = {};
|
|
|
|
|
|
|
|
if (a_terms) {
|
2023-10-01 07:29:14 +00:00
|
|
|
scatter_terms (a, a_adds, a_subs);
|
2023-09-28 15:44:09 +00:00
|
|
|
} else {
|
|
|
|
a_adds[0] = a;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (b_terms) {
|
2023-10-01 07:29:14 +00:00
|
|
|
scatter_terms (b, b_adds, b_subs);
|
2023-09-28 15:44:09 +00:00
|
|
|
} else {
|
|
|
|
b_adds[0] = b;
|
|
|
|
}
|
|
|
|
|
|
|
|
a = b = 0;
|
|
|
|
|
|
|
|
for (auto i = a_adds; *i; i++) {
|
|
|
|
for (auto j = b_adds; *j; j++) {
|
2023-09-29 04:29:19 +00:00
|
|
|
auto p = product (type, *i, *j);
|
|
|
|
if (p) {
|
2025-01-02 16:03:28 +00:00
|
|
|
p = fold_constants (p);
|
2023-09-28 15:44:09 +00:00
|
|
|
p = edag_add_expr (p);
|
|
|
|
a = sum_expr (type, a, p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (auto i = a_subs; *i; i++) {
|
|
|
|
for (auto j = b_subs; *j; j++) {
|
2023-09-29 04:29:19 +00:00
|
|
|
auto p = product (type, *i, *j);
|
|
|
|
if (p) {
|
2025-01-02 16:03:28 +00:00
|
|
|
p = fold_constants (p);
|
2023-09-28 15:44:09 +00:00
|
|
|
p = edag_add_expr (p);
|
|
|
|
a = sum_expr (type, a, p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (auto i = a_adds; *i; i++) {
|
|
|
|
for (auto j = b_subs; *j; j++) {
|
2023-09-29 04:29:19 +00:00
|
|
|
auto p = product (type, *i, *j);
|
|
|
|
if (p) {
|
2025-01-02 16:03:28 +00:00
|
|
|
p = fold_constants (p);
|
2023-09-28 15:44:09 +00:00
|
|
|
p = edag_add_expr (p);
|
|
|
|
b = sum_expr (type, b, p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (auto i = a_subs; *i; i++) {
|
|
|
|
for (auto j = b_adds; *j; j++) {
|
2023-09-29 04:29:19 +00:00
|
|
|
auto p = product (type, *i, *j);
|
|
|
|
if (p) {
|
2025-01-02 16:03:28 +00:00
|
|
|
p = fold_constants (p);
|
2023-09-28 15:44:09 +00:00
|
|
|
p = edag_add_expr (p);
|
|
|
|
b = sum_expr (type, b, p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-09-29 02:00:44 +00:00
|
|
|
if (neg) {
|
|
|
|
// note order ----------------------V--V
|
|
|
|
auto sum = sum_expr_low (type, '-', b, a);
|
|
|
|
return sum;
|
|
|
|
} else {
|
|
|
|
// note order ----------------------V--V
|
|
|
|
auto sum = sum_expr_low (type, '-', a, b);
|
|
|
|
return sum;
|
|
|
|
}
|
2023-09-28 15:44:09 +00:00
|
|
|
}
|
|
|
|
|
2023-09-29 04:13:35 +00:00
|
|
|
static const expr_t *
|
|
|
|
extract_scale (const expr_t **expr, const expr_t *prod)
|
|
|
|
{
|
|
|
|
if (is_scale (*expr)) {
|
|
|
|
auto s = (*expr)->expr.e2;
|
|
|
|
prod = prod ? scale_expr (get_type (prod), prod, s) : s;
|
|
|
|
*expr = (*expr)->expr.e1;
|
|
|
|
}
|
|
|
|
return prod;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const expr_t *
|
2024-02-13 14:09:28 +00:00
|
|
|
apply_scale (const type_t *type, const expr_t *expr, const expr_t *prod)
|
2023-09-29 04:13:35 +00:00
|
|
|
{
|
|
|
|
if (expr && prod) {
|
2025-01-02 16:03:28 +00:00
|
|
|
expr = fold_constants (expr);
|
2023-09-29 09:39:33 +00:00
|
|
|
expr = edag_add_expr (expr);
|
2023-09-29 04:13:35 +00:00
|
|
|
expr = scale_expr (type, expr, prod);
|
|
|
|
}
|
|
|
|
return expr;
|
|
|
|
}
|
|
|
|
|
2023-09-29 04:29:19 +00:00
|
|
|
static const expr_t *
|
2024-02-13 14:09:28 +00:00
|
|
|
do_mult (const type_t *type, const expr_t *a, const expr_t *b)
|
2023-09-29 04:29:19 +00:00
|
|
|
{
|
|
|
|
return typed_binary_expr (type, '*', a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const expr_t *
|
2024-02-13 14:09:28 +00:00
|
|
|
do_scale (const type_t *type, const expr_t *a, const expr_t *b)
|
2023-09-29 04:29:19 +00:00
|
|
|
{
|
2023-09-29 06:06:07 +00:00
|
|
|
const expr_t *prod = extract_scale (&a, b);
|
|
|
|
if (prod) {
|
|
|
|
b = prod;
|
|
|
|
}
|
2023-10-24 10:50:31 +00:00
|
|
|
return typed_binary_expr (type, QC_SCALE, a, b);
|
2023-09-29 04:29:19 +00:00
|
|
|
}
|
|
|
|
|
2023-10-01 07:29:14 +00:00
|
|
|
const expr_t *
|
2024-02-13 14:09:28 +00:00
|
|
|
scale_expr (const type_t *type, const expr_t *a, const expr_t *b)
|
2023-08-25 08:24:47 +00:00
|
|
|
{
|
2023-09-02 08:21:16 +00:00
|
|
|
if (!a || !b) {
|
|
|
|
// propagated zero
|
|
|
|
return 0;
|
|
|
|
}
|
2023-08-25 08:24:47 +00:00
|
|
|
if (!is_scalar (get_type (b)) || !is_real (get_type (b))) {
|
|
|
|
internal_error (b, "not a real scalar type");
|
2023-08-23 12:51:01 +00:00
|
|
|
}
|
2023-08-31 11:22:59 +00:00
|
|
|
if (!is_real (get_type (b))) {
|
2023-08-25 08:24:47 +00:00
|
|
|
internal_error (b, "not a real scalar type");
|
|
|
|
}
|
2023-08-23 12:51:01 +00:00
|
|
|
|
2023-09-29 04:29:19 +00:00
|
|
|
auto op = is_scalar (get_type (a)) ? do_mult : do_scale;
|
|
|
|
auto scale = distribute_product (type, a, b, op, false);
|
2023-09-28 15:44:09 +00:00
|
|
|
if (!scale) {
|
|
|
|
return 0;
|
|
|
|
}
|
2023-09-11 03:29:10 +00:00
|
|
|
scale = cast_expr (type, scale);
|
2023-09-25 07:09:51 +00:00
|
|
|
scale = edag_add_expr (scale);
|
2023-09-02 04:18:27 +00:00
|
|
|
return scale;
|
2023-09-02 02:18:50 +00:00
|
|
|
}
|
|
|
|
|
2023-09-28 15:44:09 +00:00
|
|
|
static bool __attribute__((pure))
|
|
|
|
reject_dot (const expr_t *a, const expr_t *b)
|
|
|
|
{
|
|
|
|
a = traverse_scale (a);
|
|
|
|
b = traverse_scale (b);
|
|
|
|
if (is_cross (a)) {
|
|
|
|
if (b == traverse_scale (a->expr.e1)
|
|
|
|
|| b == traverse_scale (a->expr.e2)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (is_cross (b)) {
|
|
|
|
if (a == traverse_scale (b->expr.e1)
|
|
|
|
|| a == traverse_scale (b->expr.e2)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-09-29 04:29:19 +00:00
|
|
|
static const expr_t *
|
2024-02-13 14:09:28 +00:00
|
|
|
do_dot (const type_t *type, const expr_t *a, const expr_t *b)
|
2023-09-29 04:29:19 +00:00
|
|
|
{
|
|
|
|
if (reject_dot (a, b)) {
|
|
|
|
return 0;
|
|
|
|
}
|
2023-09-29 06:06:07 +00:00
|
|
|
|
|
|
|
const expr_t *prod = 0;
|
|
|
|
prod = extract_scale (&a, prod);
|
|
|
|
prod = extract_scale (&b, prod);
|
|
|
|
|
2023-10-24 10:50:31 +00:00
|
|
|
auto dot = typed_binary_expr (type, QC_DOT, a, b);
|
2023-09-29 06:06:07 +00:00
|
|
|
dot = apply_scale (type, dot, prod);
|
|
|
|
return dot;
|
2023-09-29 04:29:19 +00:00
|
|
|
}
|
|
|
|
|
2023-09-27 03:41:31 +00:00
|
|
|
static const expr_t *
|
2024-02-13 14:09:28 +00:00
|
|
|
dot_expr (const type_t *type, const expr_t *a, const expr_t *b)
|
2023-08-23 06:31:20 +00:00
|
|
|
{
|
2023-09-02 08:21:16 +00:00
|
|
|
if (!a || !b) {
|
|
|
|
// propagated zero
|
|
|
|
return 0;
|
|
|
|
}
|
2023-09-02 04:18:27 +00:00
|
|
|
|
2023-09-29 04:29:19 +00:00
|
|
|
auto dot = distribute_product (type, a, b, do_dot, false);
|
2023-08-23 06:31:20 +00:00
|
|
|
return dot;
|
|
|
|
}
|
|
|
|
|
2023-09-28 15:44:09 +00:00
|
|
|
static bool __attribute__((pure))
|
|
|
|
reject_cross (const expr_t *a, const expr_t *b)
|
|
|
|
{
|
|
|
|
return traverse_scale (a) == traverse_scale (b);
|
|
|
|
}
|
|
|
|
|
2023-09-29 04:29:19 +00:00
|
|
|
static const expr_t *
|
2024-02-13 14:09:28 +00:00
|
|
|
do_cross (const type_t *type, const expr_t *a, const expr_t *b)
|
2023-09-29 04:29:19 +00:00
|
|
|
{
|
|
|
|
if (reject_cross (a, b)) {
|
|
|
|
return 0;
|
|
|
|
}
|
2023-09-29 06:06:07 +00:00
|
|
|
|
|
|
|
const expr_t *prod = 0;
|
|
|
|
prod = extract_scale (&a, prod);
|
|
|
|
prod = extract_scale (&b, prod);
|
|
|
|
|
2023-10-24 10:50:31 +00:00
|
|
|
auto cross = typed_binary_expr (type, QC_CROSS, a, b);
|
2023-09-29 06:06:07 +00:00
|
|
|
cross = apply_scale (type, cross, prod);
|
|
|
|
return cross;
|
2023-09-29 04:29:19 +00:00
|
|
|
}
|
|
|
|
|
2023-09-27 03:41:31 +00:00
|
|
|
static const expr_t *
|
2024-02-13 14:09:28 +00:00
|
|
|
cross_expr (const type_t *type, const expr_t *a, const expr_t *b)
|
2023-08-24 06:49:52 +00:00
|
|
|
{
|
2023-09-02 08:21:16 +00:00
|
|
|
if (!a || !b) {
|
|
|
|
// propagated zero
|
|
|
|
return 0;
|
|
|
|
}
|
2023-09-25 07:21:51 +00:00
|
|
|
|
2023-09-29 04:29:19 +00:00
|
|
|
auto cross = distribute_product (type, a, b, do_cross, true);
|
2023-08-24 06:49:52 +00:00
|
|
|
return cross;
|
|
|
|
}
|
|
|
|
|
2023-09-28 15:44:09 +00:00
|
|
|
static bool __attribute__((pure))
|
|
|
|
reject_wedge (const expr_t *a, const expr_t *b)
|
|
|
|
{
|
|
|
|
return traverse_scale (a) == traverse_scale (b);
|
|
|
|
}
|
|
|
|
|
2023-09-29 04:29:19 +00:00
|
|
|
static const expr_t *
|
2024-02-13 14:09:28 +00:00
|
|
|
do_wedge (const type_t *type, const expr_t *a, const expr_t *b)
|
2023-09-29 04:29:19 +00:00
|
|
|
{
|
|
|
|
if (reject_wedge (a, b)) {
|
|
|
|
return 0;
|
|
|
|
}
|
2023-09-29 06:06:07 +00:00
|
|
|
|
|
|
|
const expr_t *prod = 0;
|
|
|
|
prod = extract_scale (&a, prod);
|
|
|
|
prod = extract_scale (&b, prod);
|
|
|
|
|
2023-10-24 10:50:31 +00:00
|
|
|
auto wedge = typed_binary_expr (type, QC_WEDGE, a, b);
|
2023-09-29 06:06:07 +00:00
|
|
|
wedge = apply_scale (type, wedge, prod);
|
|
|
|
return wedge;
|
2023-09-29 04:29:19 +00:00
|
|
|
}
|
|
|
|
|
2023-09-27 03:41:31 +00:00
|
|
|
static const expr_t *
|
2024-02-13 14:09:28 +00:00
|
|
|
wedge_expr (const type_t *type, const expr_t *a, const expr_t *b)
|
2023-08-31 11:22:59 +00:00
|
|
|
{
|
2023-09-02 08:21:16 +00:00
|
|
|
if (!a || !b) {
|
|
|
|
// propagated zero
|
|
|
|
return 0;
|
|
|
|
}
|
2023-09-29 04:29:19 +00:00
|
|
|
auto wedge = distribute_product (type, a, b, do_wedge, true);
|
2023-09-25 07:09:51 +00:00
|
|
|
return wedge;
|
2023-08-31 11:22:59 +00:00
|
|
|
}
|
|
|
|
|
2023-09-28 04:53:52 +00:00
|
|
|
typedef void (*pga_func) (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg);
|
|
|
|
|
2023-08-23 06:31:20 +00:00
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
scale_component (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-23 06:31:20 +00:00
|
|
|
{
|
2023-08-26 14:57:37 +00:00
|
|
|
if (is_algebra (get_type (b))) {
|
2023-08-25 08:24:47 +00:00
|
|
|
auto t = a;
|
|
|
|
a = b;
|
|
|
|
b = t;
|
|
|
|
}
|
2023-08-26 14:57:37 +00:00
|
|
|
if (!is_algebra (get_type (a))) {
|
2023-08-25 08:24:47 +00:00
|
|
|
a = promote_scalar (alg->type, a);
|
|
|
|
}
|
|
|
|
auto scale_type = get_type (a);
|
|
|
|
b = promote_scalar (alg->type, b);
|
|
|
|
auto scale = scale_expr (scale_type, a, b);
|
|
|
|
int group = get_group (scale_type, alg);
|
2023-08-23 06:31:20 +00:00
|
|
|
c[group] = scale;
|
|
|
|
}
|
|
|
|
|
[qfcc] Split up pga3 4-component scales
While splitting up the scaled vector into scaled xyz and scaled w does
cost an extra instruction, it allows for other optimizations to be
applied. For one, extends get all the way to the top now, and there are
at most two (in my test cases), thus either break-even or even a slight
reduction in instruction count. However, in the initial implementation,
I forgot to do the actual scaling, and 12 instructions were removed from
my fancy zero case, but real tests failed :P It looks like it's just
distributivity and commutativity holding things back (eg,
omega*gamma*sigma - gamma*omega*sigma: should be 0, but not recognized
as that).
2023-09-28 06:29:37 +00:00
|
|
|
static void
|
|
|
|
pga3_scale_component (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
|
|
|
{
|
|
|
|
if (is_algebra (get_type (b))) {
|
|
|
|
auto t = a;
|
|
|
|
a = b;
|
|
|
|
b = t;
|
|
|
|
}
|
|
|
|
b = promote_scalar (alg->type, b);
|
|
|
|
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
auto scale_type = get_type (a);
|
|
|
|
auto va = scale_expr (vtype, offset_cast (vtype, a, 0), b);
|
|
|
|
auto sa = scale_expr (stype, offset_cast (stype, a, 3), b);
|
|
|
|
auto scale = sum_expr (scale_type, ext_expr (va, scale_type, 0, false),
|
|
|
|
ext_expr (sa, scale_type, 0, true));
|
|
|
|
int group = get_group (scale_type, alg);
|
|
|
|
c[group] = scale;
|
|
|
|
}
|
|
|
|
|
2023-08-24 06:49:52 +00:00
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_x_y_z_w_dot_x_y_z_w (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-24 06:49:52 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
auto dot_type = algebra_mvec_type (alg, 0x04);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto va = offset_cast (vtype, a, 0);
|
|
|
|
auto vb = offset_cast (vtype, b, 0);
|
2023-08-24 06:49:52 +00:00
|
|
|
c[2] = dot_expr (dot_type, va, vb);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_x_y_z_w_dot_yz_zx_xy (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-24 06:49:52 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
auto dot_type = algebra_mvec_type (alg, 0x01);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto va = offset_cast (vtype, a, 0);
|
2024-02-03 11:56:04 +00:00
|
|
|
b = offset_cast (vtype, b, 0);
|
2023-09-02 08:21:16 +00:00
|
|
|
c[0] = ext_expr (cross_expr (vtype, b, va), dot_type, 0, false);
|
2023-08-24 06:49:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_x_y_z_w_dot_wx_wy_wz (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-24 06:49:52 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto va = offset_cast (vtype, a, 0);
|
2024-02-03 11:56:04 +00:00
|
|
|
b = offset_cast (vtype, b, 0);
|
2023-09-02 02:18:50 +00:00
|
|
|
auto cs = neg_expr (dot_expr (stype, b, va));
|
2023-09-02 08:21:16 +00:00
|
|
|
c[0] = ext_expr (cs, algebra_mvec_type (alg, 0x01), 0, true);
|
2023-08-24 06:49:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_x_y_z_w_dot_wxyz (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-24 06:49:52 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
2023-08-25 13:34:41 +00:00
|
|
|
auto vtype = vector_type (stype, 3);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto va = offset_cast (vtype, a, 0);
|
|
|
|
auto sb = offset_cast (stype, b, 0);
|
2023-08-25 13:34:41 +00:00
|
|
|
auto cv = scale_expr (vtype, va, sb);
|
2023-09-02 08:21:16 +00:00
|
|
|
c[5] = ext_expr (cv, algebra_mvec_type (alg, 0x20), 0, false);
|
2023-08-24 06:49:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_x_y_z_w_dot_wzy_wxz_wyx_xyz (const expr_t **c,
|
|
|
|
const expr_t *a, const expr_t *b,
|
2023-08-24 06:49:52 +00:00
|
|
|
algebra_t *alg)
|
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
auto bvtype = algebra_mvec_type (alg, 0x02);
|
|
|
|
auto bmtype = algebra_mvec_type (alg, 0x08);
|
2023-09-02 08:21:16 +00:00
|
|
|
auto va = offset_cast (vtype, a, 0);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto vb = offset_cast (vtype, b, 0);
|
|
|
|
auto sb = offset_cast (stype, b, 3);
|
2023-08-25 08:24:47 +00:00
|
|
|
c[1] = scale_expr (bvtype, va, sb);
|
2023-08-24 06:49:52 +00:00
|
|
|
c[3] = cross_expr (bmtype, vb, va);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_yz_zx_xy_dot_x_y_z_w (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-24 06:49:52 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
auto dot_type = algebra_mvec_type (alg, 0x01);
|
2024-02-03 11:56:04 +00:00
|
|
|
a = offset_cast (vtype, a, 0);
|
2023-08-29 12:13:12 +00:00
|
|
|
auto vb = offset_cast (vtype, b, 0);
|
2023-09-02 08:21:16 +00:00
|
|
|
c[0] = ext_expr (cross_expr (vtype, vb, a), dot_type, 0, false);
|
2023-08-24 06:49:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_yz_zx_xy_dot_yz_zx_xy (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-24 06:49:52 +00:00
|
|
|
{
|
2024-02-03 11:56:04 +00:00
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
a = offset_cast (vtype, a, 0);
|
|
|
|
b = offset_cast (vtype, b, 0);
|
2023-08-24 06:49:52 +00:00
|
|
|
auto dot_type = algebra_mvec_type (alg, 0x04);
|
2023-09-02 02:18:50 +00:00
|
|
|
c[2] = neg_expr (dot_expr (dot_type, a, b));
|
2023-08-24 06:49:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_yz_zx_xy_dot_wxyz (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-24 06:49:52 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
2023-09-02 08:21:16 +00:00
|
|
|
auto vtype = vector_type (stype, 3);
|
2023-08-24 06:49:52 +00:00
|
|
|
auto bmtype = algebra_mvec_type (alg, 0x08);
|
2023-09-02 08:21:16 +00:00
|
|
|
auto va = offset_cast (vtype, a, 0);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto sb = offset_cast (stype, b, 0);
|
2023-09-02 02:18:50 +00:00
|
|
|
c[3] = neg_expr (scale_expr (bmtype, va, sb));
|
2023-08-24 06:49:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_yz_zx_xy_dot_wzy_wxz_wyx_xyz (const expr_t **c,
|
|
|
|
const expr_t *a, const expr_t *b,
|
2023-08-24 06:49:52 +00:00
|
|
|
algebra_t *alg)
|
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
auto dot_type = algebra_mvec_type (alg, 0x01);
|
|
|
|
|
2023-08-26 14:57:37 +00:00
|
|
|
auto vb = offset_cast (vtype, b, 0);
|
|
|
|
auto sb = offset_cast (stype, b, 3);
|
2023-08-24 06:49:52 +00:00
|
|
|
|
2023-08-25 13:34:41 +00:00
|
|
|
auto cv = scale_expr (vtype, a, sb);
|
2023-08-24 06:49:52 +00:00
|
|
|
auto cs = dot_expr (stype, a, vb);
|
|
|
|
|
2023-09-02 08:21:16 +00:00
|
|
|
cv = ext_expr (neg_expr (cv), dot_type, 0, false);
|
|
|
|
cs = ext_expr (cs, dot_type, 0, true);
|
2023-09-02 02:43:49 +00:00
|
|
|
c[0] = sum_expr (dot_type, cv, cs);
|
2023-08-24 06:49:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_wx_wy_wz_dot_x_y_z_w (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-24 06:49:52 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
2024-02-03 11:56:04 +00:00
|
|
|
a = offset_cast (vtype, a, 0);
|
2023-08-29 12:13:12 +00:00
|
|
|
auto vb = offset_cast (vtype, b, 0);
|
|
|
|
auto cs = dot_expr (stype, a, vb);
|
2023-09-02 08:21:16 +00:00
|
|
|
c[0] = ext_expr (cs, algebra_mvec_type (alg, 0x01), 0, true);
|
2023-08-24 06:49:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_wxyz_dot_x_y_z_w (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-24 06:49:52 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto dot_type = algebra_mvec_type (alg, 0x20);
|
2023-09-25 07:09:51 +00:00
|
|
|
auto vb = edag_add_expr (new_swizzle_expr (b, "-x-y-z0"));
|
2023-08-26 14:57:37 +00:00
|
|
|
auto sa = offset_cast (stype, a, 0);
|
2023-08-25 08:24:47 +00:00
|
|
|
c[5] = scale_expr (dot_type, vb, sa);
|
2023-08-24 06:49:52 +00:00
|
|
|
}
|
|
|
|
|
2023-08-29 12:13:12 +00:00
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_wxyz_dot_yz_zx_xy (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-29 12:13:12 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
2023-09-02 08:21:16 +00:00
|
|
|
auto vtype = vector_type (stype, 3);
|
2023-08-29 12:13:12 +00:00
|
|
|
auto bmtype = algebra_mvec_type (alg, 0x08);
|
|
|
|
auto sa = offset_cast (stype, a, 0);
|
2023-09-02 08:21:16 +00:00
|
|
|
auto vb = offset_cast (vtype, b, 0);
|
2023-09-02 02:18:50 +00:00
|
|
|
c[3] = neg_expr (scale_expr (bmtype, vb, sa));
|
2023-08-29 12:13:12 +00:00
|
|
|
}
|
|
|
|
|
2023-08-24 06:49:52 +00:00
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_wxyz_dot_wzy_wxz_wyx_xyz (const expr_t **c,
|
|
|
|
const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-24 06:49:52 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
2023-08-26 14:57:37 +00:00
|
|
|
auto sa = offset_cast (stype, a, 0);
|
|
|
|
auto sb = offset_cast (stype, b, 3);
|
2023-09-02 02:18:50 +00:00
|
|
|
auto cs = neg_expr (scale_expr (stype, sa, sb));
|
2023-09-02 08:21:16 +00:00
|
|
|
c[0] = ext_expr (cs, algebra_mvec_type (alg, 0x01), 0, true);
|
2023-08-24 06:49:52 +00:00
|
|
|
}
|
|
|
|
|
2023-08-29 12:13:12 +00:00
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_wzy_wxz_wyx_xyz_dot_x_y_z_w (const expr_t **c,
|
|
|
|
const expr_t *a, const expr_t *b,
|
2023-08-29 12:13:12 +00:00
|
|
|
algebra_t *alg)
|
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
auto bvtype = algebra_mvec_type (alg, 0x02);
|
|
|
|
auto bmtype = algebra_mvec_type (alg, 0x08);
|
|
|
|
auto sa = offset_cast (stype, a, 3);
|
|
|
|
auto va = offset_cast (vtype, a, 0);
|
|
|
|
auto vb = offset_cast (vtype, b, 0);
|
|
|
|
c[1] = scale_expr (bvtype, vb, sa);
|
|
|
|
c[3] = cross_expr (bmtype, va, vb);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_wzy_wxz_wyx_xyz_dot_yz_zx_xy (const expr_t **c,
|
|
|
|
const expr_t *a, const expr_t *b,
|
2023-08-29 12:13:12 +00:00
|
|
|
algebra_t *alg)
|
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
2024-02-03 11:56:04 +00:00
|
|
|
b = offset_cast (vtype, b, 0);
|
2023-08-29 12:13:12 +00:00
|
|
|
auto dot_type = algebra_mvec_type (alg, 0x01);
|
|
|
|
|
|
|
|
auto va = offset_cast (vtype, a, 0);
|
|
|
|
auto sa = offset_cast (stype, a, 3);
|
|
|
|
|
|
|
|
auto cv = scale_expr (vtype, b, sa);
|
|
|
|
auto cs = dot_expr (stype, b, va);
|
|
|
|
|
2023-09-02 08:21:16 +00:00
|
|
|
cv = ext_expr (neg_expr (cv), dot_type, 0, false);
|
|
|
|
cs = ext_expr (cs, dot_type, 0, true);
|
2023-09-02 02:43:49 +00:00
|
|
|
c[0] = sum_expr (dot_type, cv, cs);
|
2023-08-29 12:13:12 +00:00
|
|
|
}
|
|
|
|
|
2023-08-24 06:49:52 +00:00
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_wzy_wxz_wyx_xyz_dot_wxyz (const expr_t **c,
|
|
|
|
const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-24 06:49:52 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
2023-08-29 12:13:12 +00:00
|
|
|
auto sa = offset_cast (stype, a, 3);
|
|
|
|
auto sb = offset_cast (stype, b, 0);
|
2023-08-25 13:34:41 +00:00
|
|
|
auto cs = scale_expr (stype, sa, sb);
|
2023-09-02 08:21:16 +00:00
|
|
|
c[0] = ext_expr (cs, algebra_mvec_type (alg, 0x01), 0, true);
|
2023-08-24 06:49:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_wzy_wxz_wyx_xyz_dot_wzy_wxz_wyx_xyz (const expr_t **c,
|
|
|
|
const expr_t *a, const expr_t *b,
|
2023-08-24 06:49:52 +00:00
|
|
|
algebra_t *alg)
|
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
2023-08-26 14:57:37 +00:00
|
|
|
auto sa = offset_cast (stype, a, 3);
|
|
|
|
auto sb = offset_cast (stype, b, 3);
|
2023-09-02 02:18:50 +00:00
|
|
|
c[0] = neg_expr (scale_expr (stype, sa, sb));
|
2023-08-24 06:49:52 +00:00
|
|
|
}
|
|
|
|
|
2023-08-23 15:19:58 +00:00
|
|
|
static pga_func pga3_dot_funcs[6][6] = {
|
2023-08-24 06:49:52 +00:00
|
|
|
[0] = {
|
|
|
|
[0] = pga3_x_y_z_w_dot_x_y_z_w,
|
|
|
|
[1] = pga3_x_y_z_w_dot_yz_zx_xy,
|
[qfcc] Split up pga3 4-component scales
While splitting up the scaled vector into scaled xyz and scaled w does
cost an extra instruction, it allows for other optimizations to be
applied. For one, extends get all the way to the top now, and there are
at most two (in my test cases), thus either break-even or even a slight
reduction in instruction count. However, in the initial implementation,
I forgot to do the actual scaling, and 12 instructions were removed from
my fancy zero case, but real tests failed :P It looks like it's just
distributivity and commutativity holding things back (eg,
omega*gamma*sigma - gamma*omega*sigma: should be 0, but not recognized
as that).
2023-09-28 06:29:37 +00:00
|
|
|
[2] = pga3_scale_component,
|
2023-08-24 06:49:52 +00:00
|
|
|
[3] = pga3_x_y_z_w_dot_wx_wy_wz,
|
|
|
|
[4] = pga3_x_y_z_w_dot_wxyz,
|
|
|
|
[5] = pga3_x_y_z_w_dot_wzy_wxz_wyx_xyz,
|
|
|
|
},
|
|
|
|
[1] = {
|
|
|
|
[0] = pga3_yz_zx_xy_dot_x_y_z_w,
|
|
|
|
[1] = pga3_yz_zx_xy_dot_yz_zx_xy,
|
|
|
|
[2] = scale_component,
|
|
|
|
[4] = pga3_yz_zx_xy_dot_wxyz,
|
|
|
|
[5] = pga3_yz_zx_xy_dot_wzy_wxz_wyx_xyz,
|
|
|
|
},
|
2023-08-23 15:19:58 +00:00
|
|
|
[2] = {
|
[qfcc] Split up pga3 4-component scales
While splitting up the scaled vector into scaled xyz and scaled w does
cost an extra instruction, it allows for other optimizations to be
applied. For one, extends get all the way to the top now, and there are
at most two (in my test cases), thus either break-even or even a slight
reduction in instruction count. However, in the initial implementation,
I forgot to do the actual scaling, and 12 instructions were removed from
my fancy zero case, but real tests failed :P It looks like it's just
distributivity and commutativity holding things back (eg,
omega*gamma*sigma - gamma*omega*sigma: should be 0, but not recognized
as that).
2023-09-28 06:29:37 +00:00
|
|
|
[0] = pga3_scale_component,
|
2023-08-24 06:49:52 +00:00
|
|
|
[1] = scale_component,
|
2023-08-23 15:19:58 +00:00
|
|
|
[2] = scale_component,
|
2023-08-24 06:49:52 +00:00
|
|
|
[3] = scale_component,
|
|
|
|
[4] = scale_component,
|
[qfcc] Split up pga3 4-component scales
While splitting up the scaled vector into scaled xyz and scaled w does
cost an extra instruction, it allows for other optimizations to be
applied. For one, extends get all the way to the top now, and there are
at most two (in my test cases), thus either break-even or even a slight
reduction in instruction count. However, in the initial implementation,
I forgot to do the actual scaling, and 12 instructions were removed from
my fancy zero case, but real tests failed :P It looks like it's just
distributivity and commutativity holding things back (eg,
omega*gamma*sigma - gamma*omega*sigma: should be 0, but not recognized
as that).
2023-09-28 06:29:37 +00:00
|
|
|
[5] = pga3_scale_component,
|
2023-08-24 06:49:52 +00:00
|
|
|
},
|
|
|
|
[3] = {
|
|
|
|
[0] = pga3_wx_wy_wz_dot_x_y_z_w,
|
|
|
|
[2] = scale_component,
|
|
|
|
},
|
|
|
|
[4] = {
|
|
|
|
[0] = pga3_wxyz_dot_x_y_z_w,
|
|
|
|
[1] = pga3_wxyz_dot_yz_zx_xy,
|
|
|
|
[2] = scale_component,
|
|
|
|
[5] = pga3_wxyz_dot_wzy_wxz_wyx_xyz,
|
|
|
|
},
|
|
|
|
[5] = {
|
|
|
|
[0] = pga3_wzy_wxz_wyx_xyz_dot_x_y_z_w,
|
|
|
|
[1] = pga3_wzy_wxz_wyx_xyz_dot_yz_zx_xy,
|
[qfcc] Split up pga3 4-component scales
While splitting up the scaled vector into scaled xyz and scaled w does
cost an extra instruction, it allows for other optimizations to be
applied. For one, extends get all the way to the top now, and there are
at most two (in my test cases), thus either break-even or even a slight
reduction in instruction count. However, in the initial implementation,
I forgot to do the actual scaling, and 12 instructions were removed from
my fancy zero case, but real tests failed :P It looks like it's just
distributivity and commutativity holding things back (eg,
omega*gamma*sigma - gamma*omega*sigma: should be 0, but not recognized
as that).
2023-09-28 06:29:37 +00:00
|
|
|
[2] = pga3_scale_component,
|
2023-08-24 06:49:52 +00:00
|
|
|
[4] = pga3_wzy_wxz_wyx_xyz_dot_wxyz,
|
|
|
|
[5] = pga3_wzy_wxz_wyx_xyz_dot_wzy_wxz_wyx_xyz,
|
2023-08-23 15:19:58 +00:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga2_yw_wx_xy_dot_yw_wx_xy (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-23 15:19:58 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
2023-08-26 14:57:37 +00:00
|
|
|
auto sa = offset_cast (stype, a, 2);
|
|
|
|
auto sb = offset_cast (stype, b, 2);
|
2023-08-23 15:19:58 +00:00
|
|
|
|
2023-09-09 12:19:50 +00:00
|
|
|
c[3] = neg_expr (scale_expr (stype, sa, sb));
|
2023-08-23 15:19:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga2_yw_wx_xy_dot_x_y_w (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-23 15:19:58 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
2023-08-31 11:22:59 +00:00
|
|
|
auto wtype = vector_type (stype, 2);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto vtype = vector_type (stype, 3);
|
2023-09-09 12:19:50 +00:00
|
|
|
auto dot_type = algebra_mvec_type (alg, 0x01);
|
2023-08-31 11:22:59 +00:00
|
|
|
auto va = offset_cast (wtype, a, 0);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto sa = offset_cast (stype, a, 2);
|
2023-08-31 11:22:59 +00:00
|
|
|
auto vb = offset_cast (wtype, b, 0);
|
2023-09-25 07:09:51 +00:00
|
|
|
auto cv = edag_add_expr (new_swizzle_expr (vb, "y-x"));
|
2023-08-31 11:22:59 +00:00
|
|
|
auto cs = wedge_expr (stype, vb, va);
|
2023-09-02 08:21:16 +00:00
|
|
|
cv = ext_expr (scale_expr (wtype, cv, sa), vtype, 0, false);
|
|
|
|
cs = ext_expr (cs, dot_type, 0, true);
|
2023-09-09 12:19:50 +00:00
|
|
|
c[0] = sum_expr (dot_type, cv, cs);
|
2023-08-23 15:19:58 +00:00
|
|
|
}
|
|
|
|
|
2023-08-27 06:24:35 +00:00
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga2_yw_wx_xy_dot_wxy (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-27 06:24:35 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto sa = offset_cast (stype, a, 2);
|
|
|
|
auto sb = offset_cast (stype, b, 0);
|
2023-09-02 02:18:50 +00:00
|
|
|
auto cs = neg_expr (scale_expr (stype, sa, sb));
|
2023-09-09 12:19:50 +00:00
|
|
|
c[2] = ext_expr (cs, algebra_mvec_type (alg, 0x04), 0, true);
|
2023-08-27 06:24:35 +00:00
|
|
|
}
|
|
|
|
|
2023-08-23 15:19:58 +00:00
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga2_x_y_w_dot_yw_wx_xy (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-23 15:19:58 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
2023-08-31 11:22:59 +00:00
|
|
|
auto wtype = vector_type (stype, 2);
|
2023-09-09 12:19:50 +00:00
|
|
|
auto dot_type = algebra_mvec_type (alg, 0x01);
|
2023-08-31 11:22:59 +00:00
|
|
|
auto va = offset_cast (wtype, a, 0);
|
|
|
|
auto vb = offset_cast (wtype, b, 0);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto sb = offset_cast (stype, b, 2);
|
2023-09-25 07:09:51 +00:00
|
|
|
auto cv = scale_expr (wtype,
|
|
|
|
edag_add_expr (new_swizzle_expr (va, "-yx")), sb);
|
2023-08-31 11:22:59 +00:00
|
|
|
auto cs = wedge_expr (stype, vb, va);
|
2023-09-02 08:21:16 +00:00
|
|
|
cv = ext_expr (cv, dot_type, 0, false);
|
|
|
|
cs = ext_expr (cs, dot_type, 0, true);
|
2023-09-09 12:19:50 +00:00
|
|
|
c[0] = sum_expr (dot_type, cs, cv);
|
2023-08-23 15:19:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga2_x_y_w_dot_x_y_w (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-23 15:19:58 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 2);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto va = offset_cast (vtype, a, 0);
|
|
|
|
auto vb = offset_cast (vtype, b, 0);
|
2023-08-23 15:19:58 +00:00
|
|
|
auto cs = dot_expr (stype, va, vb);
|
2023-09-09 12:19:50 +00:00
|
|
|
c[3] = cs;
|
2023-08-23 15:19:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga2_x_y_w_dot_wxy (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-23 15:19:58 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 2);
|
2023-09-09 12:19:50 +00:00
|
|
|
auto dot_type = algebra_mvec_type (alg, 0x04);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto va = offset_cast (vtype, a, 0);
|
2023-08-27 06:24:35 +00:00
|
|
|
auto cv = scale_expr (vtype, va, b);
|
2023-08-25 13:34:41 +00:00
|
|
|
|
2023-09-09 12:19:50 +00:00
|
|
|
c[2] = ext_expr (cv, dot_type, 0, false);
|
2023-08-23 15:19:58 +00:00
|
|
|
}
|
|
|
|
|
2023-08-27 06:24:35 +00:00
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga2_wxy_dot_yw_wx_xy (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-27 06:24:35 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto sa = offset_cast (stype, a, 0);
|
|
|
|
auto sb = offset_cast (stype, b, 2);
|
2023-09-02 02:18:50 +00:00
|
|
|
auto cs = neg_expr (scale_expr (stype, sa, sb));
|
2023-09-09 12:19:50 +00:00
|
|
|
c[2] = ext_expr (cs, algebra_mvec_type (alg, 0x04), 0, true);
|
2023-08-27 06:24:35 +00:00
|
|
|
}
|
|
|
|
|
2023-08-23 15:19:58 +00:00
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga2_wxy_dot_x_y_w (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-23 15:19:58 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 2);
|
2023-09-09 12:19:50 +00:00
|
|
|
auto dot_type = algebra_mvec_type (alg, 0x04);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto sa = offset_cast (stype, a, 0);
|
|
|
|
auto vb = offset_cast (vtype, b, 0);
|
2023-08-27 06:24:35 +00:00
|
|
|
auto cv = scale_expr (vtype, vb, sa);
|
2023-09-09 12:19:50 +00:00
|
|
|
c[2] = ext_expr (cv, dot_type, 0, false);
|
2023-08-23 15:19:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static pga_func pga2_dot_funcs[4][4] = {
|
|
|
|
[0] = {
|
2023-09-09 12:19:50 +00:00
|
|
|
[0] = pga2_x_y_w_dot_x_y_w,
|
|
|
|
[1] = pga2_x_y_w_dot_wxy,
|
|
|
|
[2] = pga2_x_y_w_dot_yw_wx_xy,
|
|
|
|
[3] = scale_component,
|
2023-08-23 15:19:58 +00:00
|
|
|
},
|
|
|
|
[1] = {
|
2023-09-09 12:19:50 +00:00
|
|
|
[0] = pga2_wxy_dot_x_y_w,
|
|
|
|
[2] = pga2_wxy_dot_yw_wx_xy,
|
2023-08-24 06:49:52 +00:00
|
|
|
[3] = scale_component,
|
2023-08-23 15:19:58 +00:00
|
|
|
},
|
|
|
|
[2] = {
|
2023-09-09 12:19:50 +00:00
|
|
|
[0] = pga2_yw_wx_xy_dot_x_y_w,
|
|
|
|
[1] = pga2_yw_wx_xy_dot_wxy,
|
|
|
|
[2] = pga2_yw_wx_xy_dot_yw_wx_xy,
|
|
|
|
[3] = scale_component,
|
2023-08-23 15:19:58 +00:00
|
|
|
},
|
|
|
|
[3] = {
|
2023-09-09 12:19:50 +00:00
|
|
|
[0] = scale_component,
|
|
|
|
[1] = scale_component,
|
|
|
|
[2] = scale_component,
|
|
|
|
[3] = scale_component,
|
2023-08-23 15:19:58 +00:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2023-09-08 02:15:36 +00:00
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
vga3_x_y_z_dot_x_y_z (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-09-08 02:15:36 +00:00
|
|
|
{
|
2024-02-03 11:56:04 +00:00
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
a = offset_cast (vtype, a, 0);
|
|
|
|
b = offset_cast (vtype, b, 0);
|
2023-09-08 02:15:36 +00:00
|
|
|
c[3] = dot_expr (algebra_mvec_type (alg, 0x08), a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
vga3_x_y_z_dot_yz_zx_xy (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-09-08 02:15:36 +00:00
|
|
|
{
|
2024-02-03 11:56:04 +00:00
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
a = offset_cast (vtype, a, 0);
|
|
|
|
b = offset_cast (vtype, b, 0);
|
2023-09-08 02:15:36 +00:00
|
|
|
c[0] = cross_expr (algebra_mvec_type (alg, 0x01), b, a);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
vga3_x_y_z_dot_xyz (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-09-08 02:15:36 +00:00
|
|
|
{
|
2024-02-03 11:56:04 +00:00
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
a = offset_cast (vtype, a, 0);
|
2023-09-08 02:15:36 +00:00
|
|
|
c[2] = scale_expr (algebra_mvec_type (alg, 0x04), a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
vga3_yz_zx_xy_dot_x_y_z (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-09-08 02:15:36 +00:00
|
|
|
{
|
2024-02-03 11:56:04 +00:00
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
a = offset_cast (vtype, a, 0);
|
|
|
|
b = offset_cast (vtype, b, 0);
|
2023-09-08 02:15:36 +00:00
|
|
|
c[0] = cross_expr (algebra_mvec_type (alg, 0x01), b, a);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
vga3_yz_zx_xy_dot_yz_zx_xy (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-09-08 02:15:36 +00:00
|
|
|
{
|
2024-02-03 11:56:04 +00:00
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
a = offset_cast (vtype, a, 0);
|
|
|
|
b = offset_cast (vtype, b, 0);
|
2023-09-08 02:15:36 +00:00
|
|
|
c[3] = neg_expr (dot_expr (algebra_mvec_type (alg, 0x08), a, b));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
vga3_yz_zx_xy_dot_xyz (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-09-08 02:15:36 +00:00
|
|
|
{
|
2024-02-03 11:56:04 +00:00
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
a = offset_cast (vtype, a, 0);
|
|
|
|
b = offset_cast (stype, b, 0);
|
2023-09-08 02:15:36 +00:00
|
|
|
c[0] = neg_expr (scale_expr (algebra_mvec_type (alg, 0x01), a, b));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
vga3_xyz_dot_x_y_z (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-09-08 02:15:36 +00:00
|
|
|
{
|
2024-02-03 11:56:04 +00:00
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
a = offset_cast (stype, a, 0);
|
|
|
|
b = offset_cast (vtype, b, 0);
|
2023-09-08 02:15:36 +00:00
|
|
|
c[2] = scale_expr (algebra_mvec_type (alg, 0x04), b, a);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
vga3_xyz_dot_yz_zx_xy (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-09-08 02:15:36 +00:00
|
|
|
{
|
2024-02-03 11:56:04 +00:00
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
a = offset_cast (stype, a, 0);
|
|
|
|
b = offset_cast (vtype, b, 0);
|
2023-09-08 02:15:36 +00:00
|
|
|
c[0] = neg_expr (scale_expr (algebra_mvec_type (alg, 0x01), b, a));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
vga3_xyz_dot_xyz (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-09-08 02:15:36 +00:00
|
|
|
{
|
2024-02-03 11:56:04 +00:00
|
|
|
auto stype = alg->type;
|
|
|
|
a = offset_cast (stype, a, 0);
|
|
|
|
b = offset_cast (stype, b, 0);
|
2023-09-08 02:15:36 +00:00
|
|
|
c[3] = neg_expr (scale_expr (algebra_mvec_type (alg, 0x08), b, a));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static pga_func vga3_dot_funcs[4][4] = {
|
|
|
|
[0] = {
|
|
|
|
[0] = vga3_x_y_z_dot_x_y_z,
|
|
|
|
[1] = vga3_x_y_z_dot_xyz,
|
|
|
|
[2] = vga3_x_y_z_dot_yz_zx_xy,
|
|
|
|
[3] = scale_component,
|
|
|
|
},
|
|
|
|
[1] = {
|
|
|
|
[0] = vga3_xyz_dot_x_y_z,
|
|
|
|
[1] = vga3_xyz_dot_xyz,
|
|
|
|
[2] = vga3_xyz_dot_yz_zx_xy,
|
|
|
|
[3] = scale_component,
|
|
|
|
},
|
|
|
|
[2] = {
|
|
|
|
[0] = vga3_yz_zx_xy_dot_x_y_z,
|
|
|
|
[1] = vga3_yz_zx_xy_dot_xyz,
|
|
|
|
[2] = vga3_yz_zx_xy_dot_yz_zx_xy,
|
|
|
|
[3] = scale_component,
|
|
|
|
},
|
|
|
|
[3] = {
|
|
|
|
[0] = scale_component,
|
|
|
|
[1] = scale_component,
|
|
|
|
[2] = scale_component,
|
|
|
|
[3] = scale_component,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2023-08-23 15:19:58 +00:00
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
component_dot (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *algebra)
|
2023-08-23 15:19:58 +00:00
|
|
|
{
|
|
|
|
int p = algebra->plus;
|
|
|
|
int m = algebra->minus;
|
|
|
|
int z = algebra->zero;
|
|
|
|
|
|
|
|
if (p == 3 && m == 0 && z == 1) {
|
|
|
|
int ga = get_group (get_type (a), algebra);
|
|
|
|
int gb = get_group (get_type (b), algebra);
|
|
|
|
if (pga3_dot_funcs[ga][gb]) {
|
|
|
|
pga3_dot_funcs[ga][gb] (c, a, b, algebra);
|
|
|
|
}
|
|
|
|
} else if (p == 2 && m == 0 && z == 1) {
|
|
|
|
int ga = get_group (get_type (a), algebra);
|
|
|
|
int gb = get_group (get_type (b), algebra);
|
|
|
|
if (pga2_dot_funcs[ga][gb]) {
|
|
|
|
pga2_dot_funcs[ga][gb] (c, a, b, algebra);
|
|
|
|
}
|
2023-09-08 02:15:36 +00:00
|
|
|
} else if (p == 3 && m == 0 && z == 0) {
|
|
|
|
int ga = get_group (get_type (a), algebra);
|
|
|
|
int gb = get_group (get_type (b), algebra);
|
|
|
|
if (vga3_dot_funcs[ga][gb]) {
|
|
|
|
vga3_dot_funcs[ga][gb] (c, a, b, algebra);
|
|
|
|
}
|
2023-08-23 15:19:58 +00:00
|
|
|
} else {
|
2023-08-28 11:34:18 +00:00
|
|
|
internal_error (a, "not implemented");
|
2023-08-23 15:19:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-27 03:41:31 +00:00
|
|
|
static const expr_t *
|
|
|
|
inner_product (const expr_t *e1, const expr_t *e2)
|
2023-08-23 15:19:58 +00:00
|
|
|
{
|
|
|
|
auto t1 = get_type (e1);
|
|
|
|
auto t2 = get_type (e2);
|
|
|
|
auto algebra = is_algebra (t1) ? algebra_get (t1) : algebra_get (t2);
|
|
|
|
auto layout = &algebra->layout;
|
2023-09-27 03:41:31 +00:00
|
|
|
const expr_t *a[layout->count] = {};
|
|
|
|
const expr_t *b[layout->count] = {};
|
|
|
|
const expr_t *c[layout->count] = {};
|
2023-08-23 15:19:58 +00:00
|
|
|
e1 = mvec_expr (e1, algebra);
|
|
|
|
e2 = mvec_expr (e2, algebra);
|
|
|
|
mvec_scatter (a, e1, algebra);
|
|
|
|
mvec_scatter (b, e2, algebra);
|
|
|
|
|
|
|
|
for (int i = 0; i < layout->count; i++) {
|
|
|
|
for (int j = 0; j < layout->count; j++) {
|
|
|
|
if (a[i] && b[j]) {
|
2023-09-27 03:41:31 +00:00
|
|
|
const expr_t *w[layout->count] = {};
|
2023-08-23 15:19:58 +00:00
|
|
|
component_dot (w, a[i], b[j], algebra);
|
2023-08-30 06:45:44 +00:00
|
|
|
if (!check_types (w, algebra)) {
|
|
|
|
internal_error (a[i], "wrong types in dot product");
|
|
|
|
}
|
2023-08-23 15:19:58 +00:00
|
|
|
component_sum ('+', c, c, w, algebra);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return mvec_gather (c, algebra);
|
|
|
|
}
|
|
|
|
|
2023-08-23 06:31:20 +00:00
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_x_y_z_w_wedge_x_y_z_w (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-23 06:31:20 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
auto wedge_type = algebra_mvec_type (alg, 0x08);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto va = offset_cast (vtype, a, 0);
|
|
|
|
auto vb = offset_cast (vtype, b, 0);
|
|
|
|
auto sa = offset_cast (stype, a, 3);
|
|
|
|
auto sb = offset_cast (stype, b, 3);
|
2023-08-24 06:49:52 +00:00
|
|
|
c[1] = cross_expr (algebra_mvec_type (alg, 0x02), va, vb);
|
2023-09-02 02:18:50 +00:00
|
|
|
c[3] = sum_expr (wedge_type,
|
|
|
|
scale_expr (wedge_type, vb, sa),
|
|
|
|
neg_expr (scale_expr (wedge_type, va, sb)));
|
2023-08-23 06:31:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_x_y_z_w_wedge_yz_zx_xy (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-23 06:31:20 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
auto wedge_type = algebra_mvec_type (alg, 0x20);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto va = offset_cast (vtype, a, 0);
|
2024-02-03 11:56:04 +00:00
|
|
|
b = offset_cast (vtype, b, 0);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto sa = offset_cast (stype, a, 3);
|
2023-08-29 10:42:00 +00:00
|
|
|
auto cv = scale_expr (vtype, b, sa);
|
2023-08-23 06:31:20 +00:00
|
|
|
auto cs = dot_expr (stype, va, b);
|
2023-08-25 13:34:41 +00:00
|
|
|
|
2023-09-02 08:21:16 +00:00
|
|
|
cv = ext_expr (neg_expr (cv), wedge_type, 0, false);
|
|
|
|
cs = ext_expr (cs, wedge_type, 0, true);
|
2023-09-02 02:43:49 +00:00
|
|
|
c[5] = sum_expr (wedge_type, cv, cs);
|
2023-08-23 06:31:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_x_y_z_w_wedge_wx_wy_wz (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-23 06:31:20 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
auto wedge_type = algebra_mvec_type (alg, 0x20);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto va = offset_cast (vtype, a, 0);
|
2024-02-03 11:56:04 +00:00
|
|
|
b = offset_cast (vtype, b, 0);
|
2023-08-24 06:49:52 +00:00
|
|
|
auto cv = cross_expr (vtype, va, b);
|
2023-09-02 08:21:16 +00:00
|
|
|
c[5] = ext_expr (cv, wedge_type, 0, false);
|
2023-08-23 06:31:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_x_y_z_w_wedge_wzy_wxz_wyx_xyz (const expr_t **c,
|
|
|
|
const expr_t *a, const expr_t *b,
|
2023-08-23 06:31:20 +00:00
|
|
|
algebra_t *alg)
|
|
|
|
{
|
|
|
|
c[4] = dot_expr (algebra_mvec_type (alg, 0x10), a, b);
|
|
|
|
}
|
|
|
|
|
2023-08-29 10:42:00 +00:00
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_yz_zx_xy_wedge_x_y_z_w (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-29 10:42:00 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
2024-02-03 11:56:04 +00:00
|
|
|
a = offset_cast (vtype, a, 0);
|
2023-08-29 10:42:00 +00:00
|
|
|
auto vb = offset_cast (vtype, b, 0);
|
|
|
|
auto sb = offset_cast (stype, b, 3);
|
|
|
|
auto cv = scale_expr (vtype, a, sb);
|
|
|
|
auto cs = dot_expr (stype, vb, a);
|
|
|
|
|
2024-02-03 11:56:04 +00:00
|
|
|
auto wedge_type = algebra_mvec_type (alg, 0x20);
|
2023-09-02 08:21:16 +00:00
|
|
|
cv = ext_expr (neg_expr (cv), wedge_type, 0, false);
|
|
|
|
cs = ext_expr (cs, wedge_type, 0, true);
|
2023-09-02 02:43:49 +00:00
|
|
|
c[5] = sum_expr (wedge_type, cv, cs);
|
2023-08-29 10:42:00 +00:00
|
|
|
}
|
|
|
|
|
2023-08-23 06:31:20 +00:00
|
|
|
// bivector-bivector wedge is commutative
|
|
|
|
#define pga3_wx_wy_wz_wedge_yz_zx_xy pga3_yz_zx_xy_wedge_wx_wy_wz
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_yz_zx_xy_wedge_wx_wy_wz (const expr_t **c,
|
|
|
|
const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-23 06:31:20 +00:00
|
|
|
{
|
|
|
|
c[4] = dot_expr (algebra_mvec_type (alg, 0x10), a, b);
|
|
|
|
}
|
|
|
|
|
2023-08-29 10:42:00 +00:00
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_wx_wy_wz_wedge_x_y_z_w (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-29 10:42:00 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
2024-02-03 11:56:04 +00:00
|
|
|
a = offset_cast (vtype, a, 0);
|
2023-08-29 10:42:00 +00:00
|
|
|
auto vb = offset_cast (vtype, b, 0);
|
|
|
|
auto cv = cross_expr (vtype, vb, a);
|
2024-02-03 11:56:04 +00:00
|
|
|
|
|
|
|
auto wedge_type = algebra_mvec_type (alg, 0x20);
|
2023-09-02 08:21:16 +00:00
|
|
|
c[5] = ext_expr (cv, wedge_type, 0, false);
|
2023-08-29 10:42:00 +00:00
|
|
|
}
|
|
|
|
|
2023-08-23 06:31:20 +00:00
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_wzy_wxz_wyx_xyz_wedge_x_y_z_w (const expr_t **c,
|
|
|
|
const expr_t *a, const expr_t *b,
|
2023-08-23 06:31:20 +00:00
|
|
|
algebra_t *alg)
|
|
|
|
{
|
2023-09-02 02:18:50 +00:00
|
|
|
c[4] = neg_expr (dot_expr (algebra_mvec_type (alg, 0x10), a, b));
|
2023-08-23 06:31:20 +00:00
|
|
|
}
|
|
|
|
|
2023-08-23 15:19:58 +00:00
|
|
|
static pga_func pga3_wedge_funcs[6][6] = {
|
2023-08-23 06:31:20 +00:00
|
|
|
[0] = {
|
|
|
|
[0] = pga3_x_y_z_w_wedge_x_y_z_w,
|
|
|
|
[1] = pga3_x_y_z_w_wedge_yz_zx_xy,
|
[qfcc] Split up pga3 4-component scales
While splitting up the scaled vector into scaled xyz and scaled w does
cost an extra instruction, it allows for other optimizations to be
applied. For one, extends get all the way to the top now, and there are
at most two (in my test cases), thus either break-even or even a slight
reduction in instruction count. However, in the initial implementation,
I forgot to do the actual scaling, and 12 instructions were removed from
my fancy zero case, but real tests failed :P It looks like it's just
distributivity and commutativity holding things back (eg,
omega*gamma*sigma - gamma*omega*sigma: should be 0, but not recognized
as that).
2023-09-28 06:29:37 +00:00
|
|
|
[2] = pga3_scale_component,
|
2023-08-23 06:31:20 +00:00
|
|
|
[3] = pga3_x_y_z_w_wedge_wx_wy_wz,
|
|
|
|
[5] = pga3_x_y_z_w_wedge_wzy_wxz_wyx_xyz,
|
|
|
|
},
|
|
|
|
[1] = {
|
|
|
|
[0] = pga3_yz_zx_xy_wedge_x_y_z_w,
|
|
|
|
[2] = scale_component,
|
|
|
|
[3] = pga3_yz_zx_xy_wedge_wx_wy_wz,
|
|
|
|
},
|
|
|
|
[2] = {
|
[qfcc] Split up pga3 4-component scales
While splitting up the scaled vector into scaled xyz and scaled w does
cost an extra instruction, it allows for other optimizations to be
applied. For one, extends get all the way to the top now, and there are
at most two (in my test cases), thus either break-even or even a slight
reduction in instruction count. However, in the initial implementation,
I forgot to do the actual scaling, and 12 instructions were removed from
my fancy zero case, but real tests failed :P It looks like it's just
distributivity and commutativity holding things back (eg,
omega*gamma*sigma - gamma*omega*sigma: should be 0, but not recognized
as that).
2023-09-28 06:29:37 +00:00
|
|
|
[0] = pga3_scale_component,
|
2023-08-23 06:31:20 +00:00
|
|
|
[1] = scale_component,
|
|
|
|
[2] = scale_component,
|
|
|
|
[3] = scale_component,
|
|
|
|
[4] = scale_component,
|
[qfcc] Split up pga3 4-component scales
While splitting up the scaled vector into scaled xyz and scaled w does
cost an extra instruction, it allows for other optimizations to be
applied. For one, extends get all the way to the top now, and there are
at most two (in my test cases), thus either break-even or even a slight
reduction in instruction count. However, in the initial implementation,
I forgot to do the actual scaling, and 12 instructions were removed from
my fancy zero case, but real tests failed :P It looks like it's just
distributivity and commutativity holding things back (eg,
omega*gamma*sigma - gamma*omega*sigma: should be 0, but not recognized
as that).
2023-09-28 06:29:37 +00:00
|
|
|
[5] = pga3_scale_component,
|
2023-08-23 06:31:20 +00:00
|
|
|
},
|
|
|
|
[3] = {
|
|
|
|
[0] = pga3_wx_wy_wz_wedge_x_y_z_w,
|
|
|
|
[1] = pga3_wx_wy_wz_wedge_yz_zx_xy,
|
|
|
|
[2] = scale_component,
|
|
|
|
},
|
|
|
|
[4] = {
|
|
|
|
[2] = scale_component,
|
|
|
|
},
|
|
|
|
[5] = {
|
|
|
|
[0] = pga3_wzy_wxz_wyx_xyz_wedge_x_y_z_w,
|
[qfcc] Split up pga3 4-component scales
While splitting up the scaled vector into scaled xyz and scaled w does
cost an extra instruction, it allows for other optimizations to be
applied. For one, extends get all the way to the top now, and there are
at most two (in my test cases), thus either break-even or even a slight
reduction in instruction count. However, in the initial implementation,
I forgot to do the actual scaling, and 12 instructions were removed from
my fancy zero case, but real tests failed :P It looks like it's just
distributivity and commutativity holding things back (eg,
omega*gamma*sigma - gamma*omega*sigma: should be 0, but not recognized
as that).
2023-09-28 06:29:37 +00:00
|
|
|
[2] = pga3_scale_component,
|
2023-08-23 06:31:20 +00:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2023-08-23 12:52:33 +00:00
|
|
|
// vector-bivector wedge is commutative
|
|
|
|
#define pga2_x_y_w_wedge_yw_wx_xy pga2_yw_wx_xy_wedge_x_y_w
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga2_yw_wx_xy_wedge_x_y_w (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-23 12:52:33 +00:00
|
|
|
{
|
2023-09-09 12:19:50 +00:00
|
|
|
c[1] = dot_expr (algebra_mvec_type (alg, 0x02), a, b);
|
2023-08-23 12:52:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga2_x_y_w_wedge_x_y_w (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-23 12:52:33 +00:00
|
|
|
{
|
2023-09-09 12:19:50 +00:00
|
|
|
auto wedge_type = algebra_mvec_type (alg, 0x04);
|
|
|
|
c[2] = cross_expr (wedge_type, a, b);
|
2023-08-23 12:52:33 +00:00
|
|
|
}
|
|
|
|
|
2023-08-23 15:19:58 +00:00
|
|
|
static pga_func pga2_wedge_funcs[4][4] = {
|
2023-08-23 12:52:33 +00:00
|
|
|
[0] = {
|
2023-09-09 12:19:50 +00:00
|
|
|
[0] = pga2_x_y_w_wedge_x_y_w,
|
|
|
|
[2] = pga2_x_y_w_wedge_yw_wx_xy,
|
|
|
|
[3] = scale_component,
|
2023-08-23 12:52:33 +00:00
|
|
|
},
|
|
|
|
[1] = {
|
|
|
|
[3] = scale_component,
|
|
|
|
},
|
|
|
|
[2] = {
|
2023-09-09 12:19:50 +00:00
|
|
|
[0] = pga2_yw_wx_xy_wedge_x_y_w,
|
|
|
|
[3] = scale_component,
|
2023-08-23 12:52:33 +00:00
|
|
|
},
|
2023-08-24 06:49:52 +00:00
|
|
|
[3] = {
|
2023-09-09 12:19:50 +00:00
|
|
|
[0] = scale_component,
|
2023-08-24 06:49:52 +00:00
|
|
|
[1] = scale_component,
|
2023-09-09 12:19:50 +00:00
|
|
|
[2] = scale_component,
|
|
|
|
[3] = scale_component,
|
2023-08-24 06:49:52 +00:00
|
|
|
},
|
2023-08-23 12:52:33 +00:00
|
|
|
};
|
|
|
|
|
2023-09-07 12:40:17 +00:00
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
vga3_x_y_z_wedge_x_y_z (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-09-07 12:40:17 +00:00
|
|
|
{
|
|
|
|
c[2] = cross_expr (algebra_mvec_type (alg, 0x04), a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
vga3_x_y_z_wedge_yz_zx_xy (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-09-07 12:40:17 +00:00
|
|
|
{
|
2023-09-08 02:15:36 +00:00
|
|
|
c[1] = dot_expr (algebra_mvec_type (alg, 0x02), a, b);
|
2023-09-07 12:40:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
vga3_yz_zx_xy_wedge_x_y_z (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-09-07 12:40:17 +00:00
|
|
|
{
|
2023-09-08 02:15:36 +00:00
|
|
|
c[1] = dot_expr (algebra_mvec_type (alg, 0x02), a, b);
|
2023-09-07 12:40:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static pga_func vga3_wedge_funcs[4][4] = {
|
|
|
|
[0] = {
|
2023-09-08 02:15:36 +00:00
|
|
|
[0] = vga3_x_y_z_wedge_x_y_z,
|
|
|
|
[2] = vga3_x_y_z_wedge_yz_zx_xy,
|
2023-09-07 12:40:17 +00:00
|
|
|
[3] = scale_component,
|
|
|
|
},
|
|
|
|
[1] = {
|
2023-09-08 02:15:36 +00:00
|
|
|
[3] = scale_component,
|
2023-09-07 12:40:17 +00:00
|
|
|
},
|
|
|
|
[2] = {
|
2023-09-08 02:15:36 +00:00
|
|
|
[0] = vga3_yz_zx_xy_wedge_x_y_z,
|
|
|
|
[3] = scale_component,
|
2023-09-07 12:40:17 +00:00
|
|
|
},
|
|
|
|
[3] = {
|
2023-09-08 02:15:36 +00:00
|
|
|
[0] = scale_component,
|
|
|
|
[1] = scale_component,
|
|
|
|
[2] = scale_component,
|
|
|
|
[3] = scale_component,
|
2023-09-07 12:40:17 +00:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2023-08-23 06:31:20 +00:00
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
component_wedge (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *algebra)
|
2023-08-23 06:31:20 +00:00
|
|
|
{
|
|
|
|
int p = algebra->plus;
|
|
|
|
int m = algebra->minus;
|
|
|
|
int z = algebra->zero;
|
|
|
|
|
|
|
|
if (p == 3 && m == 0 && z == 1) {
|
|
|
|
int ga = get_group (get_type (a), algebra);
|
|
|
|
int gb = get_group (get_type (b), algebra);
|
|
|
|
if (pga3_wedge_funcs[ga][gb]) {
|
|
|
|
pga3_wedge_funcs[ga][gb] (c, a, b, algebra);
|
|
|
|
}
|
|
|
|
} else if (p == 2 && m == 0 && z == 1) {
|
2023-08-23 12:52:33 +00:00
|
|
|
int ga = get_group (get_type (a), algebra);
|
|
|
|
int gb = get_group (get_type (b), algebra);
|
|
|
|
if (pga2_wedge_funcs[ga][gb]) {
|
|
|
|
pga2_wedge_funcs[ga][gb] (c, a, b, algebra);
|
|
|
|
}
|
2023-09-07 12:40:17 +00:00
|
|
|
} else if (p == 3 && m == 0 && z == 0) {
|
|
|
|
int ga = get_group (get_type (a), algebra);
|
|
|
|
int gb = get_group (get_type (b), algebra);
|
|
|
|
if (vga3_wedge_funcs[ga][gb]) {
|
|
|
|
vga3_wedge_funcs[ga][gb] (c, a, b, algebra);
|
|
|
|
}
|
2023-08-23 06:31:20 +00:00
|
|
|
} else {
|
2023-08-28 11:34:18 +00:00
|
|
|
internal_error (a, "not implemented");
|
2023-08-23 06:31:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-27 03:41:31 +00:00
|
|
|
static const expr_t *
|
|
|
|
outer_product (const expr_t *e1, const expr_t *e2)
|
2023-08-23 06:31:20 +00:00
|
|
|
{
|
2023-08-24 13:07:04 +00:00
|
|
|
auto t1 = get_type (e1);
|
|
|
|
auto t2 = get_type (e2);
|
|
|
|
auto algebra = is_algebra (t1) ? algebra_get (t1) : algebra_get (t2);
|
|
|
|
auto layout = &algebra->layout;
|
2023-09-27 03:41:31 +00:00
|
|
|
const expr_t *a[layout->count] = {};
|
|
|
|
const expr_t *b[layout->count] = {};
|
|
|
|
const expr_t *c[layout->count] = {};
|
2023-08-24 13:07:04 +00:00
|
|
|
e1 = mvec_expr (e1, algebra);
|
|
|
|
e2 = mvec_expr (e2, algebra);
|
|
|
|
mvec_scatter (a, e1, algebra);
|
|
|
|
mvec_scatter (b, e2, algebra);
|
|
|
|
|
|
|
|
for (int i = 0; i < layout->count; i++) {
|
|
|
|
for (int j = 0; j < layout->count; j++) {
|
|
|
|
if (a[i] && b[j]) {
|
2023-09-27 03:41:31 +00:00
|
|
|
const expr_t *w[layout->count] = {};
|
2023-08-24 13:07:04 +00:00
|
|
|
component_wedge (w, a[i], b[j], algebra);
|
2023-08-30 06:45:44 +00:00
|
|
|
if (!check_types (w, algebra)) {
|
|
|
|
internal_error (a[i], "wrong types in wedge product");
|
|
|
|
}
|
2023-08-24 13:07:04 +00:00
|
|
|
component_sum ('+', c, c, w, algebra);
|
|
|
|
}
|
|
|
|
}
|
2023-08-23 06:31:20 +00:00
|
|
|
}
|
2023-08-24 13:07:04 +00:00
|
|
|
return mvec_gather (c, algebra);
|
|
|
|
}
|
|
|
|
|
2023-08-25 08:30:25 +00:00
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_x_y_z_w_geom_x_y_z_w (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-25 08:30:25 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
auto geom_type = algebra_mvec_type (alg, 0x08);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto va = offset_cast (vtype, a, 0);
|
|
|
|
auto vb = offset_cast (vtype, b, 0);
|
|
|
|
auto sa = offset_cast (stype, a, 3);
|
|
|
|
auto sb = offset_cast (stype, b, 3);
|
2023-08-30 06:45:44 +00:00
|
|
|
c[2] = dot_expr (stype, va, vb);
|
2023-08-25 08:30:25 +00:00
|
|
|
c[1] = cross_expr (algebra_mvec_type (alg, 0x02), va, vb);
|
2023-09-02 02:18:50 +00:00
|
|
|
c[3] = sum_expr (geom_type,
|
|
|
|
scale_expr (geom_type, vb, sa),
|
|
|
|
neg_expr (scale_expr (geom_type, va, sb)));
|
2023-08-25 08:30:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_x_y_z_w_geom_yz_zx_xy (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-25 08:30:25 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
auto geom_type = algebra_mvec_type (alg, 0x20);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto va = offset_cast (vtype, a, 0);
|
|
|
|
auto sa = offset_cast (stype, a, 3);
|
2023-08-30 06:00:27 +00:00
|
|
|
auto cv = scale_expr (vtype, b, sa);
|
2023-08-25 08:30:25 +00:00
|
|
|
auto cs = dot_expr (stype, va, b);
|
2023-09-02 08:21:16 +00:00
|
|
|
c[0] = ext_expr (cross_expr (vtype, b, va),
|
2023-08-30 06:00:27 +00:00
|
|
|
algebra_mvec_type (alg, 0x01), 0, false);
|
2023-09-02 08:21:16 +00:00
|
|
|
cv = ext_expr (neg_expr (cv), geom_type, 0, false);
|
|
|
|
cs = ext_expr (cs, geom_type, 0, true);
|
2023-09-02 02:43:49 +00:00
|
|
|
c[5] = sum_expr (geom_type, cv, cs);
|
2023-08-25 08:30:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_x_y_z_w_geom_wx_wy_wz (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-25 08:30:25 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
auto geom_type = algebra_mvec_type (alg, 0x20);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto va = offset_cast (vtype, a, 0);
|
2023-09-02 02:18:50 +00:00
|
|
|
auto cs = neg_expr (dot_expr (stype, va, b));
|
2023-09-02 08:21:16 +00:00
|
|
|
c[5] = ext_expr (cross_expr (vtype, va, b), geom_type, 0, false);
|
|
|
|
c[0] = ext_expr (cs, algebra_mvec_type (alg, 0x01), 0, true);
|
2023-08-25 08:30:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_x_y_z_w_geom_wxyz (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-25 08:30:25 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
auto geom_type = algebra_mvec_type (alg, 0x20);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto va = offset_cast (vtype, a, 0);
|
|
|
|
auto sb = offset_cast (stype, b, 0);
|
2023-08-30 06:00:27 +00:00
|
|
|
auto cv = scale_expr (vtype, va, sb);
|
2023-09-02 08:21:16 +00:00
|
|
|
c[5] = ext_expr (cv, geom_type, 0, false);
|
2023-08-25 08:30:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_x_y_z_w_geom_wzy_wxz_wyx_xyz (const expr_t **c,
|
|
|
|
const expr_t *a, const expr_t *b,
|
2023-08-25 08:30:25 +00:00
|
|
|
algebra_t *alg)
|
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
auto geom_type = algebra_mvec_type (alg, 0x10);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto va = offset_cast (vtype, a, 0);
|
|
|
|
auto vb = offset_cast (vtype, b, 0);
|
|
|
|
auto sb = offset_cast (stype, b, 3);
|
2023-08-25 08:30:25 +00:00
|
|
|
c[1] = scale_expr (algebra_mvec_type (alg, 0x02), va, sb);
|
2023-08-30 06:00:27 +00:00
|
|
|
c[3] = cross_expr (algebra_mvec_type (alg, 0x08), vb, va);
|
2023-08-25 08:30:25 +00:00
|
|
|
c[4] = dot_expr (geom_type, a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_yz_zx_xy_geom_x_y_z_w (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-25 08:30:25 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
auto geom_type = algebra_mvec_type (alg, 0x20);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto vb = offset_cast (vtype, b, 0);
|
|
|
|
auto sb = offset_cast (stype, b, 3);
|
2023-08-30 06:00:27 +00:00
|
|
|
auto cv = scale_expr (vtype, a, sb);
|
2023-08-25 08:30:25 +00:00
|
|
|
auto cs = dot_expr (stype, vb, a);
|
2023-09-02 08:21:16 +00:00
|
|
|
c[0] = ext_expr (cross_expr (vtype, vb, a),
|
2023-08-30 06:00:27 +00:00
|
|
|
algebra_mvec_type (alg, 0x01), 0, false);
|
2023-09-02 08:21:16 +00:00
|
|
|
cv = ext_expr (neg_expr (cv), geom_type, 0, false);
|
|
|
|
cs = ext_expr (cs, geom_type, 0, true);
|
2023-09-02 02:43:49 +00:00
|
|
|
c[5] = sum_expr (geom_type, cv, cs);
|
2023-08-25 08:30:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_yz_zx_xy_geom_yz_zx_xy (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-25 08:30:25 +00:00
|
|
|
{
|
2024-02-03 11:56:04 +00:00
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
a = offset_cast (vtype, a, 0);
|
|
|
|
b = offset_cast (vtype, b, 0);
|
2023-08-25 08:30:25 +00:00
|
|
|
c[1] = cross_expr (algebra_mvec_type (alg, 0x02), b, a);
|
2023-09-02 02:18:50 +00:00
|
|
|
c[2] = neg_expr (dot_expr (algebra_mvec_type (alg, 0x04), b, a));
|
2023-08-25 08:30:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_yz_zx_xy_geom_wx_wy_wz (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-25 08:30:25 +00:00
|
|
|
{
|
2024-02-03 11:56:04 +00:00
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
a = offset_cast (vtype, a, 0);
|
|
|
|
b = offset_cast (vtype, b, 0);
|
2023-08-25 08:30:25 +00:00
|
|
|
c[3] = cross_expr (algebra_mvec_type (alg, 0x08), b, a);
|
|
|
|
c[4] = dot_expr (algebra_mvec_type (alg, 0x10), b, a);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_yz_zx_xy_geom_wxyz (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-25 08:30:25 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
2023-08-26 14:57:37 +00:00
|
|
|
auto sb = offset_cast (stype, b, 0);
|
2023-09-02 02:18:50 +00:00
|
|
|
c[3] = neg_expr (scale_expr (algebra_mvec_type (alg, 0x08), a, sb));
|
2023-08-25 08:30:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_yz_zx_xy_geom_wzy_wxz_wyx_xyz (const expr_t **c,
|
|
|
|
const expr_t *a, const expr_t *b,
|
2023-08-25 08:30:25 +00:00
|
|
|
algebra_t *alg)
|
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
auto geom_type = algebra_mvec_type (alg, 0x01);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto vb = offset_cast (vtype, b, 0);
|
|
|
|
auto sb = offset_cast (stype, b, 3);
|
2023-08-30 06:00:27 +00:00
|
|
|
auto cv = scale_expr (vtype, a, sb);
|
2023-08-25 08:30:25 +00:00
|
|
|
auto cs = dot_expr (stype, vb, a);
|
2023-09-02 08:21:16 +00:00
|
|
|
cv = ext_expr (neg_expr (cv), geom_type, 0, false);
|
|
|
|
cs = ext_expr (cs, geom_type, 0, true);
|
2023-09-02 02:43:49 +00:00
|
|
|
c[0] = sum_expr (geom_type, cv, cs);
|
2023-09-02 08:21:16 +00:00
|
|
|
c[5] = ext_expr (cross_expr (vtype, vb, a),
|
2023-08-30 06:00:27 +00:00
|
|
|
algebra_mvec_type (alg, 0x20), 0, false);
|
2023-08-25 08:30:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_wx_wy_wz_geom_x_y_z_w (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-25 08:30:25 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
auto geom_type = algebra_mvec_type (alg, 0x20);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto vb = offset_cast (vtype, b, 0);
|
2023-08-25 08:30:25 +00:00
|
|
|
auto cs = dot_expr (stype, vb, a);
|
2023-09-02 08:21:16 +00:00
|
|
|
c[5] = ext_expr (cross_expr (vtype, vb, a), geom_type, 0, false);
|
|
|
|
c[0] = ext_expr (cs, algebra_mvec_type (alg, 0x01), 0, true);
|
2023-08-25 08:30:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_wx_wy_wz_geom_yz_zx_xy (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-25 08:30:25 +00:00
|
|
|
{
|
2024-02-03 11:56:04 +00:00
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
a = offset_cast (vtype, a, 0);
|
|
|
|
b = offset_cast (vtype, b, 0);
|
2023-08-30 06:00:27 +00:00
|
|
|
c[3] = cross_expr (algebra_mvec_type (alg, 0x08), b, a);
|
2023-08-25 08:30:25 +00:00
|
|
|
c[4] = dot_expr (algebra_mvec_type (alg, 0x10), a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_wx_wy_wz_geom_wzy_wxz_wyx_xyz (const expr_t **c,
|
|
|
|
const expr_t *a, const expr_t *b,
|
2023-08-25 08:30:25 +00:00
|
|
|
algebra_t *alg)
|
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
2023-08-30 06:00:27 +00:00
|
|
|
auto vtype = vector_type (stype, 3);
|
2023-08-25 08:30:25 +00:00
|
|
|
auto geom_type = algebra_mvec_type (alg, 0x20);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto vs = offset_cast (stype, b, 3);
|
2023-09-02 02:18:50 +00:00
|
|
|
auto cv = neg_expr (scale_expr (vtype, a, vs));
|
2023-09-02 08:21:16 +00:00
|
|
|
c[5] = ext_expr (cv, geom_type, 0, false);
|
2023-08-25 08:30:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_wxyz_geom_x_y_z_w (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-25 08:30:25 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
auto geom_type = algebra_mvec_type (alg, 0x20);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto sa = offset_cast (stype, a, 0);
|
|
|
|
auto vb = offset_cast (vtype, b, 0);
|
2023-09-02 02:18:50 +00:00
|
|
|
auto cv = neg_expr (scale_expr (vtype, vb, sa));
|
2023-09-02 08:21:16 +00:00
|
|
|
c[5] = ext_expr (cv, geom_type, 0, false);
|
2023-08-30 06:00:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_wxyz_geom_yz_zx_xy (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-30 06:00:27 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto sa = offset_cast (stype, a, 0);
|
2023-09-02 02:18:50 +00:00
|
|
|
c[3] = neg_expr (scale_expr (algebra_mvec_type (alg, 0x08), b, sa));
|
2023-08-25 08:30:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_wxyz_geom_wzy_wxz_wyx_xyz (const expr_t **c,
|
|
|
|
const expr_t *a, const expr_t *b,
|
2023-08-25 08:30:25 +00:00
|
|
|
algebra_t *alg)
|
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
2023-08-26 14:57:37 +00:00
|
|
|
auto sa = offset_cast (stype, a, 0);
|
|
|
|
auto sb = offset_cast (stype, b, 3);
|
2023-08-25 08:30:25 +00:00
|
|
|
auto geom_type = algebra_mvec_type (alg, 0x01);
|
|
|
|
auto cs = scale_expr (stype, sa, sb);
|
2023-09-02 08:21:16 +00:00
|
|
|
c[0] = ext_expr (neg_expr (cs), geom_type, 0, true);
|
2023-08-25 08:30:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_wzy_wxz_wyx_xyz_geom_x_y_z_w (const expr_t **c,
|
|
|
|
const expr_t *a, const expr_t *b,
|
2023-08-25 08:30:25 +00:00
|
|
|
algebra_t *alg)
|
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
auto geom_type = algebra_mvec_type (alg, 0x10);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto va = offset_cast (vtype, a, 0);
|
|
|
|
auto sa = offset_cast (stype, a, 3);
|
|
|
|
auto vb = offset_cast (vtype, b, 0);
|
2023-08-25 08:30:25 +00:00
|
|
|
c[1] = scale_expr (algebra_mvec_type (alg, 0x02), vb, sa);
|
2023-08-30 06:00:27 +00:00
|
|
|
c[3] = cross_expr (algebra_mvec_type (alg, 0x08), va, vb);
|
2023-09-02 02:18:50 +00:00
|
|
|
c[4] = neg_expr (dot_expr (geom_type, b, a));
|
2023-08-30 06:00:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_wzy_wxz_wyx_xyz_geom_yz_zx_xy (const expr_t **c,
|
|
|
|
const expr_t *a, const expr_t *b,
|
2023-08-30 06:00:27 +00:00
|
|
|
algebra_t *alg)
|
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
auto geom_type = algebra_mvec_type (alg, 0x01);
|
|
|
|
auto va = offset_cast (vtype, a, 0);
|
|
|
|
auto sa = offset_cast (stype, a, 3);
|
|
|
|
auto cv = scale_expr (vtype, b, sa);
|
|
|
|
auto cs = dot_expr (stype, va, b);
|
2023-09-02 08:21:16 +00:00
|
|
|
cv = ext_expr (neg_expr (cv), geom_type, 0, false);
|
|
|
|
cs = ext_expr (cs, geom_type, 0, true);
|
2023-09-02 02:43:49 +00:00
|
|
|
c[0] = sum_expr (geom_type, cv, cs);
|
2023-09-02 08:21:16 +00:00
|
|
|
c[5] = ext_expr (cross_expr (vtype, b, va),
|
2023-08-30 06:00:27 +00:00
|
|
|
algebra_mvec_type (alg, 0x20), 0, false);
|
2023-08-25 08:30:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_wzy_wxz_wyx_xyz_geom_wx_wy_wz (const expr_t **c,
|
|
|
|
const expr_t *a, const expr_t *b,
|
2023-08-25 08:30:25 +00:00
|
|
|
algebra_t *alg)
|
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
2023-08-30 06:00:27 +00:00
|
|
|
auto vtype = vector_type (stype, 3);
|
2023-08-25 08:30:25 +00:00
|
|
|
auto geom_type = algebra_mvec_type (alg, 0x20);
|
2023-08-30 06:00:27 +00:00
|
|
|
auto sa = offset_cast (stype, a, 3);
|
|
|
|
auto cv = scale_expr (vtype, b, sa);
|
2023-09-02 08:21:16 +00:00
|
|
|
c[5] = ext_expr (cv, geom_type, 0, false);
|
2023-08-25 08:30:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_wzy_wxz_wyx_xyz_geom_wxyz (const expr_t **c,
|
|
|
|
const expr_t *a, const expr_t *b,
|
2023-08-25 08:30:25 +00:00
|
|
|
algebra_t *alg)
|
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
2023-08-30 06:00:27 +00:00
|
|
|
auto sa = offset_cast (stype, a, 3);
|
|
|
|
auto sb = offset_cast (stype, b, 0);
|
2023-08-25 08:30:25 +00:00
|
|
|
auto geom_type = algebra_mvec_type (alg, 0x01);
|
|
|
|
auto cs = scale_expr (stype, sa, sb);
|
2023-09-02 08:21:16 +00:00
|
|
|
c[0] = ext_expr (cs, geom_type, 0, true);
|
2023-08-25 08:30:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga3_wzy_wxz_wyx_xyz_geom_wzy_wxz_wyx_xyz (const expr_t **c,
|
|
|
|
const expr_t *a, const expr_t *b,
|
2023-08-25 08:30:25 +00:00
|
|
|
algebra_t *alg)
|
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
auto geom_type = algebra_mvec_type (alg, 0x08);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto va = offset_cast (vtype, a, 0);
|
|
|
|
auto vb = offset_cast (vtype, b, 0);
|
|
|
|
auto sa = offset_cast (stype, a, 3);
|
|
|
|
auto sb = offset_cast (stype, b, 3);
|
2023-09-02 02:18:50 +00:00
|
|
|
c[2] = neg_expr (scale_expr (stype, sa, sb));
|
|
|
|
c[3] = sum_expr (geom_type,
|
|
|
|
scale_expr (geom_type, va, sb),
|
|
|
|
neg_expr (scale_expr (geom_type, vb, sa)));
|
2023-08-25 08:30:25 +00:00
|
|
|
}
|
|
|
|
|
2023-08-24 13:07:04 +00:00
|
|
|
static pga_func pga3_geometric_funcs[6][6] = {
|
2023-08-25 08:30:25 +00:00
|
|
|
[0] = {
|
|
|
|
[0] = pga3_x_y_z_w_geom_x_y_z_w,
|
|
|
|
[1] = pga3_x_y_z_w_geom_yz_zx_xy,
|
[qfcc] Split up pga3 4-component scales
While splitting up the scaled vector into scaled xyz and scaled w does
cost an extra instruction, it allows for other optimizations to be
applied. For one, extends get all the way to the top now, and there are
at most two (in my test cases), thus either break-even or even a slight
reduction in instruction count. However, in the initial implementation,
I forgot to do the actual scaling, and 12 instructions were removed from
my fancy zero case, but real tests failed :P It looks like it's just
distributivity and commutativity holding things back (eg,
omega*gamma*sigma - gamma*omega*sigma: should be 0, but not recognized
as that).
2023-09-28 06:29:37 +00:00
|
|
|
[2] = pga3_scale_component,
|
2023-08-25 08:30:25 +00:00
|
|
|
[3] = pga3_x_y_z_w_geom_wx_wy_wz,
|
|
|
|
[4] = pga3_x_y_z_w_geom_wxyz,
|
|
|
|
[5] = pga3_x_y_z_w_geom_wzy_wxz_wyx_xyz,
|
|
|
|
},
|
|
|
|
[1] = {
|
|
|
|
[0] = pga3_yz_zx_xy_geom_x_y_z_w,
|
|
|
|
[1] = pga3_yz_zx_xy_geom_yz_zx_xy,
|
|
|
|
[2] = scale_component,
|
|
|
|
[3] = pga3_yz_zx_xy_geom_wx_wy_wz,
|
|
|
|
[4] = pga3_yz_zx_xy_geom_wxyz,
|
|
|
|
[5] = pga3_yz_zx_xy_geom_wzy_wxz_wyx_xyz,
|
|
|
|
},
|
2023-08-24 13:07:04 +00:00
|
|
|
[2] = {
|
[qfcc] Split up pga3 4-component scales
While splitting up the scaled vector into scaled xyz and scaled w does
cost an extra instruction, it allows for other optimizations to be
applied. For one, extends get all the way to the top now, and there are
at most two (in my test cases), thus either break-even or even a slight
reduction in instruction count. However, in the initial implementation,
I forgot to do the actual scaling, and 12 instructions were removed from
my fancy zero case, but real tests failed :P It looks like it's just
distributivity and commutativity holding things back (eg,
omega*gamma*sigma - gamma*omega*sigma: should be 0, but not recognized
as that).
2023-09-28 06:29:37 +00:00
|
|
|
[0] = pga3_scale_component,
|
2023-08-24 13:07:04 +00:00
|
|
|
[1] = scale_component,
|
|
|
|
[2] = scale_component,
|
|
|
|
[3] = scale_component,
|
|
|
|
[4] = scale_component,
|
[qfcc] Split up pga3 4-component scales
While splitting up the scaled vector into scaled xyz and scaled w does
cost an extra instruction, it allows for other optimizations to be
applied. For one, extends get all the way to the top now, and there are
at most two (in my test cases), thus either break-even or even a slight
reduction in instruction count. However, in the initial implementation,
I forgot to do the actual scaling, and 12 instructions were removed from
my fancy zero case, but real tests failed :P It looks like it's just
distributivity and commutativity holding things back (eg,
omega*gamma*sigma - gamma*omega*sigma: should be 0, but not recognized
as that).
2023-09-28 06:29:37 +00:00
|
|
|
[5] = pga3_scale_component,
|
2023-08-24 13:07:04 +00:00
|
|
|
},
|
2023-08-25 08:30:25 +00:00
|
|
|
[3] = {
|
|
|
|
[0] = pga3_wx_wy_wz_geom_x_y_z_w,
|
|
|
|
[1] = pga3_wx_wy_wz_geom_yz_zx_xy,
|
|
|
|
[2] = scale_component,
|
|
|
|
[5] = pga3_wx_wy_wz_geom_wzy_wxz_wyx_xyz,
|
|
|
|
},
|
|
|
|
[4] = {
|
|
|
|
[0] = pga3_wxyz_geom_x_y_z_w,
|
|
|
|
[1] = pga3_wxyz_geom_yz_zx_xy,
|
|
|
|
[2] = scale_component,
|
|
|
|
[5] = pga3_wxyz_geom_wzy_wxz_wyx_xyz,
|
|
|
|
},
|
|
|
|
[5] = {
|
|
|
|
[0] = pga3_wzy_wxz_wyx_xyz_geom_x_y_z_w,
|
|
|
|
[1] = pga3_wzy_wxz_wyx_xyz_geom_yz_zx_xy,
|
[qfcc] Split up pga3 4-component scales
While splitting up the scaled vector into scaled xyz and scaled w does
cost an extra instruction, it allows for other optimizations to be
applied. For one, extends get all the way to the top now, and there are
at most two (in my test cases), thus either break-even or even a slight
reduction in instruction count. However, in the initial implementation,
I forgot to do the actual scaling, and 12 instructions were removed from
my fancy zero case, but real tests failed :P It looks like it's just
distributivity and commutativity holding things back (eg,
omega*gamma*sigma - gamma*omega*sigma: should be 0, but not recognized
as that).
2023-09-28 06:29:37 +00:00
|
|
|
[2] = pga3_scale_component,
|
2023-08-25 08:30:25 +00:00
|
|
|
[3] = pga3_wzy_wxz_wyx_xyz_geom_wx_wy_wz,
|
|
|
|
[4] = pga3_wzy_wxz_wyx_xyz_geom_wxyz,
|
|
|
|
[5] = pga3_wzy_wxz_wyx_xyz_geom_wzy_wxz_wyx_xyz,
|
|
|
|
},
|
2023-08-24 13:07:04 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga2_yw_wx_xy_geom_yw_wx_xy (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-24 13:07:04 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
2023-08-31 11:22:59 +00:00
|
|
|
auto vtype = vector_type (stype, 3);
|
|
|
|
auto ctype = vector_type (stype, 2);
|
2023-09-09 12:19:50 +00:00
|
|
|
auto geom_type = algebra_mvec_type (alg, 0x04);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto sa = offset_cast (stype, a, 2);
|
|
|
|
auto sb = offset_cast (stype, b, 2);
|
2024-02-11 12:47:21 +00:00
|
|
|
auto cv = cross_expr (vtype, b, a);
|
2023-08-24 13:07:04 +00:00
|
|
|
|
2024-02-11 12:47:21 +00:00
|
|
|
if (cv) {
|
|
|
|
c[2] = ext_expr (offset_cast (ctype, cv, 0), geom_type, 0, false);
|
|
|
|
}
|
2023-09-09 12:19:50 +00:00
|
|
|
c[3] = neg_expr (scale_expr (algebra_mvec_type (alg, 0x08), sa, sb));
|
2023-08-24 13:07:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga2_yw_wx_xy_geom_x_y_w (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-24 13:07:04 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
2023-08-31 11:22:59 +00:00
|
|
|
auto wtype = vector_type (stype, 2);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto vtype = vector_type (stype, 3);
|
2023-08-31 11:22:59 +00:00
|
|
|
auto va = offset_cast (wtype, a, 0);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto sa = offset_cast (stype, a, 2);
|
2023-08-31 11:22:59 +00:00
|
|
|
auto vb = offset_cast (wtype, b, 0);
|
2023-09-25 07:09:51 +00:00
|
|
|
auto cv = edag_add_expr (new_swizzle_expr (vb, "y-x"));
|
2023-08-31 11:22:59 +00:00
|
|
|
auto cs = wedge_expr (stype, vb, va);
|
2024-02-11 12:47:21 +00:00
|
|
|
cs = ext_expr (cs, vtype, 0, true);
|
2023-09-02 08:21:16 +00:00
|
|
|
cv = ext_expr (scale_expr (wtype, cv, sa), vtype, 0, false);
|
2024-02-11 12:47:21 +00:00
|
|
|
c[0] = sum_expr (algebra_mvec_type (alg, 0x01), cv, cs);
|
2023-09-09 12:19:50 +00:00
|
|
|
c[1] = dot_expr (algebra_mvec_type (alg, 0x02), a, b);
|
2023-08-24 13:07:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga2_yw_wx_xy_geom_wxy (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-24 13:07:04 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
2023-08-27 06:24:35 +00:00
|
|
|
auto sa = offset_cast (stype, a, 2);
|
|
|
|
auto sb = offset_cast (stype, b, 0);
|
2023-09-02 02:18:50 +00:00
|
|
|
auto cs = neg_expr (scale_expr (stype, sa, sb));
|
2023-09-09 12:19:50 +00:00
|
|
|
c[2] = ext_expr (cs, algebra_mvec_type (alg, 0x04), 0, true);
|
2023-08-24 13:07:04 +00:00
|
|
|
}
|
2023-08-23 06:31:20 +00:00
|
|
|
|
2023-08-24 13:07:04 +00:00
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga2_x_y_w_geom_yw_wx_xy (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-24 13:07:04 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
2023-08-31 11:22:59 +00:00
|
|
|
auto wtype = vector_type (stype, 2);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto vtype = vector_type (stype, 3);
|
2023-09-09 12:19:50 +00:00
|
|
|
auto geom_type = algebra_mvec_type (alg, 0x01);
|
2023-08-31 11:22:59 +00:00
|
|
|
auto va = offset_cast (wtype, a, 0);
|
|
|
|
auto vb = offset_cast (wtype, b, 0);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto sb = offset_cast (stype, b, 2);
|
2023-09-25 07:09:51 +00:00
|
|
|
auto cv = edag_add_expr (new_swizzle_expr (va, "-yx"));
|
2023-08-31 11:22:59 +00:00
|
|
|
auto cs = wedge_expr (stype, vb, va);
|
2023-09-02 08:21:16 +00:00
|
|
|
cs = ext_expr (cs, geom_type, 0, true);
|
|
|
|
cv = ext_expr (scale_expr (wtype, cv, sb), vtype, 0, false);
|
2023-09-09 12:19:50 +00:00
|
|
|
c[0] = sum_expr (geom_type, cv, cs);
|
|
|
|
c[1] = dot_expr (algebra_mvec_type (alg, 0x02), a, b);
|
2023-08-24 13:07:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga2_x_y_w_geom_x_y_w (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-24 13:07:04 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 2);
|
2023-09-09 12:19:50 +00:00
|
|
|
auto geom_type = algebra_mvec_type (alg, 0x04);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto va = offset_cast (vtype, a, 0);
|
|
|
|
auto vb = offset_cast (vtype, b, 0);
|
2023-09-09 12:19:50 +00:00
|
|
|
c[3] = dot_expr (stype, va, vb);
|
|
|
|
c[2] = cross_expr (geom_type, a, b);
|
2023-08-24 13:07:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga2_x_y_w_geom_wxy (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-24 13:07:04 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 2);
|
2023-09-09 12:19:50 +00:00
|
|
|
auto geom_type = algebra_mvec_type (alg, 0x04);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto va = offset_cast (vtype, a, 0);
|
2023-08-27 06:24:35 +00:00
|
|
|
auto cv = scale_expr (vtype, va, b);
|
2023-08-24 13:07:04 +00:00
|
|
|
|
2023-09-09 12:19:50 +00:00
|
|
|
c[2] = ext_expr (cv, geom_type, 0, false);
|
2023-08-24 13:07:04 +00:00
|
|
|
}
|
|
|
|
|
2023-08-27 06:24:35 +00:00
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga2_wxy_geom_yw_wx_xy (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-27 06:24:35 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto sa = offset_cast (stype, a, 0);
|
|
|
|
auto sb = offset_cast (stype, b, 2);
|
2023-09-02 02:18:50 +00:00
|
|
|
auto cs = neg_expr (scale_expr (stype, sa, sb));
|
2023-09-09 12:19:50 +00:00
|
|
|
c[2] = ext_expr (cs, algebra_mvec_type (alg, 0x04), 0, true);
|
2023-08-27 06:24:35 +00:00
|
|
|
}
|
|
|
|
|
2023-08-24 13:07:04 +00:00
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
pga2_wxy_geom_x_y_w (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-08-24 13:07:04 +00:00
|
|
|
{
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, 2);
|
2023-09-09 12:19:50 +00:00
|
|
|
auto geom_type = algebra_mvec_type (alg, 0x04);
|
2023-08-26 14:57:37 +00:00
|
|
|
auto vb = offset_cast (vtype, b, 0);
|
2023-08-27 06:24:35 +00:00
|
|
|
auto cv = scale_expr (vtype, vb, a);
|
2023-08-24 13:07:04 +00:00
|
|
|
|
2023-09-09 12:19:50 +00:00
|
|
|
c[2] = ext_expr (cv, geom_type, 0, false);
|
2023-08-24 13:07:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static pga_func pga2_geometric_funcs[6][6] = {
|
|
|
|
[0] = {
|
2023-09-09 12:19:50 +00:00
|
|
|
[0] = pga2_x_y_w_geom_x_y_w,
|
|
|
|
[1] = pga2_x_y_w_geom_wxy,
|
|
|
|
[2] = pga2_x_y_w_geom_yw_wx_xy,
|
|
|
|
[3] = scale_component,
|
2023-08-24 13:07:04 +00:00
|
|
|
},
|
|
|
|
[1] = {
|
2023-09-09 12:19:50 +00:00
|
|
|
[0] = pga2_wxy_geom_x_y_w,
|
|
|
|
[2] = pga2_wxy_geom_yw_wx_xy,
|
2023-08-24 13:07:04 +00:00
|
|
|
[3] = scale_component,
|
|
|
|
},
|
|
|
|
[2] = {
|
2023-09-09 12:19:50 +00:00
|
|
|
[0] = pga2_yw_wx_xy_geom_x_y_w,
|
|
|
|
[1] = pga2_yw_wx_xy_geom_wxy,
|
|
|
|
[2] = pga2_yw_wx_xy_geom_yw_wx_xy,
|
|
|
|
[3] = scale_component,
|
2023-08-24 13:07:04 +00:00
|
|
|
},
|
|
|
|
[3] = {
|
2023-09-09 12:19:50 +00:00
|
|
|
[0] = scale_component,
|
2023-08-24 13:07:04 +00:00
|
|
|
[1] = scale_component,
|
2023-09-09 12:19:50 +00:00
|
|
|
[2] = scale_component,
|
|
|
|
[3] = scale_component,
|
2023-08-24 13:07:04 +00:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2023-09-08 02:15:36 +00:00
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
vga3_x_y_z_geom_x_y_z (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-09-08 02:15:36 +00:00
|
|
|
{
|
|
|
|
c[3] = dot_expr (algebra_mvec_type (alg, 0x08), a, b);
|
|
|
|
c[2] = cross_expr (algebra_mvec_type (alg, 0x04), a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
vga3_x_y_z_geom_yz_zx_xy (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-09-08 02:15:36 +00:00
|
|
|
{
|
|
|
|
c[0] = cross_expr (algebra_mvec_type (alg, 0x01), b, a);
|
|
|
|
c[1] = dot_expr (algebra_mvec_type (alg, 0x02), a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
vga3_x_y_z_geom_xyz (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-09-08 02:15:36 +00:00
|
|
|
{
|
|
|
|
c[2] = scale_expr (algebra_mvec_type (alg, 0x04), a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
vga3_yz_zx_xy_geom_x_y_z (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-09-08 02:15:36 +00:00
|
|
|
{
|
|
|
|
c[0] = cross_expr (algebra_mvec_type (alg, 0x01), b, a);
|
|
|
|
c[1] = dot_expr (algebra_mvec_type (alg, 0x02), a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
vga3_yz_zx_xy_geom_yz_zx_xy (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-09-08 02:15:36 +00:00
|
|
|
{
|
|
|
|
c[3] = neg_expr (dot_expr (algebra_mvec_type (alg, 0x08), a, b));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
vga3_yz_zx_xy_geom_xyz (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-09-08 02:15:36 +00:00
|
|
|
{
|
|
|
|
c[0] = neg_expr (scale_expr (algebra_mvec_type (alg, 0x01), a, b));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
vga3_xyz_geom_x_y_z (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-09-08 02:15:36 +00:00
|
|
|
{
|
|
|
|
c[2] = scale_expr (algebra_mvec_type (alg, 0x04), b, a);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
vga3_xyz_geom_yz_zx_xy (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-09-08 02:15:36 +00:00
|
|
|
{
|
|
|
|
c[0] = neg_expr (scale_expr (algebra_mvec_type (alg, 0x01), b, a));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
vga3_xyz_geom_xyz (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *alg)
|
2023-09-08 02:15:36 +00:00
|
|
|
{
|
|
|
|
c[3] = neg_expr (scale_expr (algebra_mvec_type (alg, 0x08), b, a));
|
|
|
|
}
|
|
|
|
|
|
|
|
static pga_func vga3_geometric_funcs[6][6] = {
|
|
|
|
[0] = {
|
|
|
|
[0] = vga3_x_y_z_geom_x_y_z,
|
|
|
|
[1] = vga3_x_y_z_geom_xyz,
|
|
|
|
[2] = vga3_x_y_z_geom_yz_zx_xy,
|
|
|
|
[3] = scale_component,
|
|
|
|
},
|
|
|
|
[1] = {
|
|
|
|
[0] = vga3_xyz_geom_x_y_z,
|
|
|
|
[1] = vga3_xyz_geom_xyz,
|
|
|
|
[2] = vga3_xyz_geom_yz_zx_xy,
|
|
|
|
[3] = scale_component,
|
|
|
|
},
|
|
|
|
[2] = {
|
|
|
|
[0] = vga3_yz_zx_xy_geom_x_y_z,
|
|
|
|
[1] = vga3_yz_zx_xy_geom_xyz,
|
|
|
|
[2] = vga3_yz_zx_xy_geom_yz_zx_xy,
|
|
|
|
[3] = scale_component,
|
|
|
|
},
|
|
|
|
[3] = {
|
|
|
|
[0] = scale_component,
|
|
|
|
[1] = scale_component,
|
|
|
|
[2] = scale_component,
|
|
|
|
[3] = scale_component,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2023-08-24 13:07:04 +00:00
|
|
|
static void
|
2023-09-28 04:53:52 +00:00
|
|
|
component_geometric (const expr_t **c, const expr_t *a, const expr_t *b,
|
|
|
|
algebra_t *algebra)
|
2023-08-24 13:07:04 +00:00
|
|
|
{
|
|
|
|
int p = algebra->plus;
|
|
|
|
int m = algebra->minus;
|
|
|
|
int z = algebra->zero;
|
|
|
|
|
|
|
|
if (p == 3 && m == 0 && z == 1) {
|
|
|
|
int ga = get_group (get_type (a), algebra);
|
|
|
|
int gb = get_group (get_type (b), algebra);
|
|
|
|
if (pga3_geometric_funcs[ga][gb]) {
|
|
|
|
pga3_geometric_funcs[ga][gb] (c, a, b, algebra);
|
|
|
|
}
|
|
|
|
} else if (p == 2 && m == 0 && z == 1) {
|
|
|
|
int ga = get_group (get_type (a), algebra);
|
|
|
|
int gb = get_group (get_type (b), algebra);
|
|
|
|
if (pga2_geometric_funcs[ga][gb]) {
|
|
|
|
pga2_geometric_funcs[ga][gb] (c, a, b, algebra);
|
|
|
|
}
|
2023-09-08 02:15:36 +00:00
|
|
|
} else if (p == 3 && m == 0 && z == 0) {
|
|
|
|
int ga = get_group (get_type (a), algebra);
|
|
|
|
int gb = get_group (get_type (b), algebra);
|
|
|
|
if (vga3_geometric_funcs[ga][gb]) {
|
|
|
|
vga3_geometric_funcs[ga][gb] (c, a, b, algebra);
|
|
|
|
}
|
2023-08-24 13:07:04 +00:00
|
|
|
} else {
|
2023-08-28 11:34:18 +00:00
|
|
|
internal_error (a, "not implemented");
|
2023-08-24 13:07:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-27 03:41:31 +00:00
|
|
|
static const expr_t *
|
|
|
|
geometric_product (const expr_t *e1, const expr_t *e2)
|
2023-08-24 13:07:04 +00:00
|
|
|
{
|
2023-08-23 06:31:20 +00:00
|
|
|
auto t1 = get_type (e1);
|
|
|
|
auto t2 = get_type (e2);
|
|
|
|
auto algebra = is_algebra (t1) ? algebra_get (t1) : algebra_get (t2);
|
|
|
|
auto layout = &algebra->layout;
|
2023-09-27 03:41:31 +00:00
|
|
|
const expr_t *a[layout->count] = {};
|
|
|
|
const expr_t *b[layout->count] = {};
|
|
|
|
const expr_t *c[layout->count] = {};
|
2023-08-23 06:31:20 +00:00
|
|
|
e1 = mvec_expr (e1, algebra);
|
|
|
|
e2 = mvec_expr (e2, algebra);
|
|
|
|
mvec_scatter (a, e1, algebra);
|
|
|
|
mvec_scatter (b, e2, algebra);
|
|
|
|
|
|
|
|
for (int i = 0; i < layout->count; i++) {
|
|
|
|
for (int j = 0; j < layout->count; j++) {
|
|
|
|
if (a[i] && b[j]) {
|
2023-09-27 03:41:31 +00:00
|
|
|
const expr_t *w[layout->count] = {};
|
2023-08-24 13:07:04 +00:00
|
|
|
component_geometric (w, a[i], b[j], algebra);
|
2023-08-30 06:45:44 +00:00
|
|
|
if (!check_types (w, algebra)) {
|
|
|
|
internal_error (a[i], "wrong types in geometric product");
|
|
|
|
}
|
2023-08-23 06:31:20 +00:00
|
|
|
component_sum ('+', c, c, w, algebra);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return mvec_gather (c, algebra);
|
|
|
|
}
|
|
|
|
|
2023-09-27 03:41:31 +00:00
|
|
|
static const expr_t *
|
|
|
|
regressive_product (const expr_t *e1, const expr_t *e2)
|
2023-08-23 06:31:20 +00:00
|
|
|
{
|
2023-08-28 11:32:29 +00:00
|
|
|
auto a = algebra_dual (e1);
|
|
|
|
auto b = algebra_dual (e2);
|
|
|
|
auto c = outer_product (a, b);
|
2024-02-09 04:49:36 +00:00
|
|
|
return algebra_undual (c);
|
2023-08-23 06:31:20 +00:00
|
|
|
}
|
|
|
|
|
2023-09-27 03:41:31 +00:00
|
|
|
static const expr_t *
|
|
|
|
multivector_sum (int op, const expr_t *e1, const expr_t *e2)
|
2023-08-21 08:37:56 +00:00
|
|
|
{
|
|
|
|
auto t1 = get_type (e1);
|
|
|
|
auto t2 = get_type (e2);
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
auto algebra = is_algebra (t1) ? algebra_get (t1) : algebra_get (t2);
|
|
|
|
auto layout = &algebra->layout;
|
2023-09-27 03:41:31 +00:00
|
|
|
const expr_t *a[layout->count] = {};
|
|
|
|
const expr_t *b[layout->count] = {};
|
|
|
|
const expr_t *c[layout->count];
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
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);
|
2023-08-21 08:37:56 +00:00
|
|
|
}
|
|
|
|
|
2023-09-27 03:41:31 +00:00
|
|
|
static const expr_t *
|
|
|
|
commutator_product (const expr_t *e1, const expr_t *e2)
|
2023-08-21 08:37:56 +00:00
|
|
|
{
|
|
|
|
auto ab = geometric_product (e1, e2);
|
|
|
|
auto ba = geometric_product (e2, e1);
|
2024-01-19 06:26:18 +00:00
|
|
|
return algebra_binary_expr ('/', multivector_sum ('-', ab, ba),
|
2024-04-18 00:46:10 +00:00
|
|
|
new_int_expr (2, false));
|
2023-08-21 08:37:56 +00:00
|
|
|
}
|
|
|
|
|
2024-09-30 10:11:40 +00:00
|
|
|
static bool
|
|
|
|
is_two (const expr_t *e)
|
|
|
|
{
|
|
|
|
if (is_integral_val (e)) {
|
|
|
|
return expr_integral (e) == 2;
|
|
|
|
}
|
|
|
|
if (is_floating_val (e)) {
|
|
|
|
return expr_floating (e) == 2;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-09-27 03:41:31 +00:00
|
|
|
static const expr_t *
|
|
|
|
multivector_divide (const expr_t *e1, const expr_t *e2)
|
2023-08-21 08:37:56 +00:00
|
|
|
{
|
2023-08-28 03:15:45 +00:00
|
|
|
if (is_algebra (get_type (e2))) {
|
|
|
|
return error (e2, "Division is left-right ambiguous (and works only"
|
|
|
|
" for versors anyway). Use explicit reversion and divide"
|
|
|
|
" by square magnitude instead.");
|
|
|
|
}
|
|
|
|
if (!is_algebra (get_type (e1))) {
|
|
|
|
internal_error (e1, "wtw?");
|
|
|
|
}
|
|
|
|
auto t1 = get_type (e1);
|
|
|
|
auto algebra = algebra_get (t1);
|
|
|
|
auto layout = &algebra->layout;
|
|
|
|
auto stype = algebra->type;
|
2023-09-27 03:41:31 +00:00
|
|
|
const expr_t *a[layout->count] = {};
|
2024-09-30 10:11:40 +00:00
|
|
|
bool is_half = is_two (e2);
|
2023-08-28 03:15:45 +00:00
|
|
|
e1 = mvec_expr (e1, algebra);
|
|
|
|
e2 = promote_scalar (algebra->type, e2);
|
|
|
|
mvec_scatter (a, e1, algebra);
|
|
|
|
|
|
|
|
for (int i = 0; i < layout->count; i++) {
|
|
|
|
if (!a[i]) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
auto den = e2;
|
2024-09-30 10:11:40 +00:00
|
|
|
if (is_half && a[i]->type == ex_expr && a[i]->expr.op == '+'
|
|
|
|
&& a[i]->expr.e1 == a[i]->expr.e2) {
|
|
|
|
a[i] = a[i]->expr.e1;
|
|
|
|
} else {
|
|
|
|
auto ct = get_type (a[i]);
|
|
|
|
int width = type_width (ct);
|
|
|
|
if (width > 1) {
|
|
|
|
den = ext_expr (den, vector_type (stype, width), 2, false);
|
|
|
|
}
|
|
|
|
a[i] = typed_binary_expr (ct, '/', a[i], den);
|
|
|
|
a[i] = edag_add_expr (a[i]);
|
2023-08-28 03:15:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return mvec_gather (a, algebra);
|
2023-08-21 08:37:56 +00:00
|
|
|
}
|
|
|
|
|
2024-02-09 03:51:00 +00:00
|
|
|
static const expr_t *
|
|
|
|
component_compare (int op, const expr_t *e1, const expr_t *e2, algebra_t *alg)
|
|
|
|
{
|
|
|
|
auto t = get_type (e1 ? e1 : e2);
|
|
|
|
auto stype = alg->type;
|
|
|
|
auto vtype = vector_type (stype, type_width (t));
|
2024-09-15 06:02:36 +00:00
|
|
|
pr_type_t zero[type_size (vtype)] = {};
|
2024-02-09 03:51:00 +00:00
|
|
|
if (!e1) {
|
2024-04-18 00:46:10 +00:00
|
|
|
e1 = new_value_expr (new_type_value (vtype, zero), false);
|
2024-02-09 03:51:00 +00:00
|
|
|
} else {
|
|
|
|
e1 = offset_cast (vtype, e1, 0);
|
|
|
|
}
|
|
|
|
if (!e2) {
|
2024-04-18 00:46:10 +00:00
|
|
|
e2 = new_value_expr (new_type_value (vtype, zero), false);
|
2024-02-09 03:51:00 +00:00
|
|
|
} else {
|
|
|
|
e2 = offset_cast (vtype, e2, 0);
|
|
|
|
}
|
|
|
|
return binary_expr (op, e1, e2);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const expr_t *
|
|
|
|
algebra_compare (int op, const expr_t *e1, const expr_t *e2)
|
|
|
|
{
|
|
|
|
auto t1 = get_type (e1);
|
|
|
|
auto t2 = get_type (e2);
|
|
|
|
auto algebra = is_algebra (t1) ? algebra_get (t1) : algebra_get (t2);
|
|
|
|
auto layout = &algebra->layout;
|
|
|
|
const expr_t *a[layout->count] = {};
|
|
|
|
const expr_t *b[layout->count] = {};
|
|
|
|
e1 = mvec_expr (e1, algebra);
|
|
|
|
e2 = mvec_expr (e2, algebra);
|
|
|
|
mvec_scatter (a, e1, algebra);
|
|
|
|
mvec_scatter (b, e2, algebra);
|
|
|
|
|
|
|
|
const expr_t *cmp = nullptr;
|
|
|
|
expr_t *bool_label = nullptr;
|
|
|
|
for (int i = 0; i < layout->count; i++) {
|
|
|
|
if (a[i] || b[i]) {
|
|
|
|
auto c = component_compare (op, a[i], b[i], algebra);
|
|
|
|
if (cmp) {
|
|
|
|
bool_label = new_label_expr ();
|
2024-04-18 00:46:10 +00:00
|
|
|
cmp = bool_expr (QC_AND, bool_label, cmp, c);
|
2024-02-09 03:51:00 +00:00
|
|
|
} else {
|
|
|
|
cmp = c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return cmp;
|
|
|
|
}
|
|
|
|
|
2023-09-27 03:41:31 +00:00
|
|
|
const expr_t *
|
|
|
|
algebra_binary_expr (int op, const expr_t *e1, const expr_t *e2)
|
2023-08-21 08:37:56 +00:00
|
|
|
{
|
|
|
|
switch (op) {
|
2024-04-18 00:46:10 +00:00
|
|
|
case QC_EQ:
|
|
|
|
case QC_NE:
|
|
|
|
case QC_LE:
|
|
|
|
case QC_GE:
|
|
|
|
case QC_LT:
|
|
|
|
case QC_GT:
|
2024-02-09 03:51:00 +00:00
|
|
|
return algebra_compare (op, e1, e2);
|
2023-10-24 10:50:31 +00:00
|
|
|
case QC_DOT:
|
2023-08-21 08:37:56 +00:00
|
|
|
return inner_product (e1, e2);
|
2023-10-24 10:50:31 +00:00
|
|
|
case QC_WEDGE:
|
2023-08-21 08:37:56 +00:00
|
|
|
return outer_product (e1, e2);
|
2023-10-24 10:50:31 +00:00
|
|
|
case QC_REGRESSIVE:
|
2023-08-21 08:37:56 +00:00
|
|
|
return regressive_product (e1, e2);
|
2023-10-24 10:50:31 +00:00
|
|
|
case QC_CROSS:
|
2023-08-21 08:37:56 +00:00
|
|
|
return commutator_product (e1, e2);
|
|
|
|
case '+':
|
|
|
|
case '-':
|
|
|
|
return multivector_sum (op, e1, e2);
|
|
|
|
case '/':
|
|
|
|
return multivector_divide (e1, e2);
|
|
|
|
case '*':
|
2023-10-24 10:50:31 +00:00
|
|
|
case QC_GEOMETRIC:
|
2023-08-21 08:37:56 +00:00
|
|
|
return geometric_product (e1, e2);
|
|
|
|
}
|
|
|
|
return error (e1, "invalid operator");
|
|
|
|
}
|
|
|
|
|
2023-09-27 03:41:31 +00:00
|
|
|
const expr_t *
|
|
|
|
algebra_negate (const expr_t *e)
|
2023-08-21 08:37:56 +00:00
|
|
|
{
|
2023-08-28 08:00:14 +00:00
|
|
|
auto t = get_type (e);
|
|
|
|
auto algebra = algebra_get (t);
|
|
|
|
auto layout = &algebra->layout;
|
2023-09-27 03:41:31 +00:00
|
|
|
const expr_t *n[layout->count] = {};
|
2023-08-28 08:00:14 +00:00
|
|
|
e = mvec_expr (e, algebra);
|
|
|
|
mvec_scatter (n, e, algebra);
|
|
|
|
|
|
|
|
for (int i = 0; i < layout->count; i++) {
|
|
|
|
if (!n[i]) {
|
|
|
|
continue;
|
|
|
|
}
|
2023-09-02 02:18:50 +00:00
|
|
|
n[i] = neg_expr (n[i]);
|
2023-08-21 08:37:56 +00:00
|
|
|
}
|
2023-08-28 08:00:14 +00:00
|
|
|
return mvec_gather (n, algebra);
|
2023-08-21 08:37:56 +00:00
|
|
|
}
|
|
|
|
|
2024-02-09 04:49:36 +00:00
|
|
|
static const expr_t *
|
|
|
|
hodge_dual (const expr_t *e, bool undual)
|
2023-08-21 08:37:56 +00:00
|
|
|
{
|
2024-02-09 02:35:40 +00:00
|
|
|
auto algebra = algebra_context (get_type (e));
|
|
|
|
if (!algebra) {
|
2024-02-09 04:49:36 +00:00
|
|
|
return error (e, "cannot take the %s of a scalar without context",
|
|
|
|
undual ? "undual" : "dual");
|
2023-08-21 08:37:56 +00:00
|
|
|
}
|
2023-08-28 11:09:53 +00:00
|
|
|
auto layout = &algebra->layout;
|
|
|
|
|
2023-09-27 03:41:31 +00:00
|
|
|
const expr_t *a[layout->count] = {};
|
|
|
|
const expr_t *b[layout->count] = {};
|
2023-08-28 11:09:53 +00:00
|
|
|
e = mvec_expr (e, algebra);
|
|
|
|
mvec_scatter (a, e, algebra);
|
|
|
|
|
2024-02-09 04:49:36 +00:00
|
|
|
int dim = algebra->dimension - algebra->zero;
|
2023-08-28 11:09:53 +00:00
|
|
|
pr_uint_t I_mask = (1u << algebra->dimension) - 1;
|
|
|
|
for (int i = 0; i < layout->count; i++) {
|
|
|
|
if (!a[i]) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
auto group = &layout->groups[i];
|
|
|
|
//FIXME assumes groups are mono-grade (either come up with something
|
|
|
|
//or reject mixed-grade groups)
|
2024-02-09 04:49:36 +00:00
|
|
|
auto blade = group->blades[0];
|
|
|
|
pr_uint_t d_mask = I_mask ^ blade.mask;
|
|
|
|
int dual_ind = layout->group_map[layout->mask_map[d_mask]][0];
|
2023-08-28 11:09:53 +00:00
|
|
|
auto dual_group = &layout->groups[dual_ind];
|
|
|
|
auto dual_type = algebra_mvec_type (algebra, dual_group->group_mask);
|
|
|
|
auto dual = cast_expr (dual_type, a[i]);
|
2024-02-11 12:42:55 +00:00
|
|
|
pr_uint_t flips = algebra_count_flips (algebra, blade.mask, d_mask);
|
|
|
|
if (flips & 1) {
|
2024-02-09 04:49:36 +00:00
|
|
|
dual = neg_expr (dual);
|
2023-08-28 11:09:53 +00:00
|
|
|
} else {
|
2024-02-09 04:49:36 +00:00
|
|
|
dual = dual;
|
2023-08-28 11:09:53 +00:00
|
|
|
}
|
2024-02-09 04:49:36 +00:00
|
|
|
if (undual && ((dim * algebra_get_grade (get_type (a[i]))) & 1)) {
|
|
|
|
dual = neg_expr (dual);
|
2023-08-28 11:09:53 +00:00
|
|
|
}
|
2024-02-09 04:49:36 +00:00
|
|
|
b[dual_ind] = dual;
|
2023-08-28 11:09:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return mvec_gather (b, algebra);
|
2023-08-21 08:37:56 +00:00
|
|
|
}
|
|
|
|
|
2024-02-09 04:49:36 +00:00
|
|
|
const expr_t *
|
|
|
|
algebra_dual (const expr_t *e)
|
|
|
|
{
|
|
|
|
return hodge_dual (e, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
const expr_t *
|
|
|
|
algebra_undual (const expr_t *e)
|
|
|
|
{
|
|
|
|
return hodge_dual (e, true);
|
|
|
|
}
|
|
|
|
|
2023-08-28 02:56:35 +00:00
|
|
|
static void
|
|
|
|
set_sign (pr_type_t *val, int sign, const type_t *type)
|
|
|
|
{
|
|
|
|
if (is_float (type)) {
|
|
|
|
(*(float *) val) = sign;
|
|
|
|
} else {
|
|
|
|
(*(double *) val) = sign;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-27 03:41:31 +00:00
|
|
|
const expr_t *
|
|
|
|
algebra_reverse (const expr_t *e)
|
2023-08-21 08:37:56 +00:00
|
|
|
{
|
2023-08-28 02:56:35 +00:00
|
|
|
auto t = get_type (e);
|
|
|
|
auto algebra = algebra_get (t);
|
|
|
|
auto layout = &algebra->layout;
|
2023-09-27 03:41:31 +00:00
|
|
|
const expr_t *r[layout->count] = {};
|
2023-08-28 02:56:35 +00:00
|
|
|
e = mvec_expr (e, algebra);
|
|
|
|
mvec_scatter (r, e, algebra);
|
|
|
|
|
|
|
|
for (int i = 0; i < layout->count; i++) {
|
|
|
|
if (!r[i]) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
auto ct = get_type (r[i]);
|
|
|
|
if (is_mono_grade (ct)) {
|
|
|
|
int grade = algebra_get_grade (ct);
|
|
|
|
if (grade & 2) {
|
2023-09-02 02:18:50 +00:00
|
|
|
r[i] = neg_expr (r[i]);
|
2023-08-28 02:56:35 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
auto group = &layout->groups[i];
|
|
|
|
pr_type_t ones[group->count * type_size (algebra->type)];
|
|
|
|
bool neg = false;
|
|
|
|
for (int j = 0; j < group->count; j++) {
|
|
|
|
int grade = algebra_blade_grade (group->blades[i]);
|
|
|
|
int sign = grade & 2 ? -1 : 1;
|
|
|
|
if (sign < 0) {
|
|
|
|
neg = true;
|
|
|
|
}
|
|
|
|
set_sign (&ones[j * type_size (algebra->type)], sign, ct);
|
|
|
|
}
|
|
|
|
if (neg) {
|
2023-10-20 11:45:58 +00:00
|
|
|
auto rev = new_value_expr (new_type_value (ct, ones), false);
|
2023-09-25 07:09:51 +00:00
|
|
|
rev = edag_add_expr (rev);
|
2023-10-24 10:50:31 +00:00
|
|
|
r[i] = typed_binary_expr (ct, QC_HADAMARD, r[i], rev);
|
2023-09-25 07:09:51 +00:00
|
|
|
r[i] = edag_add_expr (rev);
|
2023-08-28 02:56:35 +00:00
|
|
|
}
|
|
|
|
}
|
2023-08-21 08:37:56 +00:00
|
|
|
}
|
2023-08-28 02:56:35 +00:00
|
|
|
return mvec_gather (r, algebra);
|
2023-08-21 08:37:56 +00:00
|
|
|
}
|
|
|
|
|
2023-09-27 03:41:31 +00:00
|
|
|
const expr_t *
|
2024-02-13 14:09:28 +00:00
|
|
|
algebra_cast_expr (const type_t *dstType, const expr_t *e)
|
2023-08-21 08:37:56 +00:00
|
|
|
{
|
2024-02-13 14:09:28 +00:00
|
|
|
auto srcType = get_type (e);
|
2023-08-21 08:37:56 +00:00
|
|
|
if (dstType->type == ev_invalid
|
|
|
|
|| srcType->type == ev_invalid
|
|
|
|
|| type_width (dstType) != type_width (srcType)) {
|
|
|
|
return cast_error (e, srcType, dstType);
|
|
|
|
}
|
2023-09-09 14:24:47 +00:00
|
|
|
if (type_size (dstType) == type_size (srcType)) {
|
2023-09-25 07:09:51 +00:00
|
|
|
return edag_add_expr (new_alias_expr (dstType, e));
|
2023-09-09 14:24:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
auto algebra = algebra_get (is_algebra (srcType) ? srcType : dstType);
|
|
|
|
if (is_algebra (srcType)) {
|
2023-09-25 07:09:51 +00:00
|
|
|
auto alias = edag_add_expr (new_alias_expr (algebra->type, e));
|
|
|
|
return edag_add_expr (cast_expr (dstType, alias));
|
2023-09-09 14:24:47 +00:00
|
|
|
} else {
|
2023-09-25 07:09:51 +00:00
|
|
|
auto cast = edag_add_expr (cast_expr (algebra->type, e));
|
|
|
|
return edag_add_expr (new_alias_expr (dstType, cast));
|
2023-09-09 14:24:47 +00:00
|
|
|
}
|
2023-08-21 08:37:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-27 03:41:31 +00:00
|
|
|
zero_components (expr_t *block, const expr_t *dst, int memset_base, int memset_size)
|
2023-08-21 08:37:56 +00:00
|
|
|
{
|
2023-09-02 04:43:22 +00:00
|
|
|
auto base = alias_expr (&type_int, dst, memset_base);
|
2023-10-19 13:52:17 +00:00
|
|
|
auto zero = new_int_expr (0, false);
|
|
|
|
auto size = new_int_expr (memset_size, false);
|
2023-08-21 08:37:56 +00:00
|
|
|
append_expr (block, new_memset_expr (base, zero, size));
|
|
|
|
}
|
|
|
|
|
2023-09-02 11:35:10 +00:00
|
|
|
static int __attribute__((const))
|
|
|
|
find_offset (const type_t *t1, const type_t *t2)
|
|
|
|
{
|
|
|
|
return type_width (t1) - type_width (t2);
|
|
|
|
}
|
|
|
|
|
2023-09-02 12:41:10 +00:00
|
|
|
static bool __attribute__((const))
|
|
|
|
summed_extend (const expr_t *e)
|
|
|
|
{
|
2023-09-25 14:40:35 +00:00
|
|
|
if (!(e->type == ex_expr && e->expr.op == '+'
|
|
|
|
&& e->expr.e1->type == ex_extend
|
|
|
|
&& e->expr.e2->type == ex_extend)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
auto ext1 = e->expr.e1->extend;
|
|
|
|
auto ext2 = e->expr.e2->extend;
|
|
|
|
pr_uint_t bits1 = (1 << type_width (get_type (ext1.src))) - 1;
|
|
|
|
pr_uint_t bits2 = (1 << type_width (get_type (ext2.src))) - 1;
|
|
|
|
if (ext1.reverse) {
|
|
|
|
bits1 <<= type_width (ext1.type) - type_width (get_type (ext1.src));
|
|
|
|
}
|
|
|
|
if (ext2.reverse) {
|
|
|
|
bits2 <<= type_width (ext2.type) - type_width (get_type (ext2.src));
|
|
|
|
}
|
|
|
|
return !(bits1 & bits2);
|
2023-09-02 12:41:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-09-27 03:41:31 +00:00
|
|
|
assign_extend (expr_t *block, const expr_t *dst, const expr_t *src)
|
2023-09-02 12:41:10 +00:00
|
|
|
{
|
2023-09-23 09:01:49 +00:00
|
|
|
auto ext1 = src->expr.e1->extend;
|
|
|
|
auto ext2 = src->expr.e2->extend;
|
2023-09-02 12:41:10 +00:00
|
|
|
auto type1 = get_type (ext1.src);
|
|
|
|
auto type2 = get_type (ext2.src);
|
|
|
|
int offs1 = ext1.reverse ? find_offset (ext1.type, type1) : 0;
|
|
|
|
int offs2 = ext2.reverse ? find_offset (ext2.type, type2) : 0;
|
|
|
|
auto dst1 = offset_cast (type1, dst, offs1);
|
|
|
|
auto dst2 = offset_cast (type2, dst, offs2);
|
2023-09-25 07:09:51 +00:00
|
|
|
append_expr (block, edag_add_expr (new_assign_expr (dst1, ext1.src)));
|
|
|
|
append_expr (block, edag_add_expr (new_assign_expr (dst2, ext2.src)));
|
2023-09-02 12:41:10 +00:00
|
|
|
}
|
|
|
|
|
2023-09-27 03:41:31 +00:00
|
|
|
const expr_t *
|
|
|
|
algebra_assign_expr (const expr_t *dst, const expr_t *src)
|
2023-08-21 08:37:56 +00:00
|
|
|
{
|
2024-02-13 14:09:28 +00:00
|
|
|
auto srcType = get_type (src);
|
|
|
|
auto dstType = get_type (dst);
|
2023-08-21 08:37:56 +00:00
|
|
|
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
if (src->type != ex_multivec) {
|
2023-08-29 07:17:07 +00:00
|
|
|
if (srcType == dstType) {
|
2023-09-02 12:41:10 +00:00
|
|
|
if (summed_extend (src)) {
|
2023-09-27 03:41:31 +00:00
|
|
|
auto block = new_block_expr (0);
|
2025-01-02 17:29:37 +00:00
|
|
|
block->block.no_flush = true;
|
2023-09-02 12:41:10 +00:00
|
|
|
assign_extend (block, dst, src);
|
|
|
|
return block;
|
|
|
|
}
|
2023-09-25 07:09:51 +00:00
|
|
|
return edag_add_expr (new_assign_expr (dst, src));
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
}
|
2023-08-21 08:37:56 +00:00
|
|
|
}
|
|
|
|
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
if (dstType->meta != ty_algebra && dstType != srcType) {
|
2023-08-21 08:37:56 +00:00
|
|
|
return 0;
|
|
|
|
}
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
auto algebra = algebra_get (dstType);
|
|
|
|
auto layout = &algebra->layout;
|
2023-09-27 03:41:31 +00:00
|
|
|
const expr_t *c[layout->count] = {};
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
src = mvec_expr (src, algebra);
|
2023-09-02 11:35:10 +00:00
|
|
|
mvec_scatter (c, src, algebra);
|
[qfcc] Use scatter-gather for multivec expressions
This makes working with them much easier, and the type system reflects
what's in the multi-vector. Unfortunately, that does mean that large
algebras will wind up having a LOT of types, but it allows for efficient
storage of sparse multi-vectors:
auto v = 4*(e1 + e032 + e123);
results in:
0005 0213 1:0008<00000008>4:void 0:0000<00000000>?:invalid
0:0044<00000044>4:void assign (<void>), v
0006 0213 1:000c<0000000c>4:void 0:0000<00000000>?:invalid
0:0048<00000048>4:void assign (<void>), {v + 4}
Where the two source vectors are:
44:1 0 .imm float:18e [4, 0, 0, 0]
48:1 0 .imm float:1aa [4, 0, 0, 4]
They just happen to be adjacent, but don't need to be.
2023-08-22 15:03:56 +00:00
|
|
|
|
2023-08-29 07:17:07 +00:00
|
|
|
auto sym = get_mvec_sym (dstType);
|
2023-09-27 03:41:31 +00:00
|
|
|
auto block = new_block_expr (0);
|
2025-01-02 17:29:37 +00:00
|
|
|
block->block.no_flush = true;
|
2023-08-21 08:37:56 +00:00
|
|
|
int memset_base = 0;
|
|
|
|
for (int i = 0; i < layout->count; i++) {
|
2023-09-02 11:35:10 +00:00
|
|
|
if (!c[i]) {
|
2023-08-29 07:17:07 +00:00
|
|
|
continue;
|
|
|
|
}
|
2023-09-02 11:35:10 +00:00
|
|
|
while (sym->type != get_type (c[i])) {
|
2023-08-29 07:17:07 +00:00
|
|
|
sym = sym->next;
|
|
|
|
}
|
2024-08-16 07:48:11 +00:00
|
|
|
int size = sym->offset - memset_base;
|
2023-08-29 07:17:07 +00:00
|
|
|
if (size) {
|
|
|
|
zero_components (block, dst, memset_base, size);
|
2023-08-21 08:37:56 +00:00
|
|
|
}
|
2024-08-16 07:48:11 +00:00
|
|
|
auto dst_alias = new_offset_alias_expr (sym->type, dst, sym->offset);
|
2023-09-02 12:41:10 +00:00
|
|
|
if (summed_extend (c[i])) {
|
|
|
|
assign_extend (block, dst_alias, c[i]);
|
2023-09-02 11:35:10 +00:00
|
|
|
} else {
|
2023-09-25 07:09:51 +00:00
|
|
|
append_expr (block,
|
|
|
|
edag_add_expr (new_assign_expr (dst_alias, c[i])));
|
2023-09-02 11:35:10 +00:00
|
|
|
}
|
2024-08-16 07:48:11 +00:00
|
|
|
memset_base = sym->offset + type_size (sym->type);
|
2023-08-21 08:37:56 +00:00
|
|
|
}
|
2023-08-29 07:17:07 +00:00
|
|
|
if (type_size (dstType) - memset_base) {
|
|
|
|
zero_components (block, dst, memset_base,
|
|
|
|
type_size (dstType) - memset_base);
|
2023-08-21 08:37:56 +00:00
|
|
|
}
|
|
|
|
return block;
|
|
|
|
}
|
2023-09-09 14:08:38 +00:00
|
|
|
|
2023-09-27 03:41:31 +00:00
|
|
|
const expr_t *
|
|
|
|
algebra_field_expr (const expr_t *mvec, const expr_t *field_name)
|
2023-09-09 14:08:38 +00:00
|
|
|
{
|
|
|
|
auto mvec_type = get_type (mvec);
|
|
|
|
auto algebra = algebra_get (mvec_type);
|
|
|
|
|
2023-09-11 01:25:35 +00:00
|
|
|
auto field_sym = get_name (field_name);
|
|
|
|
if (!field_sym) {
|
|
|
|
return error (field_name, "multi-vector reference is not a name");
|
|
|
|
}
|
|
|
|
auto mvec_struct = get_mvec_struct (mvec_type);
|
|
|
|
auto field = mvec_struct ? symtab_lookup (mvec_struct, field_sym->name) : 0;
|
|
|
|
if (!field) {
|
2024-08-16 08:23:29 +00:00
|
|
|
mvec_struct = algebra->mvec_sym->type->symtab;
|
2023-09-11 01:25:35 +00:00
|
|
|
field = symtab_lookup (mvec_struct, field_sym->name);
|
|
|
|
if (field) {
|
|
|
|
debug (field_name, "'%s' not in sub-type '%s' of '%s', "
|
|
|
|
"returning zero of type '%s'", field_sym->name,
|
|
|
|
mvec_type->name, algebra->mvec_sym->type->name,
|
|
|
|
mvec_type->name);
|
2023-09-25 07:09:51 +00:00
|
|
|
return edag_add_expr (new_zero_expr (field->type));
|
2023-09-09 14:08:38 +00:00
|
|
|
}
|
2023-09-11 01:25:35 +00:00
|
|
|
return error (field_name, "'%s' has no member named '%s'",
|
|
|
|
mvec_type->name, field_sym->name);
|
2023-09-09 14:08:38 +00:00
|
|
|
}
|
2023-09-11 01:25:35 +00:00
|
|
|
auto layout = &algebra->layout;
|
2023-09-27 03:41:31 +00:00
|
|
|
const expr_t *a[layout->count] = {};
|
2023-09-11 01:25:35 +00:00
|
|
|
mvec_scatter (a, mvec_expr (mvec, algebra), algebra);
|
|
|
|
pr_uint_t group_mask = get_group_mask (field->type, algebra);
|
|
|
|
for (int i = 0; i < layout->count; i++) {
|
|
|
|
if (!(group_mask & (1u << i))) {
|
|
|
|
a[i] = 0;
|
2023-09-10 01:53:59 +00:00
|
|
|
}
|
|
|
|
}
|
2023-09-11 01:25:35 +00:00
|
|
|
return mvec_gather (a, algebra);
|
2023-09-09 14:08:38 +00:00
|
|
|
}
|