mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-24 12:42:32 +00:00
[qfcc] Distribute products over sums
While this does "explode" the instruction count (I'll have to collect like terms later), it does allow for many more opportunities for things to cancel out to 0 (once (pseudo)commutativity is taken care of).
This commit is contained in:
parent
2bf855657c
commit
14d1148523
2 changed files with 119 additions and 5 deletions
|
@ -630,6 +630,76 @@ component_sum (int op, const expr_t **c, const expr_t **a, const expr_t **b,
|
|||
}
|
||||
}
|
||||
|
||||
static const expr_t *
|
||||
distribute_product (type_t *type, int op, const expr_t *a, const expr_t *b,
|
||||
bool (*reject) (const expr_t *a, const expr_t *b))
|
||||
{
|
||||
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) {
|
||||
distribute_terms (a, a_adds, a_subs);
|
||||
} else {
|
||||
a_adds[0] = a;
|
||||
}
|
||||
|
||||
if (b_terms) {
|
||||
distribute_terms (b, b_adds, b_subs);
|
||||
} else {
|
||||
b_adds[0] = b;
|
||||
}
|
||||
|
||||
a = b = 0;
|
||||
|
||||
for (auto i = a_adds; *i; i++) {
|
||||
for (auto j = b_adds; *j; j++) {
|
||||
if (!reject || !reject(*i, *j)) {
|
||||
auto p = typed_binary_expr (type, op, *i, *j);
|
||||
p = fold_constants (p);
|
||||
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++) {
|
||||
if (!reject || !reject(*i, *j)) {
|
||||
auto p = typed_binary_expr (type, op, *i, *j);
|
||||
p = fold_constants (p);
|
||||
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++) {
|
||||
if (!reject || !reject(*i, *j)) {
|
||||
auto p = typed_binary_expr (type, op, *i, *j);
|
||||
p = fold_constants (p);
|
||||
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++) {
|
||||
if (!reject || !reject(*i, *j)) {
|
||||
auto p = typed_binary_expr (type, op, *i, *j);
|
||||
p = fold_constants (p);
|
||||
p = edag_add_expr (p);
|
||||
b = sum_expr (type, b, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
auto sum = sum_expr_low (type, '-', a, b);
|
||||
return sum;
|
||||
}
|
||||
|
||||
static const expr_t *
|
||||
scale_expr (type_t *type, const expr_t *a, const expr_t *b)
|
||||
{
|
||||
|
@ -661,7 +731,10 @@ scale_expr (type_t *type, const expr_t *a, const expr_t *b)
|
|||
a = a->expr.e1;
|
||||
}
|
||||
|
||||
auto scale = typed_binary_expr (type, op, a, b);
|
||||
auto scale = distribute_product (type, op, a, b, 0);
|
||||
if (!scale) {
|
||||
return 0;
|
||||
}
|
||||
scale = fold_constants (scale);
|
||||
scale = edag_add_expr (scale);
|
||||
if (neg) {
|
||||
|
@ -709,6 +782,26 @@ check_dot (const expr_t *a, const expr_t *b, int b_count)
|
|||
return collect_terms (get_type (b), b_adds, b_subs);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static const expr_t *
|
||||
dot_expr (type_t *type, const expr_t *a, const expr_t *b)
|
||||
{
|
||||
|
@ -749,7 +842,10 @@ dot_expr (type_t *type, const expr_t *a, const expr_t *b)
|
|||
b = b->expr.e1;
|
||||
}
|
||||
|
||||
auto dot = typed_binary_expr (type, DOT, a, b);
|
||||
auto dot = distribute_product (type, DOT, a, b, reject_dot);
|
||||
if (!dot) {
|
||||
return 0;
|
||||
}
|
||||
dot = edag_add_expr (dot);
|
||||
if (prod) {
|
||||
dot = scale_expr (type, dot, prod);
|
||||
|
@ -786,6 +882,12 @@ check_cross (const expr_t *a, const expr_t *b, int b_count)
|
|||
return collect_terms (get_type (b), b_adds, b_subs);
|
||||
}
|
||||
|
||||
static bool __attribute__((pure))
|
||||
reject_cross (const expr_t *a, const expr_t *b)
|
||||
{
|
||||
return traverse_scale (a) == traverse_scale (b);
|
||||
}
|
||||
|
||||
static const expr_t *
|
||||
cross_expr (type_t *type, const expr_t *a, const expr_t *b)
|
||||
{
|
||||
|
@ -821,11 +923,20 @@ cross_expr (type_t *type, const expr_t *a, const expr_t *b)
|
|||
b = check_cross (a, b, b_terms);
|
||||
}
|
||||
|
||||
auto cross = typed_binary_expr (type, CROSS, a, b);
|
||||
auto cross = distribute_product (type, CROSS, a, b, reject_cross);
|
||||
if (!cross) {
|
||||
return 0;
|
||||
}
|
||||
cross = edag_add_expr (cross);
|
||||
return cross;
|
||||
}
|
||||
|
||||
static bool __attribute__((pure))
|
||||
reject_wedge (const expr_t *a, const expr_t *b)
|
||||
{
|
||||
return traverse_scale (a) == traverse_scale (b);
|
||||
}
|
||||
|
||||
static const expr_t *
|
||||
wedge_expr (type_t *type, const expr_t *a, const expr_t *b)
|
||||
{
|
||||
|
@ -847,7 +958,10 @@ wedge_expr (type_t *type, const expr_t *a, const expr_t *b)
|
|||
a = b;
|
||||
b = t;
|
||||
}
|
||||
auto wedge = typed_binary_expr (type, WEDGE, a, b);
|
||||
auto wedge = distribute_product (type, WEDGE, a, b, reject_wedge);
|
||||
if (!wedge) {
|
||||
return 0;
|
||||
}
|
||||
wedge = edag_add_expr (wedge);
|
||||
return wedge;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ main (void)
|
|||
point_t p = (point_t)'10 4 -1.5 1'f;
|
||||
point_t n = apply_motor (m, p);
|
||||
printf ("n: %.9q\n", n);
|
||||
if ((vec4)n != '10 -4 -1.49999988 0.99999994'f) {
|
||||
if ((vec4)n != '9.99999905 -4.00000048 -1.49999988 0.99999994'f) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
|
Loading…
Reference in a new issue