+/* Convert "if (m < 0) x = b; else x = 0;" to "x = (m >> C) & b;". */
+
+static int
+noce_try_sign_mask (struct noce_if_info *if_info)
+{
+ rtx cond, t, m, c, seq;
+ enum machine_mode mode;
+ enum rtx_code code;
+
+ if (no_new_pseudos)
+ return FALSE;
+
+ cond = if_info->cond;
+ code = GET_CODE (cond);
+ m = XEXP (cond, 0);
+ c = XEXP (cond, 1);
+
+ t = NULL_RTX;
+ if (if_info->a == const0_rtx)
+ {
+ if ((code == LT && c == const0_rtx)
+ || (code == LE && c == constm1_rtx))
+ t = if_info->b;
+ }
+ else if (if_info->b == const0_rtx)
+ {
+ if ((code == GE && c == const0_rtx)
+ || (code == GT && c == constm1_rtx))
+ t = if_info->a;
+ }
+
+ if (! t || side_effects_p (t))
+ return FALSE;
+
+ /* We currently don't handle different modes. */
+ mode = GET_MODE (t);
+ if (GET_MODE (m) != mode)
+ return FALSE;
+
+ /* This is only profitable if T is cheap, or T is unconditionally
+ executed/evaluated in the original insn sequence. */
+ if (rtx_cost (t, SET) >= COSTS_N_INSNS (2)
+ && (!if_info->b_unconditional
+ || t != if_info->b))
+ return FALSE;
+
+ start_sequence ();
+ /* Use emit_store_flag to generate "m < 0 ? -1 : 0" instead of expanding
+ "(signed) m >> 31" directly. This benefits targets with specialized
+ insns to obtain the signmask, but still uses ashr_optab otherwise. */
+ m = emit_store_flag (gen_reg_rtx (mode), LT, m, const0_rtx, mode, 0, -1);
+ t = m ? expand_binop (mode, and_optab, m, t, NULL_RTX, 0, OPTAB_DIRECT)
+ : NULL_RTX;
+
+ if (!t)
+ {
+ end_sequence ();
+ return FALSE;
+ }
+
+ noce_emit_move_insn (if_info->x, t);
+
+ seq = end_ifcvt_sequence (if_info);
+ if (!seq)
+ return FALSE;
+
+ emit_insn_before_setloc (seq, if_info->jump, INSN_LOCATOR (if_info->insn_a));
+ return TRUE;
+}
+
+
+/* Optimize away "if (x & C) x |= C" and similar bit manipulation
+ transformations. */
+
+static int
+noce_try_bitop (struct noce_if_info *if_info)
+{
+ rtx cond, x, a, result, seq;
+ enum machine_mode mode;
+ enum rtx_code code;
+ int bitnum;
+
+ x = if_info->x;
+ cond = if_info->cond;
+ code = GET_CODE (cond);
+
+ /* Check for no else condition. */
+ if (! rtx_equal_p (x, if_info->b))
+ return FALSE;
+
+ /* Check for a suitable condition. */
+ if (code != NE && code != EQ)
+ return FALSE;
+ if (XEXP (cond, 1) != const0_rtx)
+ return FALSE;
+ cond = XEXP (cond, 0);
+
+ /* ??? We could also handle AND here. */
+ if (GET_CODE (cond) == ZERO_EXTRACT)
+ {
+ if (XEXP (cond, 1) != const1_rtx
+ || GET_CODE (XEXP (cond, 2)) != CONST_INT
+ || ! rtx_equal_p (x, XEXP (cond, 0)))
+ return FALSE;
+ bitnum = INTVAL (XEXP (cond, 2));
+ mode = GET_MODE (x);
+ if (bitnum >= HOST_BITS_PER_WIDE_INT)
+ return FALSE;
+ }
+ else
+ return FALSE;
+
+ a = if_info->a;
+ if (GET_CODE (a) == IOR || GET_CODE (a) == XOR)
+ {
+ /* Check for "if (X & C) x = x op C". */
+ if (! rtx_equal_p (x, XEXP (a, 0))
+ || GET_CODE (XEXP (a, 1)) != CONST_INT
+ || (INTVAL (XEXP (a, 1)) & GET_MODE_MASK (mode))
+ != (unsigned HOST_WIDE_INT) 1 << bitnum)
+ return FALSE;
+
+ /* if ((x & C) == 0) x |= C; is transformed to x |= C. */
+ /* if ((x & C) != 0) x |= C; is transformed to nothing. */
+ if (GET_CODE (a) == IOR)
+ result = (code == NE) ? a : NULL_RTX;
+ else if (code == NE)
+ {
+ /* if ((x & C) == 0) x ^= C; is transformed to x |= C. */
+ result = gen_int_mode ((HOST_WIDE_INT) 1 << bitnum, mode);
+ result = simplify_gen_binary (IOR, mode, x, result);
+ }
+ else
+ {
+ /* if ((x & C) != 0) x ^= C; is transformed to x &= ~C. */
+ result = gen_int_mode (~((HOST_WIDE_INT) 1 << bitnum), mode);
+ result = simplify_gen_binary (AND, mode, x, result);
+ }
+ }
+ else if (GET_CODE (a) == AND)
+ {
+ /* Check for "if (X & C) x &= ~C". */
+ if (! rtx_equal_p (x, XEXP (a, 0))
+ || GET_CODE (XEXP (a, 1)) != CONST_INT
+ || (INTVAL (XEXP (a, 1)) & GET_MODE_MASK (mode))
+ != (~((HOST_WIDE_INT) 1 << bitnum) & GET_MODE_MASK (mode)))
+ return FALSE;
+
+ /* if ((x & C) == 0) x &= ~C; is transformed to nothing. */
+ /* if ((x & C) != 0) x &= ~C; is transformed to x &= ~C. */
+ result = (code == EQ) ? a : NULL_RTX;
+ }
+ else
+ return FALSE;
+
+ if (result)
+ {
+ start_sequence ();
+ noce_emit_move_insn (x, result);
+ seq = end_ifcvt_sequence (if_info);
+ if (!seq)
+ return FALSE;
+
+ emit_insn_before_setloc (seq, if_info->jump,
+ INSN_LOCATOR (if_info->insn_a));
+ }
+ return TRUE;
+}
+
+