Prevent SSA construction from running into endless loops.
[libfirm] / ir / lower / lower_dw.c
index ae08491..04b5b3e 100644 (file)
@@ -138,6 +138,8 @@ struct lower_env_t {
        ir_type  *value_param_tp;     /**< the old value param type */
 };
 
+static void lower_node(lower_env_t *env, ir_node *node);
+
 /**
  * Create a method type for a Conv emulation from imode to omode.
  */
@@ -980,6 +982,27 @@ static void lower_Not(ir_node *node, ir_mode *mode, lower_env_t *env)
        set_lowered(env, node, res_low, res_high);
 }
 
+static bool is_equality_cmp_0(const ir_node *node)
+{
+       ir_relation relation = get_Cmp_relation(node);
+       ir_node    *left     = get_Cmp_left(node);
+       ir_node    *right    = get_Cmp_right(node);
+       ir_mode    *mode     = get_irn_mode(left);
+
+       /* this probably makes no sense if unordered is involved */
+       assert(!mode_is_float(mode));
+
+       if (!is_Const(right) || !is_Const_null(right))
+               return false;
+       if (relation == ir_relation_equal)
+               return true;
+       if (mode_is_signed(mode)) {
+               return relation == ir_relation_less_greater;
+       } else {
+               return relation == ir_relation_greater;
+       }
+}
+
 /**
  * Translate a Cond.
  */
@@ -1005,18 +1028,25 @@ static void lower_Cond(ir_node *node, ir_mode *mode, lower_env_t *env)
                        /* bad we can't really handle Switch with 64bit offsets */
                        panic("Cond with 64bit jumptable not supported");
                }
+               lower_node(env, sel);
                return;
        }
 
-       if (!is_Cmp(sel))
+       if (!is_Cmp(sel)) {
+               lower_node(env, sel);
                return;
+       }
 
        left     = get_Cmp_left(sel);
        cmp_mode = get_irn_mode(left);
-       if (cmp_mode != env->high_signed && cmp_mode != env->high_unsigned)
+       if (cmp_mode != env->high_signed && cmp_mode != env->high_unsigned) {
+               lower_node(env, sel);
                return;
+       }
 
        right  = get_Cmp_right(sel);
+       lower_node(env, left);
+       lower_node(env, right);
        lentry = get_node_entry(env, left);
        rentry = get_node_entry(env, right);
 
@@ -1043,17 +1073,15 @@ static void lower_Cond(ir_node *node, ir_mode *mode, lower_env_t *env)
        dbg      = get_irn_dbg_info(sel);
        relation = get_Cmp_relation(sel);
 
