ifcvt.c (noce_try_abs): Recognize pattern and call expand_one_cmpl_abs_nojump.
authorEaswaran Raman <eraman@google.com>
Mon, 28 Sep 2009 21:26:31 +0000 (21:26 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Mon, 28 Sep 2009 21:26:31 +0000 (21:26 +0000)
./: * ifcvt.c (noce_try_abs): Recognize pattern and call
expand_one_cmpl_abs_nojump.
* optabs.c (expand_one_cmpl_abs_nojump): New function.
* optabs.h (expand_one_cmpl_abs_nojump): Declare.
testsuite/:
* gcc.target/i386/ifcvt-onecmpl-abs-1.c: New file.
* gcc.c-torture/execute/ifcvt-onecmpl-abs-1.c: New file.

From-SVN: r152253

gcc/ChangeLog
gcc/ifcvt.c
gcc/optabs.c
gcc/optabs.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/execute/ifcvt-onecmpl-abs-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/ifcvt-onecmpl-abs-1.c [new file with mode: 0644]

index 2a84e345669652c920988269185514697180f743..38ac22c9a4fde407a5149f037ca39d5e9afe1cd9 100644 (file)
@@ -1,3 +1,10 @@
+2009-09-28  Easwaran Raman  <eraman@google.com>
+
+       * ifcvt.c (noce_try_abs): Recognize pattern and call
+       expand_one_cmpl_abs_nojump.
+       * optabs.c (expand_one_cmpl_abs_nojump): New function.
+       * optabs.h (expand_one_cmpl_abs_nojump): Declare.
+
 2009-09-28  Ian Lance Taylor  <iant@google.com>
 
        PR middle-end/40500
index 1cf2608a1778a78daaff2d14357cb9817eda9134..1ef2d21f903402ab4483004bdf6eae77cb26cff7 100644 (file)
@@ -1744,13 +1744,16 @@ noce_try_minmax (struct noce_if_info *if_info)
   return TRUE;
 }
 
-/* Convert "if (a < 0) x = -a; else x = a;" to "x = abs(a);", etc.  */
+/* Convert "if (a < 0) x = -a; else x = a;" to "x = abs(a);",
+   "if (a < 0) x = ~a; else x = a;" to "x = one_cmpl_abs(a);",
+   etc.  */
 
 static int
 noce_try_abs (struct noce_if_info *if_info)
 {
   rtx cond, earliest, target, seq, a, b, c;
   int negate;
+  bool one_cmpl = false;
 
   /* Reject modes with signed zeros.  */
   if (HONOR_SIGNED_ZEROS (GET_MODE (if_info->x)))
@@ -1768,6 +1771,17 @@ noce_try_abs (struct noce_if_info *if_info)
       c = a; a = b; b = c;
       negate = 1;
     }
+  else if (GET_CODE (a) == NOT && rtx_equal_p (XEXP (a, 0), b))
+    {
+      negate = 0;
+      one_cmpl = true;
+    }
+  else if (GET_CODE (b) == NOT && rtx_equal_p (XEXP (b, 0), a))
+    {
+      c = a; a = b; b = c;
+      negate = 1;
+      one_cmpl = true;
+    }
   else
     return FALSE;
 
@@ -1839,13 +1853,23 @@ noce_try_abs (struct noce_if_info *if_info)
     }
 
   start_sequence ();
-
-  target = expand_abs_nojump (GET_MODE (if_info->x), b, if_info->x, 1);
+  if (one_cmpl)
+    target = expand_one_cmpl_abs_nojump (GET_MODE (if_info->x), b,
+                                         if_info->x);
+  else
+    target = expand_abs_nojump (GET_MODE (if_info->x), b, if_info->x, 1);
 
   /* ??? It's a quandary whether cmove would be better here, especially
      for integers.  Perhaps combine will clean things up.  */
   if (target && negate)
