aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEaswaran Raman <eraman@google.com>2009-09-28 21:26:31 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2009-09-28 21:26:31 +0000
commit650260479ac18d6e26af41f77c74b451ce426a46 (patch)
tree2b4602f59f93e1c9ebfa00346b0b70ecdd95b378
parent13ebf17b66c3ff8f4291f046158347191fe396c1 (diff)
downloadgcc-650260479ac18d6e26af41f77c74b451ce426a46.zip
gcc-650260479ac18d6e26af41f77c74b451ce426a46.tar.gz
gcc-650260479ac18d6e26af41f77c74b451ce426a46.tar.bz2
ifcvt.c (noce_try_abs): Recognize pattern and call expand_one_cmpl_abs_nojump.
./: * 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
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/ifcvt.c32
-rw-r--r--gcc/optabs.c54
-rw-r--r--gcc/optabs.h3
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/ifcvt-onecmpl-abs-1.c19
-rw-r--r--gcc/testsuite/gcc.target/i386/ifcvt-onecmpl-abs-1.c15
7 files changed, 131 insertions, 4 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 2a84e34..38ac22c 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c
index 1cf2608..1ef2d21 100644
--- a/gcc/ifcvt.c
+++ b/gcc/ifcvt.c
@@ -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)
{
diff --git a/gcc/optabs.c b/gcc/optabs.c
index a1adc58..1c13623 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -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,
diff --git a/gcc/optabs.h b/gcc/optabs.h
index af3ea66..c4acb17 100644
--- a/gcc/optabs.h
+++ b/gcc/optabs.h
@@ -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);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 7d6539a..c5f4438 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 0000000..679e552
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/ifcvt-onecmpl-abs-1.c
@@ -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
index 0000000..736053d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/ifcvt-onecmpl-abs-1.c
@@ -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;
+}