fpaStf is now Proj less
[libfirm] / ir / lower / lower_dw.c
index 88da4d4..25d9d68 100644 (file)
@@ -1,23 +1,33 @@
 /*
- * Project:     libFIRM
- * File name:   ir/lower/lower_dw.c
- * Purpose:     Lower Double word operations, ie Mode L -> I.
- * Author:      Michael Beck
- * Created:            8.10.2004
- * CVS-ID:      $Id$
- * Copyright:   (c) 1998-2006 Universität Karlsruhe
- * Licence:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
+ * Copyright (C) 1995-2007 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief   Lower Double word operations, ie 64bit -> 32bit, 32bit -> 16bit etc.
+ * @date    8.10.2004
+ * @author  Michael Beck
+ * @version $Id$
  */
 #ifdef HAVE_CONFIG_H
 # include "config.h"
 #endif
 
-#ifdef HAVE_MALLOC_H
-# include <malloc.h>
-#endif
-#ifdef HAVE_ALLOCA_H
-# include <alloca.h>
-#endif
 #ifdef HAVE_STRING_H
 # include <string.h>
 #endif
@@ -27,6 +37,7 @@
 
 #include <assert.h>
 
+#include "lowering.h"
 #include "irnode_t.h"
 #include "irgraph_t.h"
 #include "irmode_t.h"
@@ -39,7 +50,6 @@
 #include "firmstat.h"
 #include "irgwalk.h"
 #include "ircons.h"
-#include "lower_dw.h"
 #include "irflag.h"
 #include "irtools.h"
 #include "debug.h"
@@ -47,6 +57,7 @@
 #include "pmap.h"
 #include "pdeq.h"
 #include "irdump.h"
+#include "xmalloc.h"
 
 /** A map from mode to a primitive type. */
 static pmap *prim_types;
@@ -73,7 +84,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 +101,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 */
 };
 
 /**
@@ -312,42 +323,6 @@ static void prepare_links(ir_node *node, void *env)
                                pmap_insert(lenv->proj_2_block, pred, node);
                }  /* for */
        }  /* if */
-
-       /* handle support for Psi nodes */
-       if (mode == mode_b || get_irn_op(node) == op_Psi) {
-               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);
-
-                               if (is_Cmp(cmp)) {
-                                       ir_node *l = get_Cmp_left(cmp);
-                                       mode = get_irn_mode(l);
-
-                                       if (mode == lenv->params->high_signed ||
-                                               mode == lenv->params->high_unsigned) {
-                                               /* ok, found a node that will be lowered */
-                                               ir_node *nproj;
-                                               int rem = get_optimize();
-
-                                               set_optimize(0);
-                                               nproj = new_rd_Proj(
-                                                       get_irn_dbg_info(proj),
-                                                       current_ir_graph,
-                                                       get_nodes_block(proj),
-                                                       cmp,
-                                                       get_irn_mode(proj),
-                                                       get_Proj_proj(proj));
-                                               set_optimize(rem);
-
-                                               set_irn_n(node, i, nproj);
-                                               lenv->flags |= MUST_BE_LOWERED;
-                                       }  /* if */
-                               }  /* if */
-                       }  /* if */
-               }  /* for */
-       }  /* if */
 }  /* prepare_links */
 
 /**
@@ -526,7 +501,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;
@@ -715,7 +690,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;
@@ -1554,6 +1531,12 @@ static void lower_Conv_from_Ls(ir_node *node, lower_env_t *env) {
 
        assert(idx < env->n_entries);
 
+       if (! env->entries[idx]->low_word) {
+               /* not ready yet, wait */
+               pdeq_putr(env->waitq, node);
+               return;
+       }  /* if */
+
        if (mode_is_int(omode) || mode_is_reference(omode)) {
                op = env->entries[idx]->low_word;
 
@@ -1592,6 +1575,12 @@ static void lower_Conv_from_Lu(ir_node *node, lower_env_t *env) {
 
        assert(idx < env->n_entries);
 
+       if (! env->entries[idx]->low_word) {
+               /* not ready yet, wait */
+               pdeq_putr(env->waitq, node);
+               return;
+       }  /* if */
+
        if (mode_is_int(omode) || mode_is_reference(omode)) {
                op = env->entries[idx]->low_word;
 
@@ -1632,7 +1621,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 */
@@ -1735,12 +1724,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) {
@@ -1792,13 +1781,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);
@@ -2142,38 +2131,48 @@ static void lower_Psi(ir_node *psi, ir_mode *mode, lower_env_t *env) {
 }  /* lower_Psi */
 
 /**
- * lower all marked Proj(Cmp)
+ * check for opcodes that must always be lowered.
+ */
+static int always_lower(ir_opcode code) {
+       switch (code) {
+       case iro_Proj:
+       case iro_Start:
+       case iro_Call:
+       case iro_Return:
+       case iro_Cond:
+       case iro_Conv:
+               return 1;
+       default:
+               return 0;
+       }  /* switch */
+}  /* always_lower */
+
+/**
+ * lower boolean Proj(Cmp)
  */
-static void lower_Proj(ir_node *node, ir_mode *mode, lower_env_t *env) {
-       int      idx, lidx, ridx;
-       ir_node  *cmp, *l, *r, *low, *high, *t, *res;
+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;
 
-       idx = get_irn_idx(node);
-       if (env->entries[idx] == NULL)
-               return;
-
-       cmp = get_Proj_pred(node);
-       l = get_Cmp_left(cmp);
+       l    = get_Cmp_left(cmp);
        lidx = get_irn_idx(l);
        if (! env->entries[lidx]->low_word) {
                /* still not ready */
-               pdeq_putr(env->waitq, node);
-               return;
+               return NULL;
        }  /* if */
 
-       r = get_Cmp_right(cmp);
+       r    = get_Cmp_right(cmp);
        ridx = get_irn_idx(r);
        if (! env->entries[ridx]->low_word) {
                /* still not ready */
-               pdeq_putr(env->waitq, node);
-               return;
+               return NULL;
        }  /* if */
 
-       pnc  = get_Proj_proj(node);
+       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);
@@ -2202,25 +2201,8 @@ static void lower_Proj(ir_node *node, ir_mode *mode, lower_env_t *env) {
                        t,
                        mode_b);
        }  /* if */
-       exchange(node, res);
-}  /* lower_Proj */
-
-/**
- * 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:
-               return 1;
-       default:
-               return 0;
-       }  /* switch */
-}  /* always_lower */
+       return res;
+}  /* lower_boolean_Proj_Cmp */
 
 /**
  * The type of a lower function.
@@ -2239,6 +2221,36 @@ 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);
+
+                               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))) {
@@ -2246,7 +2258,7 @@ static void lower_ops(ir_node *node, void *env)
                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;
@@ -2302,7 +2314,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)
@@ -2312,13 +2324,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);
@@ -2405,12 +2417,11 @@ void lower_dw_ops(const lwrdw_param_t *param)
        LOWER(Shr);
        LOWER(Shrs);
        LOWER(Rot);
-       LOWER2(Minus, lower_Minus);
+       LOWER(Minus);
        LOWER(DivMod);
        LOWER(Div);
        LOWER(Mod);
        LOWER_UN(Abs);
-       LOWER2(Proj, lower_Proj);
 
        LOWER(Conv);
 
@@ -2461,8 +2472,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);
@@ -2473,13 +2482,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));