** iropt --- optimizations intertwined with IR construction.
*/
-# include "iropt.h"
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+# include "irnode_t.h"
+# include "irgraph_t.h"
+# include "iropt_t.h"
# include "ircons.h"
# include "irgmod.h"
# include "irvrfy.h"
# include "tv.h"
+# include "tune.h"
+# include "debinfo.h"
/* Make types visible to allow most efficient access */
# include "entity_t.h"
return n;
}
-
static inline tarval *
value_of (ir_node *n)
{
return NULL;
}
-
/* if n can be computed, return the value, else NULL. Performs
- constant Folding. GL: Only if n is arithmetic operator? */
+ constant folding. GL: Only if n is arithmetic operator? */
tarval *
computed_value (ir_node *n)
{
case iro_Abs:
if (ta)
res = /*tarval_abs (ta);*/ res;
- /* allowded or problems with max/min ?? */
+ /* allowed or problems with max/min ?? */
break;
case iro_And:
if (ta && tb) {
}
break;
case iro_Eor: if (ta && tb) { res = tarval_eor (ta, tb); } break;
- case iro_Not: if(ta) { /*res = tarval_not (ta)*/; } break;
+ case iro_Not: if (ta) { /*res = tarval_not (ta)*/; } break;
case iro_Shl: if (ta && tb) { res = tarval_shl (ta, tb); } break;
case iro_Shr: if (ta && tb) { res = tarval_shr (ta, tb); } break;
case iro_Shrs: if(ta && tb) { /*res = tarval_shrs (ta, tb)*/; } break;
- case iro_Rot: if(ta && tb) { /*res = tarval_rot (ta, tb)*/; } break;
- case iro_Conv: if (ta) { res = tarval_convert_to (ta, get_irn_mode (n)); }
+ case iro_Rot: if (ta && tb) { /*res = tarval_rot (ta, tb)*/; } break;
+ case iro_Conv: if(ta) { res = tarval_convert_to (ta, get_irn_mode (n)); }
break;
case iro_Proj:
{
a = get_unop_op(n);
}
-
/* skip unnecessary nodes. */
switch (get_irn_opcode (n)) {
case iro_Block:
{
- /* The Block constructor does not call optimize, therefore
- dead blocks are not removed without an extra optimizing
- pass through the graph. */
+ /* The Block constructor does not call optimize, but mature_block
+ calls the optimization. */
assert(get_Block_matured(n));
- /* a single entry Region following a single exit Region can be merged */
+ /* A single entry Block following a single exit Block can be merged,
+ if it is not the Start block. */
/* !!! Beware, all Phi-nodes of n must have been optimized away.
- This is true, as the block is matured before optimize is called. */
+ 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? */
if (get_Block_n_cfgpreds(n) == 1
&& get_irn_op(get_Block_cfgpred(n, 0)) == op_Jmp) {
n = get_nodes_Block(get_Block_cfgpred(n, 0));
- } else if (n != current_ir_graph->start_block) {
- int i;
+ } else if ((n != current_ir_graph->start_block) &&
+ (n != current_ir_graph->end_block) ) {
+ int i;
/* If all inputs are dead, this block is dead too, except if it is
- the start block. This is a step of unreachable code elimination */
-
+ 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;
}
}
break;
- case iro_Jmp: /* GL: ??? Why not same for op_Raise?? */
+ case iro_Jmp: /* GL: Why not same for op_Raise?? */
/* unreachable code elimination */
if (is_Bad(get_nodes_Block(n))) n = new_Bad();
break;
- /* GL: Why isn't there a case that checks whether input ot Cond is
- constant true or false? For unreachable code elimination
- is this done in Proj? It's not here as it generates a new node,
- a Jmp. It is in transform_node. *
- case iro_Cond:
- break;
- */
- /* remove stuff as x+0, x*1 x&true ... constant expression evaluation */
+ /* 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. */
+ /** remove stuff as x+0, x*1 x&true ... constant expression evaluation **/
case iro_Or: if (a == b) {n = a; break;}
case iro_Add:
case iro_Eor:
themselves.
*/
int i, n_preds;
+
+
ir_node *block = NULL; /* to shutup gcc */
ir_node *first_val = NULL; /* to shutup gcc */
ir_node *scnd_val = NULL; /* to shutup gcc */
/* skip Id's */
set_Phi_pred(n, i, first_val);
if ( (first_val != n) /* not self pointer */
- && (get_irn_op(first_val) != op_Bad) /* value not dead */
+ && (get_irn_op(first_val) != op_Bad) /* value not dead */
&& !(is_Bad (get_Block_cfgpred(block, i))) ) { /* not dead control flow */
break; /* then found first value. */
}
}
- /* A totally Bad or self-referencing Phi */
- if (i > n_preds) { n = new_Bad(); break; }
+ /* A totally Bad or self-referencing Phi (we didn't break the above loop) */
+ if (i >= n_preds) { n = new_Bad(); break; }
scnd_val = NULL;
}
/* Fold, if no multiple distinct non-self-referencing inputs */
- if (i > n_preds) {
- n = a;
+ if (i >= n_preds) {
+ n = first_val;
} else {
/* skip the remaining Ids. */
- while (++i < n_preds)
+ while (++i < n_preds) {
set_Phi_pred(n, i, follow_Id(get_Phi_pred(n, i)));
+ }
}
}
break;
if ( get_Proj_proj(n) <= get_Tuple_n_preds(a) ) {
n = get_Tuple_pred(a, get_Proj_proj(n));
} else {
- assert(0); /* This should not happen?! (GL added this assert) */
+ assert(0); /* This should not happen! (GL added this assert) */
n = new_Bad();
}
} else if (get_irn_mode(n) == mode_X &&
/* Replace the Cond by a Jmp if it branches on a constant
condition. */
ir_node *jmp;
-
a = get_Cond_selector(n);
ta = value_of(a);
I generate the Jmp here, and remember it in link. Link is used
when optimizing Proj. */
set_irn_link(n, new_r_Jmp(current_ir_graph, get_nodes_Block(n)));
- } else if ( ((get_irn_op(get_Cond_selector(n)) == op_Eor)
- /* || (get_irn_op(get_Cond_selector(a)) == op_Not)*/)
+ } else if ( (get_irn_op(get_Cond_selector(n)) == op_Eor)
&& (get_irn_mode(get_Cond_selector(n)) == mode_b)
&& (tarval_classify(computed_value(get_Eor_right(a))) == 1)) {
/* 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),
get_Eor_left(a)));
+ } else if ( (get_irn_op(get_Cond_selector(n)) == op_Not)
+ && (get_irn_mode(get_Cond_selector(n)) == mode_b)) {
+ /* A Not before the Cond. Generate a new Cond without the Not,
+ simulate the Not by exchanging the results. */
+ set_irn_link(n, new_r_Cond(current_ir_graph, get_nodes_Block(n),
+ get_Not_op(a)));
}
}
break;
&& get_irn_op(get_irn_link(a)) == op_Cond) {
/* Use the better Cond if the Proj projs from a Cond which get's
its result from an Eor/Not. */
- assert ( ((get_irn_op(get_Cond_selector(a)) == op_Eor)
- /* || (get_irn_op(get_Cond_selector(a)) == op_Not)*/)
+ assert ( ( (get_irn_op(get_Cond_selector(a)) == op_Eor)
+ || (get_irn_op(get_Cond_selector(a)) == op_Not))
&& (get_irn_mode(get_Cond_selector(a)) == mode_b)
&& (get_irn_op(get_irn_link(a)) == op_Cond)
&& (get_Cond_selector(get_irn_link(a)) ==
n = new_r_Not(current_ir_graph, get_nodes_Block(n), a, mode_b);
}
break;
- case iro_Not: { /* @@@ not tested as boolean Eor not allowed any more. */
+ case iro_Not: {
a = get_Not_op(n);
if ( (get_irn_mode(n) == mode_b)
return n;
}
-/***************** Common Subexpression Elimination *****************/
+/* **************** Common Subexpression Elimination **************** */
/* Compare function for two nodes in the hash table. Gets two */
/* nodes as parameters. */
return (get_irn_symconst_attr(a).num != get_irn_symconst_attr(b).num)
|| (get_irn_symconst_attr(a).tori.typ != get_irn_symconst_attr(b).tori.typ);
case iro_Call:
- return (get_irn_call_attr(a)->kind != get_irn_call_attr(b)->kind)
- || (get_irn_call_attr(a)->arity != get_irn_call_attr(b)->arity);
+ return (get_irn_call_attr(a) != get_irn_call_attr(b));
case iro_Sel:
return (get_irn_sel_attr(a).ent->kind != get_irn_sel_attr(b).ent->kind)
|| (get_irn_sel_attr(a).ent->name != get_irn_sel_attr(b).ent->name)
if ( op != op_Block && op != op_Phi && op != op_Tuple) {
for (i = -1; i < get_irn_arity(node); i++) {
if (is_Bad(get_irn_n(node, i))) {
- node = new_Bad();
- break;
+ return new_Bad();
}
}
}
+#if 0
+ /* If Block has only Bads as predecessors it's garbage. */
+ /* If Phi has only Bads as predecessors it's garbage. */
+ if (op == op_Block || op == op_Phi) {
+ for (i = 0; i < get_irn_arity(node); i++) {
+ if (!is_Bad(get_irn_n(node, i))) break;
+ }
+ if (i = get_irn_arity(node)) node = new_Bad();
+ }
+#endif
return node;
}
tarval *tv;
ir_node *old_n = n;
+ /* Allways optimize Phi nodes: part of the construction. */
if ((!get_optimize()) && (get_irn_op(n) != op_Phi)) return n;
/* if not optimize return n */
/* evaluation was succesful -- replace the node. */
obstack_free (current_ir_graph->obst, n);
return new_Const (get_tv_mode (tv), tv);
- /* xprintf("* optimize: computed node %I\n", n->op->name); */
}
}
}
+
/* remove unnecessary nodes */
if (get_opt_constant_folding() || get_irn_op(n) == op_Phi)
n = equivalent_node (n);
/* The block input is used to distinguish different subexpressions. Right
now all nodes are pinned to blocks, i.e., the cse only finds common
subexpressions within a block. */
-
if (get_opt_cse())
n = identify (current_ir_graph->value_table, n);
-
/* identify found a cse, so deallocate the old node. */
if (n != old_n) {
obstack_free (current_ir_graph->obst, old_n);
/* Now we have a legal, useful node. Enter it in hash table for cse */
if (get_opt_cse()) {
- /* aborts ??! set/pset can not handle several hash tables??!
- No, suddenly it works. */
n = identify_remember (current_ir_graph->value_table, n);
}
ir_node *
optimize_in_place (ir_node *n)
{
-
tarval *tv;
ir_node *old_n = n;
+ if (!get_optimize()) return n;
+
/* if not optimize return n */
if (n == NULL) {
/* Here this is possible. Why? */
tv = computed_value (n);
if (tv != NULL) {
/* evaluation was succesful -- replace the node. */
- return new_Const (get_tv_mode (tv), tv);
+ n = new_Const (get_tv_mode (tv), tv);
+ deb_info_copy(n, old_n, id_from_str("const_eval", 10));
+ return n;
/* xprintf("* optimize: computed node %I\n", n->op->name);*/
}
}
}
+
/* remove unnecessary nodes */
+ /*if (get_opt_constant_folding()) */
if (get_opt_constant_folding() || get_irn_op(n) == op_Phi)
n = equivalent_node (n);
/* The block input is used to distinguish different subexpressions. Right
now all nodes are pinned to blocks, i.e., the cse only finds common
subexpressions within a block. */
-
if (get_opt_cse())
n = identify (current_ir_graph->value_table, n);
/* The AmRoq fiasco returns n here. Martin's version doesn't. */
}
-#if 0
/* Some more constant expression evaluation. */
if (get_opt_constant_folding())
n = transform_node (n);
-#endif
/* Remove nodes with dead (Bad) input. */
n = gigo (n);
/* Now we can verify the node, as it has no dead inputs any more. */
irn_vrfy(n);
- /* Now we have a legal, useful node. Enter it in hash table for cse */
- if (get_opt_cse()) {
- /* aborts ??! set/pset can not handle several hash tables??!
- No, suddenly it works. */
+ /* Now we have a legal, useful node. Enter it in hash table for cse.
+ Blocks should be unique anyways. (Except the successor of start:
+ is cse with the start block!) */
+ if (get_opt_cse() && (get_irn_opcode(n) != iro_Block))
n = identify_remember (current_ir_graph->value_table, n);
- }
return n;
}