-       if (is_Const(right) && is_Const_null(right)) {
-               if (relation == ir_relation_equal || relation == ir_relation_less_greater) {
-                       /* x ==/!= 0 ==> or(low,high) ==/!= 0 */
-                       ir_mode *mode   = env->low_unsigned;
-                       ir_node *low    = new_r_Conv(block, lentry->low_word, mode);
-                       ir_node *high   = new_r_Conv(block, lentry->high_word, mode);
-                       ir_node *ornode = new_rd_Or(dbg, block, low, high, mode);
-                       ir_node *cmp    = new_rd_Cmp(dbg, block, ornode, new_r_Const_long(irg, mode, 0), relation);
-                       set_Cond_selector(node, cmp);
-                       return;
-               }
+       if (is_equality_cmp_0(sel)) {
+               /* x ==/!= 0 ==> or(low,high) ==/!= 0 */
+               ir_mode *mode   = env->low_unsigned;
+               ir_node *low    = new_r_Conv(block, lentry->low_word, mode);
+               ir_node *high   = new_r_Conv(block, lentry->high_word, mode);
+               ir_node *ornode = new_rd_Or(dbg, block, low, high, mode);
+               ir_node *cmp    = new_rd_Cmp(dbg, block, ornode, new_r_Const_long(irg, mode, 0), relation);
+               set_Cond_selector(node, cmp);
+               return;
        }
 
        if (relation == ir_relation_equal) {
@@ -1296,47 +1324,58 @@ static void lower_Cmp(ir_node *cmp, ir_mode *m, lower_env_t *env)
        ir_mode  *mode = get_irn_mode(l);
        ir_node  *r, *low, *high, *t, *res;
        ir_relation relation;
-       ir_node  *blk;
-       dbg_info *db;
+       ir_node  *block;
+       dbg_info *dbg;
        const node_entry_t *lentry;
        const node_entry_t *rentry;
        (void) m;
 
-       if (mode != env->high_signed && mode != env->high_unsigned) {
+       if (mode != env->high_signed && mode != env->high_unsigned)
                return;
-       }
 
        r        = get_Cmp_right(cmp);
        lentry   = get_node_entry(env, l);
        rentry   = get_node_entry(env, r);
        relation = get_Cmp_relation(cmp);
-       blk      = get_nodes_block(cmp);
-       db       = get_irn_dbg_info(cmp);
+       block    = get_nodes_block(cmp);
+       dbg      = get_irn_dbg_info(cmp);
+
+       /* easy case for x ==/!= 0 (see lower_Cond for details) */
+       if (is_equality_cmp_0(cmp)) {
+               ir_graph *irg     = get_irn_irg(cmp);
+               ir_mode  *mode    = env->low_unsigned;
+               ir_node  *low     = new_r_Conv(block, lentry->low_word, mode);
+               ir_node  *high    = new_r_Conv(block, lentry->high_word, mode);
+               ir_node  *ornode  = new_rd_Or(dbg, block, low, high, mode);
+               ir_node  *new_cmp = new_rd_Cmp(dbg, block, ornode, new_r_Const_long(irg, mode, 0), relation);
+               exchange(cmp, new_cmp);
+               return;
+       }
 
        if (relation == ir_relation_equal) {
                /* simple case:a == b <==> a_h == b_h && a_l == b_l */
-               low  = new_rd_Cmp(db, blk, lentry->low_word, rentry->low_word,
+               low  = new_rd_Cmp(dbg, block, lentry->low_word, rentry->low_word,
                                  relation);
-               high = new_rd_Cmp(db, blk, lentry->high_word, rentry->high_word,
+               high = new_rd_Cmp(dbg, block, lentry->high_word, rentry->high_word,
                                  relation);
-               res  = new_rd_And(db, blk, low, high, mode_b);
+               res  = new_rd_And(dbg, block, low, high, mode_b);
        } else if (relation == ir_relation_less_greater) {
                /* simple case:a != b <==> a_h != b_h || a_l != b_l */
-               low  = new_rd_Cmp(db, blk, lentry->low_word, rentry->low_word,
+               low  = new_rd_Cmp(dbg, block, lentry->low_word, rentry->low_word,
                                  relation);
-               high = new_rd_Cmp(db, blk, lentry->high_word, rentry->high_word,
+               high = new_rd_Cmp(dbg, block, lentry->high_word, rentry->high_word,
                                  relation);
-               res = new_rd_Or(db, blk, low, high, mode_b);
+               res = new_rd_Or(dbg, block, low, high, mode_b);
        } else {
                /* a rel b <==> a_h REL b_h || (a_h == b_h && a_l rel b_l) */
-               ir_node *high1 = new_rd_Cmp(db, blk, lentry->high_word,
+               ir_node *high1 = new_rd_Cmp(dbg, block, lentry->high_word,
                        rentry->high_word, relation & ~ir_relation_equal);
-               low  = new_rd_Cmp(db, blk, lentry->low_word, rentry->low_word,
+               low  = new_rd_Cmp(dbg, block, lentry->low_word, rentry->low_word,
                                  relation);
-               high = new_rd_Cmp(db, blk, lentry->high_word, rentry->high_word,
+               high = new_rd_Cmp(dbg, block, lentry->high_word, rentry->high_word,
                                  ir_relation_equal);
-               t = new_rd_And(db, blk, low, high, mode_b);
-               res = new_rd_Or(db, blk, high1, t, mode_b);
+               t = new_rd_And(dbg, block, low, high, mode_b);
+               res = new_rd_Or(dbg, block, high1, t, mode_b);
        }
        exchange(cmp, res);
 }
@@ -1391,7 +1430,6 @@ static size_t get_entity_arg_idx(const ir_entity *ent) {
 static ir_type *lower_mtp(lower_env_t *env, ir_type *mtp)
 {
        pmap_entry *entry;
-       ident      *lid;
        ir_type    *res, *value_type;
 
        if (is_lowered_type(mtp))
@@ -1481,7 +1519,6 @@ static ir_type *lower_mtp(lower_env_t *env, ir_type *mtp)
                        /* set new param positions for all entities of the value type */
                        for (i = n_param = 0; i < orig_n_params; ++i) {
                                ir_type   *tp  = get_method_param_type(mtp, i);
-                               ident     *id  = get_method_param_ident(mtp, i);
                                ir_entity *ent = get_method_value_param_ent(mtp, i);
 
                                set_entity_arg_idx(ent, n_param);
@@ -1489,22 +1526,10 @@ static ir_type *lower_mtp(lower_env_t *env, ir_type *mtp)
                                        ir_mode *mode = get_type_mode(tp);
 
                                        if (mode == env->high_signed || mode == env->high_unsigned) {
-                                               if (id != NULL) {
-                                                       lid = id_mangle(id, env->first_id);
-                                                       set_method_param_ident(res, n_param, lid);
-                                                       set_entity_ident(get_method_value_param_ent(res, n_param), lid);
-                                                       lid = id_mangle(id, env->next_id);
-                                                       set_method_param_ident(res, n_param + 1, lid);
-                                                       set_entity_ident(get_method_value_param_ent(res, n_param + 1), lid);
-                                               }
                                                n_param += 2;
                                                continue;
                                        }
                                }
-                               if (id != NULL) {
-                                       set_method_param_ident(res, n_param, id);
-                                       set_entity_ident(get_method_value_param_ent(res, n_param), id);
-                               }
                                ++n_param;
                        }
 
@@ -1668,7 +1693,8 @@ static void lower_Call(ir_node *node, ir_mode *mode, lower_env_t *env)
        ir_node  **in, *proj, *results;
        size_t   n_params, n_res;
        bool     need_lower = false;
-       int      i, j;
+       size_t   i, j;
+       size_t   p;
        long     *res_numbers = NULL;
        (void) mode;
 
@@ -1681,8 +1707,8 @@ static void lower_Call(ir_node *node, ir_mode *mode, lower_env_t *env)
        assert(! is_lowered_type(call_tp));
 
        n_params = get_method_n_params(call_tp);
-       for (i = 0; i < n_params; ++i) {
-               ir_type *tp = get_method_param_type(call_tp, i);
+       for (p = 0; p < n_params; ++p) {
+               ir_type *tp = get_method_param_type(call_tp, p);
 
                if (is_Primitive_type(tp)) {
                        ir_mode *mode = get_type_mode(tp);
@@ -1913,30 +1939,106 @@ static void lower_Mux(ir_node *mux, ir_mode *mode, lower_env_t *env)
  */
 static void lower_ASM(ir_node *asmn, ir_mode *mode, lower_env_t *env)
 {
-       ir_mode *his = env->high_signed;
-       ir_mode *hiu = env->high_unsigned;
+       ir_mode           *high_signed        = env->high_signed;
+       ir_mode           *high_unsigned      = env->high_unsigned;
+       int                n_outs             = get_ASM_n_output_constraints(asmn);
+       ir_asm_constraint *output_constraints = get_ASM_output_constraints(asmn);
+       ir_asm_constraint *input_constraints  = get_ASM_input_constraints(asmn);
+       unsigned           n_64bit_outs       = 0;
        int      i;
        ir_node *n;
 
        (void)mode;
 
        for (i = get_irn_arity(asmn) - 1; i >= 0; --i) {
-               ir_mode *op_mode = get_irn_mode(get_irn_n(asmn, i));
-               if (op_mode == his || op_mode == hiu) {
-                       panic("lowering ASM unimplemented");
+               ir_node *op      = get_irn_n(asmn, i);
+               ir_mode *op_mode = get_irn_mode(op);
+               if (op_mode == high_signed || op_mode == high_unsigned) {
+                       panic("lowering ASM 64bit input unimplemented");
+               }
+       }
+
+       for (i = 0; i < n_outs; ++i) {
+               const ir_asm_constraint *constraint = &output_constraints[i];
+               if (constraint->mode == high_signed || constraint->mode == high_unsigned) {
+                       const char *constr = get_id_str(constraint->constraint);
+                       ++n_64bit_outs;
+                       /* TODO: How to do this architecture neutral? This is very
+                        * i386 specific... */
+                       if (constr[0] != '=' || constr[1] != 'A') {
+                               panic("lowering ASM 64bit output only supports '=A' currently");
+                       }
                }
        }
 
-       for (n = asmn;;) {
-               ir_mode *proj_mode;
+       if (n_64bit_outs == 0)
+               return;
 
-               n = (ir_node*)get_irn_link(n);
-               if (n == NULL)
-                       break;
+       {
+               dbg_info          *dbgi       = get_irn_dbg_info(asmn);
+               ir_node           *block      = get_nodes_block(asmn);
+               int                arity      = get_irn_arity(asmn);
+               ir_node          **in         = get_irn_in(asmn) + 1;
+               int                n_outs     = get_ASM_n_output_constraints(asmn);
+               int                new_n_outs = 0;
+               int                n_clobber  = get_ASM_n_clobbers(asmn);
+               long              *proj_map   = ALLOCAN(long, n_outs);
+               ident            **clobbers   = get_ASM_clobbers(asmn);
+               ident             *asm_text   = get_ASM_text(asmn);
+               ir_asm_constraint *new_outputs
+                       = ALLOCAN(ir_asm_constraint, n_outs+n_64bit_outs);
+               ir_node           *new_asm;
+
+               for (i = 0; i < n_outs; ++i) {
+                       const ir_asm_constraint *constraint = &output_constraints[i];
+                       if (constraint->mode == high_signed || constraint->mode == high_unsigned) {
+                               new_outputs[new_n_outs].pos        = constraint->pos;
+                               new_outputs[new_n_outs].constraint = new_id_from_str("=a");
+                               new_outputs[new_n_outs].mode       = env->low_unsigned;
+                               proj_map[i] = new_n_outs;
+                               ++new_n_outs;
+                               new_outputs[new_n_outs].pos        = constraint->pos;
+                               new_outputs[new_n_outs].constraint = new_id_from_str("=d");
+                               if (constraint->mode == high_signed)
+                                       new_outputs[new_n_outs].mode = env->low_signed;
+                               else
+                                       new_outputs[new_n_outs].mode = env->low_unsigned;
+                               ++new_n_outs;
+                       } else {
+                               new_outputs[new_n_outs] = *constraint;
+                               proj_map[i] = new_n_outs;
+                               ++new_n_outs;
+                       }
+               }
+               assert(new_n_outs == n_outs+(int)n_64bit_outs);
 
-               proj_mode = get_irn_mode(n);
-               if (proj_mode == his || proj_mode == hiu) {
-                       panic("lowering ASM unimplemented");
+               new_asm = new_rd_ASM(dbgi, block, arity, in, input_constraints,
+                                    new_n_outs, new_outputs, n_clobber, clobbers,
+                                    asm_text);
+
+               for (n = asmn;;) {
+                       long pn;
+                       ir_mode *proj_mode;
+                       n = (ir_node*)get_irn_link(n);
+                       if (n == NULL)
+                               break;
+                       proj_mode = get_irn_mode(n);
+                       pn = get_Proj_proj(n);
+                       if (pn < n_outs)
+                               pn = proj_map[pn];
+                       else
+                               pn = new_n_outs + pn - n_outs;
+
+                       if (proj_mode == high_signed || proj_mode == high_unsigned) {
+                               ir_mode *high_mode
+                                       = proj_mode == high_signed ? env->low_signed : env->low_unsigned;
+                               ir_node *np_low  = new_r_Proj(new_asm, env->low_unsigned, pn);
+                               ir_node *np_high = new_r_Proj(new_asm, high_mode, pn+1);
+                               set_lowered(env, n, np_low, np_high);
+                       } else {
+                               ir_node *np = new_r_Proj(new_asm, proj_mode, pn);
+                               exchange(n, np);
+                       }
                }
        }
 }
@@ -2151,10 +2253,12 @@ static void lower_node(lower_env_t *env, ir_node *node)
                lower_node(env, block);
        }
 
-       arity = get_irn_arity(node);
-       for (i = 0; i < arity; ++i) {
-               ir_node *pred = get_irn_n(node, i);
-               lower_node(env, pred);
+       if (!is_Cond(node)) {
+               arity = get_irn_arity(node);
+               for (i = 0; i < arity; ++i) {
+                       ir_node *pred = get_irn_n(node, i);
+                       lower_node(env, pred);
+               }
        }
 
        op   = get_irn_op(node);