+ /* Remove unnecessary conversions */
+ /* TODO handle constants */
+ if (is_Conv(left) && is_Conv(right)) {
+ ir_mode *mode = get_irn_mode(left);
+ ir_node *op_left = get_Conv_op(left);
+ ir_node *op_right = get_Conv_op(right);
+ ir_mode *mode_left = get_irn_mode(op_left);
+ ir_mode *mode_right = get_irn_mode(op_right);
+
+ if (smaller_mode(mode_left, mode) && smaller_mode(mode_right, mode)) {
+ ir_graph *irg = current_ir_graph;
+ ir_node *block = get_nodes_block(n);
+
+ if (mode_left == mode_right) {
+ left = op_left;
+ right = op_right;
+ changed |= 1;
+ } else if (smaller_mode(mode_left, mode_right)) {
+ left = new_r_Conv(irg, block, op_left, mode_right);
+ right = op_right;
+ changed |= 1;
+ } else if (smaller_mode(mode_right, mode_left)) {
+ left = op_left;
+ right = new_r_Conv(irg, block, op_right, mode_left);
+ changed |= 1;
+ }
+ }
+ }
+
+ /* TODO extend to arbitrary constants */
+ if (is_Conv(left) && is_Const(right) && is_Const_null(right)) {
+ ir_mode* mode = get_irn_mode(left);
+ ir_node* op = get_Conv_op(left);
+ ir_mode* op_mode = get_irn_mode(op);
+
+ if (get_mode_size_bits(mode) > get_mode_size_bits(op_mode) &&
+ (mode_is_signed(mode) || !mode_is_signed(op_mode))) {
+ ir_node *null = new_Const(op_mode, get_mode_null(op_mode));
+ set_Cmp_left( n, op);
+ set_Cmp_right(n, null);
+ return proj;
+ }
+ }
+
+ /* remove Casts */
+ if (is_Cast(left))
+ left = get_Cast_op(left);
+ if (is_Cast(right))
+ right = get_Cast_op(right);
+
+ /* remove operation of both sides if possible */
+ if (proj_nr == pn_Cmp_Eq || proj_nr == pn_Cmp_Lg) {
+ ir_opcode lop = get_irn_opcode(left);
+
+ if (lop == get_irn_opcode(right)) {
+ ir_node *ll, *lr, *rl, *rr;
+
+ /* same operation on both sides, try to remove */
+ switch (lop) {
+ case iro_Not:
+ case iro_Minus:
+ /* ~a CMP ~b => a CMP b, -a CMP -b ==> a CMP b */
+ left = get_unop_op(left);
+ right = get_unop_op(right);
+ changed |= 1;
+ break;
+ case iro_Add:
+ ll = get_Add_left(left);
+ lr = get_Add_right(left);
+ rl = get_Add_left(right);
+ rr = get_Add_right(right);
+
+ if (ll == rl) {
+ /* X + a CMP X + b ==> a CMP b */
+ left = lr;
+ right = rr;
+ changed |= 1;
+ } else if (ll == rr) {
+ /* X + a CMP b + X ==> a CMP b */
+ left = lr;
+ right = rl;
+ changed |= 1;
+ } else if (lr == rl) {
+ /* a + X CMP X + b ==> a CMP b */
+ left = ll;
+ right = rr;
+ changed |= 1;
+ } else if (lr == rr) {
+ /* a + X CMP b + X ==> a CMP b */
+ left = ll;
+ right = rl;
+ changed |= 1;
+ }
+ break;
+ case iro_Sub:
+ ll = get_Sub_left(left);
+ lr = get_Sub_right(left);
+ rl = get_Sub_left(right);
+ rr = get_Sub_right(right);
+
+ if (ll == rl) {
+ /* X - a CMP X - b ==> a CMP b */
+ left = lr;
+ right = rr;
+ changed |= 1;
+ } else if (lr == rr) {
+ /* a - X CMP b - X ==> a CMP b */
+ left = ll;
+ right = rl;
+ changed |= 1;
+ }
+ break;
+ case iro_Rot:
+ if (get_Rot_right(left) == get_Rot_right(right)) {
+ /* a ROT X CMP b ROT X */
+ left = get_Rot_left(left);
+ right = get_Rot_left(right);
+ changed |= 1;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (get_irn_mode(left) == mode_b) {
+ ir_graph *irg = current_ir_graph;
+ ir_node *block = get_nodes_block(n);
+
+ switch (proj_nr) {
+ case pn_Cmp_Le: return new_r_Or( irg, block, new_r_Not(irg, block, left, mode_b), right, mode_b);
+ case pn_Cmp_Lt: return new_r_And(irg, block, new_r_Not(irg, block, left, mode_b), right, mode_b);
+ case pn_Cmp_Ge: return new_r_Or( irg, block, left, new_r_Not(irg, block, right, mode_b), mode_b);
+ case pn_Cmp_Gt: return new_r_And(irg, block, left, new_r_Not(irg, block, right, mode_b), mode_b);
+ case pn_Cmp_Lg: return new_r_Eor(irg, block, left, right, mode_b);
+ case pn_Cmp_Eq: return new_r_Not(irg, block, new_r_Eor(irg, block, left, right, mode_b), mode_b);
+ }
+ }
+