* 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.
*/
# 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);
}
/**
/* a - a */
if (a == b && !is_Bad(a))
- return get_tarval_null(get_irn_mode(n));
+ return get_mode_null(get_irn_mode(n));
ta = value_of(a);
tb = value_of(b);
tarval *ta, *tb;
if (a == b)
- return get_tarval_null(get_irn_mode(n));
+ return get_mode_null(get_irn_mode(n));
ta = value_of(a);
tb = value_of(b);
return tarval_bad;
}
+/**
+ * return the value of a Proj(Cmp)
+ *
+ * This performs a first step of unreachable code elimination.
+ * Proj can not be computed, but folding a Cmp above the Proj here is
+ * not as wasteful as folding a Cmp into a Tuple of 16 Consts of which
+ * only 1 is used.
+ * There are several case where we can evaluate a Cmp node, see later.
+ */
+static tarval *computed_value_Proj_Cmp(ir_node *n)
+{
+ ir_node *a = get_Proj_pred(n);
+ ir_node *aa = get_Cmp_left(a);
+ ir_node *ab = get_Cmp_right(a);
+ long proj_nr = get_Proj_proj(n);
+
+ /*
+ * BEWARE: a == a is NOT always True for floating Point values, as
+ * NaN != NaN is defined, so we must check this here.
+ */
+ if (aa == ab && (
+ !mode_is_float(get_irn_mode(aa)) || proj_nr == pn_Cmp_Lt || proj_nr == pn_Cmp_Gt)
+ ) { /* 1.: */
+
+ /* 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 == pn_Cmp_Eq, mode_b) */
+ return new_tarval_from_long (proj_nr & pn_Cmp_Eq, mode_b);
+ }
+ else {
+ tarval *taa = value_of(aa);
+ tarval *tab = value_of(ab);
+ ir_mode *mode = get_irn_mode(aa);
+
+ /*
+ * The predecessors of Cmp are target values. We can evaluate
+ * the Cmp.
+ */
+ if ((taa != tarval_bad) && (tab != tarval_bad)) {
+ /* strange checks... */
+ pn_Cmp flags = tarval_cmp(taa, tab);
+ if (flags != pn_Cmp_False) {
+ return new_tarval_from_long (proj_nr & flags, mode_b);
+ }
+ }
+ /* for integer values, we can check against MIN/MAX */
+ else if (mode_is_int(mode)) {
+ /* MIN <=/> x. This results in true/false. */
+ if (taa == get_mode_min(mode)) {
+ /* a compare with the MIN value */
+ if (proj_nr == pn_Cmp_Le)
+ return get_tarval_b_true();
+ else if (proj_nr == pn_Cmp_Gt)
+ return get_tarval_b_false();
+ }
+ /* x >=/< MIN. This results in true/false. */
+ else
+ if (tab == get_mode_min(mode)) {
+ /* a compare with the MIN value */
+ if (proj_nr == pn_Cmp_Ge)
+ return get_tarval_b_true();
+ else if (proj_nr == pn_Cmp_Lt)
+ return get_tarval_b_false();
+ }
+ /* MAX >=/< x. This results in true/false. */
+ else if (taa == get_mode_max(mode)) {
+ if (proj_nr == pn_Cmp_Ge)
+ return get_tarval_b_true();
+ else if (proj_nr == pn_Cmp_Lt)
+ return get_tarval_b_false();
+ }
+ /* x <=/> MAX. This results in true/false. */
+ else if (tab == get_mode_max(mode)) {
+ if (proj_nr == pn_Cmp_Le)
+ return get_tarval_b_true();
+ else if (proj_nr == pn_Cmp_Gt)
+ return get_tarval_b_false();
+ }
+ }
+ /*
+ * The predecessors are Allocs or (void*)(0) constants. Allocs never
+ * return NULL, they raise an exception. Therefore we can predict
+ * the Cmp result.
+ */
+ else {
+ ir_node *aaa = skip_Id(skip_Proj(aa));
+ ir_node *aba = skip_Id(skip_Proj(ab));
+
+ if ( ( (/* aa is ProjP and aaa is Alloc */
+ (get_irn_op(aa) == op_Proj)
+ && (mode_is_reference(get_irn_mode(aa)))
+ && (get_irn_op(aaa) == op_Alloc))
+ && ( (/* ab is NULL */
+ (get_irn_op(ab) == op_Const)
+ && (mode_is_reference(get_irn_mode(ab)))
+ && (get_Const_tarval(ab) == get_mode_null(get_irn_mode(ab))))
+ || (/* ab is other Alloc */
+ (get_irn_op(ab) == op_Proj)
+ && (mode_is_reference(get_irn_mode(ab)))
+ && (get_irn_op(aba) == op_Alloc)
+ && (aaa != aba))))
+ || (/* aa is NULL and aba is Alloc */
+ (get_irn_op(aa) == op_Const)
+ && (mode_is_reference(get_irn_mode(aa)))
+ && (get_Const_tarval(aa) == get_mode_null(get_irn_mode(aa)))
+ && (get_irn_op(ab) == op_Proj)
+ && (mode_is_reference(get_irn_mode(ab)))
+ && (get_irn_op(aba) == op_Alloc)))
+ /* 3.: */
+ return new_tarval_from_long(proj_nr & pn_Cmp_Ne, mode_b);
+ }
+ }
+ return tarval_bad;
+}
+
/**
* return the value of a Proj, handle Proj(Cmp), Proj(Div), Proj(Mod), Proj(DivMod)
*/
static tarval *computed_value_Proj(ir_node *n)
{
ir_node *a = get_Proj_pred(n);
- ir_node *aa, *ab;
long proj_nr;
- /* Optimize Cmp nodes.
- This performs a first step of unreachable code elimination.
- Proj can not be computed, but folding a Cmp above the Proj here is
- not as wasteful as folding a Cmp into a Tuple of 16 Consts of which
- only 1 is used.
- There are several case where we can evaluate a Cmp node:
- 1. The nodes compared are both the same. If we compare for
- equal, greater equal, ... this will return true, else it
- will return false. This step relies on cse.
- 2. The predecessors of Cmp are target values. We can evaluate
- the Cmp.
- 3. The predecessors are Allocs or void* constants. Allocs never
- return NULL, they raise an exception. Therefore we can predict
- the Cmp result. */
switch (get_irn_opcode(a)) {
case iro_Cmp:
- aa = get_Cmp_left(a);
- ab = get_Cmp_right(a);
- proj_nr = get_Proj_proj(n);
-
- if (aa == ab && !mode_is_float(get_irn_mode(aa))) { /* 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);
- } else {
- 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) {
- return new_tarval_from_long (proj_nr & flags, mode_b);
- }
- } else { /* check for 3.: */
- ir_node *aaa = skip_Id(skip_Proj(aa));
- ir_node *aba = skip_Id(skip_Proj(ab));
-
- if ( ( (/* aa is ProjP and aaa is Alloc */
- (get_irn_op(aa) == op_Proj)
- && (mode_is_reference(get_irn_mode(aa)))
- && (get_irn_op(aaa) == op_Alloc))
- && ( (/* ab is constant void */
- (get_irn_op(ab) == op_Const)
- && (mode_is_reference(get_irn_mode(ab)))
- && (get_Const_tarval(ab) == get_mode_null(get_irn_mode(ab))))
- || (/* ab is other Alloc */
- (get_irn_op(ab) == op_Proj)
- && (mode_is_reference(get_irn_mode(ab)))
- && (get_irn_op(aba) == op_Alloc)
- && (aaa != aba))))
- || (/* aa is void and aba is Alloc */
- (get_irn_op(aa) == op_Const)
- && (mode_is_reference(get_irn_mode(aa)))
- && (get_Const_tarval(aa) == get_mode_null(get_irn_mode(aa)))
- && (get_irn_op(ab) == op_Proj)
- && (mode_is_reference(get_irn_mode(ab)))
- && (get_irn_op(aba) == op_Alloc)))
- /* 3.: */
- return new_tarval_from_long (proj_nr & Ne, mode_b);
- }
- }
- break;
+ return computed_value_Proj_Cmp(n);
case iro_DivMod:
/* compute either the Div or the Mod part */
}
#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. */
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) {
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. */
static ir_node *equivalent_node_Cond(ir_node *n)
{
/* We do not evaluate Cond here as we replace it by a new node, a Jmp.
- See cases for iro_Cond and iro_Proj in transform_node. */
+ See cases for iro_Cond and iro_Proj in transform_node(). */
return n;
}
#define equivalent_node_Rot equivalent_node_left_zero
/**
- * Er, a "symmetic unop", ie op(op(n)) = n.
+ * Optimize an "idempotent unary op", 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)
+static ir_node *equivalent_node_idempotent_unop(ir_node *n)
{
ir_node *oldn = n;
ir_node *pred = get_unop_op(n);
return n;
}
-/* NotNot x == x */
-#define equivalent_node_Not equivalent_node_symmetric_unop
+/* Not(Not(x)) == x */
+#define equivalent_node_Not equivalent_node_idempotent_unop
/* --x == x */ /* ??? Is this possible or can --x raise an
out of bounds exception if min =! max? */
-#define equivalent_node_Minus equivalent_node_symmetric_unop
+#define equivalent_node_Minus equivalent_node_idempotent_unop
/**
* Optimize a * 1 = 1 * a = a.
}
/**
- * Try to remove useless conv's:
+ * Try to remove useless Conv's:
*/
static ir_node *equivalent_node_Conv(ir_node *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);
}
}
}
/**
* A Cast may be removed if the type of the previous node
- * is already to type of the Cast.
+ * is already the type of the Cast.
*/
static ir_node *equivalent_node_Cast(ir_node *n) {
ir_node *pred = get_Cast_op(n);
*/
static ir_node *equivalent_node_Mux(ir_node *n)
{
- ir_node *sel = get_Mux_sel(n);
+ ir_node *oldn = n, *sel = get_Mux_sel(n);
tarval *ts = value_of(sel);
- if (ts == get_tarval_b_true())
- return get_Mux_true(n);
- else if (ts == get_tarval_b_false())
- return get_Mux_false(n);
- else if(get_Mux_false(n) == get_Mux_true(n))
- return get_Mux_true(n);
+ /* 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(Proj);
CASE(Id);
CASE(Mux);
+ CASE(Cmp);
default:
op->equivalent_node = NULL;
}
/**
* Transform AddP(P, ConvIs(Iu)), AddP(P, ConvIu(Is)) and
- * SubP(P, ConvIs(Iu)), SubP(P, ConvIu(Is)) if possible.
+ * SubP(P, ConvIs(Iu)), SubP(P, ConvIu(Is)).
+ * If possible, remove the Conv's.
*/
static ir_node *transform_node_AddSub(ir_node *n)
{
return n;
}
-#define transform_node_Add transform_node_AddSub
-
/**
- * Do the AddSub optimization, then Transform Sub(0,a) into Minus(a).
+ * Do the AddSub optimization, then Transform Add(a,a) into Mul(a, 2)
+ * if the mode is integer or float.
+ * Transform Add(a,-b) into Sub(a,b).
+ * Reassociation might fold this further.
*/
-static ir_node *transform_node_Sub(ir_node *n)
+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)) {
- if (classify_Const(get_Sub_left(n)) == CNST_NULL) {
- n = new_rd_Minus(
+ 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);
+ }
+ else {
+ ir_node *b = get_Add_right(n);
+
+ if (get_irn_op(a) == op_Minus) {
+ n = new_rd_Sub(
get_irn_dbg_info(n),
current_ir_graph,
get_nodes_block(n),
- get_Sub_right(n),
+ b,
+ get_Minus_op(a),
mode);
+ DBG_OPT_ALGSIM0(oldn, n);
+ }
+ else if (get_irn_op(b) == op_Minus) {
+ n = new_rd_Sub(
+ get_irn_dbg_info(n),
+ current_ir_graph,
+ get_nodes_block(n),
+ a,
+ get_Minus_op(b),
+ 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 */
+/**
+ Transform Mul(a,-1) into -a.
+ * Do architecture dependend optimizations on Mul nodes
+ */
static ir_node *transform_node_Mul(ir_node *n) {
+ ir_node *oldn = n;
+ ir_mode *mode = get_irn_mode(n);
+
+ if (mode_is_signed(mode)) {
+ ir_node *r = NULL;
+ ir_node *a = get_Mul_left(n);
+ ir_node *b = get_Mul_right(n);
+
+ if (value_of(a) == get_mode_minus_one(mode))
+ r = b;
+ else if (value_of(b) == get_mode_minus_one(mode))
+ r = a;
+ if (r) {
+ n = new_rd_Minus(get_irn_dbg_info(n), current_ir_graph, get_nodes_block(n), r, mode);
+ DBG_OPT_ALGSIM1(oldn, a, b, n);
+ return n;
+ }
+ }
return arch_dep_replace_mul_with_shifts(n);
}
+/**
+ * transform a Div Node
+ */
static ir_node *transform_node_Div(ir_node *n)
{
tarval *tv = value_of(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);
- else /* Try architecture dependand optimization */
+
+ DBG_OPT_CSTEVAL(n, value);
+ }
+ else /* Try architecture dependend optimization */
value = arch_dep_replace_div_by_const(n);
if (value != n) {
return n;
}
+/**
+ * transform a Mod node
+ */
static ir_node *transform_node_Mod(ir_node *n)
{
tarval *tv = value_of(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);
- else /* Try architecture dependand optimization */
+
+ DBG_OPT_CSTEVAL(n, value);
+ }
+ else /* Try architecture dependend optimization */
value = arch_dep_replace_mod_by_const(n);
if (value != n) {
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 */
+ else { /* Try architecture dependend optimization */
arch_dep_replace_divmod_by_const(&a, &b, n);
evaluated = a != NULL;
}
return n;
}
+
+/**
+ * Optimize Abs(x) => x if x is Confirmed >= 0
+ * Optimize Abs(x) => -x if x is Confirmed <= 0
+ */
+static ir_node *transform_node_Abs(ir_node *n)
+{
+ ir_node *oldn = n;
+ ir_node *a = get_Abs_op(n);
+ tarval *tv, *c;
+ ir_mode *mode;
+ pn_Cmp cmp, ncmp;
+ int do_minus = 0;
+
+ if (get_irn_op(a) != op_Confirm)
+ return n;
+
+ tv = value_of(get_Confirm_bound(n));
+ if (tv == tarval_bad)
+ return n;
+
+ mode = get_irn_mode(n);
+
+ /*
+ * We can handle only >=, >, <, <= cases.
+ * We could handle == too, but this should not happen.
+ *
+ * Note that for integer modes we have a slightly better
+ * optimization possibilities, so we handle this
+ * different.
+ */
+ cmp = get_Confirm_cmp(n);
+
+ switch (cmp) {
+ case pn_Cmp_Lt:
+ /*
+ * must be x < c <= 1 to be useful if integer mode and -0 = 0
+ * x < c <= 0 to be useful else
+ */
+ case pn_Cmp_Le:
+ /*
+ * must be x <= c < 1 to be useful if integer mode and -0 = 0
+ * x <= c < 0 to be useful else
+ */
+ c = mode_is_int(mode) && mode_honor_signed_zeros(mode) ?
+ get_mode_one(mode) : get_mode_null(mode);
+
+ ncmp = tarval_cmp(tv, c) ^ pn_Cmp_Eq;
+ if (cmp != ncmp)
+ return n;
+
+ /* yep, we can replace by -x */
+ do_minus = 1;
+ break;
+
+ case pn_Cmp_Ge:
+ /*
+ * must be x >= c > -1 to be useful if integer mode
+ * x >= c >= 0 to be useful else
+ */
+ case pn_Cmp_Gt:
+ /*
+ * must be x > c >= -1 to be useful if integer mode
+ * x > c >= 0 to be useful else
+ */
+ if (mode_is_int(mode)) {
+ c = get_mode_minus_one(mode);
+
+ ncmp = tarval_cmp(tv, c) ^ pn_Cmp_Eq;
+ if (cmp != ncmp)
+ return n;
+ }
+ else {
+ c = get_mode_minus_one(mode);
+
+ ncmp = tarval_cmp(tv, c);
+
+ if (ncmp != pn_Cmp_Eq && ncmp != pn_Cmp_Gt)
+ return n;
+ }
+
+ /* yep, we can replace by x */
+ do_minus = 0;
+ break;
+
+ default:
+ return n;
+ }
+
+ /*
+ * Ok, when we get here, we can replace the Abs
+ * by either x or -x. In the second case we eve could
+ * add a new Confirm.
+ *
+ * Note that -x would create a new node, so we could
+ * not run it in the equivalent_node() context.
+ */
+ if (do_minus) {
+ ir_node *c;
+
+ n = new_rd_Minus(get_irn_dbg_info(n), current_ir_graph,
+ get_nodes_block(n), a, mode);
+
+ c = new_Const(mode, tarval_neg(tv));
+ n = new_r_Confirm(current_ir_graph, get_nodes_block(n), n, c, get_inversed_pnc(cmp));
+ }
+ else {
+ n = a;
+ }
+
+ 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
*/
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);
+ ir_mode *mode = get_irn_mode(n);
- if ((get_irn_mode(n) == mode_b)
+ if (a == b) {
+ /* a ^ a = 0 */
+ n = new_rd_Const(get_irn_dbg_info(n), current_ir_graph, get_nodes_block(n),
+ mode, get_mode_null(mode));
+ DBG_OPT_ALGSIM0(oldn, n);
+ }
+ else if ((mode == mode_b)
&& (get_irn_op(a) == op_Proj)
&& (get_irn_mode(a) == mode_b)
&& (classify_tarval (value_of(b)) == TV_CLASSIFY_ONE)
- && (get_irn_op(get_Proj_pred(a)) == op_Cmp))
+ && (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)));
- else if ((get_irn_mode(n) == mode_b)
- && (classify_tarval (value_of(b)) == TV_CLASSIFY_ONE))
+
+ DBG_OPT_ALGSIM0(oldn, n);
+ }
+ else if ((mode == mode_b)
+ && (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(pred);
+ 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 it creates new
- * nodes.
+ * Transform a Proj(Div) 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.
*/
-static ir_node *transform_node_Proj(ir_node *proj)
+static ir_node *transform_node_Proj_Div(ir_node *proj)
{
ir_node *n = get_Proj_pred(proj);
ir_node *b;
tarval *tb;
long proj_nr;
- switch (get_irn_opcode(n)) {
- case iro_Div:
- b = get_Div_right(n);
- tb = value_of(b);
+ b = get_Div_right(n);
+ 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);
+ 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);
+ /* 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 */
- ir_node *res = get_Div_mem(n);
- set_Div_mem(n, get_irg_no_mem(current_ir_graph));
- if (proj_nr == pn_Div_M)
- return res;
- }
+ if (proj_nr == pn_Div_X_except) {
+ /* we found an exception handler, remove it */
+ return new_Bad();
+ } else {
+ /* the memory Proj can be removed */
+ ir_node *res = get_Div_mem(n);
+ 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 = value_of(b);
+ }
+ return proj;
+}
+
+/**
+ * Transform a Proj(Mod) with a non-zero constant.
+ * Removes the exceptions and routes the memory to the NoMem node.
+ */
+static ir_node *transform_node_Proj_Mod(ir_node *proj)
+{
+ ir_node *n = get_Proj_pred(proj);
+ ir_node *b;
+ tarval *tb;
+ long proj_nr;
- if (tb != tarval_bad && classify_tarval(tb) != TV_CLASSIFY_NULL) { /* mod(x, c) && c != 0 */
- proj_nr = get_Proj_proj(proj);
+ b = get_Mod_right(n);
+ tb = value_of(b);
- /* this node may float */
- set_irn_pinned(n, op_pin_state_floats);
+ if (tb != tarval_bad && classify_tarval(tb) != TV_CLASSIFY_NULL) {
+ /* mod(x, c) && c != 0 */
+ proj_nr = get_Proj_proj(proj);
- if (proj_nr == pn_Mod_X_except) {
- /* we found an exception handler, remove it */
- return new_Bad();
- } else {
- /* the memory Proj can be removed */
- ir_node *res = get_Mod_mem(n);
- set_Mod_mem(n, get_irg_no_mem(current_ir_graph));
- if (proj_nr == pn_Mod_M)
- return res;
- }
+ /* 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 */
+ ir_node *res = get_Mod_mem(n);
+ set_Mod_mem(n, get_irg_no_mem(current_ir_graph));
+ if (proj_nr == pn_Mod_M)
+ return res;
}
- break;
- case iro_DivMod:
- b = get_DivMod_right(n);
- tb = value_of(b);
+ }
+ return proj;
+}
+
+/**
+ * Transform a Proj(DivMod) with a non-zero constant.
+ * Removes the exceptions and routes the memory to the NoMem node.
+ */
+static ir_node *transform_node_Proj_DivMod(ir_node *proj)
+{
+ ir_node *n = get_Proj_pred(proj);
+ ir_node *b;
+ tarval *tb;
+ long proj_nr;
- if (tb != tarval_bad && classify_tarval(tb) != TV_CLASSIFY_NULL) { /* DivMod(x, c) && c != 0 */
- proj_nr = get_Proj_proj(proj);
+ b = get_DivMod_right(n);
+ tb = value_of(b);
- /* this node may float */
- set_irn_pinned(n, op_pin_state_floats);
+ if (tb != tarval_bad && classify_tarval(tb) != TV_CLASSIFY_NULL) {
+ /* DivMod(x, c) && c != 0 */
+ proj_nr = get_Proj_proj(proj);
- if (proj_nr == pn_DivMod_X_except) {
- /* we found an exception handler, remove it */
- return new_Bad();
- }
- else {
- /* the memory Proj can be removed */
- ir_node *res = get_DivMod_mem(n);
- set_DivMod_mem(n, get_irg_no_mem(current_ir_graph));
- if (proj_nr == pn_DivMod_M)
- return res;
+ /* 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 */
+ ir_node *res = get_DivMod_mem(n);
+ set_DivMod_mem(n, get_irg_no_mem(current_ir_graph));
+ if (proj_nr == pn_DivMod_M)
+ return res;
+ }
+ }
+ return proj;
+}
+
+/**
+ * Optimizes jump tables (CondIs or CondIu) by removing all impossible cases.
+ */
+static ir_node *transform_node_Proj_Cond(ir_node *proj)
+{
+ if (get_opt_unreachable_code()) {
+ ir_node *n = get_Proj_pred(proj);
+ ir_node *b = get_Cond_selector(n);
+ tarval *tb = value_of(b);
+
+ if (tb != tarval_bad && mode_is_int(get_tarval_mode(tb))) {
+ /* we have a constant switch */
+ long num = get_Proj_proj(proj);
+
+ if (num != get_Cond_defaultProj(n)) { /* we cannot optimize default Proj's yet */
+ if (get_tarval_long(tb) == num) {
+ /* Do NOT create a jump here, or we will have 2 control flow ops
+ * in a block. This case is optimized away in optimize_cf(). */
+ return proj;
+ }
+ else {
+ /* this case will NEVER be taken, kill it */
+ return new_Bad();
+ }
}
}
- break;
+ }
+ return proj;
+}
- case iro_Cond:
- if (get_opt_unreachable_code()) {
- b = get_Cond_selector(n);
- tb = value_of(b);
-
- if (tb != tarval_bad && mode_is_int(get_tarval_mode(tb))) {
- /* we have a constant switch */
- long num = get_Proj_proj(proj);
-
- if (num != get_Cond_defaultProj(n)) { /* we cannot optimize default Proj's yet */
- if (get_tarval_long(tb) == num) {
- /* Do NOT create a jump here, or we will have 2 control flow ops
- * in a block. This case is optimized away in optimize_cf(). */
- return proj;
- }
- else
- return new_Bad();
+/**
+ * Normalizes and optimizes Cmp nodes.
+ */
+static ir_node *transform_node_Proj_Cmp(ir_node *proj)
+{
+ if (get_opt_reassociation()) {
+ ir_node *n = get_Proj_pred(proj);
+ 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;
+ long 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
+ * this case 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_inversed_pnc(proj_nr);
+ changed |= 1;
+ }
+ else if (left > right) {
+ ir_node *t = left;
+
+ left = right;
+ right = t;
+
+ proj_nr = get_inversed_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 possible 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_mode_null(mode), tv);
+
+ proj_nr = get_inversed_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_mode_null(mode)) == pn_Cmp_Gt) {
+ tv = tarval_sub(tv, get_mode_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_mode_null(mode)) == pn_Cmp_Lt) {
+ tv = tarval_add(tv, get_mode_one(mode));
+
+ proj_nr ^= pn_Cmp_Eq;
+ changed |= 2;
+ }
+
+ /* the following reassociations work only for == and != */
+ if (proj_nr == pn_Cmp_Eq || proj_nr == pn_Cmp_Lg) {
+
+ /* a-b == 0 ==> a == b, a-b != 0 ==> a != b */
+ if (classify_tarval(tv) == TV_CLASSIFY_NULL && get_irn_op(left) == op_Sub) {
+ right = get_Sub_right(left);
+ left = get_Sub_left(left);
+
+ tv = value_of(right);
+ changed = 1;
+ }
+
+ if (tv != tarval_bad) {
+ 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;
+ }
+ }
+ }
+ /* -a == c ==> a == -c, -a != c ==> a != -c */
+ else if (op == op_Minus) {
+ tarval *tv2 = tarval_sub(get_mode_null(mode), tv);
+
+ if (tv2 != tarval_bad) {
+ left = get_Minus_op(left);
+ tv = tv2;
+ changed |= 2;
+ }
+ }
+ }
+ } /* == or != */
+ /* the following reassociations work only for <= */
+ else if (proj_nr == pn_Cmp_Le || proj_nr == pn_Cmp_Lt) {
+ if (tv != tarval_bad) {
+ ir_op *op = get_irn_op(left);
+
+ /* c >= 0 : Abs(a) <= c ==> (unsigned)(a + c) <= 2*c */
+ if (op == op_Abs) {
+ }
+ }
+ }
+ } /* mode_is_int */
}
}
- return proj;
+
+ 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;
+}
+
+/**
+ * Does all optimizations on nodes that must be done on it's Proj's
+ * because of creating new nodes.
+ */
+static ir_node *transform_node_Proj(ir_node *proj)
+{
+ ir_node *n = get_Proj_pred(proj);
+
+ switch (get_irn_opcode(n)) {
+ case iro_Div:
+ return transform_node_Proj_Div(proj);
+
+ case iro_Mod:
+ return transform_node_Proj_Mod(proj);
+
+ case iro_DivMod:
+ return transform_node_Proj_DivMod(proj);
+
+ case iro_Cond:
+ return transform_node_Proj_Cond(proj);
+
+ case iro_Cmp:
+ return transform_node_Proj_Cmp(proj);
case iro_Tuple:
/* should not happen, but if it does will be optimized away */
- break;
+ return equivalent_node_Proj(proj);
default:
/* do nothing */
return proj;
}
-
- /* we have added a Tuple, optimize it for the current Proj away */
- return equivalent_node_Proj(proj);
}
/**
{
ir_mode *mode = get_irn_mode(or);
ir_node *shl, *shr, *block;
- ir_node *irn, *x, *c1, *c2, *v, *sub;
+ ir_node *irn, *x, *c1, *c2, *v, *sub, *n;
tarval *tv1, *tv2;
if (! mode_is_int(mode))
/* yet, condition met */
block = get_nodes_block(or);
- return new_r_Rot(current_ir_graph, block, x, c1, mode);
+ 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;
block = get_nodes_block(or);
/* a Rot right is not supported, so use a rot left */
- return new_r_Rot(current_ir_graph, block, x, sub, mode);
+ 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;
block = get_nodes_block(or);
/* a Rot Left */
- return new_r_Rot(current_ir_graph, block, x, v, mode);
+ n = new_r_Rot(current_ir_graph, block, x, v, mode);
+
+ DBG_OPT_ALGSIM0(or, n);
+ return n;
}
return or;
/**
* Optimize (a >> c1) >> c2), works for Shr, Shrs, Shl
*/
-static ir_node * transform_node_shift(ir_node *n)
+static ir_node *transform_node_shift(ir_node *n)
{
- ir_node *left;
+ ir_node *left, *right;
tarval *tv1, *tv2, *res;
ir_mode *mode;
int modulo_shf, flag;
if (get_irn_op(left) != get_irn_op(n))
return n;
- tv1 = value_of(get_binop_right(n));
+ right = get_binop_right(n);
+ tv1 = value_of(right);
if (tv1 == tarval_bad)
return n;
if (modulo_shf > 0) {
tarval *modulo = new_tarval_from_long(modulo_shf, get_tarval_mode(res));
- if (tarval_cmp(res, modulo) & Lt)
+ if (tarval_cmp(res, modulo) & pn_Cmp_Lt)
flag = 1;
}
else
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;
}
-static ir_node * transform_node_End(ir_node *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);
- /* Remove dead blocks in keepalive list.
- We do not generate a new End node. */
for (i = 0; i < n_keepalives; ++i) {
ir_node *ka = get_End_keepalive(n, i);
if (is_Block(ka) && is_Block_dead(ka))
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);
+}
/**
* Tries several [inplace] [optimizing] transformations and returns an
CASE(Div);
CASE(Mod);
CASE(DivMod);
+ CASE(Abs);
CASE(Cond);
CASE(Eor);
CASE(Not);
CASE(Cast);
CASE(Proj);
+ CASE(Sel);
CASE(Or);
+ CASE(Shr);
+ CASE(Shrs);
+ CASE(Shl);
CASE(End);
- case iro_Shr:
- case iro_Shrs:
- case iro_Shl:
- op->transform_node = transform_node_shift;
- break;
+ CASE(Mux);
default:
- op->transform_node = NULL;
+ op->transform_node = NULL;
}
return op;
/** 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
+ 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);
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);
+ (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. */
+ 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);
+ n = identify_remember (current_ir_graph->value_table, 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;
}