-    target = expand_simple_unop (GET_MODE (target), NEG, target, if_info->x, 0);
+    {
+      if (one_cmpl)
+        target = expand_simple_unop (GET_MODE (target), NOT, target,
+                                     if_info->x, 0);
+      else
+        target = expand_simple_unop (GET_MODE (target), NEG, target,
+                                     if_info->x, 0);
+    }
 
   if (! target)
     {
index a1adc581dc12462e9fdde3e2b71ff9caa505eaa3..1c13623606062dff19c07b7907a584d6b7006717 100644 (file)
@@ -3488,6 +3488,60 @@ expand_abs (enum machine_mode mode, rtx op0, rtx target,
   return target;
 }
 
+/* Emit code to compute the one's complement absolute value of OP0
+   (if (OP0 < 0) OP0 = ~OP0), with result to TARGET if convenient.
+   (TARGET may be NULL_RTX.)  The return value says where the result
+   actually is to be found.
+
+   MODE is the mode of the operand; the mode of the result is
+   different but can be deduced from MODE.  */
+
+rtx
+expand_one_cmpl_abs_nojump (enum machine_mode mode, rtx op0, rtx target)
+{
+  rtx temp;
+
+  /* Not applicable for floating point modes.  */
+  if (FLOAT_MODE_P (mode))
+    return NULL_RTX;
+
+  /* If we have a MAX insn, we can do this as MAX (x, ~x).  */
+  if (optab_handler (smax_optab, mode)->insn_code != CODE_FOR_nothing)
+    {
+      rtx last = get_last_insn ();
+
+      temp = expand_unop (mode, one_cmpl_optab, op0, NULL_RTX, 0);
+      if (temp != 0)
+       temp = expand_binop (mode, smax_optab, op0, temp, target, 0,
+                            OPTAB_WIDEN);
+
+      if (temp != 0)
+       return temp;
+
+      delete_insns_since (last);
+    }
+
+  /* If this machine has expensive jumps, we can do one's complement
+     absolute value of X as (((signed) x >> (W-1)) ^ x).  */
+
+  if (GET_MODE_CLASS (mode) == MODE_INT
+      && BRANCH_COST (optimize_insn_for_speed_p (),
+                    false) >= 2)
+    {
+      rtx extended = expand_shift (RSHIFT_EXPR, mode, op0,
+                                  size_int (GET_MODE_BITSIZE (mode) - 1),
+                                  NULL_RTX, 0);
+
+      temp = expand_binop (mode, xor_optab, extended, op0, target, 0,
+                          OPTAB_LIB_WIDEN);
+
+      if (temp != 0)
+       return temp;
+    }
+
+  return NULL_RTX;
+}
+
 /* A subroutine of expand_copysign, perform the copysign operation using the
    abs and neg primitives advertised to exist on the target.  The assumption
    is that we have a split register file, and leaving op0 in fp registers,
index af3ea66de8731e855a50f24ae318d6a4a275c9ce..c4acb17eedd7bab09bc5eefb12be76451089caaa 100644 (file)
@@ -706,6 +706,9 @@ extern rtx expand_unop (enum machine_mode, optab, rtx, rtx, int);
 extern rtx expand_abs_nojump (enum machine_mode, rtx, rtx, int);
 extern rtx expand_abs (enum machine_mode, rtx, rtx, int, int);
 
+/* Expand the one's complement absolute value operation.  */
+extern rtx expand_one_cmpl_abs_nojump (enum machine_mode, rtx, rtx);
+
 /* Expand the copysign operation.  */
 extern rtx expand_copysign (rtx, rtx, rtx);
 
index 7d6539aa3589d37e5d6caddb33c1f6ca557258aa..c5f4438fd50585144c5151953c198e93000051c6 100644 (file)
@@ -1,3 +1,8 @@
+2009-09-28  Easwaran Raman  <eraman@google.com>
+
+       * gcc.target/i386/ifcvt-onecmpl-abs-1.c: New file.
+       * gcc.c-torture/execute/ifcvt-onecmpl-abs-1.c: New file.
+
 2009-09-28  Janis Johnson  <janis187@us.ibm.com>
 
        * g++.dg/dfp/dfp.exp: Run tests from c-c++-common/dfp.
diff --git a/gcc/testsuite/gcc.c-torture/execute/ifcvt-onecmpl-abs-1.c b/gcc/testsuite/gcc.c-torture/execute/ifcvt-onecmpl-abs-1.c
new file mode 100644 (file)
index 0000000..679e552
--- /dev/null
@@ -0,0 +1,19 @@
+
+extern void abort(void);
+
+__attribute__ ((noinline))
+int foo(int n)
+{
+  if (n < 0)
+    n = ~n;
+
+  return n;
+}
+
+int main(void)
+{
+  if (foo (-1) != 0)
+    abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/ifcvt-onecmpl-abs-1.c b/gcc/testsuite/gcc.target/i386/ifcvt-onecmpl-abs-1.c
new file mode 100644 (file)
index 0000000..736053d
--- /dev/null
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* This test checks for if-conversion of one's complement
+ * abs function.  */
+/* { dg-options "-O" } */
+/* { dg-final { scan-assembler "sar" } } */
+/* { dg-final { scan-assembler "xor" } } */
+
+/* Check code generation for one's complement version of abs */
+
+int onecmplabs(int x)
+{
+  if (x < 0)
+    x = ~x;
+  return x;
+}