diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 007ce347a..dc4b068de 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -55,6 +55,8 @@ typedef enum { */ typedef struct ex_expr_s { int op; ///< op-code of this expression + bool commutative; ///< e1 and e2 can be swapped + bool anticommute; ///< e1 and e2 can be swapped with negation struct type_s *type; ///< the type of the result of this expression struct expr_s *e1; ///< left side of binary, sole of unary struct expr_s *e2; ///< right side of binary, null for unary diff --git a/tools/qfcc/include/options.h b/tools/qfcc/include/options.h index e0a602dc8..9ab00d08b 100644 --- a/tools/qfcc/include/options.h +++ b/tools/qfcc/include/options.h @@ -47,6 +47,9 @@ typedef struct { bool ifstring; // expand if (str) to if (str != "") bool const_initializers; // initialied globals are constant bool promote_float; // promote float through ... + bool commute_float_add; // allow fp addition to commute + bool commute_float_mul; // allow fp multiplication to commute + bool commute_float_dot; // allow fp dot product to commute bool help; } code_options_t; diff --git a/tools/qfcc/source/expr_algebra.c b/tools/qfcc/source/expr_algebra.c index 46759d85f..02e071200 100644 --- a/tools/qfcc/source/expr_algebra.c +++ b/tools/qfcc/source/expr_algebra.c @@ -92,9 +92,7 @@ ext_expr (expr_t *src, type_t *type, int extend, bool reverse) static bool __attribute__((const)) anti_com (const expr_t *e) { - return (e->type == ex_expr - && (e->expr.op == CROSS || e->expr.op == WEDGE - || e->expr.op == '-')); + return e && e->type == ex_expr && e->expr.anticommute; } static expr_t * @@ -455,6 +453,8 @@ sum_expr (type_t *type, expr_t *a, expr_t *b) } auto sum = new_binary_expr (op, a, b); sum->expr.type = type; + sum->expr.commutative = op == '+'; + sum->expr.anticommute = op == '-'; sum = edag_add_expr (sum); if (neg) { sum = neg_expr (sum); @@ -589,6 +589,7 @@ cross_expr (type_t *type, expr_t *a, expr_t *b) auto cross = new_binary_expr (CROSS, a, b); cross->expr.type = type; + cross->expr.anticommute = true; cross = edag_add_expr (cross); return cross; } @@ -616,6 +617,7 @@ wedge_expr (type_t *type, expr_t *a, expr_t *b) } auto wedge = new_binary_expr (WEDGE, a, b); wedge->expr.type = type; + wedge->expr.anticommute = true; wedge = edag_add_expr (wedge); return wedge; } diff --git a/tools/qfcc/source/expr_binary.c b/tools/qfcc/source/expr_binary.c index 065e30f62..269fa7308 100644 --- a/tools/qfcc/source/expr_binary.c +++ b/tools/qfcc/source/expr_binary.c @@ -44,7 +44,9 @@ typedef struct { type_t *result_type; type_t *a_cast; type_t *b_cast; - expr_t *(*process)(int op, expr_t *e1, expr_t *e2); + expr_t *(*process)(int op, expr_t *e1, expr_t *e2); + bool (*commutative) (void); + bool (*anticommute) (void); } expr_type_t; static expr_t *pointer_arithmetic (int op, expr_t *e1, expr_t *e2); @@ -58,6 +60,26 @@ static expr_t *vector_multiply (int op, expr_t *e1, expr_t *e2); static expr_t *vector_scale (int op, expr_t *e1, expr_t *e2); static expr_t *entity_compare (int op, expr_t *e1, expr_t *e2); +static bool always (void) +{ + return true; +} + +static bool fp_add (void) +{ + return options.code.commute_float_add; +} + +static bool fp_mul (void) +{ + return options.code.commute_float_mul; +} + +static bool fp_dot (void) +{ + return options.code.commute_float_dot; +} + static expr_type_t string_string[] = { {'+', &type_string}, {EQ, &type_int}, @@ -70,13 +92,13 @@ static expr_type_t string_string[] = { }; static expr_type_t float_float[] = { - {'+', &type_float}, - {'-', &type_float}, - {'*', &type_float}, + {'+', &type_float, .commutative = fp_add}, + {'-', &type_float, .anticommute = fp_add}, + {'*', &type_float, .commutative = fp_mul}, {'/', &type_float}, - {'&', &type_float}, - {'|', &type_float}, - {'^', &type_float}, + {'&', &type_float, .commutative = always}, + {'|', &type_float, .commutative = always}, + {'^', &type_float, .commutative = always}, {'%', &type_float}, {MOD, &type_float}, {SHL, &type_float}, @@ -103,13 +125,13 @@ static expr_type_t float_quat[] = { }; static expr_type_t float_int[] = { - {'+', &type_float, 0, &type_float}, - {'-', &type_float, 0, &type_float}, - {'*', &type_float, 0, &type_float}, + {'+', &type_float, 0, &type_float, .commutative = fp_add}, + {'-', &type_float, 0, &type_float, .anticommute = fp_add}, + {'*', &type_float, 0, &type_float, .commutative = fp_mul}, {'/', &type_float, 0, &type_float}, - {'&', &type_float, 0, &type_float}, - {'|', &type_float, 0, &type_float}, - {'^', &type_float, 0, &type_float}, + {'&', &type_float, 0, &type_float, .commutative = always}, + {'|', &type_float, 0, &type_float, .commutative = always}, + {'^', &type_float, 0, &type_float, .commutative = always}, {'%', &type_float, 0, &type_float}, {MOD, &type_float, 0, &type_float}, {SHL, &type_float, 0, &type_float}, @@ -126,9 +148,9 @@ static expr_type_t float_int[] = { #define float_short float_int static expr_type_t float_double[] = { - {'+', &type_double, &type_double, 0}, - {'-', &type_double, &type_double, 0}, - {'*', &type_double, &type_double, 0}, + {'+', &type_double, &type_double, 0, .commutative = fp_add}, + {'-', &type_double, &type_double, 0, .anticommute = fp_add}, + {'*', &type_double, &type_double, 0, .commutative = fp_mul}, {'/', &type_double, &type_double, 0}, {'%', &type_double, &type_double, 0}, {MOD, &type_double, &type_double, 0}, @@ -148,11 +170,11 @@ static expr_type_t vector_float[] = { }; static expr_type_t vector_vector[] = { - {'+', &type_vector}, - {'-', &type_vector}, - {DOT, .process = vector_dot}, - {CROSS, &type_vector}, - {HADAMARD, &type_vector}, + {'+', &type_vector, .commutative = fp_add}, + {'-', &type_vector, .anticommute = fp_add}, + {DOT, .process = vector_dot, .commutative = fp_dot}, + {CROSS, &type_vector, .anticommute = fp_add}, + {HADAMARD, &type_vector, .commutative = fp_mul}, {'*', .process = vector_multiply}, {EQ, .process = vector_compare}, {NE, .process = vector_compare}, @@ -218,8 +240,8 @@ static expr_type_t quat_vector[] = { }; static expr_type_t quat_quat[] = { - {'+', &type_quaternion}, - {'-', &type_quaternion}, + {'+', &type_quaternion, .commutative = fp_add}, + {'-', &type_quaternion, .anticommute = fp_add}, {'*', &type_quaternion}, {EQ, &type_int}, {NE, &type_int}, @@ -241,13 +263,13 @@ static expr_type_t quat_double[] = { }; static expr_type_t int_float[] = { - {'+', &type_float, &type_float, 0}, - {'-', &type_float, &type_float, 0}, - {'*', &type_float, &type_float, 0}, + {'+', &type_float, &type_float, 0, .commutative = fp_add}, + {'-', &type_float, &type_float, 0, .anticommute = fp_add}, + {'*', &type_float, &type_float, 0, .commutative = fp_mul}, {'/', &type_float, &type_float, 0}, - {'&', &type_float, &type_float, 0}, - {'|', &type_float, &type_float, 0}, - {'^', &type_float, &type_float, 0}, + {'&', &type_float, &type_float, 0, .commutative = always}, + {'|', &type_float, &type_float, 0, .commutative = always}, + {'^', &type_float, &type_float, 0, .commutative = always}, {'%', &type_float, &type_float, 0}, {MOD, &type_float, &type_float, 0}, {SHL, &type_int, 0, &type_int}, //FIXME? @@ -277,13 +299,13 @@ static expr_type_t int_quat[] = { }; static expr_type_t int_int[] = { - {'+', &type_int}, - {'-', &type_int}, - {'*', &type_int}, + {'+', &type_int, .commutative = always}, + {'-', &type_int, .anticommute = always}, + {'*', &type_int, .commutative = always}, {'/', &type_int}, - {'&', &type_int}, - {'|', &type_int}, - {'^', &type_int}, + {'&', &type_int, .commutative = always}, + {'|', &type_int, .commutative = always}, + {'^', &type_int, .commutative = always}, {'%', &type_int}, {MOD, &type_int}, {SHL, &type_int}, @@ -300,13 +322,13 @@ static expr_type_t int_int[] = { }; static expr_type_t int_uint[] = { - {'+', &type_int, 0, &type_int}, - {'-', &type_int, 0, &type_int}, - {'*', &type_int, 0, &type_int}, + {'+', &type_int, 0, &type_int, .commutative = always}, + {'-', &type_int, 0, &type_int, .anticommute = always}, + {'*', &type_int, 0, &type_int, .commutative = always}, {'/', &type_int, 0, &type_int}, - {'&', &type_int, 0, &type_int}, - {'|', &type_int, 0, &type_int}, - {'^', &type_int, 0, &type_int}, + {'&', &type_int, 0, &type_int, .commutative = always}, + {'|', &type_int, 0, &type_int, .commutative = always}, + {'^', &type_int, 0, &type_int, .commutative = always}, {'%', &type_int, 0, &type_int}, {MOD, &type_int, 0, &type_int}, {SHL, &type_int, 0, &type_int}, @@ -321,13 +343,13 @@ static expr_type_t int_uint[] = { }; static expr_type_t int_short[] = { - {'+', &type_int, 0, &type_int}, - {'-', &type_int, 0, &type_int}, - {'*', &type_int, 0, &type_int}, + {'+', &type_int, 0, &type_int, .commutative = always}, + {'-', &type_int, 0, &type_int, .anticommute = always}, + {'*', &type_int, 0, &type_int, .commutative = always}, {'/', &type_int, 0, &type_int}, - {'&', &type_int, 0, &type_int}, - {'|', &type_int, 0, &type_int}, - {'^', &type_int, 0, &type_int}, + {'&', &type_int, 0, &type_int, .commutative = always}, + {'|', &type_int, 0, &type_int, .commutative = always}, + {'^', &type_int, 0, &type_int, .commutative = always}, {'%', &type_int, 0, &type_int}, {MOD, &type_int, 0, &type_int}, {SHL, &type_int, 0, &type_int}, @@ -342,9 +364,9 @@ static expr_type_t int_short[] = { }; static expr_type_t int_double[] = { - {'+', &type_double, &type_double, 0}, - {'-', &type_double, &type_double, 0}, - {'*', &type_double, &type_double, 0}, + {'+', &type_double, &type_double, 0, .commutative = fp_add}, + {'-', &type_double, &type_double, 0, .anticommute = fp_add}, + {'*', &type_double, &type_double, 0, .commutative = fp_mul}, {'/', &type_double, &type_double, 0}, {'%', &type_double, &type_double, 0}, {MOD, &type_double, &type_double, 0}, @@ -363,13 +385,13 @@ static expr_type_t int_double[] = { #define uint_quat int_quat static expr_type_t uint_int[] = { - {'+', &type_int, &type_int, &type_int }, - {'-', &type_int, &type_int, &type_int }, - {'*', &type_int, &type_int, &type_int }, + {'+', &type_int, &type_int, &type_int, .commutative = always}, + {'-', &type_int, &type_int, &type_int, .anticommute = always }, + {'*', &type_int, &type_int, &type_int, .commutative = always}, {'/', &type_int, &type_int, &type_int }, - {'&', &type_int, &type_int, &type_int }, - {'|', &type_int, &type_int, &type_int }, - {'^', &type_int, &type_int, &type_int }, + {'&', &type_int, &type_int, &type_int, .commutative = always}, + {'|', &type_int, &type_int, &type_int, .commutative = always}, + {'^', &type_int, &type_int, &type_int, .commutative = always}, {'%', &type_int, &type_int, &type_int }, {MOD, &type_int, &type_int, &type_int }, {SHL, &type_uint, &type_int, &type_int }, @@ -384,13 +406,13 @@ static expr_type_t uint_int[] = { }; static expr_type_t uint_uint[] = { - {'+', &type_uint}, - {'-', &type_uint}, - {'*', &type_uint}, + {'+', &type_uint, .commutative = always}, + {'-', &type_uint, .commutative = always}, + {'*', &type_uint, .commutative = always}, {'/', &type_uint}, - {'&', &type_uint}, - {'|', &type_uint}, - {'^', &type_uint}, + {'&', &type_uint, .commutative = always}, + {'|', &type_uint, .commutative = always}, + {'^', &type_uint, .commutative = always}, {'%', &type_uint}, {MOD, &type_uint}, {SHL, &type_uint}, @@ -412,13 +434,13 @@ static expr_type_t uint_uint[] = { #define short_quat int_quat static expr_type_t short_int[] = { - {'+', &type_int, &type_int, 0}, - {'-', &type_int, &type_int, 0}, - {'*', &type_int, &type_int, 0}, + {'+', &type_int, &type_int, 0, .commutative = always}, + {'-', &type_int, &type_int, 0, .commutative = always}, + {'*', &type_int, &type_int, 0, .commutative = always}, {'/', &type_int, &type_int, 0}, - {'&', &type_int, &type_int, 0}, - {'|', &type_int, &type_int, 0}, - {'^', &type_int, &type_int, 0}, + {'&', &type_int, &type_int, 0, .commutative = always}, + {'|', &type_int, &type_int, 0, .commutative = always}, + {'^', &type_int, &type_int, 0, .commutative = always}, {'%', &type_int, &type_int, 0}, {MOD, &type_int, &type_int, 0}, {SHL, &type_short}, @@ -433,13 +455,13 @@ static expr_type_t short_int[] = { }; static expr_type_t short_uint[] = { - {'+', &type_uint, &type_uint, 0}, - {'-', &type_uint, &type_uint, 0}, - {'*', &type_uint, &type_uint, 0}, + {'+', &type_uint, &type_uint, 0, .commutative = always}, + {'-', &type_uint, &type_uint, 0, .commutative = always}, + {'*', &type_uint, &type_uint, 0, .commutative = always}, {'/', &type_uint, &type_uint, 0}, - {'&', &type_uint, &type_uint, 0}, - {'|', &type_uint, &type_uint, 0}, - {'^', &type_uint, &type_uint, 0}, + {'&', &type_uint, &type_uint, 0, .commutative = always}, + {'|', &type_uint, &type_uint, 0, .commutative = always}, + {'^', &type_uint, &type_uint, 0, .commutative = always}, {'%', &type_uint, &type_uint, 0}, {MOD, &type_uint, &type_uint, 0}, {SHL, &type_short}, @@ -476,9 +498,9 @@ static expr_type_t short_short[] = { #define short_double int_double static expr_type_t double_float[] = { - {'+', &type_double, 0, &type_double}, - {'-', &type_double, 0, &type_double}, - {'*', &type_double, 0, &type_double}, + {'+', &type_double, 0, &type_double, .commutative = fp_add}, + {'-', &type_double, 0, &type_double, .anticommute = fp_add}, + {'*', &type_double, 0, &type_double, .commutative = fp_mul}, {'/', &type_double, 0, &type_double}, {'%', &type_double, 0, &type_double}, {MOD, &type_double, 0, &type_double}, @@ -502,9 +524,9 @@ static expr_type_t double_quat[] = { }; static expr_type_t double_int[] = { - {'+', &type_double, 0, &type_double}, - {'-', &type_double, 0, &type_double}, - {'*', &type_double, 0, &type_double}, + {'+', &type_double, 0, &type_double, .commutative = fp_add}, + {'-', &type_double, 0, &type_double, .anticommute = fp_add}, + {'*', &type_double, 0, &type_double, .commutative = fp_mul}, {'/', &type_double, 0, &type_double}, {'%', &type_double, 0, &type_double}, {MOD, &type_double, 0, &type_double}, @@ -520,9 +542,9 @@ static expr_type_t double_int[] = { #define double_short double_int static expr_type_t double_double[] = { - {'+', &type_double}, - {'-', &type_double}, - {'*', &type_double}, + {'+', &type_double, .commutative = fp_add}, + {'-', &type_double, .anticommute = fp_add}, + {'*', &type_double, .commutative = fp_mul}, {'/', &type_double}, {'%', &type_double}, {MOD, &type_double}, @@ -536,13 +558,13 @@ static expr_type_t double_double[] = { }; static expr_type_t long_long[] = { - {'+', &type_long}, - {'-', &type_long}, - {'*', &type_long}, + {'+', &type_long, .commutative = always}, + {'-', &type_long, .anticommute = fp_add}, + {'*', &type_long, .commutative = always}, {'/', &type_long}, - {'&', &type_long}, - {'|', &type_long}, - {'^', &type_long}, + {'&', &type_long, .commutative = always}, + {'|', &type_long, .commutative = always}, + {'^', &type_long, .commutative = always}, {'%', &type_long}, {MOD, &type_long}, {SHL, &type_long}, @@ -557,13 +579,13 @@ static expr_type_t long_long[] = { }; static expr_type_t ulong_ulong[] = { - {'+', &type_ulong}, - {'-', &type_ulong}, - {'*', &type_ulong}, + {'+', &type_ulong, .commutative = always}, + {'-', &type_ulong, .anticommute = always}, + {'*', &type_ulong, .commutative = always}, {'/', &type_ulong}, - {'&', &type_ulong}, - {'|', &type_ulong}, - {'^', &type_ulong}, + {'&', &type_ulong, .commutative = always}, + {'|', &type_ulong, .commutative = always}, + {'^', &type_ulong, .commutative = always}, {'%', &type_ulong}, {MOD, &type_ulong}, {SHL, &type_ulong}, @@ -1249,6 +1271,12 @@ binary_expr (int op, expr_t *e1, expr_t *e2) e = new_binary_expr (op, e1, e2); e->expr.type = expr_type->result_type; + if (expr_type->commutative) { + e->expr.commutative = expr_type->commutative (); + } + if (expr_type->anticommute) { + e->expr.anticommute = expr_type->anticommute (); + } if (is_compare (op) || is_logic (op)) { if (options.code.progsversion == PROG_ID_VERSION) { e->expr.type = &type_float; diff --git a/tools/qfcc/source/expr_dag.c b/tools/qfcc/source/expr_dag.c index d726fccb2..c28bc5fb2 100644 --- a/tools/qfcc/source/expr_dag.c +++ b/tools/qfcc/source/expr_dag.c @@ -88,8 +88,12 @@ edag_add_expr (expr_t *expr) case ex_expr: if (e->expr.type == expr->expr.type && e->expr.op == expr->expr.op - && e->expr.e1 == expr->expr.e1 - && e->expr.e2 == expr->expr.e2) { + && e->expr.commutative == expr->expr.commutative + && ((e->expr.e1 == expr->expr.e1 + && e->expr.e2 == expr->expr.e2) + || (e->expr.commutative + && e->expr.e1 == expr->expr.e2 + && e->expr.e2 == expr->expr.e1))) { return e; } break;