* Modified by: Goetz Lindenmaier
* Created:
* CVS-ID: $Id$
- * Copyright: (c) 1998-2003 Universität Karlsruhe
+ * Copyright: (c) 1998-2005 Universität Karlsruhe
* Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
*/
#ifdef HAVE_CONFIG_H
-# include <config.h>
+# include "config.h"
+#endif
+
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
#endif
# include "irnode_t.h"
# include "irgraph_t.h"
+# include "iredges_t.h"
# include "irmode_t.h"
# include "iropt_t.h"
# include "ircons_t.h"
# include "dbginfo_t.h"
# include "iropt_dbg.h"
# include "irflag_t.h"
-# include "firmstat.h"
+# include "irhooks.h"
# include "irarch.h"
+# include "hashptr.h"
+# include "archop.h"
+# include "opt_polymorphy.h"
/* Make types visible to allow most efficient access */
# include "entity_t.h"
*/
static tarval *computed_value_Const(ir_node *n)
{
- return get_Const_tarval(n);
+ return get_Const_tarval(n);
}
/**
tarval *ta = value_of(a);
tarval *tb = value_of(b);
- if ((ta != tarval_bad) && (tb != tarval_bad)
- && (get_irn_mode(a) == get_irn_mode(b))
- && !(get_mode_sort(get_irn_mode(a)) == irms_reference)) {
+ if ((ta != tarval_bad) && (tb != tarval_bad) && (get_irn_mode(a) == get_irn_mode(b)))
return tarval_add(ta, tb);
- }
+
return tarval_bad;
}
tarval *tb;
/* a - a */
- if (a == b)
+ if (a == b && !is_Bad(a))
return get_tarval_null(get_irn_mode(n));
ta = value_of(a);
tb = value_of(b);
- if ((ta != tarval_bad) && (tb != tarval_bad)
- && (get_irn_mode(a) == get_irn_mode(b))
- && !(get_mode_sort(get_irn_mode(a)) == irms_reference)) {
+ if ((ta != tarval_bad) && (tb != tarval_bad) && (get_irn_mode(a) == get_irn_mode(b)))
return tarval_sub(ta, tb);
- }
+
return tarval_bad;
}
/* a*0 = 0 or 0*b = 0:
calls computed_value recursive and returns the 0 with proper
mode. */
- tarval *v;
-
- if ( ( ((v = ta) != tarval_bad)
- && (v == get_mode_null(get_tarval_mode(v))) )
- || ( ((v = tb) != tarval_bad)
- && (v == get_mode_null(get_tarval_mode(v))) )) {
- return v;
- }
+ if ((ta != tarval_bad) && (ta == get_mode_null(get_tarval_mode(ta))))
+ return ta;
+ if ((tb != tarval_bad) && (tb == get_mode_null(get_tarval_mode(tb))))
+ return tb;
}
return tarval_bad;
}
tarval *tb = value_of(b);
/* Compute c1 / c2 or 0 / a, a != 0 */
- if ((ta != tarval_bad) && (tb != get_mode_null(get_irn_mode(b)))) {
- if (tb != tarval_bad) /* div by zero: return tarval_bad */
+ if (ta != tarval_bad) {
+ if ((tb != tarval_bad) && (tb != get_mode_null(get_irn_mode(b)))) /* div by zero: return tarval_bad */
return tarval_div(ta, tb);
else if (ta == get_mode_null(get_tarval_mode(ta))) /* 0 / b == 0 */
return ta;
} else {
tarval *v;
- if ( (classify_tarval ((v = computed_value (a))) == TV_CLASSIFY_NULL)
- || (classify_tarval ((v = computed_value (b))) == TV_CLASSIFY_NULL)) {
+ if ( (classify_tarval ((v = ta)) == TV_CLASSIFY_NULL)
+ || (classify_tarval ((v = tb)) == TV_CLASSIFY_NULL)) {
return v;
}
}
return tarval_or (ta, tb);
} else {
tarval *v;
- if ( (classify_tarval ((v = computed_value (a))) == TV_CLASSIFY_ALL_ONE)
- || (classify_tarval ((v = computed_value (b))) == TV_CLASSIFY_ALL_ONE)) {
+ if ( (classify_tarval ((v = ta)) == TV_CLASSIFY_ALL_ONE)
+ || (classify_tarval ((v = tb)) == TV_CLASSIFY_ALL_ONE)) {
return v;
}
}
ir_node *a = get_Eor_left(n);
ir_node *b = get_Eor_right(n);
- tarval *ta = value_of(a);
- tarval *tb = value_of(b);
+ tarval *ta, *tb;
+
+ if (a == b)
+ return get_tarval_null(get_irn_mode(n));
+
+ ta = value_of(a);
+ tb = value_of(b);
if ((ta != tarval_bad) && (tb != tarval_bad)) {
return tarval_eor (ta, tb);
ab = get_Cmp_right(a);
proj_nr = get_Proj_proj(n);
- if (aa == ab) { /* 1.: */
+ if (aa == ab && (
+ !mode_is_float(get_irn_mode(aa)) || proj_nr == pn_Cmp_Lt || proj_nr == pn_Cmp_Gt)
+ ) { /* 1.: */
+ /* BEWARE: a == a is NOT always True for floating Point!!! */
/* This is a trick with the bits used for encoding the Cmp
Proj numbers, the following statement is not the same:
- return new_tarval_from_long (proj_nr == Eq, mode_b) */
- return new_tarval_from_long (proj_nr & Eq, mode_b);
+ return new_tarval_from_long (proj_nr == pn_Cmp_Eq, mode_b) */
+ return new_tarval_from_long (proj_nr & pn_Cmp_Eq, mode_b);
} else {
- tarval *taa = computed_value (aa);
- tarval *tab = computed_value (ab);
+ tarval *taa = value_of(aa);
+ tarval *tab = value_of(ab);
if ((taa != tarval_bad) && (tab != tarval_bad)) { /* 2.: */
/* strange checks... */
- pnc_number flags = tarval_cmp (taa, tab);
- if (flags != False) {
+ pn_Cmp flags = tarval_cmp (taa, tab);
+ if (flags != pn_Cmp_False) {
return new_tarval_from_long (proj_nr & flags, mode_b);
}
} else { /* check for 3.: */
&& (mode_is_reference(get_irn_mode(ab)))
&& (get_irn_op(aba) == op_Alloc)))
/* 3.: */
- return new_tarval_from_long (proj_nr & Ne, mode_b);
+ return new_tarval_from_long (proj_nr & pn_Cmp_Ne, mode_b);
}
}
break;
return tarval_bad;
}
+/**
+ * calculate the value of a Mux: can be evaluated, if the
+ * sel and the right input are known
+ */
+static tarval *computed_value_Mux(ir_node *n)
+{
+ ir_node *sel = get_Mux_sel(n);
+ tarval *ts = value_of(sel);
+
+ if (ts == get_tarval_b_true()) {
+ ir_node *v = get_Mux_true(n);
+ return value_of(v);
+ }
+ else if (ts == get_tarval_b_false()) {
+ ir_node *v = get_Mux_false(n);
+ return value_of(v);
+ }
+ return tarval_bad;
+}
+
/**
* If the parameter n can be computed, return its value, else tarval_bad.
* Performs constant folding.
CASE(Rot);
CASE(Conv);
CASE(Proj);
+ CASE(Mux);
default:
op->computed_value = NULL;
}
}
#endif
+/**
+ * Returns a equivalent block for another block.
+ * If the block has only one predecessor, this is
+ * the equivalent one. If the only predecessor of a block is
+ * the block itself, this is a dead block.
+ *
+ * If both predecessors of a block are the branches of a binary
+ * Cond, the equivalent block is Cond's block.
+ *
+ * If all predecessors of a block are bad or lies in a dead
+ * block, the current block is dead as well.
+ *
+ * Note, that blocks are NEVER turned into Bad's, instead
+ * the dead_block flag is set. So, never test for is_Bad(block),
+ * always use is_dead_Block(block).
+ */
static ir_node *equivalent_node_Block(ir_node *n)
{
ir_node *oldn = n;
+ int n_preds = get_Block_n_cfgpreds(n);
/* The Block constructor does not call optimize, but mature_immBlock
calls the optimization. */
This should be true, as the block is matured before optimize is called.
But what about Phi-cycles with the Phi0/Id that could not be resolved?
Remaining Phi nodes are just Ids. */
- if ((get_Block_n_cfgpreds(n) == 1) &&
- (get_irn_op(get_Block_cfgpred(n, 0)) == op_Jmp)) {
+ if ((n_preds == 1) && (get_irn_op(get_Block_cfgpred(n, 0)) == op_Jmp)) {
ir_node *predblock = get_nodes_block(get_Block_cfgpred(n, 0));
if (predblock == oldn) {
/* Jmp jumps into the block it is in -- deal self cycle. */
- n = new_Bad();
+ n = set_Block_dead(n);
DBG_OPT_DEAD(oldn, n);
} else if (get_opt_control_flow_straightening()) {
n = predblock;
DBG_OPT_STG(oldn, n);
}
}
- else if ((get_Block_n_cfgpreds(n) == 1) &&
+ else if ((n_preds == 1) &&
(get_irn_op(skip_Proj(get_Block_cfgpred(n, 0))) == op_Cond)) {
ir_node *predblock = get_nodes_block(get_Block_cfgpred(n, 0));
if (predblock == oldn) {
/* Jmp jumps into the block it is in -- deal self cycle. */
- n = new_Bad();
+ n = set_Block_dead(n);
DBG_OPT_DEAD(oldn, n);
}
}
- else if ((get_Block_n_cfgpreds(n) == 2) &&
+ else if ((n_preds == 2) &&
(get_opt_control_flow_weak_simplification())) {
/* Test whether Cond jumps twice to this block
@@@ we could do this also with two loops finding two preds from several ones. */
} else if (get_opt_unreachable_code() &&
(n != current_ir_graph->start_block) &&
(n != current_ir_graph->end_block) ) {
- int i;
+ int i, n_cfg = get_Block_n_cfgpreds(n);
+
/* If all inputs are dead, this block is dead too, except if it is
the start or end block. This is a step of unreachable code
elimination */
- for (i = 0; i < get_Block_n_cfgpreds(n); i++) {
- if (!is_Bad(get_Block_cfgpred(n, i))) break;
+ for (i = 0; i < n_cfg; i++) {
+ ir_node *pred = get_Block_cfgpred(n, i);
+ ir_node *pred_blk;
+
+ if (is_Bad(pred)) continue;
+ pred_blk = get_nodes_block(pred);
+
+ if (is_Block_dead(pred_blk)) continue;
+
+ if (pred_blk != n) {
+ /* really found a living input */
+ break;
+ }
}
- if (i == get_Block_n_cfgpreds(n))
- n = new_Bad();
+ if (i == n_cfg)
+ n = set_Block_dead(n);
}
return n;
{
/* GL: Why not same for op_Raise?? */
/* unreachable code elimination */
- if (is_Bad(get_nodes_block(n)))
+ if (is_Block_dead(get_nodes_block(n)))
n = new_Bad();
return n;
return n;
}
-/**
- * Use algebraic simplification a v a = a.
- */
-static ir_node *equivalent_node_Or(ir_node *n)
-{
- ir_node *oldn = n;
-
- ir_node *a = get_Or_left(n);
- ir_node *b = get_Or_right(n);
-
- /* remove a v a */
- if (a == b) {
- n = a;
-
- DBG_OPT_ALGSIM1(oldn, a, b, n);
- }
-
- return n;
-}
-
/**
* optimize operations that are commutative and have neutral 0,
* so a op 0 = 0 op a = a.
/* After running compute_node there is only one constant predecessor.
Find this predecessors value and remember the other node: */
- if ((tv = computed_value(a)) != tarval_bad) {
+ if ((tv = value_of(a)) != tarval_bad) {
on = b;
- } else if ((tv = computed_value(b)) != tarval_bad) {
+ } else if ((tv = value_of(b)) != tarval_bad) {
on = a;
} else
return n;
ir_node *a = get_binop_left(n);
ir_node *b = get_binop_right(n);
- if (classify_tarval(computed_value(b)) == TV_CLASSIFY_NULL) {
+ if (classify_tarval(value_of(b)) == TV_CLASSIFY_NULL) {
n = a;
DBG_OPT_ALGSIM1(oldn, a, b, n);
/**
* Er, a "symmetic unop", ie op(op(n)) = n.
+ *
+ * @fixme -(-a) == a, but might overflow two times.
+ * We handle it anyway here but the better way would be a
+ * flag. This would be needed for Pascal for instance.
*/
static ir_node *equivalent_node_symmetric_unop(ir_node *n)
{
ir_node *b = get_Mul_right(n);
/* Mul is commutative and has again an other neutral element. */
- if (classify_tarval (computed_value (a)) == TV_CLASSIFY_ONE) {
+ if (classify_tarval(value_of(a)) == TV_CLASSIFY_ONE) {
n = b;
DBG_OPT_ALGSIM1(oldn, a, b, n);
- } else if (classify_tarval (computed_value (b)) == TV_CLASSIFY_ONE) {
+ } else if (classify_tarval(value_of(b)) == TV_CLASSIFY_ONE) {
n = a;
DBG_OPT_ALGSIM1(oldn, a, b, n);
}
ir_node *b = get_Div_right(n);
/* Div is not commutative. */
- if (classify_tarval(computed_value(b)) == TV_CLASSIFY_ONE) { /* div(x, 1) == x */
+ if (classify_tarval(value_of(b)) == TV_CLASSIFY_ONE) { /* div(x, 1) == x */
/* Turn Div into a tuple (mem, bad, a) */
ir_node *mem = get_Div_mem(n);
turn_into_tuple(n, 3);
ir_node *b = get_DivMod_right(n);
/* Div is not commutative. */
- if (classify_tarval(computed_value(b)) == TV_CLASSIFY_ONE) { /* div(x, 1) == x */
+ if (classify_tarval(value_of(b)) == TV_CLASSIFY_ONE) { /* div(x, 1) == x */
/* Turn DivMod into a tuple (mem, bad, a, 0) */
ir_node *mem = get_Div_mem(n);
ir_mode *mode = get_irn_mode(b);
return n;
}
+/**
+ * Use algebraic simplification a | a = a | 0 = 0 | a = a.
+ */
+static ir_node *equivalent_node_Or(ir_node *n)
+{
+ ir_node *oldn = n;
+
+ ir_node *a = get_Or_left(n);
+ ir_node *b = get_Or_right(n);
+
+ if (a == b) {
+ n = a; /* Or has it's own neutral element */
+ } else if (classify_tarval(value_of(a)) == TV_CLASSIFY_NULL) {
+ n = b;
+ DBG_OPT_ALGSIM1(oldn, a, b, n);
+ } else if (classify_tarval(value_of(b)) == TV_CLASSIFY_NULL) {
+ n = a;
+ DBG_OPT_ALGSIM1(oldn, a, b, n);
+ }
+
+ return n;
+}
+
/**
* Optimize a & 0b1...1 = 0b1...1 & a = a & a = a.
*/
if (a == b) {
n = a; /* And has it's own neutral element */
- } else if (classify_tarval(computed_value(a)) == TV_CLASSIFY_ALL_ONE) {
+ } else if (classify_tarval(value_of(a)) == TV_CLASSIFY_ALL_ONE) {
n = b;
DBG_OPT_ALGSIM1(oldn, a, b, n);
- } else if (classify_tarval(computed_value(b)) == TV_CLASSIFY_ALL_ONE) {
+ } else if (classify_tarval(value_of(b)) == TV_CLASSIFY_ALL_ONE) {
n = a;
DBG_OPT_ALGSIM1(oldn, a, b, n);
}
if (n_mode == b_mode) {
if (n_mode == mode_b) {
n = b; /* Convb(Conv*(xxxb(...))) == xxxb(...) */
- DBG_OPT_ALGSIM1(oldn, a, b, n);
+ DBG_OPT_ALGSIM1(oldn, a, b, n);
}
else if (mode_is_int(n_mode) || mode_is_character(n_mode)) {
if (smaller_mode(b_mode, a_mode)){
n = b; /* ConvS(ConvL(xxxS(...))) == xxxS(...) */
- DBG_OPT_ALGSIM1(oldn, a, b, n);
+ DBG_OPT_ALGSIM1(oldn, a, b, n);
}
}
}
return n;
}
+/**
+ * A Cast may be removed if the type of the previous node
+ * is already the type of the Cast.
+ */
+static ir_node *equivalent_node_Cast(ir_node *n) {
+ ir_node *pred = get_Cast_op(n);
+ if (get_irn_type(pred) == get_Cast_type(n))
+ n = pred;
+ return n;
+}
+
+/* Several optimizations:
+ - no Phi in start block.
+ - remove Id operators that are inputs to Phi
+ - fold Phi-nodes, iff they have only one predecessor except
+ themselves.
+*/
static ir_node *equivalent_node_Phi(ir_node *n)
{
- /* Several optimizations:
- - no Phi in start block.
- - remove Id operators that are inputs to Phi
- - fold Phi-nodes, iff they have only one predecessor except
- themselves.
- */
int i, n_preds;
ir_node *oldn = n;
block = get_nodes_block(n);
/* @@@ fliegt 'raus, sollte aber doch immer wahr sein!!!
assert(get_irn_arity(block) == n_preds && "phi in wrong block!"); */
- if ((is_Bad(block)) || /* Control dead */
+ if ((is_Block_dead(block)) || /* Control dead */
(block == current_ir_graph->start_block)) /* There should be no Phi nodes */
return new_Bad(); /* in the Start Block. */
n = new_Bad();
}
} else if (get_irn_mode(n) == mode_X &&
- is_Bad(get_nodes_block(n))) {
+ is_Block_dead(get_nodes_block(n))) {
/* Remove dead control flow -- early gigo. */
n = new_Bad();
}
return n;
}
+/**
+ * optimize a Mux
+ */
+static ir_node *equivalent_node_Mux(ir_node *n)
+{
+ ir_node *oldn = n, *sel = get_Mux_sel(n);
+ tarval *ts = value_of(sel);
+
+ /* Mux(true, f, t) == t */
+ if (ts == get_tarval_b_true()) {
+ n = get_Mux_true(n);
+ DBG_OPT_ALGSIM0(oldn, n);
+ }
+ /* Mux(false, f, t) == f */
+ else if (ts == get_tarval_b_false()) {
+ n = get_Mux_false(n);
+ DBG_OPT_ALGSIM0(oldn, n);
+ }
+ /* Mux(v, x, x) == x */
+ else if (get_Mux_false(n) == get_Mux_true(n)) {
+ n = get_Mux_true(n);
+ DBG_OPT_ALGSIM0(oldn, n);
+ }
+ else if (get_irn_op(sel) == op_Proj && !mode_honor_signed_zeros(get_irn_mode(n))) {
+ ir_node *cmp = get_Proj_pred(sel);
+ long proj_nr = get_Proj_proj(sel);
+ ir_node *b = get_Mux_false(n);
+ ir_node *a = get_Mux_true(n);
+
+ /*
+ * Note: normalization puts the constant on the right site,
+ * so we check only one case.
+ *
+ * Note further that these optimization work even for floating point
+ * with NaN's because -NaN == NaN.
+ * However, if +0 and -0 is handled differently, we cannot use the first one.
+ */
+ if (get_irn_op(cmp) == op_Cmp && get_Cmp_left(cmp) == a) {
+ if (classify_Const(get_Cmp_right(cmp)) == CNST_NULL) {
+ /* Mux(a CMP 0, X, a) */
+ if (get_irn_op(b) == op_Minus && get_Minus_op(b) == a) {
+ /* Mux(a CMP 0, -a, a) */
+ if (proj_nr == pn_Cmp_Eq) {
+ /* Mux(a == 0, -a, a) ==> -a */
+ n = b;
+ DBG_OPT_ALGSIM0(oldn, n);
+ }
+ else if (proj_nr == pn_Cmp_Lg || proj_nr == pn_Cmp_Ne) {
+ /* Mux(a != 0, -a, a) ==> a */
+ n = a;
+ DBG_OPT_ALGSIM0(oldn, n);
+ }
+ }
+ else if (classify_Const(b) == CNST_NULL) {
+ /* Mux(a CMP 0, 0, a) */
+ if (proj_nr == pn_Cmp_Lg || proj_nr == pn_Cmp_Ne) {
+ /* Mux(a != 0, 0, a) ==> a */
+ n = a;
+ DBG_OPT_ALGSIM0(oldn, n);
+ }
+ else if (proj_nr == pn_Cmp_Eq) {
+ /* Mux(a == 0, 0, a) ==> 0 */
+ n = b;
+ DBG_OPT_ALGSIM0(oldn, n);
+ }
+ }
+ }
+ }
+ }
+
+ return n;
+}
+
+/**
+ * Optimize -a CMP -b into b CMP a.
+ * This works only for for modes where unary Minus
+ * cannot Overflow.
+ * Note that two-complement integers can Overflow
+ * so it will NOT work.
+ */
+static ir_node *equivalent_node_Cmp(ir_node *n)
+{
+ ir_node *left = get_Cmp_left(n);
+ ir_node *right = get_Cmp_right(n);
+
+ if (get_irn_op(left) == op_Minus && get_irn_op(right) == op_Minus &&
+ !mode_overflow_on_unary_Minus(get_irn_mode(left))) {
+ left = get_Minus_op(left);
+ right = get_Minus_op(right);
+ set_Cmp_left(n, right);
+ set_Cmp_right(n, left);
+ }
+ return n;
+}
+
/**
* equivalent_node() returns a node equivalent to input n. It skips all nodes that
* perform no actual computation, as, e.g., the Id nodes. It does not create
CASE(DivMod);
CASE(And);
CASE(Conv);
+ CASE(Cast);
CASE(Phi);
CASE(Proj);
CASE(Id);
+ CASE(Mux);
+ CASE(Cmp);
default:
op->equivalent_node = NULL;
}
} /* end switch */
}
-static ir_node *transform_node_Mul(ir_node *n)
+/**
+ * Transform AddP(P, ConvIs(Iu)), AddP(P, ConvIu(Is)) and
+ * SubP(P, ConvIs(Iu)), SubP(P, ConvIu(Is)).
+ * If possible, remove the Conv's.
+ */
+static ir_node *transform_node_AddSub(ir_node *n)
+{
+ ir_mode *mode = get_irn_mode(n);
+
+ if (mode_is_reference(mode)) {
+ ir_node *left = get_binop_left(n);
+ ir_node *right = get_binop_right(n);
+ int ref_bits = get_mode_size_bits(mode);
+
+ if (get_irn_op(left) == op_Conv) {
+ ir_mode *mode = get_irn_mode(left);
+ int bits = get_mode_size_bits(mode);
+
+ if (ref_bits == bits &&
+ mode_is_int(mode) &&
+ get_mode_arithmetic(mode) == irma_twos_complement) {
+ ir_node *pre = get_Conv_op(left);
+ ir_mode *pre_mode = get_irn_mode(pre);
+
+ if (mode_is_int(pre_mode) &&
+ get_mode_size_bits(pre_mode) == bits &&
+ get_mode_arithmetic(pre_mode) == irma_twos_complement) {
+ /* ok, this conv just changes to sign, moreover the calculation
+ * is done with same number of bits as our address mode, so
+ * we can ignore the conv as address calculation can be viewed
+ * as either signed or unsigned
+ */
+ set_binop_left(n, pre);
+ }
+ }
+ }
+
+ if (get_irn_op(right) == op_Conv) {
+ ir_mode *mode = get_irn_mode(right);
+ int bits = get_mode_size_bits(mode);
+
+ if (ref_bits == bits &&
+ mode_is_int(mode) &&
+ get_mode_arithmetic(mode) == irma_twos_complement) {
+ ir_node *pre = get_Conv_op(right);
+ ir_mode *pre_mode = get_irn_mode(pre);
+
+ if (mode_is_int(pre_mode) &&
+ get_mode_size_bits(pre_mode) == bits &&
+ get_mode_arithmetic(pre_mode) == irma_twos_complement) {
+ /* ok, this conv just changes to sign, moreover the calculation
+ * is done with same number of bits as our address mode, so
+ * we can ignore the conv as address calculation can be viewed
+ * as either signed or unsigned
+ */
+ set_binop_right(n, pre);
+ }
+ }
+ }
+ }
+ return n;
+}
+
+/**
+ * Do the AddSub optimization, then Transform Add(a,a) into Mul(a, 2)
+ * if the mode is integer or float.
+ * Reassociation might fold this further.
+ */
+static ir_node *transform_node_Add(ir_node *n)
+{
+ ir_mode *mode;
+ ir_node *oldn = n;
+
+ n = transform_node_AddSub(n);
+
+ mode = get_irn_mode(n);
+ if (mode_is_num(mode)) {
+ ir_node *a = get_Add_left(n);
+
+ if (a == get_Add_right(n)) {
+ ir_node *block = get_nodes_block(n);
+
+ n = new_rd_Mul(
+ get_irn_dbg_info(n),
+ current_ir_graph,
+ block,
+ a,
+ new_r_Const_long(current_ir_graph, block, mode, 2),
+ mode);
+ DBG_OPT_ALGSIM0(oldn, n);
+ }
+ }
+ return n;
+}
+
+/**
+ * Do the AddSub optimization, then Transform Sub(0,a) into Minus(a).
+ */
+static ir_node *transform_node_Sub(ir_node *n)
{
+ ir_mode *mode;
+ ir_node *oldn = n;
+
+ n = transform_node_AddSub(n);
+
+ mode = get_irn_mode(n);
+ if (mode_is_num(mode) && (classify_Const(get_Sub_left(n)) == CNST_NULL)) {
+ n = new_rd_Minus(
+ get_irn_dbg_info(n),
+ current_ir_graph,
+ get_nodes_block(n),
+ get_Sub_right(n),
+ mode);
+ DBG_OPT_ALGSIM0(oldn, n);
+ }
+
+ return n;
+}
+
+/** Do architecture dependend optimizations on Mul nodes */
+static ir_node *transform_node_Mul(ir_node *n) {
return arch_dep_replace_mul_with_shifts(n);
}
+/**
+ * transform a Div Node
+ */
static ir_node *transform_node_Div(ir_node *n)
{
- tarval *tv = computed_value(n);
+ tarval *tv = value_of(n);
ir_node *value = n;
/* BEWARE: it is NOT possible to optimize a/a to 1, as this may cause a exception */
- if (tv != tarval_bad)
+ if (tv != tarval_bad) {
value = new_Const(get_tarval_mode(tv), tv);
+
+ DBG_OPT_CSTEVAL(n, value);
+ }
else /* Try architecture dependand optimization */
- value = arch_dep_replace_div_with_shifts(n);
+ value = arch_dep_replace_div_by_const(n);
if (value != n) {
/* Turn Div into a tuple (mem, bad, value) */
return n;
}
+/**
+ * transform a Mod node
+ */
static ir_node *transform_node_Mod(ir_node *n)
{
- tarval *tv = computed_value(n);
+ tarval *tv = value_of(n);
ir_node *value = n;
/* BEWARE: it is NOT possible to optimize a%a to 0, as this may cause a exception */
- if (tv != tarval_bad)
+ if (tv != tarval_bad) {
value = new_Const(get_tarval_mode(tv), tv);
+
+ DBG_OPT_CSTEVAL(n, value);
+ }
else /* Try architecture dependand optimization */
- value = arch_dep_replace_mod_with_shifts(n);
+ value = arch_dep_replace_mod_by_const(n);
if (value != n) {
/* Turn Mod into a tuple (mem, bad, value) */
return n;
}
+/**
+ * transform a DivMod node
+ */
static ir_node *transform_node_DivMod(ir_node *n)
{
int evaluated = 0;
if (tb == get_mode_one(get_tarval_mode(tb))) {
b = new_Const (mode, get_mode_null(mode));
evaluated = 1;
- } else if (ta != tarval_bad) {
+
+ DBG_OPT_CSTEVAL(n, b);
+ }
+ else if (ta != tarval_bad) {
tarval *resa, *resb;
resa = tarval_div (ta, tb);
if (resa == tarval_bad) return n; /* Causes exception!!! Model by replacing through
a = new_Const (mode, resa);
b = new_Const (mode, resb);
evaluated = 1;
+
+ DBG_OPT_CSTEVAL(n, a);
+ DBG_OPT_CSTEVAL(n, b);
}
else { /* Try architecture dependand optimization */
- arch_dep_replace_divmod_with_shifts(&a, &b, n);
+ arch_dep_replace_divmod_by_const(&a, &b, n);
evaluated = a != NULL;
}
} else if (ta == get_mode_null(mode)) {
return n;
}
+/**
+ * transform a Cond node
+ */
static ir_node *transform_node_Cond(ir_node *n)
{
/* Replace the Cond by a Jmp if it branches on a constant
add_End_keepalive(get_irg_end(current_ir_graph), get_nodes_block(n));
} else if ((get_irn_op(a) == op_Eor)
&& (get_irn_mode(a) == mode_b)
- && (classify_tarval(computed_value(get_Eor_right(a))) == TV_CLASSIFY_ONE)) {
+ && (classify_tarval(value_of(get_Eor_right(a))) == TV_CLASSIFY_ONE)) {
/* The Eor is a negate. Generate a new Cond without the negate,
simulate the negate by exchanging the results. */
set_irn_link(n, new_r_Cond(current_ir_graph, get_nodes_block(n),
return n;
}
+/**
+ * Transform an Eor.
+ */
static ir_node *transform_node_Eor(ir_node *n)
{
+ ir_node *oldn = n;
ir_node *a = get_Eor_left(n);
ir_node *b = get_Eor_right(n);
if ((get_irn_mode(n) == mode_b)
&& (get_irn_op(a) == op_Proj)
&& (get_irn_mode(a) == mode_b)
- && (classify_tarval (computed_value (b)) == TV_CLASSIFY_ONE)
- && (get_irn_op(get_Proj_pred(a)) == op_Cmp))
+ && (classify_tarval (value_of(b)) == TV_CLASSIFY_ONE)
+ && (get_irn_op(get_Proj_pred(a)) == op_Cmp)) {
/* The Eor negates a Cmp. The Cmp has the negated result anyways! */
n = new_r_Proj(current_ir_graph, get_nodes_block(n), get_Proj_pred(a),
mode_b, get_negated_pnc(get_Proj_proj(a)));
+
+ DBG_OPT_ALGSIM0(oldn, n);
+ }
else if ((get_irn_mode(n) == mode_b)
- && (classify_tarval (computed_value (b)) == TV_CLASSIFY_ONE))
+ && (classify_tarval (value_of(b)) == TV_CLASSIFY_ONE)) {
/* The Eor is a Not. Replace it by a Not. */
/* ????!!!Extend to bitfield 1111111. */
n = new_r_Not(current_ir_graph, get_nodes_block(n), a, mode_b);
+ DBG_OPT_ALGSIM0(oldn, n);
+ }
+
return n;
}
*/
static ir_node *transform_node_Not(ir_node *n)
{
+ ir_node *oldn = n;
ir_node *a = get_Not_op(n);
if ( (get_irn_mode(n) == mode_b)
&& (get_irn_op(a) == op_Proj)
&& (get_irn_mode(a) == mode_b)
- && (get_irn_op(get_Proj_pred(a)) == op_Cmp))
+ && (get_irn_op(get_Proj_pred(a)) == op_Cmp)) {
/* We negate a Cmp. The Cmp has the negated result anyways! */
n = new_r_Proj(current_ir_graph, get_nodes_block(n), get_Proj_pred(a),
mode_b, get_negated_pnc(get_Proj_proj(a)));
+ DBG_OPT_ALGSIM0(oldn, n);
+ }
+
+ return n;
+}
+
+/**
+ * Transform a Cast of a Const into a new Const
+ */
+static ir_node *transform_node_Cast(ir_node *n) {
+ ir_node *oldn = n;
+ ir_node *pred = get_Cast_op(n);
+ type *tp = get_irn_type(n);
+
+ if (get_irn_op(pred) == op_Const && get_Const_type(pred) != tp) {
+ n = new_rd_Const_type(NULL, current_ir_graph, get_nodes_block(pred), get_irn_mode(pred),
+ get_Const_tarval(pred), tp);
+ DBG_OPT_CSTEVAL(oldn, n);
+ } else if ((get_irn_op(pred) == op_SymConst) && (get_SymConst_value_type(pred) != tp)) {
+ n = new_rd_SymConst_type(NULL, current_ir_graph, get_nodes_block(pred), get_SymConst_symbol(pred),
+ get_SymConst_kind(pred), tp);
+ DBG_OPT_CSTEVAL(oldn, n);
+ }
return n;
}
/**
- * Transform a Div/Mod/DivMod with a non-zero constant. Must be
- * done here instead of equivalent node because in creates new
- * nodes.
- * Removes the exceptions and routes the memory to the initial mem.
+ * Does all optimizations on nodes that must be done on it's Proj's
+ * because of creating new nodes.
+ *
+ * Transform a Div/Mod/DivMod with a non-zero constant.
+ * Removes the exceptions and routes the memory to the NoMem node.
*
- * Further, it optimizes jump tables by removing all impossible cases.
+ * Optimizes jump tables by removing all impossible cases.
+ *
+ * Normalizes and optimizes Cmp nodes.
*/
static ir_node *transform_node_Proj(ir_node *proj)
{
switch (get_irn_opcode(n)) {
case iro_Div:
b = get_Div_right(n);
- tb = computed_value(b);
+ tb = value_of(b);
if (tb != tarval_bad && classify_tarval(tb) != TV_CLASSIFY_NULL) { /* div(x, c) && c != 0 */
proj_nr = get_Proj_proj(proj);
+ /* this node may float */
+ set_irn_pinned(n, op_pin_state_floats);
+
if (proj_nr == pn_Div_X_except) {
/* we found an exception handler, remove it */
return new_Bad();
- }
- else {
- /* the memory Proj can be removed */
+ } else {
+ /* the memory Proj can be removed */
ir_node *res = get_Div_mem(n);
- set_Div_mem(n, get_irg_initial_mem(current_ir_graph));
- if (proj_nr == pn_Div_M)
+ set_Div_mem(n, get_irg_no_mem(current_ir_graph));
+ if (proj_nr == pn_Div_M)
return res;
}
}
break;
case iro_Mod:
b = get_Mod_right(n);
- tb = computed_value(b);
+ tb = value_of(b);
if (tb != tarval_bad && classify_tarval(tb) != TV_CLASSIFY_NULL) { /* mod(x, c) && c != 0 */
proj_nr = get_Proj_proj(proj);
+ /* this node may float */
+ set_irn_pinned(n, op_pin_state_floats);
+
if (proj_nr == pn_Mod_X_except) {
/* we found an exception handler, remove it */
return new_Bad();
- }
- else {
- /* the memory Proj can be removed */
+ } else {
+ /* the memory Proj can be removed */
ir_node *res = get_Mod_mem(n);
- set_Mod_mem(n, get_irg_initial_mem(current_ir_graph));
+ set_Mod_mem(n, get_irg_no_mem(current_ir_graph));
if (proj_nr == pn_Mod_M)
- return res;
+ return res;
}
}
break;
case iro_DivMod:
b = get_DivMod_right(n);
- tb = computed_value(b);
+ tb = value_of(b);
if (tb != tarval_bad && classify_tarval(tb) != TV_CLASSIFY_NULL) { /* DivMod(x, c) && c != 0 */
proj_nr = get_Proj_proj(proj);
+ /* this node may float */
+ set_irn_pinned(n, op_pin_state_floats);
+
if (proj_nr == pn_DivMod_X_except) {
/* we found an exception handler, remove it */
return new_Bad();
}
else {
- /* the memory Proj can be removed */
+ /* the memory Proj can be removed */
ir_node *res = get_DivMod_mem(n);
- set_DivMod_mem(n, get_irg_initial_mem(current_ir_graph));
+ set_DivMod_mem(n, get_irg_no_mem(current_ir_graph));
if (proj_nr == pn_DivMod_M)
- return res;
+ return res;
}
}
break;
case iro_Cond:
if (get_opt_unreachable_code()) {
b = get_Cond_selector(n);
- tb = computed_value(b);
+ tb = value_of(b);
if (tb != tarval_bad && mode_is_int(get_tarval_mode(tb))) {
/* we have a constant switch */
}
return proj;
+ case iro_Cmp:
+ if (get_opt_reassociation()) {
+ ir_node *left = get_Cmp_left(n);
+ ir_node *right = get_Cmp_right(n);
+ ir_node *c = NULL;
+ tarval *tv = NULL;
+ int changed = 0;
+ ir_mode *mode = NULL;
+
+ proj_nr = get_Proj_proj(proj);
+
+ /*
+ * First step: normalize the compare op
+ * by placing the constant on the right site
+ * or moving the lower address node to the left.
+ * We ignore the case that both are constants, then
+ * this compare should be optimized away.
+ */
+ if (get_irn_op(right) == op_Const)
+ c = right;
+ else if (get_irn_op(left) == op_Const) {
+ c = left;
+ left = right;
+ right = c;
+
+ proj_nr = get_swapped_pnc(proj_nr);
+ changed |= 1;
+ }
+ else if (left > right) {
+ ir_node *t = left;
+
+ left = right;
+ right = t;
+
+ proj_nr = get_swapped_pnc(proj_nr);
+ changed |= 1;
+ }
+
+ /*
+ * Second step: Try to reduce the magnitude
+ * of a constant. This may help to generate better code
+ * later and may help to normalize more compares.
+ * Of course this is only possible for integer values.
+ */
+ if (c) {
+ mode = get_irn_mode(c);
+ tv = get_Const_tarval(c);
+
+ if (tv != tarval_bad) {
+ /* the following optimization is possibe on modes without Overflow
+ * on Unary Minus or on == and !=:
+ * -a CMP c ==> a swap(CMP) -c
+ *
+ * Beware: for two-complement Overflow may occur, so only == and != can
+ * be optimized, see this:
+ * -MININT < 0 =/=> MININT > 0 !!!
+ */
+ if (get_opt_constant_folding() && get_irn_op(left) == op_Minus &&
+ (!mode_overflow_on_unary_Minus(mode) ||
+ (mode_is_int(mode) && (proj_nr == pn_Cmp_Eq || proj_nr == pn_Cmp_Lg)))) {
+ left = get_Minus_op(left);
+ tv = tarval_sub(get_tarval_null(mode), tv);
+
+ proj_nr = get_swapped_pnc(proj_nr);
+ changed |= 2;
+ }
+
+ /* for integer modes, we have more */
+ if (mode_is_int(mode)) {
+ /* Ne includes Unordered which is not possible on integers.
+ * However, frontends often use this wrong, so fix it here */
+ if (proj_nr == pn_Cmp_Ne) {
+ proj_nr = pn_Cmp_Lg;
+ set_Proj_proj(proj, proj_nr);
+ }
+
+ /* c > 0 : a < c ==> a <= (c-1) a >= c ==> a > (c-1) */
+ if ((proj_nr == pn_Cmp_Lt || proj_nr == pn_Cmp_Ge) &&
+ tarval_cmp(tv, get_tarval_null(mode)) == pn_Cmp_Gt) {
+ tv = tarval_sub(tv, get_tarval_one(mode));
+
+ proj_nr ^= pn_Cmp_Eq;
+ changed |= 2;
+ }
+ /* c < 0 : a > c ==> a >= (c+1) a <= c ==> a < (c+1) */
+ else if ((proj_nr == pn_Cmp_Gt || proj_nr == pn_Cmp_Le) &&
+ tarval_cmp(tv, get_tarval_null(mode)) == pn_Cmp_Lt) {
+ tv = tarval_add(tv, get_tarval_one(mode));
+
+ proj_nr ^= pn_Cmp_Eq;
+ changed |= 2;
+ }
+
+ /* the following reassociations work only for == and != */
+
+ /* a-b == 0 ==> a == b, a-b != 0 ==> a != b */
+ if (classify_tarval(tv) == TV_CLASSIFY_NULL && get_irn_op(left) == op_Sub) {
+ if (proj_nr == pn_Cmp_Eq || proj_nr == pn_Cmp_Lg) {
+ right = get_Sub_right(left);
+ left = get_Sub_left(left);
+
+ tv = value_of(right);
+ changed = 1;
+ }
+ }
+
+ if ((tv != tarval_bad) && (proj_nr == pn_Cmp_Eq || proj_nr == pn_Cmp_Lg)) {
+ ir_op *op = get_irn_op(left);
+
+ /* a-c1 == c2 ==> a == c2+c1, a-c1 != c2 ==> a != c2+c1 */
+ if (op == op_Sub) {
+ ir_node *c1 = get_Sub_right(left);
+ tarval *tv2 = value_of(c1);
+
+ if (tv2 != tarval_bad) {
+ tv2 = tarval_add(tv, value_of(c1));
+
+ if (tv2 != tarval_bad) {
+ left = get_Sub_left(left);
+ tv = tv2;
+ changed = 2;
+ }
+ }
+ }
+ /* a+c1 == c2 ==> a == c2-c1, a+c1 != c2 ==> a != c2-c1 */
+ else if (op == op_Add) {
+ ir_node *a_l = get_Add_left(left);
+ ir_node *a_r = get_Add_right(left);
+ ir_node *a;
+ tarval *tv2;
+
+ if (get_irn_op(a_l) == op_Const) {
+ a = a_r;
+ tv2 = value_of(a_l);
+ }
+ else {
+ a = a_l;
+ tv2 = value_of(a_r);
+ }
+
+ if (tv2 != tarval_bad) {
+ tv2 = tarval_sub(tv, tv2);
+
+ if (tv2 != tarval_bad) {
+ left = a;
+ tv = tv2;
+ changed = 2;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (changed) {
+ ir_node *block = get_nodes_block(n);
+
+ if (changed & 2) /* need a new Const */
+ right = new_Const(mode, tv);
+
+ /* create a new compare */
+ n = new_rd_Cmp(get_irn_dbg_info(n), current_ir_graph, block,
+ left, right);
+
+ set_Proj_pred(proj, n);
+ set_Proj_proj(proj, proj_nr);
+ }
+ }
+ return proj;
+
case iro_Tuple:
/* should not happen, but if it does will be optimized away */
break;
* AND c1
* OR
*/
-static ir_node *transform_node_Or(ir_node *or)
+static ir_node *transform_node_Or_bf_store(ir_node *or)
{
ir_node *and, *c1;
ir_node *or_l, *c2;
set_Or_right(or, new_const);
/* check for more */
- return transform_node_Or(or);
+ return transform_node_Or_bf_store(or);
+}
+
+/**
+ * Optimize an Or(shl(x, c), shr(x, bits - c)) into a Rot
+ */
+static ir_node *transform_node_Or_Rot(ir_node *or)
+{
+ ir_mode *mode = get_irn_mode(or);
+ ir_node *shl, *shr, *block;
+ ir_node *irn, *x, *c1, *c2, *v, *sub, *n;
+ tarval *tv1, *tv2;
+
+ if (! mode_is_int(mode))
+ return or;
+
+ shl = get_binop_left(or);
+ shr = get_binop_right(or);
+
+ if (get_irn_op(shl) == op_Shr) {
+ if (get_irn_op(shr) != op_Shl)
+ return or;
+
+ irn = shl;
+ shl = shr;
+ shr = irn;
+ }
+ else if (get_irn_op(shl) != op_Shl)
+ return or;
+ else if (get_irn_op(shr) != op_Shr)
+ return or;
+
+ x = get_Shl_left(shl);
+ if (x != get_Shr_left(shr))
+ return or;
+
+ c1 = get_Shl_right(shl);
+ c2 = get_Shr_right(shr);
+ if (get_irn_op(c1) == op_Const && get_irn_op(c2) == op_Const) {
+ tv1 = get_Const_tarval(c1);
+ if (! tarval_is_long(tv1))
+ return or;
+
+ tv2 = get_Const_tarval(c2);
+ if (! tarval_is_long(tv2))
+ return or;
+
+ if (get_tarval_long(tv1) + get_tarval_long(tv2)
+ != get_mode_size_bits(mode))
+ return or;
+
+ /* yet, condition met */
+ block = get_nodes_block(or);
+
+ n = new_r_Rot(current_ir_graph, block, x, c1, mode);
+
+ DBG_OPT_ALGSIM1(or, shl, shr, n);
+ return n;
+ }
+ else if (get_irn_op(c1) == op_Sub) {
+ v = c2;
+ sub = c1;
+
+ if (get_Sub_right(sub) != v)
+ return or;
+
+ c1 = get_Sub_left(sub);
+ if (get_irn_op(c1) != op_Const)
+ return or;
+
+ tv1 = get_Const_tarval(c1);
+ if (! tarval_is_long(tv1))
+ return or;
+
+ if (get_tarval_long(tv1) != get_mode_size_bits(mode))
+ return or;
+
+ /* yet, condition met */
+ block = get_nodes_block(or);
+
+ /* a Rot right is not supported, so use a rot left */
+ n = new_r_Rot(current_ir_graph, block, x, sub, mode);
+
+ DBG_OPT_ALGSIM0(or, n);
+ return n;
+ }
+ else if (get_irn_op(c2) == op_Sub) {
+ v = c1;
+ sub = c2;
+
+ c1 = get_Sub_left(sub);
+ if (get_irn_op(c1) != op_Const)
+ return or;
+
+ tv1 = get_Const_tarval(c1);
+ if (! tarval_is_long(tv1))
+ return or;
+
+ if (get_tarval_long(tv1) != get_mode_size_bits(mode))
+ return or;
+
+ /* yet, condition met */
+ block = get_nodes_block(or);
+
+ /* a Rot Left */
+ n = new_r_Rot(current_ir_graph, block, x, v, mode);
+
+ DBG_OPT_ALGSIM0(or, n);
+ return n;
+ }
+
+ return or;
+}
+
+/**
+ * Optimize an Or
+ */
+static ir_node *transform_node_Or(ir_node *or)
+{
+ or = transform_node_Or_bf_store(or);
+ or = transform_node_Or_Rot(or);
+
+ return or;
+}
+
+/* forward */
+static ir_node *transform_node(ir_node *n);
+
+/**
+ * Optimize (a >> c1) >> c2), works for Shr, Shrs, Shl
+ */
+static ir_node *transform_node_shift(ir_node *n)
+{
+ ir_node *left, *right;
+ tarval *tv1, *tv2, *res;
+ ir_mode *mode;
+ int modulo_shf, flag;
+
+ left = get_binop_left(n);
+
+ /* different operations */
+ if (get_irn_op(left) != get_irn_op(n))
+ return n;
+
+ right = get_binop_right(n);
+ tv1 = value_of(right);
+ if (tv1 == tarval_bad)
+ return n;
+
+ tv2 = value_of(get_binop_right(left));
+ if (tv2 == tarval_bad)
+ return n;
+
+ res = tarval_add(tv1, tv2);
+
+ /* beware: a simple replacement works only, if res < modulo shift */
+ mode = get_irn_mode(n);
+
+ flag = 0;
+
+ modulo_shf = get_mode_modulo_shift(mode);
+ if (modulo_shf > 0) {
+ tarval *modulo = new_tarval_from_long(modulo_shf, get_tarval_mode(res));
+
+ if (tarval_cmp(res, modulo) & pn_Cmp_Lt)
+ flag = 1;
+ }
+ else
+ flag = 1;
+
+ if (flag) {
+ /* ok, we can replace it */
+ ir_node *in[2], *irn, *block = get_nodes_block(n);
+
+ in[0] = get_binop_left(left);
+ in[1] = new_r_Const(current_ir_graph, block, get_tarval_mode(res), res);
+
+ irn = new_ir_node(NULL, current_ir_graph, block, get_irn_op(n), mode, 2, in);
+
+ DBG_OPT_ALGSIM0(n, irn);
+
+ return transform_node(irn);
+ }
+ return n;
+}
+
+#define transform_node_Shr transform_node_shift
+#define transform_node_Shrs transform_node_shift
+#define transform_node_Shl transform_node_shift
+
+/**
+ * Remove dead blocks in keepalive list. We do not generate a new End node.
+ */
+static ir_node *transform_node_End(ir_node *n) {
+ int i, n_keepalives = get_End_n_keepalives(n);
+
+ for (i = 0; i < n_keepalives; ++i) {
+ ir_node *ka = get_End_keepalive(n, i);
+ if (is_Block(ka) && is_Block_dead(ka))
+ set_End_keepalive(n, i, new_Bad());
+ }
+ return n;
+}
+
+/**
+ * Optimize a Mux into some simplier cases.
+ */
+static ir_node *transform_node_Mux(ir_node *n)
+{
+ ir_node *oldn = n, *sel = get_Mux_sel(n);
+ ir_mode *mode = get_irn_mode(n);
+
+ if (get_irn_op(sel) == op_Proj && !mode_honor_signed_zeros(mode)) {
+ ir_node *cmp = get_Proj_pred(sel);
+ long proj_nr = get_Proj_proj(sel);
+ ir_node *f = get_Mux_false(n);
+ ir_node *t = get_Mux_true(n);
+
+ if (get_irn_op(cmp) == op_Cmp && classify_Const(get_Cmp_right(cmp)) == CNST_NULL) {
+ ir_node *block = get_nodes_block(n);
+
+ /*
+ * Note: normalization puts the constant on the right site,
+ * so we check only one case.
+ *
+ * Note further that these optimization work even for floating point
+ * with NaN's because -NaN == NaN.
+ * However, if +0 and -0 is handled differently, we cannot use the first one.
+ */
+ if (get_irn_op(f) == op_Minus &&
+ get_Minus_op(f) == t &&
+ get_Cmp_left(cmp) == t) {
+
+ if (proj_nr == pn_Cmp_Ge || proj_nr == pn_Cmp_Gt) {
+ /* Mux(a >=/> 0, -a, a) ==> Abs(a) */
+ n = new_rd_Abs(get_irn_dbg_info(n),
+ current_ir_graph,
+ block,
+ t, mode);
+ DBG_OPT_ALGSIM1(oldn, cmp, sel, n);
+ return n;
+ }
+ else if (proj_nr == pn_Cmp_Le || proj_nr == pn_Cmp_Lt) {
+ /* Mux(a <=/< 0, -a, a) ==> Minus(Abs(a)) */
+ n = new_rd_Abs(get_irn_dbg_info(n),
+ current_ir_graph,
+ block,
+ t, mode);
+ n = new_rd_Minus(get_irn_dbg_info(n),
+ current_ir_graph,
+ block,
+ n, mode);
+
+ DBG_OPT_ALGSIM1(oldn, cmp, sel, n);
+ return n;
+ }
+ }
+ else if (get_irn_op(t) == op_Minus &&
+ get_Minus_op(t) == f &&
+ get_Cmp_left(cmp) == f) {
+
+ if (proj_nr == pn_Cmp_Le || proj_nr == pn_Cmp_Lt) {
+ /* Mux(a <=/< 0, a, -a) ==> Abs(a) */
+ n = new_rd_Abs(get_irn_dbg_info(n),
+ current_ir_graph,
+ block,
+ f, mode);
+ DBG_OPT_ALGSIM1(oldn, cmp, sel, n);
+ return n;
+ }
+ else if (proj_nr == pn_Cmp_Ge || proj_nr == pn_Cmp_Gt) {
+ /* Mux(a >=/> 0, a, -a) ==> Minus(Abs(a)) */
+ n = new_rd_Abs(get_irn_dbg_info(n),
+ current_ir_graph,
+ block,
+ f, mode);
+ n = new_rd_Minus(get_irn_dbg_info(n),
+ current_ir_graph,
+ block,
+ n, mode);
+
+ DBG_OPT_ALGSIM1(oldn, cmp, sel, n);
+ return n;
+ }
+ }
+
+ if (mode_is_int(mode) && mode_is_signed(mode) &&
+ get_mode_arithmetic(mode) == irma_twos_complement) {
+ ir_node *x = get_Cmp_left(cmp);
+
+ /* the following optimization works only with signed integer two-complement mode */
+
+ if (mode == get_irn_mode(x)) {
+ /*
+ * FIXME: this restriction is two rigid, as it would still
+ * work if mode(x) = Hs and mode == Is, but at least it removes
+ * all wrong cases.
+ */
+ if ((proj_nr == pn_Cmp_Lt || proj_nr == pn_Cmp_Le) &&
+ classify_Const(t) == CNST_ALL_ONE &&
+ classify_Const(f) == CNST_NULL) {
+ /*
+ * Mux(x:T </<= 0, 0, -1) -> Shrs(x, sizeof_bits(T) - 1)
+ * Conditions:
+ * T must be signed.
+ */
+ n = new_rd_Shrs(get_irn_dbg_info(n),
+ current_ir_graph, block, x,
+ new_r_Const_long(current_ir_graph, block, mode_Iu,
+ get_mode_size_bits(mode) - 1),
+ mode);
+ DBG_OPT_ALGSIM1(oldn, cmp, sel, n);
+ return n;
+ }
+ else if ((proj_nr == pn_Cmp_Gt || proj_nr == pn_Cmp_Ge) &&
+ classify_Const(t) == CNST_ONE &&
+ classify_Const(f) == CNST_NULL) {
+ /*
+ * Mux(x:T >/>= 0, 0, 1) -> Shr(-x, sizeof_bits(T) - 1)
+ * Conditions:
+ * T must be signed.
+ */
+ n = new_rd_Shr(get_irn_dbg_info(n),
+ current_ir_graph, block,
+ new_r_Minus(current_ir_graph, block, x, mode),
+ new_r_Const_long(current_ir_graph, block, mode_Iu,
+ get_mode_size_bits(mode) - 1),
+ mode);
+ DBG_OPT_ALGSIM1(oldn, cmp, sel, n);
+ return n;
+ }
+ }
+ }
+ }
+ }
+ return arch_transform_node_Mux(n);
}
/**
break
switch (op->code) {
+ CASE(Add);
+ CASE(Sub);
CASE(Mul);
CASE(Div);
CASE(Mod);
CASE(Cond);
CASE(Eor);
CASE(Not);
+ CASE(Cast);
CASE(Proj);
+ CASE(Sel);
CASE(Or);
+ CASE(Shr);
+ CASE(Shrs);
+ CASE(Shl);
+ CASE(End);
+ CASE(Mux);
default:
- op->transform_node = NULL;
+ op->transform_node = NULL;
}
return op;
/** Compares the attributes of two Free nodes. */
static int node_cmp_attr_Free(ir_node *a, ir_node *b)
{
- return (get_irn_free_attr(a) != get_irn_free_attr(b));
+ return (get_irn_free_attr(a).where != get_irn_free_attr(b).where)
+ || (get_irn_free_attr(a).type != get_irn_free_attr(b).type);
}
/** Compares the attributes of two SymConst nodes. */
static int node_cmp_attr_SymConst(ir_node *a, ir_node *b)
{
return (get_irn_symconst_attr(a).num != get_irn_symconst_attr(b).num)
- || (get_irn_symconst_attr(a).sym.type_p != get_irn_symconst_attr(b).sym.type_p);
+ || (get_irn_symconst_attr(a).sym.type_p != get_irn_symconst_attr(b).sym.type_p)
+ || (get_irn_symconst_attr(a).tp != get_irn_symconst_attr(b).tp);
}
/** Compares the attributes of two Call nodes. */
return (get_irn_call_attr(a) != get_irn_call_attr(b));
}
-/** Compares the attributes of two FuncCall nodes. */
-static int node_cmp_attr_FuncCall(ir_node *a, ir_node *b)
-{
- return (get_irn_funccall_attr(a) != get_irn_funccall_attr(b));
-}
-
/** Compares the attributes of two Sel nodes. */
static int node_cmp_attr_Sel(ir_node *a, ir_node *b)
{
{
/* NEVER do CSE on volatile Stores */
return (get_Store_volatility(a) == volatility_is_volatile ||
- get_Load_volatility(b) == volatility_is_volatile);
+ get_Store_volatility(b) == volatility_is_volatile);
}
/**
CASE(Free);
CASE(SymConst);
CASE(Call);
- CASE(FuncCall);
CASE(Sel);
CASE(Phi);
CASE(Cast);
if ((get_irn_op(a) != get_irn_op(b)) ||
(get_irn_mode(a) != get_irn_mode(b))) return 1;
- /* compare if a's in and b's in are equal */
- irn_arity_a = get_irn_arity (a);
- if (irn_arity_a != get_irn_arity(b))
+ /* compare if a's in and b's in are of equal length */
+ irn_arity_a = get_irn_intra_arity (a);
+ if (irn_arity_a != get_irn_intra_arity(b))
return 1;
/* for block-local cse and op_pin_state_pinned nodes: */
if (!get_opt_global_cse() || (get_irn_pinned(a) == op_pin_state_pinned)) {
- if (get_irn_n(a, -1) != get_irn_n(b, -1))
+ if (get_irn_intra_n(a, -1) != get_irn_intra_n(b, -1))
return 1;
}
/* compare a->in[0..ins] with b->in[0..ins] */
for (i = 0; i < irn_arity_a; i++)
- if (get_irn_n(a, i) != get_irn_n(b, i))
+ if (get_irn_intra_n(a, i) != get_irn_intra_n(b, i))
return 1;
/*
if (node->op == op_Const) {
/* special value for const, as they only differ in their tarval. */
- h = ((unsigned) node->attr.con.tv)>>3 ;
- h = 9*h + (unsigned)get_irn_mode(node);
+ h = HASH_PTR(node->attr.con.tv);
+ h = 9*h + HASH_PTR(get_irn_mode(node));
} else if (node->op == op_SymConst) {
/* special value for const, as they only differ in their symbol. */
- h = ((unsigned) node->attr.i.sym.type_p)>>3 ;
- h = 9*h + (unsigned)get_irn_mode(node);
+ h = HASH_PTR(node->attr.i.sym.type_p);
+ h = 9*h + HASH_PTR(get_irn_mode(node));
} else {
/* hash table value = 9*(9*(9*(9*(9*arity+in[0])+in[1])+ ...)+mode)+code */
- h = irn_arity = get_irn_arity(node);
+ h = irn_arity = get_irn_intra_arity(node);
- /* consider all in nodes... except the block. */
- for (i = 0; i < irn_arity; i++) {
- h = 9*h + (unsigned)get_irn_n(node, i);
+ /* consider all in nodes... except the block if not a control flow. */
+ for (i = is_cfop(node) ? -1 : 0; i < irn_arity; i++) {
+ h = 9*h + HASH_PTR(get_irn_intra_n(node, i));
}
/* ...mode,... */
- h = 9*h + (unsigned) get_irn_mode (node);
+ h = 9*h + HASH_PTR(get_irn_mode(node));
/* ...and code */
- h = 9*h + (unsigned) get_irn_op (node);
+ h = 9*h + HASH_PTR(get_irn_op(node));
}
return h;
}
pset *
-new_identities (void)
-{
- return new_pset (vt_cmp, N_IR_NODES);
+new_identities(void) {
+ return new_pset(vt_cmp, N_IR_NODES);
}
void
-del_identities (pset *value_table)
-{
- del_pset (value_table);
+del_identities(pset *value_table) {
+ del_pset(value_table);
}
/**
and replacing the control flow by Bad. */
if (get_irn_mode(node) == mode_X) {
ir_node *block = get_nodes_block(node);
+ if (!get_Block_matured(block)) return node; /* Don't optimize nodes in immature blocks. */
if (op == op_End) return node; /* Don't optimize End, may have Bads. */
+
if (get_irn_op(block) == op_Block && get_Block_matured(block)) {
irn_arity = get_irn_arity(block);
for (i = 0; i < irn_arity; i++) {
blocks predecessors is dead. */
if ( op != op_Block && op != op_Phi && op != op_Tuple) {
irn_arity = get_irn_arity(node);
- for (i = -1; i < irn_arity; i++) {
+
+ if (is_Block_dead(get_nodes_block(node)))
+ return new_Bad();
+
+ for (i = 0; i < irn_arity; i++) {
if (is_Bad(get_irn_n(node, i))) {
return new_Bad();
}
ir_node *
optimize_node (ir_node *n)
{
- tarval *tv;
- ir_node *oldn = n;
- opcode iro = get_irn_opcode(n);
-
- /* Always optimize Phi nodes: part of the construction. */
- if ((!get_opt_optimize()) && (iro != iro_Phi)) return n;
-
- /* constant expression evaluation / constant folding */
- if (get_opt_constant_folding()) {
- /* constants can not be evaluated */
- if (iro != iro_Const) {
- /* try to evaluate */
- tv = computed_value (n);
- if ((get_irn_mode(n) != mode_T) && (tv != tarval_bad)) {
- /*
- * we MUST copy the node here temporary, because it's still needed
- * for DBG_OPT_ALGSIM0
- */
- int node_size = offsetof(ir_node, attr) + n->op->attr_size;
- oldn = alloca(node_size);
-
- memcpy(oldn, n, node_size);
- CLONE_ARR_A(ir_node *, oldn->in, n->in);
-
- /* ARG, copy the in array, we need it for statistics */
- memcpy(oldn->in, n->in, ARR_LEN(n->in) * sizeof(n->in[0]));
-
- /* evaluation was successful -- replace the node. */
- obstack_free (current_ir_graph->obst, n);
- n = new_Const (get_tarval_mode (tv), tv);
-
- DBG_OPT_ALGSIM0(oldn, n);
- return n;
- }
- }
- }
-
- /* remove unnecessary nodes */
- if (get_opt_constant_folding() ||
- (iro == iro_Phi) || /* always optimize these nodes. */
- (iro == iro_Id) ||
- (iro == iro_Proj) ||
- (iro == iro_Block) ) /* Flags tested local. */
- n = equivalent_node (n);
-
- optimize_preds(n); /* do node specific optimizations of nodes predecessors. */
-
- /** common subexpression elimination **/
- /* Checks whether n is already available. */
- /* The block input is used to distinguish different subexpressions. Right
- now all nodes are op_pin_state_pinned to blocks, i.e., the cse only finds common
- subexpressions within a block. */
- if (get_opt_cse())
- n = identify_cons (current_ir_graph->value_table, n);
-
- if (n != oldn) {
- /* We found an existing, better node, so we can deallocate the old node. */
- obstack_free (current_ir_graph->obst, oldn);
-
- return n;
- }
-
- /* Some more constant expression evaluation that does not allow to
- free the node. */
- iro = get_irn_opcode(n);
- if (get_opt_constant_folding() ||
- (iro == iro_Cond) ||
- (iro == iro_Proj)) /* Flags tested local. */
- n = transform_node (n);
-
- /* Remove nodes with dead (Bad) input.
- Run always for transformation induced Bads. */
- n = gigo (n);
-
- /* Now we have a legal, useful node. Enter it in hash table for cse */
- if (get_opt_cse() && (get_irn_opcode(n) != iro_Block)) {
- n = identify_remember (current_ir_graph->value_table, n);
- }
-
- return n;
+ tarval *tv;
+ ir_node *oldn = n;
+ opcode iro = get_irn_opcode(n);
+
+ type *old_tp = get_irn_type(n);
+ {
+ int i, arity = get_irn_arity(n);
+ for (i = 0; i < arity && !old_tp; ++i)
+ old_tp = get_irn_type(get_irn_n(n, i));
+ }
+
+ /* Always optimize Phi nodes: part of the construction. */
+ if ((!get_opt_optimize()) && (iro != iro_Phi)) return n;
+
+ /* constant expression evaluation / constant folding */
+ if (get_opt_constant_folding()) {
+ /* constants can not be evaluated */
+ if (iro != iro_Const) {
+ /* try to evaluate */
+ tv = computed_value(n);
+ if ((get_irn_mode(n) != mode_T) && (tv != tarval_bad)) {
+ ir_node *nw;
+
+ /*
+ * we MUST copy the node here temporary, because it's still needed
+ * for DBG_OPT_CSTEVAL
+ */
+ int node_size = offsetof(ir_node, attr) + n->op->attr_size;
+ oldn = alloca(node_size);
+
+ memcpy(oldn, n, node_size);
+ CLONE_ARR_A(ir_node *, oldn->in, n->in);
+
+ /* ARG, copy the in array, we need it for statistics */
+ memcpy(oldn->in, n->in, ARR_LEN(n->in) * sizeof(n->in[0]));
+
+
+ edges_node_deleted(n, current_ir_graph);
+
+ /* evaluation was successful -- replace the node. */
+ obstack_free (current_ir_graph->obst, n);
+ nw = new_Const (get_tarval_mode (tv), tv);
+
+ if (old_tp && get_type_mode(old_tp) == get_tarval_mode (tv))
+ set_Const_type(nw, old_tp);
+ DBG_OPT_CSTEVAL(oldn, nw);
+ return nw;
+ }
+ }
+ }
+
+ /* remove unnecessary nodes */
+ if (get_opt_constant_folding() ||
+ (iro == iro_Phi) || /* always optimize these nodes. */
+ (iro == iro_Id) ||
+ (iro == iro_Proj) ||
+ (iro == iro_Block) ) /* Flags tested local. */
+ n = equivalent_node (n);
+
+ optimize_preds(n); /* do node specific optimizations of nodes predecessors. */
+
+ /** common subexpression elimination **/
+ /* Checks whether n is already available. */
+ /* The block input is used to distinguish different subexpressions. Right
+ now all nodes are op_pin_state_pinned to blocks, i.e., the cse only finds common
+ subexpressions within a block. */
+ if (get_opt_cse())
+ n = identify_cons (current_ir_graph->value_table, n);
+
+ if (n != oldn) {
+ edges_node_deleted(oldn, current_ir_graph);
+
+ /* We found an existing, better node, so we can deallocate the old node. */
+ obstack_free (current_ir_graph->obst, oldn);
+
+ return n;
+ }
+
+ /* Some more constant expression evaluation that does not allow to
+ free the node. */
+ iro = get_irn_opcode(n);
+ if (get_opt_constant_folding() ||
+ (iro == iro_Cond) ||
+ (iro == iro_Proj) ||
+ (iro == iro_Sel)) /* Flags tested local. */
+ n = transform_node (n);
+
+ /* Remove nodes with dead (Bad) input.
+ Run always for transformation induced Bads. */
+ n = gigo (n);
+
+ /* Now we have a legal, useful node. Enter it in hash table for cse */
+ if (get_opt_cse() && (get_irn_opcode(n) != iro_Block)) {
+ n = identify_remember (current_ir_graph->value_table, n);
+ }
+
+ return n;
}
/**
- * These optimizations never deallocate nodes. This can cause dead
+ * These optimizations never deallocate nodes (in place). This can cause dead
* nodes lying on the obstack. Remove these by a dead node elimination,
* i.e., a copying garbage collection.
*/
ir_node *oldn = n;
opcode iro = get_irn_opcode(n);
+ type *old_tp = get_irn_type(n);
+ {
+ int i, arity = get_irn_arity(n);
+ for (i = 0; i < arity && !old_tp; ++i)
+ old_tp = get_irn_type(get_irn_n(n, i));
+ }
+
if (!get_opt_optimize() && (get_irn_op(n) != op_Phi)) return n;
/* if not optimize return n */
return n;
}
-
/* constant expression evaluation / constant folding */
if (get_opt_constant_folding()) {
/* constants can not be evaluated */
if (iro != iro_Const) {
/* try to evaluate */
- tv = computed_value (n);
+ tv = computed_value(n);
if ((get_irn_mode(n) != mode_T) && (tv != tarval_bad)) {
/* evaluation was successful -- replace the node. */
n = new_Const (get_tarval_mode (tv), tv);
- DBG_OPT_ALGSIM0(oldn, n);
+ if (old_tp && get_type_mode(old_tp) == get_tarval_mode (tv))
+ set_Const_type(n, old_tp);
+
+ DBG_OPT_CSTEVAL(oldn, n);
return n;
}
}
iro = get_irn_opcode(n);
if (get_opt_constant_folding() ||
(iro == iro_Cond) ||
- (iro == iro_Proj)) /* Flags tested local. */
+ (iro == iro_Proj) ||
+ (iro == iro_Sel)) /* Flags tested local. */
n = transform_node (n);
/* Remove nodes with dead (Bad) input.
op = firm_set_default_equivalent_node(op);
op = firm_set_default_transform_node(op);
op = firm_set_default_node_cmp_attr(op);
+ op = firm_set_default_get_type(op);
return op;
}