Turn alloca() with fixed size into array.
[libfirm] / ir / opt / combo.c
index 7181600..1701b58 100644 (file)
@@ -34,9 +34,7 @@
  * in some cases from Firm terminology.  Especially, Click's type is a
  * Firm tarval/entity, nevertheless we call it type here for "maximum compatibility".
  */
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
+#include "config.h"
 
 #include <assert.h>
 
@@ -323,7 +321,7 @@ static void check_list(const node_t *list, const partition_t *Z) {
 #endif /* CHECK_PARTITIONS */
 
 #ifdef DEBUG_libfirm
-static INLINE lattice_elem_t get_partition_type(const partition_t *X);
+static inline lattice_elem_t get_partition_type(const partition_t *X);
 
 /**
  * Dump partition to output.
@@ -550,7 +548,7 @@ static void sort_irn_outs(node_t *node) {
  *
  * @return the associated type of this node
  */
-static INLINE lattice_elem_t get_node_type(const ir_node *irn) {
+static inline lattice_elem_t get_node_type(const ir_node *irn) {
        return get_irn_node(irn)->type;
 }  /* get_node_type */
 
@@ -561,7 +559,7 @@ static INLINE lattice_elem_t get_node_type(const ir_node *irn) {
  *
  * @return the associated type of this node
  */
-static INLINE tarval *get_node_tarval(const ir_node *irn) {
+static inline tarval *get_node_tarval(const ir_node *irn) {
        lattice_elem_t type = get_node_type(irn);
 
        if (is_tarval(type.tv))
@@ -572,7 +570,7 @@ static INLINE tarval *get_node_tarval(const ir_node *irn) {
 /**
  * Add a partition to the worklist.
  */
-static INLINE void add_to_worklist(partition_t *X, environment_t *env) {
+static inline void add_to_worklist(partition_t *X, environment_t *env) {
        assert(X->on_worklist == 0);
        DB((dbg, LEVEL_2, "Adding part%d to worklist\n", X->nr));
        X->wl_next     = env->worklist;
@@ -587,7 +585,7 @@ static INLINE void add_to_worklist(partition_t *X, environment_t *env) {
  *
  * @return a newly allocated partition
  */
-static INLINE partition_t *new_partition(environment_t *env) {
+static inline partition_t *new_partition(environment_t *env) {
        partition_t *part = obstack_alloc(&env->obst, sizeof(*part));
 
        INIT_LIST_HEAD(&part->Leader);
@@ -617,7 +615,7 @@ static INLINE partition_t *new_partition(environment_t *env) {
 /**
  * Get the first node from a partition.
  */
-static INLINE node_t *get_first_node(const partition_t *X) {
+static inline node_t *get_first_node(const partition_t *X) {
        return list_entry(X->Leader.next, node_t, node_list);
 }  /* get_first_node */
 
@@ -629,7 +627,7 @@ static INLINE node_t *get_first_node(const partition_t *X) {
  *
  * @return the type of the first element of the partition
  */
-static INLINE lattice_elem_t get_partition_type(const partition_t *X) {
+static inline lattice_elem_t get_partition_type(const partition_t *X) {
        const node_t *first = get_first_node(X);
        return first->type;
 }  /* get_partition_type */
@@ -713,7 +711,7 @@ static void create_initial_partitions(ir_node *irn, void *ctx) {
  * @param y    a node
  * @param env  the environment
  */
-static INLINE void add_to_touched(node_t *y, environment_t *env) {
+static inline void add_to_touched(node_t *y, environment_t *env) {
        if (y->on_touched == 0) {
                partition_t *part = y->part;
 
@@ -1083,9 +1081,9 @@ static partition_t *split(partition_t **pX, node_t *gg, environment_t *env) {
        partition_t *X = *pX;
        partition_t *X_prime;
        list_head   tmp;
-       step_env    env1, env2, *winner;
+       step_env    senv[2];
        node_t      *g, *h, *node, *t;
-       int         max_input, transitions;
+       int         max_input, transitions, winner, shf;
        unsigned    n;
        DEBUG_ONLY(static int run = 0;)
 
@@ -1122,44 +1120,60 @@ static partition_t *split(partition_t **pX, node_t *gg, environment_t *env) {
        /* restore X.Leader */
        list_splice(&tmp, &X->Leader);
 
-       env1.initial       = g;
-       env1.unwalked      = NULL;
-       env1.walked        = NULL;
-       env1.index         = 0;
-       env1.side          = 1;
+       senv[0].initial   = g;
+       senv[0].unwalked  = NULL;
+       senv[0].walked    = NULL;
+       senv[0].index     = 0;
+       senv[0].side      = 1;
 
-       env2.initial       = h;
-       env2.unwalked      = NULL;
-       env2.walked        = NULL;
-       env2.index         = 0;
-       env2.side          = 2;
+       senv[1].initial   = h;
+       senv[1].unwalked  = NULL;
+       senv[1].walked    = NULL;
+       senv[1].index     = 0;
+       senv[1].side      = 2;
 
+       /*
+        * Some informations on the race that are not stated clearly in Click's
+        * thesis.
+        * 1) A follower stays on the side that reach him first.
+        * 2) If the other side reches a follower, if will be converted to
+        *    a leader. /This must be done after the race is over, else the
+        *    edges we are iterating on are renumbered./
+        * 3) /New leader might end up on both sides./
+        * 4) /If one side ends up with new Leaders, we must ensure that
+        *    they can split out by opcode, hence we have to put _every_
+        *    partition with new Leader nodes on the cprop list, as
+        *    opcode splitting is done by split_by() at the end of
+        *    constant propagation./
+        */
        for (;;) {
-               if (step(&env1)) {
-                       winner = &env1;
+               if (step(&senv[0])) {
+                       winner = 0;
                        break;
                }
-               if (step(&env2)) {
-                       winner = &env2;
+               if (step(&senv[1])) {
+                       winner = 1;
                        break;
                }
        }
-       assert(winner->initial == NULL);
-       assert(winner->unwalked == NULL);
+       assert(senv[winner].initial == NULL);
+       assert(senv[winner].unwalked == NULL);
 
        /* clear flags from walked/unwalked */
-       transitions  = clear_flags(env1.unwalked);
-       transitions |= clear_flags(env1.walked);
-       transitions |= clear_flags(env2.unwalked);
-       transitions |= clear_flags(env2.walked);
+       shf = winner;
+       transitions  = clear_flags(senv[0].unwalked) << shf;
+       transitions |= clear_flags(senv[0].walked)   << shf;
+       shf ^= 1;
+       transitions |= clear_flags(senv[1].unwalked) << shf;
+       transitions |= clear_flags(senv[1].walked)   << shf;
 
-       dump_race_list("winner ", winner->walked);
+       dump_race_list("winner ", senv[winner].walked);
 
        /* Move walked_{winner} to a new partition, X'. */
        X_prime   = new_partition(env);
        max_input = 0;
        n         = 0;
-       for (node = winner->walked; node != NULL; node = node->race_next) {
+       for (node = senv[winner].walked; node != NULL; node = node->race_next) {
                list_del(&node->node_list);
                node->part = X_prime;
                if (node->is_follower) {
@@ -1185,7 +1199,7 @@ static partition_t *split(partition_t **pX, node_t *gg, environment_t *env) {
        list_for_each_entry_safe(node_t, node, t, &X_prime->Follower, node_list) {
                if (identity(node) == node) {
                        follower_to_leader(node);
-                       transitions = 1;
+                       transitions |= 1;
                }
        }
 
@@ -1199,20 +1213,28 @@ static partition_t *split(partition_t **pX, node_t *gg, environment_t *env) {
         * If there where follower to leader transitions, ensure that the nodes
         * can be split out if necessary.
         */
-       if (transitions) {
-               /* place partitions on the cprop list */
+       if (transitions & 1) {
+               /* place winner partition on the cprop list */
                if (X_prime->on_cprop == 0) {
                        X_prime->cprop_next = env->cprop;
                        env->cprop          = X_prime;
                        X_prime->on_cprop   = 1;
                }
        }
+       if (transitions & 2) {
+               /* place other partition on the cprop list */
+               if (X->on_cprop == 0) {
+                       X->cprop_next = env->cprop;
+                       env->cprop    = X;
+                       X->on_cprop   = 1;
+               }
+       }
 
        dump_partition("Now ", X);
        dump_partition("Created new ", X_prime);
 
        /* we have to ensure that the partition containing g is returned */
-       if (winner == &env2) {
+       if (winner != 0) {
                *pX = X_prime;
                return X;
        }
@@ -3023,6 +3045,27 @@ static void apply_cf(ir_node *block, void *ctx) {
        }
 }  /* apply_cf */
 
+/**
+ * Exchange a node by its leader.
+ * Beware: in rare cases the mode might be wrong here, for instance
+ * AddP(x, NULL) is a follower of x, but with different mode.
+ * Fix it here.
+ */
+static void exchange_leader(ir_node *irn, ir_node *leader) {
+       ir_mode *mode = get_irn_mode(irn);
+       if (mode != get_irn_mode(leader)) {
+               /* The conv is a no-op, so we are fre to place in
+                * either in the block of the leader OR in irn's block.
+                * Propably placing it into leaders block might reduce
+                * the number of Conv due to CSE. */
+               ir_node  *block = get_nodes_block(leader);
+               dbg_info *dbg   = get_irn_dbg_info(irn);
+
+               leader = new_rd_Conv(dbg, current_ir_graph, block, leader, mode);
+       }
+       exchange(irn, leader);
+}
+
 /**
  * Post-Walker, apply the analysis results;
  */
@@ -3095,7 +3138,7 @@ static void apply_result(ir_node *irn, void *ctx) {
                                        node->node = c;
                                        DB((dbg, LEVEL_1, "%+F is replaced by %+F\n", irn, c));
                                        DBG_OPT_COMBO(irn, c, FS_OPT_COMBO_CONST);
-                                       exchange(irn, c);
+                                       exchange_leader(irn, c);
                                        env->modified = 1;
                                }
                        } else if (is_entity(node->type.sym.entity_p)) {
@@ -3107,7 +3150,7 @@ static void apply_result(ir_node *irn, void *ctx) {
 
                                        DB((dbg, LEVEL_1, "%+F is replaced by %+F\n", irn, symc));
                                        DBG_OPT_COMBO(irn, symc, FS_OPT_COMBO_CONST);
-                                       exchange(irn, symc);
+                                       exchange_leader(irn, symc);
                                        env->modified = 1;
                                }
                        } else if (is_Confirm(irn)) {
@@ -3121,7 +3164,7 @@ static void apply_result(ir_node *irn, void *ctx) {
                                                DBG_OPT_COMBO(irn, leader, FS_OPT_COMBO_FOLLOWER);
                                        else
                                                DBG_OPT_COMBO(irn, leader, FS_OPT_COMBO_CONGRUENT);
-                                       exchange(irn, leader);
+                                       exchange_leader(irn, leader);
                                        env->modified = 1;
                                }
                        }