Include limits.h for LONG_{MAX,MIN}.
[libfirm] / ir / opt / combo.c
index 32966c4..0c2b981 100644 (file)
@@ -37,7 +37,6 @@
 #include "irflag.h"
 #include "ircons.h"
 #include "list.h"
-#include "array.h"
 #include "set.h"
 #include "pmap.h"
 #include "obstack.h"
@@ -126,6 +125,7 @@ struct node_t {
 struct partition_t {
        list_head         entries;         /**< The head of partition node list. */
        list_head         cprop;           /**< The head of partition.cprop list. */
+       list_head         split_list;      /**< Double-linked list of entries that must be processed by split_by(). */
        partition_t       *wl_next;        /**< Next entry in the work list if any. */
        partition_t       *touched_next;   /**< Points to the next partition in the touched set. */
        partition_t       *cprop_next;     /**< Points to the next partition in the cprop list. */
@@ -385,6 +385,7 @@ static INLINE partition_t *new_partition(environment_t *env) {
 
        INIT_LIST_HEAD(&part->entries);
        INIT_LIST_HEAD(&part->cprop);
+       INIT_LIST_HEAD(&part->split_list);
        part->wl_next         = NULL;
        part->touched_next    = NULL;
        part->cprop_next      = NULL;
@@ -733,7 +734,7 @@ static void cause_splits(environment_t *env) {
                                y = get_irn_node(succ);
                                if (is_constant_type(y->type)) {
                                        code = get_irn_opcode(succ);
-                                       if (code == iro_Sub || (code == iro_Proj && is_Cmp(get_Proj_pred(succ))))
+                                       if (code == iro_Sub || code == iro_Cmp)
                                                add_node_to_cprop(y, env);
                                }
 
@@ -772,13 +773,13 @@ static void cause_splits(environment_t *env) {
  *
  * @param X     the partition to split
  * @param What  a function returning an Id for every node of the partition X
- * @param P     an flexible array to store the result partitions or NULL
+ * @param P     a list head to store the result partitions
  * @param env   the environment
  *
- * @return if P != NULL P will be filled with the resulting partitions and returned
+ * @return P
  */
-static partition_t **split_by_what(partition_t *X, what_func What,
-                                   partition_t **P, environment_t *env) {
+static list_head *split_by_what(partition_t *X, what_func What,
+                                list_head *P, environment_t *env) {
        node_t          *x, *S;
        listmap_t       map;
        listmap_entry_t *iter;
@@ -812,14 +813,10 @@ static partition_t **split_by_what(partition_t *X, what_func What,
                /* Add SPLIT( X, S ) to P. */
                DB((dbg, LEVEL_2, "Split part%d by what\n", X->nr));
                R = split(X, S, env);
-               if (P != NULL) {
-                       ARR_APP1(partition_t *, P, R);
-               }
+               list_add(&R->split_list, P);
        }
        /* Add X to P. */
-       if (P != NULL) {
-               ARR_APP1(partition_t *, P, X);
-       }
+       list_add(&X->split_list, P);
 
        listmap_term(&map);
        return P;
@@ -896,40 +893,69 @@ static int is_type_constant(lattice_elem_t type) {
  * @param env  the environment
  */
 static void split_by(partition_t *X, environment_t *env) {
-       partition_t **P = NEW_ARR_F(partition_t *, 0);
-       int         i, j, k;
+       list_head hP;
+       list_head *P = &hP;
+       int       input;
 
+       INIT_LIST_HEAD(P);
        DB((dbg, LEVEL_2, "WHAT = lambda n.(n.type) on part%d\n", X->nr));
        P = split_by_what(X, lambda_type, P, env);
-       for (i = ARR_LEN(P) - 1; i >= 0; --i) {
-               partition_t *Y = P[i];
+       do {
+               partition_t *Y = list_entry(P->next, partition_t, split_list);
 
+               list_del(&Y->split_list);
                if (Y->n_nodes > 1) {
                        lattice_elem_t type = get_partition_type(Y);
 
                        /* we do not want split the TOP or constant partitions */
                        if (type.tv != tarval_top && !is_type_constant(type)) {
-                               partition_t **Q = NEW_ARR_F(partition_t *, 0);
+                               list_head hQ;
+                               list_head *Q = &hQ;
 
+                               INIT_LIST_HEAD(Q);
                                DB((dbg, LEVEL_2, "WHAT = lambda n.(n.opcode) on part%d\n", Y->nr));
                                Q = split_by_what(Y, lambda_opcode, Q, env);
 
-                               for (j = ARR_LEN(Q) - 1; j >= 0; --j) {
-                                       partition_t *Z = Q[j];
-
-                                       for (k = Z->max_arity - 1; k >= -1; --k) {
-                                               if (Z->n_nodes > 1) {
-                                                       env->lambda_input = k;
-                                                       DB((dbg, LEVEL_2, "WHAT = lambda n.(n[%d].partition) on part%d\n", k, Z->nr));
-                                                       split_by_what(Z, lambda_partition, NULL, env);
+                               do {
+                                       list_head   hR, hS;
+                                       partition_t *Z        = list_entry(Q->next, partition_t, split_list);
+                                       int         max_arity = Z->max_arity;
+                                       list_head   *R = &hR, *S = &hS, *T;
+
+                                       list_del(&Z->split_list);
+
+                                       if (Z->n_nodes > 1) {
+                                               INIT_LIST_HEAD(R);
+                                               INIT_LIST_HEAD(S);
+
+                                               /*
+                                                * BEWARE: during splitting by input 2 for instance we might
+                                                * create new partitions which are different by input 1, so collect
+                                                * them and split further.
+                                                */
+                                               list_add(&Z->split_list, R);
+                                               for (input = max_arity - 1; input >= -1; --input) {
+                                                       do {
+                                                               partition_t *Z_prime = list_entry(R->next, partition_t, split_list);
+
+                                                               list_del(&Z_prime->split_list);
+                                                               if (Z_prime->n_nodes > 1) {
+                                                                       env->lambda_input = input;
+                                                                       DB((dbg, LEVEL_2, "WHAT = lambda n.(n[%d].partition) on part%d\n", input, Z_prime->nr));
+                                                                       S = split_by_what(Z_prime, lambda_partition, S, env);
+                                                               } else {
+                                                                       list_add(&Z_prime->split_list, S);
+                                                               }
+                                                       } while (!list_empty(R));
+                                                       T = R;
+                                                       R = S;
+                                                       S = T;
                                                }
                                        }
-                               }
-                               DEL_ARR_F(Q);
+                               } while (!list_empty(Q));
                        }
                }
-       }
-       DEL_ARR_F(P);
+       } while (!list_empty(P));
 }  /* split_by */
 
 /**
@@ -1201,6 +1227,31 @@ static void compute_Sub(node_t *node) {
        }
 }  /* compute_Sub */
 
+/**
+ * (Re-)compute the type for Cmp.
+ *
+ * @param node  the node
+ */
+static void compute_Cmp(node_t *node) {
+       ir_node        *cmp  = node->node;
+       node_t         *l    = get_irn_node(get_Cmp_left(cmp));
+       node_t         *r    = get_irn_node(get_Cmp_right(cmp));
+       lattice_elem_t a     = l->type;
+       lattice_elem_t b     = r->type;
+
+       if (a.tv == tarval_top || b.tv == tarval_top) {
+               node->type.tv = tarval_top;
+       } else if (is_con(a) && is_con(b)) {
+               /* both nodes are constants, we can propbably do something */
+               node->type.tv = tarval_b_true;
+       } else if (r->part == l->part) {
+               /* both nodes congruent, we can probably do something */
+               node->type.tv = tarval_b_true;
+       } else {
+               node->type.tv = tarval_bottom;
+       }
+}  /* compute_Proj_Cmp */
+
 /**
  * (Re-)compute the type for a Proj(Cmp).
  *
@@ -1412,9 +1463,9 @@ static void propagate(environment_t *env) {
 
        while (env->cprop != NULL) {
                /* remove the first partition X from cprop */
-               X          = env->cprop;
+               X           = env->cprop;
                X->on_cprop = 0;
-               env->cprop = X->cprop_next;
+               env->cprop  = X->cprop_next;
 
                DB((dbg, LEVEL_2, "Propagate type on part%d\n", X->nr));
                fallen   = NULL;
@@ -1490,7 +1541,9 @@ static ir_node *get_leader(node_t *node) {
  * @param pred  the control flow exit
  */
 static int can_exchange(ir_node *pred) {
-       if (is_Jmp(pred))
+       if (is_Start(pred))
+               return 0;
+       else if (is_Jmp(pred))
                return 1;
        else if (get_irn_mode(pred) == mode_T) {
                int i, k;
@@ -1607,7 +1660,7 @@ static void apply_cf(ir_node *block, void *ctx) {
                if (can_exchange(pred))
                        exchange(block, get_nodes_block(pred));
        } else {
-               set_irn_in(block, j, in_X);
+               set_irn_in(block, k, in_X);
        }
 }
 
@@ -1618,34 +1671,32 @@ static void apply_result(ir_node *irn, void *ctx) {
        node_t *node = get_irn_node(irn);
 
        (void) ctx;
-       if (is_Block(irn) || is_End(irn)) {
+       if (is_Block(irn) || is_End(irn) || is_Bad(irn)) {
                /* blocks already handled, do not touch the End node */
        } else {
                node_t *block = get_irn_node(get_nodes_block(irn));
 
                if (block->type.tv == tarval_unreachable) {
-                       if (! is_Bad(irn)) {
-                               ir_node *bad = get_irg_bad(current_ir_graph);
-
-                               /* here, bad might already have a node, but this can be safely ignored
-                                  as long as bad has at least ONE valid node */
-                               set_irn_node(bad, node);
-                               node->node = bad;
-                               DB((dbg, LEVEL_1, "%+F is unreachable\n", irn));
-                               exchange(irn, bad);
-                       }
+                       ir_node *bad = get_irg_bad(current_ir_graph);
+
+                       /* here, bad might already have a node, but this can be safely ignored
+                          as long as bad has at least ONE valid node */
+                       set_irn_node(bad, node);
+                       node->node = bad;
+                       DB((dbg, LEVEL_1, "%+F is unreachable\n", irn));
+                       exchange(irn, bad);
+               }
+               else if (node->type.tv == tarval_unreachable) {
+                       ir_node *bad = get_irg_bad(current_ir_graph);
+
+                       /* see comment above */
+                       set_irn_node(bad, node);
+                       node->node = bad;
+                       DB((dbg, LEVEL_1, "%+F is unreachable\n", irn));
+                       exchange(irn, bad);
                }
                else if (get_irn_mode(irn) == mode_X) {
-                       if (node->type.tv == tarval_unreachable) {
-                               ir_node *bad = get_irg_bad(current_ir_graph);
-
-                               /* see comment above */
-                               set_irn_node(bad, node);
-                               node->node = bad;
-                               DB((dbg, LEVEL_1, "%+F is unreachable\n", irn));
-                               exchange(irn, bad);
-                       }
-                       else if (is_Proj(irn)) {
+                       if (is_Proj(irn)) {
                                /* leave or Jmp */
                                ir_node *cond = get_Proj_pred(irn);
 
@@ -1720,6 +1771,7 @@ static void set_compute_functions(void) {
        SET(Add);
        SET(Sub);
        SET(SymConst);
+       SET(Cmp);
        SET(Proj);
        SET(Confirm);
        SET(End);
@@ -1743,9 +1795,9 @@ void combo(ir_graph *irg) {
 
        /* register a debug mask */
        FIRM_DBG_REGISTER(dbg, "firm.opt.combo");
-       firm_dbg_set_mask(dbg, SET_LEVEL_1);
+       //firm_dbg_set_mask(dbg, SET_LEVEL_3);
 
-       //DB((dbg, LEVEL_1, "Doing COMBO for %+F\n", irg));
+       DB((dbg, LEVEL_1, "Doing COMBO for %+F\n", irg));
 
        obstack_init(&env.obst);
        env.worklist       = NULL;
@@ -1787,10 +1839,13 @@ void combo(ir_graph *irg) {
 
        dump_all_partitions(&env);
 
+#if 0
        set_dump_node_vcgattr_hook(dump_partition_hook);
        dump_ir_block_graph(irg, "-partition");
        set_dump_node_vcgattr_hook(NULL);
-
+#else
+       (void)dump_partition_hook;
+#endif
 
        /* apply the result */
        irg_block_walk_graph(irg, NULL, apply_cf, &env);