fixed doxygen output
[libfirm] / ir / lower / lower_dw.c
index abffdef..5d4a967 100644 (file)
@@ -3,7 +3,7 @@
  * File name:   ir/lower/lower_dw.c
  * Purpose:     Lower Double word operations, ie Mode L -> I.
  * Author:      Michael Beck
- * Created:            8.10.2004
+ * Created:     8.10.2004
  * CVS-ID:      $Id$
  * Copyright:   (c) 1998-2006 Universität Karlsruhe
  * Licence:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
@@ -73,7 +73,7 @@ typedef struct _op_mode_entry {
        const ir_op   *op;    /**< the op */
        const ir_mode *imode; /**< the input mode */
        const ir_mode *omode; /**< the output mode */
-       entity        *ent;   /**< the associated entity of this (op, imode, omode) triple */
+       ir_entity     *ent;   /**< the associated entity of this (op, imode, omode) triple */
 } op_mode_entry_t;
 
 /**
@@ -90,13 +90,13 @@ typedef struct _conv_tp_entry {
  * we need some store to hold the replacement:
  */
 typedef struct _node_entry_t {
-       ir_node *low_word;        /**< the low word */
-       ir_node *high_word;       /**< the high word */
+       ir_node *low_word;    /**< the low word */
+       ir_node *high_word;   /**< the high word */
 } node_entry_t;
 
 enum lower_flags {
-       MUST_BE_LOWERED = 1,   /**< graph must be lowered */
-       CF_CHANGED      = 2,   /**< control flow was changed */
+       MUST_BE_LOWERED = 1,  /**< graph must be lowered */
+       CF_CHANGED      = 2,  /**< control flow was changed */
 };
 
 /**
@@ -490,7 +490,7 @@ static ir_node *get_intrinsic_address(ir_type *method, ir_op *op,
                                       ir_mode *imode, ir_mode *omode,
                                       ir_node *block, lower_env_t *env) {
        symconst_symbol sym;
-       entity *ent;
+       ir_entity *ent;
        op_mode_entry_t key, *entry;
 
        key.op    = op;
@@ -679,7 +679,9 @@ static void lower_Mod(ir_node *node, ir_mode *mode, lower_env_t *env) {
  * Create two intrinsic Calls.
  */
 static void lower_DivMod(ir_node *node, ir_mode *mode, lower_env_t *env) {
-       ir_node  *block, *proj, *irn, *mem, *callDiv, *callMod, *resDiv, *resMod;
+       ir_node  *block, *proj, *irn, *mem, *callDiv, *callMod;
+       ir_node  *resDiv = NULL;
+       ir_node  *resMod = NULL;
        ir_node  *in[4];
        ir_mode  *opmode;
        dbg_info *dbg;
@@ -1161,6 +1163,42 @@ static void lower_Not(ir_node *node, ir_mode *mode, lower_env_t *env) {
        env->entries[idx]->high_word = new_rd_Not(dbg, current_ir_graph, block, op_h, mode);
 }  /* lower_Not */
 
+/**
+ * Translate a Minus.
+ *
+ * Create two Minus'.
+ */
+static void lower_Minus(ir_node *node, ir_mode *mode, lower_env_t *env) {
+       ir_node  *block, *irn;
+       ir_node  *op_l, *op_h;
+       dbg_info *dbg;
+       int      idx;
+       ir_graph *irg;
+       node_entry_t *entry;
+
+       irn   = get_Minus_op(node);
+       entry = env->entries[get_irn_idx(irn)];
+       assert(entry);
+
+       if (! entry->low_word) {
+               /* not ready yet, wait */
+               pdeq_putr(env->waitq, node);
+               return;
+       }  /* if */
+
+       op_l = entry->low_word;
+       op_h = entry->high_word;
+
+       dbg   = get_irn_dbg_info(node);
+       block = get_nodes_block(node);
+       irg   = current_ir_graph;
+
+       idx = get_irn_idx(node);
+       assert(idx < env->n_entries);
+       env->entries[idx]->low_word  = new_rd_Minus(dbg, current_ir_graph, block, op_l, mode);
+       env->entries[idx]->high_word = new_rd_Minus(dbg, current_ir_graph, block, op_h, mode);
+}  /* lower_Minus */
+
 /**
  * Translate a Cond.
  */
@@ -1292,7 +1330,7 @@ static void lower_Cond(ir_node *node, ir_mode *mode, lower_env_t *env) {
                        mark_irn_visited(proj);
                        exchange(projF, proj);
                } else {
-                       /* a rel b <==> a_h rel b_h || (a_h == b_h && a_l rel b_l) */
+                       /* a rel b <==> a_h REL b_h || (a_h == b_h && a_l rel b_l) */
                        ir_node *dstT, *dstF, *newbl_eq, *newbl_l;
                        pmap_entry *entry;
 
@@ -1304,7 +1342,7 @@ static void lower_Cond(ir_node *node, ir_mode *mode, lower_env_t *env) {
                        assert(entry);
                        dstF = entry->value;
 
-                       irn = new_r_Proj(irg, block, cmpH, mode_b, pnc);
+                       irn = new_r_Proj(irg, block, cmpH, mode_b, pnc & ~pn_Cmp_Eq);
                        dbg = get_irn_dbg_info(node);
                        irn = new_rd_Cond(dbg, irg, block, irn);
 
@@ -1560,7 +1598,7 @@ static void lower_Conv(ir_node *node, ir_mode *mode, lower_env_t *env) {
 
                if (mode == env->params->high_signed) {
                        lower_Conv_from_Ls(node, env);
-        } else if (mode == env->params->high_unsigned) {
+               } else if (mode == env->params->high_unsigned) {
                        lower_Conv_from_Lu(node, env);
                }  /* if */
        }  /* if */
@@ -1663,12 +1701,12 @@ static ir_type *lower_mtp(ir_type *mtp, lower_env_t *env) {
  * Translate a Return.
  */
 static void lower_Return(ir_node *node, ir_mode *mode, lower_env_t *env) {
-       ir_graph *irg = current_ir_graph;
-       entity   *ent = get_irg_entity(irg);
-       ir_type  *mtp = get_entity_type(ent);
-       ir_node  **in;
-       int      i, j, n, idx;
-       int      need_conv = 0;
+       ir_graph  *irg = current_ir_graph;
+       ir_entity *ent = get_irg_entity(irg);
+       ir_type   *mtp = get_entity_type(ent);
+       ir_node   **in;
+       int       i, j, n, idx;
+       int       need_conv = 0;
 
        /* check if this return must be lowered */
        for (i = 0, n = get_Return_n_ress(node); i < n; ++i) {
@@ -1720,13 +1758,13 @@ static void lower_Return(ir_node *node, ir_mode *mode, lower_env_t *env) {
  * Translate the parameters.
  */
 static void lower_Start(ir_node *node, ir_mode *mode, lower_env_t *env) {
-       ir_graph *irg = current_ir_graph;
-       entity   *ent = get_irg_entity(irg);
-       ir_type  *tp  = get_entity_type(ent);
-       ir_type  *mtp;
-       long     *new_projs;
-       int      i, j, n_params, rem;
-       ir_node  *proj, *args;
+       ir_graph  *irg = current_ir_graph;
+       ir_entity *ent = get_irg_entity(irg);
+       ir_type   *tp  = get_entity_type(ent);
+       ir_type   *mtp;
+       long      *new_projs;
+       int       i, j, n_params, rem;
+       ir_node   *proj, *args;
 
        if (is_lowered_type(tp)) {
                mtp = get_associated_type(tp);
@@ -2015,22 +2053,134 @@ static void lower_Phi(ir_node *phi, ir_mode *mode, lower_env_t *env) {
        }  /* if */
 }  /* lower_Phi */
 
+/**
+ * Translate a Psi.
+ */
+static void lower_Psi(ir_node *psi, ir_mode *mode, lower_env_t *env) {
+       ir_graph *irg = current_ir_graph;
+       ir_node  *block, *val;
+       ir_node  **valsl, **valsh, **conds;
+       dbg_info *dbg;
+       int      idx, i, n_conds = get_Psi_n_conds(psi);
+
+       /* first create a new in array */
+       NEW_ARR_A(ir_node *, valsl, n_conds + 1);
+       NEW_ARR_A(ir_node *, valsh, n_conds + 1);
+
+       for (i = 0; i < n_conds; ++i) {
+               val = get_Psi_val(psi, i);
+               idx = get_irn_idx(val);
+               if (env->entries[idx]->low_word) {
+                       /* Values already build */
+                       valsl[i] = env->entries[idx]->low_word;
+                       valsh[i] = env->entries[idx]->high_word;
+               } else {
+                       /* still not ready */
+                       pdeq_putr(env->waitq, psi);
+                       return;
+               }  /* if */
+       }  /* for */
+       val = get_Psi_default(psi);
+       idx = get_irn_idx(val);
+       if (env->entries[idx]->low_word) {
+               /* Values already build */
+               valsl[i] = env->entries[idx]->low_word;
+               valsh[i] = env->entries[idx]->high_word;
+       } else {
+               /* still not ready */
+               pdeq_putr(env->waitq, psi);
+               return;
+       }  /* if */
+
+
+       NEW_ARR_A(ir_node *, conds, n_conds);
+       for (i = 0; i < n_conds; ++i) {
+               conds[i] = get_Psi_cond(psi, i);
+       }  /* for */
+
+       dbg   = get_irn_dbg_info(psi);
+       block = get_nodes_block(psi);
+
+       idx = get_irn_idx(psi);
+       assert(idx < env->n_entries);
+       env->entries[idx]->low_word  = new_rd_Psi(dbg, irg, block, n_conds, conds, valsl, mode);
+       env->entries[idx]->high_word = new_rd_Psi(dbg, irg, block, n_conds, conds, valsh, mode);
+}  /* lower_Psi */
+
 /**
  * check for opcodes that must always be lowered.
  */
 static int always_lower(opcode code) {
        switch (code) {
+       case iro_Proj:
        case iro_Start:
        case iro_Call:
        case iro_Return:
        case iro_Cond:
-    case iro_Conv:
+       case iro_Conv:
                return 1;
        default:
                return 0;
        }  /* switch */
 }  /* always_lower */
 
+/**
+ * lower boolean Proj(Cmp)
+ */
+static ir_node *lower_boolean_Proj_Cmp(ir_node *proj, ir_node *cmp, lower_env_t *env) {
+       int      lidx, ridx;
+       ir_node  *l, *r, *low, *high, *t, *res;
+       pn_Cmp   pnc;
+       ir_node  *blk;
+       ir_graph *irg = current_ir_graph;
+       dbg_info *db;
+
+       l    = get_Cmp_left(cmp);
+       lidx = get_irn_idx(l);
+       if (! env->entries[lidx]->low_word) {
+               /* still not ready */
+               return NULL;
+       }  /* if */
+
+       r    = get_Cmp_right(cmp);
+       ridx = get_irn_idx(r);
+       if (! env->entries[ridx]->low_word) {
+               /* still not ready */
+               return NULL;
+       }  /* if */
+
+       pnc  = get_Proj_proj(proj);
+       blk  = get_nodes_block(cmp);
+       db   = get_irn_dbg_info(cmp);
+       low  = new_rd_Cmp(db, irg, blk, env->entries[lidx]->low_word, env->entries[ridx]->low_word);
+       high = new_rd_Cmp(db, irg, blk, env->entries[lidx]->high_word, env->entries[ridx]->high_word);
+
+       if (pnc == pn_Cmp_Eq) {
+               /* simple case:a == b <==> a_h == b_h && a_l == b_l */
+               res = new_rd_And(db, irg, blk,
+                       new_r_Proj(irg, blk, low, mode_b, pnc),
+                       new_r_Proj(irg, blk, high, mode_b, pnc),
+                       mode_b);
+       } else if (pnc == pn_Cmp_Lg) {
+               /* simple case:a != b <==> a_h != b_h || a_l != b_l */
+               res = new_rd_Or(db, irg, blk,
+                       new_r_Proj(irg, blk, low, mode_b, pnc),
+                       new_r_Proj(irg, blk, high, mode_b, pnc),
+                       mode_b);
+       } else {
+               /* a rel b <==> a_h REL b_h || (a_h == b_h && a_l rel b_l) */
+               t = new_rd_And(db, irg, blk,
+                       new_r_Proj(irg, blk, low, mode_b, pnc),
+                       new_r_Proj(irg, blk, high, mode_b, pn_Cmp_Eq),
+                       mode_b);
+               res = new_rd_Or(db, irg, blk,
+                       new_r_Proj(irg, blk, high, mode_b, pnc & ~pn_Cmp_Eq),
+                       t,
+                       mode_b);
+       }  /* if */
+       return res;
+}  /* lower_boolean_Proj_Cmp */
+
 /**
  * The type of a lower function.
  *
@@ -2048,14 +2198,44 @@ static void lower_ops(ir_node *node, void *env)
        lower_env_t  *lenv = env;
        node_entry_t *entry;
        int          idx = get_irn_idx(node);
+       ir_mode      *mode = get_irn_mode(node);
+
+       if (mode == mode_b || get_irn_op(node) == op_Psi) {
+               int i;
+
+               for (i = get_irn_arity(node) - 1; i >= 0; --i) {
+                       ir_node *proj = get_irn_n(node, i);
+
+                       if (is_Proj(proj)) {
+                               ir_node *cmp = get_Proj_pred(proj);
 
-       entry = lenv->entries[idx];
+                               if (is_Cmp(cmp)) {
+                                       ir_node *arg = get_Cmp_left(cmp);
+
+                                       mode = get_irn_mode(arg);
+                                       if (mode == lenv->params->high_signed ||
+                                               mode == lenv->params->high_unsigned) {
+                                               ir_node *res = lower_boolean_Proj_Cmp(proj, cmp, lenv);
+
+                                               if (res == NULL) {
+                                                       /* could not lower because predecessors not ready */
+                                                       waitq_put(lenv->waitq, node);
+                                                       return;
+                                               }  /* if */
+                                               set_irn_n(node, i, res);
+                                       }  /* if */
+                               }  /* if */
+                       }  /* if */
+               }  /* for */
+       }  /* if */
+
+       entry = idx < lenv->n_entries ? lenv->entries[idx] : NULL;
        if (entry || always_lower(get_irn_opcode(node))) {
                ir_op      *op = get_irn_op(node);
                lower_func func = (lower_func)op->ops.generic;
 
                if (func) {
-                       ir_mode *mode = get_irn_op_mode(node);
+                       mode = get_irn_op_mode(node);
 
                        if (mode == lenv->params->high_signed)
                                mode = lenv->params->low_signed;
@@ -2111,7 +2291,7 @@ void lower_dw_ops(const lwrdw_param_t *param)
        assert(2 * get_mode_size_bits(param->low_unsigned) == get_mode_size_bits(param->high_unsigned));
        assert(get_mode_size_bits(param->low_signed) == get_mode_size_bits(param->low_unsigned));
 
-    /* create the necessary maps */
+       /* create the necessary maps */
        if (! prim_types)
                prim_types = pmap_create();
        if (! intrinsic_fkt)
@@ -2121,13 +2301,13 @@ void lower_dw_ops(const lwrdw_param_t *param)
        if (! lowered_type)
                lowered_type = pmap_create();
 
-    /* create a primitive unsigned and signed type */
+       /* create a primitive unsigned and signed type */
        if (! tp_u)
                tp_u = get_primitive_type(param->low_unsigned);
        if (! tp_s)
                tp_s = get_primitive_type(param->low_signed);
 
-    /* create method types for the created binop calls */
+       /* create method types for the created binop calls */
        if (! binop_tp_u) {
                binop_tp_u = new_type_method(IDENT("binop_u_intrinsic"), 4, 2);
                set_method_param_type(binop_tp_u, 0, tp_u);
@@ -2191,7 +2371,7 @@ void lower_dw_ops(const lwrdw_param_t *param)
 #define LOWER_BIN(op)     LOWER2(op, lower_Binop)
 #define LOWER_UN(op)      LOWER2(op, lower_Unop)
 
-    /* the table of all operations that must be lowered follows */
+       /* the table of all operations that must be lowered follows */
        LOWER(Load);
        LOWER(Store);
        LOWER(Const);
@@ -2204,6 +2384,7 @@ void lower_dw_ops(const lwrdw_param_t *param)
        LOWER(Call);
        LOWER(Unknown);
        LOWER(Phi);
+       LOWER(Psi);
        LOWER(Start);
 
        LOWER_BIN(Add);
@@ -2213,7 +2394,7 @@ void lower_dw_ops(const lwrdw_param_t *param)
        LOWER(Shr);
        LOWER(Shrs);
        LOWER(Rot);
-       LOWER_UN(Minus);
+       LOWER(Minus);
        LOWER(DivMod);
        LOWER(Div);
        LOWER(Mod);
@@ -2268,8 +2449,6 @@ void lower_dw_ops(const lwrdw_param_t *param)
                                set_irg_extblk_inconsistent(irg);
                                set_irg_loopinfo_inconsistent(irg);
                        }  /* if */
-
-                       dump_ir_block_graph(irg, "-dw");
                }  /* if */
                pmap_destroy(lenv.proj_2_block);
                free(lenv.entries);
@@ -2280,13 +2459,13 @@ void lower_dw_ops(const lwrdw_param_t *param)
 }  /* lower_dw_ops */
 
 /* Default implementation. */
-entity *def_create_intrinsic_fkt(ir_type *method, const ir_op *op,
-                                 const ir_mode *imode, const ir_mode *omode,
-                                 void *context)
+ir_entity *def_create_intrinsic_fkt(ir_type *method, const ir_op *op,
+                                    const ir_mode *imode, const ir_mode *omode,
+                                    void *context)
 {
        char buf[64];
        ident *id;
-       entity *ent;
+       ir_entity *ent;
 
        if (imode == omode) {
                snprintf(buf, sizeof(buf), "__l%s%s", get_op_name(op), get_mode_name(imode));