+/**
+ * Returns the earliest were a,b are available.
+ * Note that we know that we know that a, b both dominate
+ * the block of the previous operation, so one must dominate the other.
+ */
+static ir_node *earliest_block(ir_node *a, ir_node *b) {
+ ir_node *blk_a = get_nodes_block(a);
+ ir_node *blk_b = get_nodes_block(b);
+
+ /* if blk_a != blk_b, one must dominate the other */
+ if (block_dominates(blk_a, blk_b))
+ return blk_b;
+ else
+ return blk_a;
+}
+
+/**
+ * Apply distributive Law for Mul and Add/Sub
+ */
+static int reverse_rule_distributive(ir_node **node) {
+ ir_node *n = *node;
+ ir_node *left = get_binop_left(n);
+ ir_node *right = get_binop_right(n);
+ ir_node *x, *blk;
+ ir_node *a, *b, *irn;
+ ir_mode *mode;
+ dbg_info *dbg;
+
+ if (! is_Mul(left) || !is_Mul(right))
+ return 0;
+
+ x = get_Mul_left(left);
+
+ if (x == get_Mul_left(right)) {
+ /* (x * a) +/- (x * b) */
+ a = get_Mul_right(left);
+ b = get_Mul_right(right);
+ goto transform;
+ } else if (x == get_Mul_right(right)) {
+ /* (x * a) +/- (b * x) */
+ a = get_Mul_right(left);
+ b = get_Mul_left(right);
+ goto transform;
+ }
+
+ x = get_Mul_right(left);
+
+ if (x == get_Mul_right(right)) {
+ /* (a * x) +/- (b * x) */
+ a = get_Mul_left(left);
+ b = get_Mul_left(right);
+ goto transform;
+ } else if (x == get_Mul_left(right)) {
+ /* (a * x) +/- (x * b) */
+ a = get_Mul_left(left);
+ b = get_Mul_right(right);
+ goto transform;
+ }
+ return 0;
+
+transform:
+ blk = earliest_block(a, b);
+
+ dbg = get_irn_dbg_info(n);
+ mode = get_irn_mode(n);
+
+ if (is_Add(n))
+ irn = new_rd_Add(dbg, current_ir_graph, blk, a, b, mode);
+ else
+ irn = new_rd_Sub(dbg, current_ir_graph, blk, a, b, mode);
+
+ blk = earliest_block(irn, x);
+ irn = new_rd_Mul(dbg, current_ir_graph, blk, irn, x, mode);
+
+ exchange(n, irn);
+ *node = irn;
+ return 1;
+} /* reverse_rule_distributive */
+
+
+/**
+ * Apply the rules in reverse order, removing code that was not collapsed
+ */
+static void reverse_rules(ir_node *node, void *env) {
+ walker_t *wenv = env;
+ ir_mode *mode = get_irn_mode(node);
+ int res;
+
+ /* for FP these optimizations are only allowed if fp_strict_algebraic is disabled */
+ if (mode_is_float(mode) && get_irg_fp_model(current_ir_graph) & fp_strict_algebraic)
+ return;
+
+ do {
+ res = 0;
+ if (is_Add(node) || is_Sub(node)) {
+ wenv->changes |= res = reverse_rule_distributive(&node);
+ }
+ } while (res);
+}
+