+
+ default: break;
+ } /* end switch */
+}
+
+/**
+ * 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 = 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) {
+ value = new_Const(get_tarval_mode(tv), tv);
+
+ DBG_OPT_CSTEVAL(n, value);
+ }
+ else /* Try architecture dependand optimization */
+ value = arch_dep_replace_div_by_const(n);
+
+ if (value != n) {
+ /* Turn Div into a tuple (mem, bad, value) */
+ ir_node *mem = get_Div_mem(n);
+
+ turn_into_tuple(n, 3);
+ set_Tuple_pred(n, pn_Div_M, mem);
+ set_Tuple_pred(n, pn_Div_X_except, new_Bad());
+ set_Tuple_pred(n, pn_Div_res, value);
+ }
+ return n;
+}
+
+/**
+ * transform a Mod node
+ */
+static ir_node *transform_node_Mod(ir_node *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) {
+ value = new_Const(get_tarval_mode(tv), tv);
+
+ DBG_OPT_CSTEVAL(n, value);
+ }
+ else /* Try architecture dependand optimization */
+ value = arch_dep_replace_mod_by_const(n);
+
+ if (value != n) {
+ /* Turn Mod into a tuple (mem, bad, value) */
+ ir_node *mem = get_Mod_mem(n);
+
+ turn_into_tuple(n, 3);
+ set_Tuple_pred(n, pn_Mod_M, mem);
+ set_Tuple_pred(n, pn_Mod_X_except, new_Bad());
+ set_Tuple_pred(n, pn_Mod_res, value);
+ }
+ return n;
+}
+
+/**
+ * transform a DivMod node
+ */
+static ir_node *transform_node_DivMod(ir_node *n)
+{
+ int evaluated = 0;
+
+ ir_node *a = get_DivMod_left(n);
+ ir_node *b = get_DivMod_right(n);
+ ir_mode *mode = get_irn_mode(a);
+ tarval *ta = value_of(a);
+ tarval *tb = value_of(b);
+
+ if (!(mode_is_int(mode) && mode_is_int(get_irn_mode(b))))
+ return n;
+
+ /* BEWARE: it is NOT possible to optimize a/a to 1, as this may cause a exception */
+
+ if (tb != tarval_bad) {
+ if (tb == get_mode_one(get_tarval_mode(tb))) {
+ b = new_Const (mode, get_mode_null(mode));
+ evaluated = 1;
+
+ 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
+ Jmp for X result!? */
+ resb = tarval_mod (ta, tb);
+ if (resb == tarval_bad) return n; /* Causes exception! */
+ 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_by_const(&a, &b, n);
+ evaluated = a != NULL;
+ }
+ } else if (ta == get_mode_null(mode)) {
+ /* 0 / non-Const = 0 */
+ b = a;
+ evaluated = 1;
+ }
+
+ if (evaluated) { /* replace by tuple */
+ ir_node *mem = get_DivMod_mem(n);
+ turn_into_tuple(n, 4);
+ set_Tuple_pred(n, pn_DivMod_M, mem);
+ set_Tuple_pred(n, pn_DivMod_X_except, new_Bad()); /* no exception */
+ set_Tuple_pred(n, pn_DivMod_res_div, a);
+ set_Tuple_pred(n, pn_DivMod_res_mod, b);
+ assert(get_nodes_block(n));
+ }
+
+ 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
+ condition. */
+ ir_node *jmp;
+ ir_node *a = get_Cond_selector(n);
+ tarval *ta = value_of(a);
+
+ if ((ta != tarval_bad) &&
+ (get_irn_mode(a) == mode_b) &&
+ (get_opt_unreachable_code())) {
+ /* It's a boolean Cond, branching on a boolean constant.
+ Replace it by a tuple (Bad, Jmp) or (Jmp, Bad) */
+ jmp = new_r_Jmp(current_ir_graph, get_nodes_block(n));
+ turn_into_tuple(n, 2);
+ if (ta == tarval_b_true) {
+ set_Tuple_pred(n, pn_Cond_false, new_Bad());
+ set_Tuple_pred(n, pn_Cond_true, jmp);
+ } else {
+ set_Tuple_pred(n, pn_Cond_false, jmp);
+ set_Tuple_pred(n, pn_Cond_true, new_Bad());
+ }
+ /* We might generate an endless loop, so keep it alive. */
+ add_End_keepalive(get_irg_end(current_ir_graph), get_nodes_block(n));
+ } else if ((ta != tarval_bad) &&
+ (get_irn_mode(a) == mode_Iu) &&
+ (get_Cond_kind(n) == dense) &&
+ (get_opt_unreachable_code())) {
+ /* I don't want to allow Tuples smaller than the biggest Proj.
+ Also this tuple might get really big...
+ 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)));
+ /* We might generate an endless loop, so keep it alive. */
+ 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(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),
+ get_Eor_left(a)));
+ } else if ((get_irn_op(a) == op_Not)
+ && (get_irn_mode(a) == 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)));
+ }
+ 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 (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 (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;
+}
+
+/**
+ * Transform a boolean Not.
+ */
+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)) {
+ /* 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;
+}
+
+/**
+ * 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.
+ *
+ * Optimizes jump tables by removing all impossible cases.
+ *
+ * Normalizes and optimizes Cmp nodes.
+ */
+static ir_node *transform_node_Proj(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);
+
+ 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 */
+ 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;
+ }