summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsayle <sayle@138bc75d-0d04-0410-961f-82ee72b054a4>2005-05-27 02:46:01 +0000
committersayle <sayle@138bc75d-0d04-0410-961f-82ee72b054a4>2005-05-27 02:46:01 +0000
commit9d6663323f8dadb20bcc817dc8546f6444c7ff1b (patch)
tree9cf44213b16d28aaf90e2b46a6d444069dfde78e
parent59e9562ea5c3a6302a64c6730b67ed53508c234d (diff)
downloadgcc-9d6663323f8dadb20bcc817dc8546f6444c7ff1b.tar.gz
PR tree-optimization/9814
* ifcvt.c (noce_emit_move_insn): If we fail to recognize the move instruction, add the necessary clobbers by re-expanding the RTL for arithmetic operations via optab.c's expand_unop/expand_binop. (noce_try_bitop): New function to optimize bit manipulation idioms of the form "if (x & C) x = x op C" and "if (!(x & C) x = x op C". (noce_process_if_block): Call noce_try_bitop. * gcc.dg/pr9814-1.c: New test case. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@100240 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog10
-rw-r--r--gcc/ifcvt.c153
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.dg/pr9814-1.c107
4 files changed, 274 insertions, 1 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 433b0f0b5f3..190a25ad6ce 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,15 @@
2005-05-26 Roger Sayle <roger@eyesopen.com>
+ PR tree-optimization/9814
+ * ifcvt.c (noce_emit_move_insn): If we fail to recognize the move
+ instruction, add the necessary clobbers by re-expanding the RTL
+ for arithmetic operations via optab.c's expand_unop/expand_binop.
+ (noce_try_bitop): New function to optimize bit manipulation idioms
+ of the form "if (x & C) x = x op C" and "if (!(x & C) x = x op C".
+ (noce_process_if_block): Call noce_try_bitop.
+
+2005-05-26 Roger Sayle <roger@eyesopen.com>
+
* reg-stack.c (convert_regs_entry, convert_regs_exit,
convert_regs_1, convert_regs_2, convert_regs): Delete prototypes.
(reg_to_stack): Move to end of the file. Initialize the per
diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c
index be02aaa7d24..9575e62b2f1 100644
--- a/gcc/ifcvt.c
+++ b/gcc/ifcvt.c
@@ -687,7 +687,57 @@ noce_emit_move_insn (rtx x, rtx y)
if (GET_CODE (x) != STRICT_LOW_PART)
{
- emit_move_insn (x, y);
+ rtx seq, insn, target;
+ optab ot;
+
+ start_sequence ();
+ insn = emit_move_insn (x, y);
+ seq = get_insns ();
+ end_sequence();
+
+ if (recog_memoized (insn) <= 0)
+ switch (GET_RTX_CLASS (GET_CODE (y)))
+ {
+ case RTX_UNARY:
+ ot = code_to_optab[GET_CODE (y)];
+ if (ot)
+ {
+ start_sequence ();
+ target = expand_unop (GET_MODE (y), ot, XEXP (y, 0), x, 0);
+ if (target != NULL_RTX)
+ {
+ if (target != x)
+ emit_move_insn (x, target);
+ seq = get_insns ();
+ }
+ end_sequence ();
+ }
+ break;
+
+ case RTX_BIN_ARITH:
+ case RTX_COMM_ARITH:
+ ot = code_to_optab[GET_CODE (y)];
+ if (ot)
+ {
+ start_sequence ();
+ target = expand_binop (GET_MODE (y), ot,
+ XEXP (y, 0), XEXP (y, 1),
+ x, 0, OPTAB_DIRECT);
+ if (target != NULL_RTX)
+ {
+ if (target != x)
+ emit_move_insn (x, target);
+ seq = get_insns ();
+ }
+ end_sequence ();
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ emit_insn (seq);
return;
}
@@ -1815,6 +1865,105 @@ noce_try_sign_mask (struct noce_if_info *if_info)
}
+/* 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;
+}
+
+
/* Similar to get_condition, only the resulting condition must be
valid at JUMP, instead of at EARLIEST. */
@@ -2078,6 +2227,8 @@ noce_process_if_block (struct ce_if_block * ce_info)
goto success;
if (noce_try_store_flag (&if_info))
goto success;
+ if (noce_try_bitop (&if_info))
+ goto success;
if (noce_try_minmax (&if_info))
goto success;
if (noce_try_abs (&if_info))
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index d460ab34dde..00185e8011a 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2005-05-26 Roger Sayle <roger@eyesopen.com>
+
+ PR tree-optimization/9814
+ * gcc.dg/pr9814-1.c: New test case.
+
2005-05-26 Ziemowit Laski <zlaski@apple.com>
* objc.dg/comp-types-8.m, objc.dg/encode-6.m,
diff --git a/gcc/testsuite/gcc.dg/pr9814-1.c b/gcc/testsuite/gcc.dg/pr9814-1.c
new file mode 100644
index 00000000000..51b79f7839b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr9814-1.c
@@ -0,0 +1,107 @@
+/* PR tree-optimization/9814 */
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+extern void abort(void);
+
+int test1(int x)
+{
+ if (x & 2)
+ x |= 2;
+ return x;
+}
+
+int test2(int x)
+{
+ if (!(x & 2))
+ x |= 2;
+ return x;
+}
+
+int test3(int x)
+{
+ if (x & 2)
+ x ^= 2;
+ return x;
+}
+
+int test4(int x)
+{
+ if (!(x & 2))
+ x ^= 2;
+ return x;
+}
+
+int test5(int x)
+{
+ if (x & 2)
+ x &= ~2;
+ return x;
+}
+
+int test6(int x)
+{
+ if (!(x & 2))
+ x &= ~2;
+ return x;
+}
+
+int main()
+{
+ if (test1(0) != 0)
+ abort();
+ if (test1(2) != 2)
+ abort();
+ if (test1(5) != 5)
+ abort();
+ if (test1(7) != 7)
+ abort();
+
+ if (test2(0) != 2)
+ abort();
+ if (test2(2) != 2)
+ abort();
+ if (test2(5) != 7)
+ abort();
+ if (test2(7) != 7)
+ abort();
+
+ if (test3(0) != 0)
+ abort();
+ if (test3(2) != 0)
+ abort();
+ if (test3(5) != 5)
+ abort();
+ if (test3(7) != 5)
+ abort();
+
+ if (test4(0) != 2)
+ abort();
+ if (test4(2) != 2)
+ abort();
+ if (test4(5) != 7)
+ abort();
+ if (test4(7) != 7)
+ abort();
+
+ if (test5(0) != 0)
+ abort();
+ if (test5(2) != 0)
+ abort();
+ if (test5(5) != 5)
+ abort();
+ if (test5(7) != 5)
+ abort();
+
+ if (test6(0) != 0)
+ abort();
+ if (test6(2) != 2)
+ abort();
+ if (test6(5) != 5)
+ abort();
+ if (test6(7) != 7)
+ abort();
+
+ return 0;
+}
+