BugFix: ensure that two ASM nodes are never congruent in combo.
[libfirm] / ir / opt / combo.c
index 9d465de..3b71669 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
+ * Copyright (C) 1995-2011 University of Karlsruhe.  All right reserved.
  *
  * This file is part of libFirm.
  *
@@ -83,6 +83,7 @@
 #include "irnodeset.h"
 #include "irpass.h"
 #include "tv_t.h"
+#include "irtools.h"
 
 #include "irprintf.h"
 #include "irdump.h"
@@ -113,7 +114,7 @@ struct opcode_key_t {
                ir_entity *ent;   /**< For Sel Nodes, its entity */
                int       intVal; /**< For Conv/Div Nodes: strict/remainderless */
                unsigned  uintVal;/**< for Builtin: the kind */
-               ir_node   *block; /**< for Block: itself */
+               ir_node   *irn;   /**< for nodes that never be construent: the node itself */
                void      *ptr;   /**< generic pointer for hash/cmp */
        } u;
 };
@@ -259,6 +260,23 @@ static void check_partition(const partition_t *T)
        }
 }  /* check_partition */
 
+/**
+ * return the result mode of a node (part of combo's opcode).
+ */
+static ir_mode *get_irn_resmode(const ir_node *irn)
+{
+       switch (get_irn_opcode(irn)) {
+       case iro_Load:
+               return get_Load_mode(irn);
+       case iro_Div:
+               return get_Div_resmode(irn);
+       case iro_Mod:
+               return get_Mod_resmode(irn);
+       default:
+               return get_irn_mode(irn);
+       }
+}  /* get_irn_resmode */
+
 /**
  * check that all leader nodes in the partition have the same opcode.
  */
@@ -273,7 +291,7 @@ static void check_opcode(const partition_t *Z)
 
                if (first) {
                        key.code   = get_irn_opcode(irn);
-                       key.mode   = get_irn_mode(irn);
+                       key.mode   = get_irn_resmode(irn);
                        key.arity  = get_irn_arity(irn);
                        key.u.proj = 0;
                        key.u.ent  = NULL;
@@ -292,10 +310,8 @@ static void check_opcode(const partition_t *Z)
                                key.u.intVal = get_Div_no_remainder(irn);
                                break;
                        case iro_Block:
-                               key.u.block = irn;
-                               break;
-                       case iro_Load:
-                               key.mode = get_Load_mode(irn);
+                       case iro_ASM:
+                               key.u.irn = irn;
                                break;
                        case iro_Builtin:
                                key.u.intVal = get_Builtin_kind(irn);
@@ -305,8 +321,8 @@ static void check_opcode(const partition_t *Z)
                        }
                        first = 0;
                } else {
-                       assert((unsigned)key.code  == get_irn_opcode(irn));
-                       assert(key.mode  == get_irn_mode(irn));
+                       assert((unsigned)key.code == get_irn_opcode(irn));
+                       assert(key.mode  == get_irn_resmode(irn));
                        assert(key.arity == get_irn_arity(irn));
 
                        switch (get_irn_opcode(irn)) {
@@ -323,13 +339,11 @@ static void check_opcode(const partition_t *Z)
                                assert(key.u.intVal == get_Div_no_remainder(irn));
                                break;
                        case iro_Block:
-                               assert(key.u.block == irn);
-                               break;
-                       case iro_Load:
-                               assert(key.mode == get_Load_mode(irn));
+                       case iro_ASM:
+                               assert(key.u.irn == irn);
                                break;
                        case iro_Builtin:
-                               assert(key.u.intVal == (int) get_Builtin_kind(irn));
+                               assert(key.u.intVal == (int)get_Builtin_kind(irn));
                                break;
                        default:
                                break;
@@ -596,7 +610,7 @@ static listmap_entry_t *listmap_find(listmap_t *map, void *id)
  */
 static unsigned opcode_hash(const opcode_key_t *entry)
 {
-       return (entry->mode - (ir_mode *)0) * 9 + entry->code + entry->u.proj * 3 + HASH_PTR(entry->u.ptr) + entry->arity;
+       return (unsigned)(PTR_TO_INT(entry->mode) * 9 + entry->code + entry->u.proj * 3 + HASH_PTR(entry->u.ptr) + entry->arity);
 }  /* opcode_hash */
 
 /**
@@ -1726,7 +1740,7 @@ static void *lambda_opcode(const node_t *node, environment_t *env)
        ir_node      *irn = node->node;
 
        key.code   = get_irn_opcode(irn);
-       key.mode   = get_irn_mode(irn);
+       key.mode   = get_irn_resmode(irn);
        key.arity  = get_irn_arity(irn);
        key.u.proj = 0;
        key.u.ent  = NULL;
@@ -1751,10 +1765,17 @@ static void *lambda_opcode(const node_t *node, environment_t *env)
                 * We fix it by never letting blocks be congruent
                 * which cannot be detected by combo either.
                 */
-               key.u.block = irn;
+               key.u.irn = irn;
                break;
-       case iro_Load:
-               key.mode = get_Load_mode(irn);
+       case iro_ASM:
+               /*
+                * If is difficult to detect when two ASM nodes are congruent: even
+                * if the assembler "text" is identical, the instruction might
+                * have a side effect like flag toggle or function call.
+                * So, do not even try it.
+                *
+                */
+               key.u.irn = irn;
                break;
        case iro_Builtin:
                key.u.intVal = get_Builtin_kind(irn);
@@ -2617,7 +2638,7 @@ static void compute(node_t *node)
 }  /* compute */
 
 /*
- * Identity functions: Note that one might thing that identity() is just a
+ * Identity functions: Note that one might think that identity() is just a
  * synonym for equivalent_node(). While this is true, we cannot use it for the algorithm
  * here, because it expects that the identity node is one of the inputs, which is NOT
  * always true for equivalent_node() which can handle (and does sometimes) DAGs.
@@ -3254,8 +3275,20 @@ static void exchange_leader(ir_node *irn, ir_node *leader)
                 * 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, block, leader, mode);
+               ir_node  *nlead = new_rd_Conv(dbg, block, leader, mode);
+
+               if (nlead != leader) {
+                       /* Note: this newly create irn has no node info because
+                        * it is created after the analysis. However, this node
+                        * replaces the node irn and should not be visited again,
+                        * so set its visited count to the count of irn.
+                        * Otherwise we might visited this node more than once if
+                        * irn had more than one user.
+                        */
+                       set_irn_node(nlead, NULL);
+                       set_irn_visited(nlead, get_irn_visited(irn));
+                       leader = nlead;
+               }
        }
        exchange(irn, leader);
 }  /* exchange_leader */
