fpaStf is now Proj less
[libfirm] / ir / lower / lower_dw.c
index fe50016..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 */
 };
 
 /**
@@ -284,12 +295,7 @@ static void prepare_links(ir_node *node, void *env)
 
                if (mode == lenv->params->high_signed ||
                        mode == lenv->params->high_unsigned) {
-                       /* must lower this node either */
-                       link = obstack_alloc(&lenv->obst, sizeof(*link));
-
-                       memset(link, 0, sizeof(*link));
-
-                       lenv->entries[get_irn_idx(node)] = link;
+                       /* must lower this node either but don't need a link */
                        lenv->flags |= MUST_BE_LOWERED;
                }  /* if */
                return;
@@ -495,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;
@@ -684,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;
@@ -1166,6 +1174,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.
  */
@@ -1297,7 +1341,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;
 
@@ -1309,7 +1353,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);
 
@@ -1487,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;
 
@@ -1525,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;
 
@@ -1565,8 +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 {
-                       assert(mode == env->params->high_unsigned);
+               } else if (mode == env->params->high_unsigned) {
                        lower_Conv_from_Lu(node, env);
                }  /* if */
        }  /* if */
@@ -1669,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) {
@@ -1726,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);
@@ -2021,22 +2076,141 @@ 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) {
+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 */
 
-/** The type of a lower function. */
+/**
+ * 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.
+ *
+ * @param node   the node to be lowered
+ * @param mode   the low mode for the destination node
+ * @param env    the lower environment
+ */
 typedef void (*lower_func)(ir_node *node, ir_mode *mode, lower_env_t *env);
 
 /**
@@ -2047,14 +2221,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;
@@ -2110,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)
@@ -2120,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);
@@ -2190,7 +2394,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);
@@ -2203,6 +2407,7 @@ void lower_dw_ops(const lwrdw_param_t *param)
        LOWER(Call);
        LOWER(Unknown);
        LOWER(Phi);
+       LOWER(Psi);
        LOWER(Start);
 
        LOWER_BIN(Add);
@@ -2212,7 +2417,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);
@@ -2267,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);
@@ -2279,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));