tree-optimization/111000 - restrict invariant motion of shifts

Message ID 20231020111940.8FD0A13584@imap2.suse-dmz.suse.de
State Accepted
Headers
Series tree-optimization/111000 - restrict invariant motion of shifts |

Checks

Context Check Description
snail/gcc-patch-check success Github commit url

Commit Message

Richard Biener Oct. 20, 2023, 11:19 a.m. UTC
  The following restricts moving variable shifts to when they are
always executed in the loop as we currently do not have an efficient
way to rewrite them to something that is unconditionally
well-defined and value range analysis will otherwise compute
invalid ranges for the shift operand.

Bootstrapped and tested on x86_64-unknown-linux-gnu, pushed.

	PR tree-optimization/111000
	* stor-layout.h (element_precision): Move ..
	* tree.h (element_precision): .. here.
	* tree-ssa-loop-im.cc (movement_possibility_1): Restrict
	motion of shifts and rotates.

	* gcc.dg/torture/pr111000.c: New testcase.
---
 gcc/stor-layout.h                       |  1 -
 gcc/testsuite/gcc.dg/torture/pr111000.c | 21 +++++++++++++++++++++
 gcc/tree-ssa-loop-im.cc                 | 18 ++++++++++++++++++
 gcc/tree.h                              |  1 +
 4 files changed, 40 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gcc.dg/torture/pr111000.c
  

Patch

diff --git a/gcc/stor-layout.h b/gcc/stor-layout.h
index e7768921c22..589ce33c950 100644
--- a/gcc/stor-layout.h
+++ b/gcc/stor-layout.h
@@ -36,7 +36,6 @@  extern void place_field (record_layout_info, tree);
 extern void compute_record_mode (tree);
 extern void finish_bitfield_layout (tree);
 extern void finish_record_layout (record_layout_info, int);
-extern unsigned int element_precision (const_tree);
 extern void finalize_size_functions (void);
 extern void fixup_unsigned_type (tree);
 extern void initialize_sizetypes (void);
diff --git a/gcc/testsuite/gcc.dg/torture/pr111000.c b/gcc/testsuite/gcc.dg/torture/pr111000.c
new file mode 100644
index 00000000000..e6821e1618d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr111000.c
@@ -0,0 +1,21 @@ 
+/* { dg-do run } */
+
+volatile int a = 68;
+int b, d, e;
+int main()
+{
+  int t = a;
+  for (; d <= 6; d++) {
+    for (b = 0; b <= 6; b++) {
+      if (t >= 31)
+        e = d;
+      else if (d > (647 >> t))
+        e = d;
+      else
+        e = 0;
+    }
+  }
+  if (e != 6)
+    __builtin_abort();
+  return 0;
+}
diff --git a/gcc/tree-ssa-loop-im.cc b/gcc/tree-ssa-loop-im.cc
index 49aeb685773..396963b6754 100644
--- a/gcc/tree-ssa-loop-im.cc
+++ b/gcc/tree-ssa-loop-im.cc
@@ -400,6 +400,24 @@  movement_possibility_1 (gimple *stmt)
       || gimple_could_trap_p (stmt))
     return MOVE_PRESERVE_EXECUTION;
 
+  if (is_gimple_assign (stmt))
+    {
+      auto code = gimple_assign_rhs_code (stmt);
+      tree type = TREE_TYPE (gimple_assign_rhs1 (stmt));
+      /* For shifts and rotates and possibly out-of-bound shift operands
+	 we currently cannot rewrite them into something unconditionally
+	 well-defined.  */
+      if ((code == LSHIFT_EXPR
+	   || code == RSHIFT_EXPR
+	   || code == LROTATE_EXPR
+	   || code == RROTATE_EXPR)
+	  && (TREE_CODE (gimple_assign_rhs2 (stmt)) != INTEGER_CST
+	      /* We cannot use ranges at 'stmt' here.  */
+	      || wi::ltu_p (wi::to_wide (gimple_assign_rhs2 (stmt)),
+			    element_precision (type))))
+	ret = MOVE_PRESERVE_EXECUTION;
+    }
+
   /* Non local loads in a transaction cannot be hoisted out.  Well,
      unless the load happens on every path out of the loop, but we
      don't take this into account yet.  */
diff --git a/gcc/tree.h b/gcc/tree.h
index 31ea52a5d6b..781297c7e77 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -2235,6 +2235,7 @@  class auto_suppress_location_wrappers
 #define SET_TYPE_MODE(NODE, MODE) \
   (TYPE_CHECK (NODE)->type_common.mode = (MODE))
 
+extern unsigned int element_precision (const_tree);
 extern machine_mode element_mode (const_tree);
 extern machine_mode vector_type_mode (const_tree);
 extern unsigned int vector_element_bits (const_tree);