re PR middle-end/91680 (Integer promotion quirk prevents efficient power of 2 division)
authorJakub Jelinek <jakub@gcc.gnu.org>
Tue, 10 Sep 2019 08:15:46 +0000 (10:15 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Tue, 10 Sep 2019 08:15:46 +0000 (10:15 +0200)
PR middle-end/91680
* match.pd ((A / (1 << B)) -> (A >> B)): Allow widening cast from
the shift type to type.

* gcc.dg/tree-ssa/pr91680.c: New test.
* g++.dg/torture/pr91680.C: New test.

From-SVN: r275587

gcc/ChangeLog
gcc/match.pd
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/torture/pr91680.C [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/pr91680.c [new file with mode: 0644]

index 3bf2a0b8628dcf6669f33292f1e6efd0ac27e453..6139e3cbd489b30350bf0737c1f7ee231ca4b395 100644 (file)
@@ -1,3 +1,9 @@
+2019-09-10  Jakub Jelinek  <jakub@redhat.com>
+
+       PR middle-end/91680
+       * match.pd ((A / (1 << B)) -> (A >> B)): Allow widening cast from
+       the shift type to type.
+
 2019-09-10  Christophe Lyon  <christophe.lyon@st.com>
 
        * config/arm/arm.md (stack_protect_combined_set_insn): Handle
@@ -5,7 +11,7 @@
        (stack_protect_combined_test_insn): Likewise.
 
 2019-09-10  Christophe Lyon  <christophe.lyon@st.com>
-       Mickaël Guêné <mickael.guene@st.com>
+           Mickaël Guêné <mickael.guene@st.com>
 
        * config/arm/arm.c (arm_load_tp): Add FDPIC support.
        * config/arm/arm.md (FDPIC_REGNUM): New constant.
@@ -13,7 +19,7 @@
        (load_tp_soft): Disable in FDPIC mode.
 
 2019-09-10  Christophe Lyon  <christophe.lyon@st.com>
-       Mickaël Guêné <mickael.guene@st.com>
+           Mickaël Guêné <mickael.guene@st.com>
 
        * config/arm/arm.c (tls_reloc): Add TLS_GD32_FDPIC,
        TLS_LDM32_FDPIC and TLS_IE32_FDPIC.
@@ -22,7 +28,7 @@
        (arm_emit_tls_decoration): Likewise.
 
 2019-09-10  Christophe Lyon  <christophe.lyon@st.com>
-       Mickaël Guêné <mickael.guene@st.com>
+           Mickaël Guêné <mickael.guene@st.com>
 
        * config/arm/arm.c (arm_asm_trampoline_template): Add FDPIC
        support.
@@ -31,7 +37,7 @@
        * config/arm/arm.h (TRAMPOLINE_SIZE): Likewise.
 
 2019-09-10  Christophe Lyon  <christophe.lyon@st.com>
-       Mickaël Guêné <mickael.guene@st.com>
+           Mickaël Guêné <mickael.guene@st.com>
 
        * config/arm/arm.c (arm_fdpic_local_funcdesc_p): New function.
        (legitimize_pic_address): Enforce binding rules on function
        (arm_assemble_integer): Likewise.
 
 2019-09-10  Christophe Lyon  <christophe.lyon@st.com>
-       Mickaël Guêné <mickael.guene@st.com>
+           Mickaël Guêné <mickael.guene@st.com>
 
        * config/arm/arm.h (PIC_REGISTER_MAY_NEED_SAVING): New helper.
        * config/arm/arm.c (arm_compute_save_reg0_reg12_mask): Handle
        FDPIC.
 
 2019-09-10  Christophe Lyon  <christophe.lyon@st.com>
-       Mickaël Guêné <mickael.guene@st.com>
+           Mickaël Guêné <mickael.guene@st.com>
 
        * ginclude/unwind-arm-common.h (unwinder_cache): Add reserved5
        field.
 
 2019-09-10  Christophe Lyon  <christophe.lyon@st.com>
-       Mickaël Guêné <mickael.guene@st.com>
+           Mickaël Guêné <mickael.guene@st.com>
 
        * config/arm/arm-c.c (__FDPIC__): Define new pre-processor macro
        in FDPIC mode.
@@ -80,7 +86,7 @@
        * config/arm/unspecs.md (UNSPEC_PIC_RESTORE): New.
 
 2019-09-10  Christophe Lyon  <christophe.lyon@st.com>
-       Mickaël Guêné <mickael.guene@st.com>
+           Mickaël Guêné <mickael.guene@st.com>
 
        * config.gcc: Handle arm*-*-uclinuxfdpiceabi.
        * config/arm/bpabi.h (TARGET_FDPIC_ASM_SPEC): New.
        * config.gcc: Handle *-*-uclinuxfdpiceabi.
 
 2019-09-10  Christophe Lyon  <christophe.lyon@st.com>
-       Mickaël Guêné  <mickael.guene@st.com>
+           Mickaël Guêné  <mickael.guene@st.com>
 
        * config/arm/arm.opt: Add -mfdpic option.
        * doc/invoke.texi: Add documentation for -mfdpic.
index 5b2d95dfa9d8feef7e7248c0364909fc061da3ab..309a094071b81fccf396c1cca43bfff9a09b62ec 100644 (file)
@@ -305,13 +305,29 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 /* (A / (1 << B)) -> (A >> B).
    Only for unsigned A.  For signed A, this would not preserve rounding
    toward zero.
-   For example: (-1 / ( 1 << B)) !=  -1 >> B.  */
-(simplify
- (trunc_div @0 (lshift integer_onep@1 @2))
+   For example: (-1 / ( 1 << B)) !=  -1 >> B.
+   Also also widening conversions, like:
+   (A / (unsigned long long) (1U << B)) -> (A >> B)
+   or
+   (A / (unsigned long long) (1 << B)) -> (A >> B).
+   If the left shift is signed, it can be done only if the upper bits
+   of A starting from shift's type sign bit are zero, as
+   (unsigned long long) (1 << 31) is -2147483648ULL, not 2147483648ULL,
+   so it is valid only if A >> 31 is zero.  */
+(simplify
+ (trunc_div @0 (convert? (lshift integer_onep@1 @2)))
  (if ((TYPE_UNSIGNED (type) || tree_expr_nonnegative_p (@0))
       && (!VECTOR_TYPE_P (type)
          || target_supports_op_p (type, RSHIFT_EXPR, optab_vector)
-         || target_supports_op_p (type, RSHIFT_EXPR, optab_scalar)))
+         || target_supports_op_p (type, RSHIFT_EXPR, optab_scalar))
+      && (useless_type_conversion_p (type, TREE_TYPE (@1))
+         || (element_precision (type) >= element_precision (TREE_TYPE (@1))
+             && (TYPE_UNSIGNED (TREE_TYPE (@1))
+                 || (element_precision (type)
+                     == element_precision (TREE_TYPE (@1)))
+                 || (get_nonzero_bits (@0)
+                     & wi::mask (element_precision (TREE_TYPE (@1)) - 1, true,
+                                 element_precision (type))) == 0))))
   (rshift @0 @2)))
 
 /* Preserve explicit divisions by 0: the C++ front-end wants to detect
index 31b54f88c8c6911f48857aa3183a917dfee2a547..6f487a8fedc9d6958391d3543d4f75524a96ad8c 100644 (file)
@@ -1,3 +1,9 @@
+2019-09-10  Jakub Jelinek  <jakub@redhat.com>
+
+       PR middle-end/91680
+       * gcc.dg/tree-ssa/pr91680.c: New test.
+       * g++.dg/torture/pr91680.C: New test.
+
 2019-09-10  Paolo Carlini  <paolo.carlini@oracle.com>
 
        * g++.dg/cpp0x/enum29.C: Test location(s) too.
diff --git a/gcc/testsuite/g++.dg/torture/pr91680.C b/gcc/testsuite/g++.dg/torture/pr91680.C
new file mode 100644 (file)
index 0000000..afed400
--- /dev/null
@@ -0,0 +1,35 @@
+/* PR middle-end/91680 */
+/* { dg-do run { target { ilp32 || lp64 } } } */
+
+extern "C" void abort ();
+
+#include "../../gcc.dg/tree-ssa/pr91680.c"
+
+int
+main ()
+{
+  unsigned char i;
+  for (i = 0; i < __SIZEOF_INT__ * __CHAR_BIT__; i++)
+    {
+      volatile unsigned long long q = 1 << i;
+      if (foo (i) != 256 / q)
+       abort ();
+      q = 1U << i;
+      if (bar (i) != 256 / q)
+       abort ();
+      q = 1 << i;
+      if (baz (i, (1U << i) - 1) != ((1U << i) - 1) / q)
+       abort ();
+      if (baz (i, 1U << i) != (1U << i) / q)
+       abort ();
+      if (baz (i, -1) != -1 / q)
+       abort ();
+      q = 1U << i;
+      if (qux (i, (1U << i) - 1) != ((1U << i) - 1) / q)
+       abort ();
+      if (qux (i, 1U << i) != (1U << i) / q)
+       abort ();
+      if (qux (i, -1) != -1 / q)
+       abort ();
+    }
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr91680.c b/gcc/testsuite/gcc.dg/tree-ssa/pr91680.c
new file mode 100644 (file)
index 0000000..6d1912b
--- /dev/null
@@ -0,0 +1,37 @@
+/* PR middle-end/91680 */
+/* { dg-do compile { target { ilp32 || lp64 } } } */
+/* { dg-options "-O2 -fdump-tree-forwprop1" } */
+/* { dg-final { scan-tree-dump-times " / " 1 "forwprop1" } } */
+/* { dg-final { scan-tree-dump-times " >> " 3 "forwprop1" } } */
+
+__attribute__((noipa)) unsigned long long
+foo (unsigned char x)
+{
+  unsigned long long q = 1 << x;
+  return 256 / q;
+}
+
+__attribute__((noipa)) unsigned long long
+bar (unsigned char x)
+{
+  unsigned long long q = 1U << x;
+  return 256 / q;
+}
+
+__attribute__((noipa)) unsigned long long
+baz (unsigned char x, unsigned long long y)
+{
+  /* This can't be optimized, at least not in C++ and maybe not
+     in C89, because for x 31 q is -2147483648ULL, not
+     2147483648ULL, and e.g. 2147483648ULL >> 31 is 1, while
+     2147483648ULL / -2147483648ULL is 0.  */
+  unsigned long long q = 1 << x;
+  return y / q;
+}
+
+__attribute__((noipa)) unsigned long long
+qux (unsigned char x, unsigned long long y)
+{
+  unsigned long long q = 1U << x;
+  return y / q;
+}