localopt: simple associativity optimisation
authorMatthias Braun <matze@braunis.de>
Fri, 4 Nov 2011 15:22:18 +0000 (16:22 +0100)
committerMatthias Braun <matze@braunis.de>
Fri, 4 Nov 2011 15:23:56 +0000 (16:23 +0100)
Add op(op(x, c0), c1) => op(x, op(c0, c1)) as localopt rule. This is an
very usual and often encountered case so it makes sense to have this
working without explicitely invoking the associativity optimisation phase.

ir/common/irtools.h
ir/ir/iropt.c

index 575dd39..53d08f5 100644 (file)
@@ -70,7 +70,7 @@ void firm_collect_block_phis(ir_node *node, void *env);
 
 /**
  * Creates an exact copy of a node with same inputs and attributes in the
- * same block.
+ * same block. The copied node will not be optimized (so no CSE is performed).
  *
  * @param node   the node to copy
  */
index 880db76..56ea289 100644 (file)
@@ -2461,6 +2461,55 @@ static bool complement_values(const ir_node *a, const ir_node *b)
        return false;
 }
 
+typedef ir_tarval *(tv_fold_binop_func)(ir_tarval *a, ir_tarval *b);
+
+/**
+ * for associative operations fold:
+ *   op(op(x, c0), c1) to op(x, op(c0, c1)) with constants folded.
+ * This is a "light" version of the reassociation phase
+ */
+static ir_node *fold_constant_associativity(ir_node *node,
+                                            tv_fold_binop_func fold)
+{
+       ir_graph  *irg;
+       ir_op     *op;
+       ir_node   *left;
+       ir_node   *right = get_binop_right(node);
+       ir_node   *left_right;
+       ir_node   *left_left;
+       ir_tarval *c0;
+       ir_tarval *c1;
+       ir_tarval *new_c;
+       ir_node   *new_const;
+       ir_node   *new_node;
+       if (!is_Const(right))
+               return node;
+
+       op   = get_irn_op(node);
+       left = get_binop_left(node);
+       if (get_irn_op(left) != op)
+               return node;
+
+       left_right = get_binop_right(left);
+       if (!is_Const(left_right))
+               return node;
+
+       left_left = get_binop_left(left);
+       c0        = get_Const_tarval(left_right);
+       c1        = get_Const_tarval(right);
+       irg       = get_irn_irg(node);
+       if (get_tarval_mode(c0) != get_tarval_mode(c1))
+               return node;
+       new_c     = fold(c0, c1);
+       if (new_c == tarval_bad)
+               return node;
+       new_const = new_r_Const(irg, new_c);
+       new_node  = exact_copy(node);
+       set_binop_left(new_node, left_left);
+       set_binop_right(new_node, new_const);
+       return new_node;
+}
+
 /**
  * Transform an Or.
  */
@@ -2472,6 +2521,10 @@ static ir_node *transform_node_Or_(ir_node *n)
        ir_node *c;
        ir_mode *mode;
 
+       n = fold_constant_associativity(n, tarval_or);
+       if (n != oldn)
+               return n;
+
        if (is_Not(a) && is_Not(b)) {
                /* ~a | ~b = ~(a&b) */
                ir_node *block = get_nodes_block(n);
@@ -2576,6 +2629,10 @@ static ir_node *transform_node_Eor_(ir_node *n)
        ir_mode *mode = get_irn_mode(n);
        ir_node *c;
 
+       n = fold_constant_associativity(n, tarval_eor);
+       if (n != oldn)
+               return n;
+
        /* we can combine the relations of two compares with the same operands */
        if (is_Cmp(a) && is_Cmp(b)) {
                ir_node *a_left  = get_Cmp_left(a);
@@ -2643,8 +2700,6 @@ static ir_node *transform_node_Eor(ir_node *n)
        return transform_node_Eor_(n);
 }
 
-
-
 /**
  * Do the AddSub optimization, then Transform
  *   Constant folding on Phi
@@ -2662,6 +2717,10 @@ static ir_node *transform_node_Add(ir_node *n)
        ir_node *c;
        ir_node *oldn = n;
 
+       n = fold_constant_associativity(n, tarval_add);
+       if (n != oldn)
+               return n;
+
        n = transform_node_AddSub(n);
        if (n != oldn)
                return n;
@@ -3149,7 +3208,8 @@ static ir_node *transform_node_Mul(ir_node *n)
        ir_node *a = get_Mul_left(n);
        ir_node *b = get_Mul_right(n);
 
-       if (is_Bad(a) || is_Bad(b))
+       n = fold_constant_associativity(n, tarval_mul);
+       if (n != oldn)
                return n;
 
        if (mode != get_irn_mode(a))
@@ -3646,6 +3706,10 @@ static ir_node *transform_node_And(ir_node *n)
        ir_node *b = get_And_right(n);
        ir_mode *mode;
 
+       n = fold_constant_associativity(n, tarval_and);
+       if (n != oldn)
+               return n;
+
        if (is_Cmp(a) && is_Cmp(b)) {
                ir_node    *a_left     = get_Cmp_left(a);
                ir_node    *a_right    = get_Cmp_right(a);