/*
- * 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
#include <assert.h>
+#include "lowering.h"
#include "irnode_t.h"
#include "irgraph_t.h"
#include "irmode_t.h"
#include "firmstat.h"
#include "irgwalk.h"
#include "ircons.h"
-#include "lower_dw.h"
#include "irflag.h"
#include "irtools.h"
#include "debug.h"
#include "pmap.h"
#include "pdeq.h"
#include "irdump.h"
+#include "xmalloc.h"
/** A map from mode to a primitive type. */
static pmap *prim_types;
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;
/**
* 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 */
};
/**
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;
dbg_info *dbg;
int idx;
node_entry_t *entry;
+ (void) node;
+ (void) mode;
irn = get_Store_value(node);
entry = env->entries[get_irn_idx(irn)];
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;
* 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;
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.
*/
ir_node *sel = get_Cond_selector(node);
ir_mode *m = get_irn_mode(sel);
int idx;
+ (void) mode;
if (m == mode_b) {
node_entry_t *lentry, *rentry;
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;
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);
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;
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;
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 */
* 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;
+ (void) mode;
/* check if this return must be lowered */
for (i = 0, n = get_Return_n_ress(node); i < n; ++i) {
* 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;
+ (void) mode;
if (is_lowered_type(tp)) {
mtp = get_associated_type(tp);
int n_params, n_res, need_lower = 0;
int i, j;
long *res_numbers = NULL;
+ (void) mode;
if (is_lowered_type(tp)) {
call_tp = get_associated_type(tp);
} /* 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);
/**
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;
static int cmp_op_mode(const void *elt, const void *key, size_t size) {
const op_mode_entry_t *e1 = elt;
const op_mode_entry_t *e2 = key;
+ (void) size;
return (e1->op - e2->op) | (e1->imode - e2->imode) | (e1->omode - e2->omode);
} /* cmp_op_mode */
static int cmp_conv_tp(const void *elt, const void *key, size_t size) {
const conv_tp_entry_t *e1 = elt;
const conv_tp_entry_t *e2 = key;
+ (void) size;
return (e1->imode - e2->imode) | (e1->omode - e2->omode);
} /* static int cmp_conv_tp */
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)
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);
#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);
LOWER(Call);
LOWER(Unknown);
LOWER(Phi);
+ LOWER(Psi);
LOWER(Start);
LOWER_BIN(Add);
LOWER(Shr);
LOWER(Shrs);
LOWER(Rot);
- LOWER_UN(Minus);
+ LOWER(Minus);
LOWER(DivMod);
LOWER(Div);
LOWER(Mod);
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);
} /* 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;
+ (void) context;
if (imode == omode) {
snprintf(buf, sizeof(buf), "__l%s%s", get_op_name(op), get_mode_name(imode));