further corrections for the keepalive hack
authorMatthias Braun <matze@braunis.de>
Fri, 31 Aug 2012 12:50:02 +0000 (14:50 +0200)
committerMatthias Braun <matze@braunis.de>
Fri, 31 Aug 2012 12:50:02 +0000 (14:50 +0200)
ir/ir/irnode.c
ir/ir/irnode_t.h
ir/ir/iropt.c
ir/opt/code_placement.c

index 9ea9fcd..2515eaf 100644 (file)
@@ -1577,5 +1577,19 @@ ir_switch_table *ir_switch_table_duplicate(ir_graph *irg,
        return res;
 }
 
+bool only_used_by_keepalive(const ir_node *node)
+{
+       foreach_out_edge(node, edge) {
+               ir_node *succ = get_edge_src_irn(edge);
+               if (is_End(succ))
+                       continue;
+               if (is_Proj(succ) && only_used_by_keepalive(succ))
+                       return true;
+               /* found a real user */
+               return false;
+       }
+       return true;
+}
+
 /* include generated code */
 #include "gen_irnode.c.inl"
index afc4dab..d8190c6 100644 (file)
@@ -563,6 +563,13 @@ void ir_register_getter_ops(void);
 /** initialize ir_node module */
 void init_irnode(void);
 
+/**
+ * because firm keepalive edges are a broken concept, we have to make sure that
+ * nodes which are only held by a keepalive edges are never moved again.
+ * This function returns true in this case.
+ */
+bool only_used_by_keepalive(const ir_node *node);
+
 /* this section MUST contain all inline functions */
 #define is_ir_node(thing)                     is_ir_node_(thing)
 #define get_irn_arity(node)                   get_irn_arity_(node)
index 9686ac0..43ac2f4 100644 (file)
@@ -6475,6 +6475,10 @@ int identities_cmp(const void *elt, const void *key)
                        if (!block_dominates(block_a, block_b)
                            && !block_dominates(block_b, block_a))
                            return 1;
+                       /* respect the workaround rule: do not move nodes which are only
+                        * held by keepalive edges */
+                       if (only_used_by_keepalive(a) || only_used_by_keepalive(b))
+                               return 1;
                }
        }
 
index 0cc25b3..0540e21 100644 (file)
@@ -44,25 +44,6 @@ static bool is_block_reachable(ir_node *block)
        return get_Block_dom_depth(block) >= 0;
 }
 
-/**
- * Firm keepalive edges are broken (the user should really be the endless loop
- * and not the End node.) This wrong place of the user will lead to wrong
- * results in place_early()/place_late(). We work around these problems by not
- * moving nodes which just have keepalive edges as their users (or no users at
- * all)
- */
-static bool float_exceptions(const ir_node *node)
-{
-       foreach_out_edge(node, edge) {
-               ir_node *succ = get_edge_src_irn(edge);
-               if (is_End(succ))
-                       continue;
-               /* found a real user */
-               return false;
-       }
-       return true;
-}
-
 /**
  * Find the earliest correct block for node n.  --- Place n into the
  * same Block as its dominance-deepest Input.
@@ -100,7 +81,7 @@ static void place_floats_early(ir_node *n, waitq *worklist)
         * This works because in firm each cycle contains a Phi or Block node
         * (which are pinned)
         */
-       if (get_irn_pinned(n) != op_pin_state_floats || float_exceptions(n)) {
+       if (get_irn_pinned(n) != op_pin_state_floats || only_used_by_keepalive(n)) {
                /* we can't move pinned nodes */
                arity = get_irn_arity(n);
                for (i = 0; i < arity; ++i) {
@@ -302,6 +283,13 @@ static ir_node *get_deepest_common_dom_ancestor(ir_node *node, ir_node *dca)
                        dca = consumer_dom_dca(dca, succ, node);
                }
        }
+       /* respect the keepalive rule: if our only user is a keepalive, then we must
+        * not move the node any further */
+       if (dca == NULL) {
+               assert(only_used_by_keepalive(node));
+               return get_nodes_block(node);
+       }
+
        foreach_out_edge_kind(node, edge, EDGE_KIND_DEP) {
                ir_node *succ = get_edge_src_irn(edge);
                assert(is_block_reachable(get_nodes_block(succ)));