# include "irhooks.h"
# include "irarch.h"
# include "hashptr.h"
+# include "archop.h"
# include "opt_polymorphy.h"
/* Make types visible to allow most efficient access */
*/
static tarval *computed_value_Const(ir_node *n)
{
- return get_Const_tarval(n);
+ return get_Const_tarval(n);
}
/**
ab = get_Cmp_right(a);
proj_nr = get_Proj_proj(n);
- if (aa == ab && !mode_is_float(get_irn_mode(aa))) { /* 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:
}
#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. */
/**
* 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)
{
/**
* 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);
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);
}
- else if(get_Mux_false(n) == get_Mux_true(n)) {
- n = get_Mux_true(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 even for floating point
+ * 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) {
+ 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);
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(
- get_irn_dbg_info(n),
- current_ir_graph,
- get_nodes_block(n),
- get_Sub_right(n),
- mode);
- DBG_OPT_ALGSIM0(oldn, 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;
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_SymConst_kind(pred), tp);
DBG_OPT_CSTEVAL(oldn, n);
}
+
return n;
}
*
* Optimizes jump tables by removing all impossible cases.
*
- * Normalizes Cmp nodes.
+ * Normalizes and optimizes Cmp nodes.
*/
static ir_node *transform_node_Proj(ir_node *proj)
{
tv = get_Const_tarval(c);
if (tv != tarval_bad) {
- /* the following optimization is possibe on non-int values either:
- * -a CMP c ==> a swap(CMP) -c */
- if (get_opt_constant_folding() && get_irn_op(left) == op_Minus) {
+ /* 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_one(mode), tv);
+ 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)
+ 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) &&
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);
- changed &= ~2;
+ 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;
+ }
+ }
}
}
}
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(Not);
CASE(Cast);
CASE(Proj);
+ CASE(Sel);
CASE(Or);
+ CASE(Shr);
+ CASE(Shrs);
+ CASE(Shl);
CASE(End);
- CASE(Sel);
- 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;