diff mbox

[match.pd] Fold (A / (1 << B)) to (A >> B)

Message ID 1497273586-9046-1-git-send-email-james.greenhalgh@arm.com
State New
Headers show

Commit Message

James Greenhalgh June 12, 2017, 1:19 p.m. UTC
Hi,

As subject, for the testcase in the patch:

  unsigned long
  f2 (unsigned long a, int b)
  {
    unsigned long x = 1UL << b;
    return a / x;
  }

We currently generate:

  f2:
	mov	x2, 1
	lsl	x1, x2, x1
	udiv	x0, x0, x1
	ret

Which could instead be transformed to:

  f2:
	lsr	x0, x0, x1
	ret

OK?

Thanks,
James

---
gcc/

2017-06-12  James Greenhalgh  <james.greenhalgh@arm.com>

	* match.pd (A / (1 << B) -> A >> B): New.

gcc/testsuite/

2017-06-12  James Greenhalgh  <james.greenhalgh@arm.com>

	* gcc.dg/tree-ssa/forwprop-37.c: New.

Comments

Richard Biener June 12, 2017, 1:56 p.m. UTC | #1
On Mon, 12 Jun 2017, James Greenhalgh wrote:

> 
> Hi,
> 
> As subject, for the testcase in the patch:
> 
>   unsigned long
>   f2 (unsigned long a, int b)
>   {
>     unsigned long x = 1UL << b;
>     return a / x;
>   }
> 
> We currently generate:
> 
>   f2:
> 	mov	x2, 1
> 	lsl	x1, x2, x1
> 	udiv	x0, x0, x1
> 	ret
> 
> Which could instead be transformed to:
> 
>   f2:
> 	lsr	x0, x0, x1
> 	ret
> 
> OK?

+   We can't do the same for signed A, as it might be negative, which 
would
+   introduce undefined behaviour.  */

huh, AFAIR it is _left_ shift of negative values that invokes
undefined behavior.

Note that as you are accepting vectors you need to make sure the
target actually supports arithmetic right shift of vectors
(you only know it supports left shift and division -- so it might
be sort-of-superfluous to check in case there is no arch that supports
those but not the other).

Richard.

> Thanks,
> James
> 
> ---
> gcc/
> 
> 2017-06-12  James Greenhalgh  <james.greenhalgh@arm.com>
> 
> 	* match.pd (A / (1 << B) -> A >> B): New.
> 
> gcc/testsuite/
> 
> 2017-06-12  James Greenhalgh  <james.greenhalgh@arm.com>
> 
> 	* gcc.dg/tree-ssa/forwprop-37.c: New.
> 
>
diff mbox

Patch

diff --git a/gcc/match.pd b/gcc/match.pd
index 54a8e04..656ede2 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -147,6 +147,14 @@  DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
     (op @0 integer_onep)
     (non_lvalue @0)))
 
+/* For unsigned A: (A / (1 << B)), (A >> B).
+   We can't do the same for signed A, as it might be negative, which would
+   introduce undefined behaviour.  */
+(simplify
+ (trunc_div @0 (lshift integer_onep@1 @2))
+ (if (TYPE_UNSIGNED (type))
+  (rshift @0 @2)))
+
 /* Preserve explicit divisions by 0: the C++ front-end wants to detect
    undefined behavior in constexpr evaluation, and assuming that the division
    traps enables better optimizations than these anyway.  */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/forwprop-37.c b/gcc/testsuite/gcc.dg/tree-ssa/forwprop-37.c
new file mode 100644
index 0000000..dec826c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/forwprop-37.c
@@ -0,0 +1,25 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-forwprop1-raw" } */
+
+unsigned int
+f1 (unsigned int a, unsigned int b)
+{
+  unsigned int x = 1U << b;
+  return a / x;
+}
+
+unsigned long
+f2 (unsigned long a, int b)
+{
+  unsigned long x = 1UL << b;
+  return a / x;
+}
+
+unsigned long long
+f3 (unsigned long long a, int b)
+{
+  unsigned long long x = 1ULL << b;
+  return a / x;
+}
+
+/* { dg-final { scan-tree-dump-not "trunc_div_expr" "forwprop1" } } */