@@ -3506,10 +3539,10 @@ static void apply_end(ir_node *end, environment_t *env)
  */
 static void set_compute_functions(void)
 {
-       int i;
+       size_t i, n;
 
        /* set the default compute function */
-       for (i = get_irp_n_opcodes() - 1; i >= 0; --i) {
+       for (i = 0, n = get_irp_n_opcodes(); i < n; ++i) {
                ir_op *op = get_irp_opcode(i);
                op->ops.generic = (op_func)default_compute;
        }
@@ -3535,10 +3568,11 @@ static void set_compute_functions(void)
 /**
  * Add memory keeps.
  */
-static void add_memory_keeps(ir_node **kept_memory, int len)
+static void add_memory_keeps(ir_node **kept_memory, size_t len)
 {
        ir_node      *end = get_irg_end(current_ir_graph);
        int          i;
+       size_t       idx;
        ir_nodeset_t set;
 
        ir_nodeset_init(&set);
@@ -3547,8 +3581,8 @@ static void add_memory_keeps(ir_node **kept_memory, int len)
        for (i = get_End_n_keepalives(end) - 1; i >= 0; --i)
                ir_nodeset_insert(&set, get_End_keepalive(end, i));
 
-       for (i = len - 1; i >= 0; --i) {
-               ir_node *ka = kept_memory[i];
+       for (idx = 0; idx < len; ++idx) {
+               ir_node *ka = kept_memory[idx];
 
                if (! ir_nodeset_contains(&set, ka)) {
                        add_End_keepalive(end, ka);
@@ -3563,7 +3597,7 @@ void combo(ir_graph *irg)
        ir_node       *initial_bl;
        node_t        *start;
        ir_graph      *rem = current_ir_graph;
-       int           len;
+       size_t        len;
 
        current_ir_graph = irg;