diff mbox

[PR,rtl-optimization/78812] Fix pruning of expressions with embedded MEMs

Message ID 57d8f7fd-fb0f-4b73-2747-dad157c9c887@redhat.com
State New
Headers show

Commit Message

Jeff Law Jan. 5, 2017, 7:46 a.m. UTC
GCSE has some smarts to detect cases when a MEM appears in a block with 
predecessor edges marked as EDGE_ABNORMAL.  Such MEMs are removed from 
the antic/transparent bitmaps.

Unfortunately this code did not work if the MEM was not the topmost RTX. 
  So something like (zero_extend (mem (...)) would not result in the MEM 
being removed.

This in turn caused code hoisting to hoist the MEM into a predecessor 
block.  The predecessor block ended with a function call so gcse was 
forced to insert the new insn before the call.  But the value is changed 
by the call.


This patch moves contains_mem_rtx_p into rtlanal.c and uses it to detect 
when there's MEMs that aren't the toplevel RTX expression.  The patch 
also knows how to look through certain toplevel expressions 
(ZERO_EXTEND, SIGN_EXTEND) to find the buried MEM expression.  This 
allows the code to prune more selectively if the MEM is a constant pool 
address or otherwise readonly.

Bootstrapped and regression tested on x86_64-linux-gnu.  ALso verified 
RTL hoisting no longer hoists the (zero_extend (mem)) expression with an 
s390x cross compiler.

Installing on the trunk.  It should be safe to backport to the release 
branches if anyone sees a need.

Jeff
commit 0998df91b6ad2035f5fd41ee024e3ab919a9cefe
Author: Jeff Law <law@redhat.com>
Date:   Thu Jan 5 00:37:57 2017 -0700

    	PR tree-optimizatin/78812
    	* rtl.h (contains_mem_rtx_p): Prototype.
    	* ifcvt.c (containts_mem_rtx_p): Move from here to...
    	* rtlanal.c (contains_mem_rtx_p): Here and remvoe static linkage.
    	* gcse.c (prune_expressions): Use contains_mem_rtx_p to discover
    	and prune MEMs that are not at the toplevel of a SET_SRC rtx.  Look
    	through ZERO_EXTEND and SIGN_EXTEND when trying to avoid pruning
    	MEMs.
    
    	PR tree-optimization/78812
    	* g++.dg/torture/pr78812.C: New test.
diff mbox

Patch

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index ce11bc4..78b4412 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,14 @@ 
+2017-01-04  Jeff Law  <law@redhat.com>
+
+	PR tree-optimizatin/78812
+	* rtl.h (contains_mem_rtx_p): Prototype.
+	* ifcvt.c (containts_mem_rtx_p): Move from here to...
+	* rtlanal.c (contains_mem_rtx_p): Here and remvoe static linkage.
+	* gcse.c (prune_expressions): Use contains_mem_rtx_p to discover
+	and prune MEMs that are not at the toplevel of a SET_SRC rtx.  Look
+	through ZERO_EXTEND and SIGN_EXTEND when trying to avoid pruning
+	MEMs.
+
 2017-01-04  Alexandre Oliva <aoliva@redhat.com>
 
 	* input.c (assert_char_at_range): Default-initialize
diff --git a/gcc/gcse.c b/gcc/gcse.c
index fbc770a..d28288d 100644
--- a/gcc/gcse.c
+++ b/gcc/gcse.c
@@ -1709,7 +1709,7 @@  prune_expressions (bool pre_p)
 	      continue;
 	    }
 
-	  if (!pre_p && MEM_P (expr->expr))
+	  if (!pre_p && contains_mem_rtx_p (expr->expr))
 	    /* Note memory references that can be clobbered by a call.
 	       We do not split abnormal edges in hoisting, so would
 	       a memory reference get hoisted along an abnormal edge,
@@ -1717,15 +1717,28 @@  prune_expressions (bool pre_p)
 	       constant memory references can be hoisted along abnormal
 	       edges.  */
 	    {
-	      if (GET_CODE (XEXP (expr->expr, 0)) == SYMBOL_REF
-		  && CONSTANT_POOL_ADDRESS_P (XEXP (expr->expr, 0)))
-		continue;
-
-	      if (MEM_READONLY_P (expr->expr)
-		  && !MEM_VOLATILE_P (expr->expr)
-		  && MEM_NOTRAP_P (expr->expr))
-		/* Constant memory reference, e.g., a PIC address.  */
-		continue;
+	      rtx x = expr->expr;
+
+	      /* Common cases where we might find the MEM which may allow us
+		 to avoid pruning the expression.  */
+	      while (GET_CODE (x) == ZERO_EXTEND || GET_CODE (x) == SIGN_EXTEND)
+		x = XEXP (x, 0);
+
+	      /* If we found the MEM, go ahead and look at it to see if it has
+		 properties that allow us to avoid pruning its expression out
+		 of the tables.  */
+	      if (MEM_P (x))
+		{
+		  if (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
+		      && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0)))
+		    continue;
+
+		  if (MEM_READONLY_P (x)
+		      && !MEM_VOLATILE_P (x)
+		      && MEM_NOTRAP_P (x))
+		    /* Constant memory reference, e.g., a PIC address.  */
+		    continue;
+		}
 
 	      /* ??? Optimally, we would use interprocedural alias
 		 analysis to determine if this mem is actually killed
diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c
index 56c785e..68c1a1d 100644
--- a/gcc/ifcvt.c
+++ b/gcc/ifcvt.c
@@ -3010,19 +3010,6 @@  noce_operand_ok (const_rtx op)
   return ! may_trap_p (op);
 }
 
-/* Return true if X contains a MEM subrtx.  */
-
-static bool
-contains_mem_rtx_p (rtx x)
-{
-  subrtx_iterator::array_type array;
-  FOR_EACH_SUBRTX (iter, array, x, ALL)
-    if (MEM_P (*iter))
-      return true;
-
-  return false;
-}
-
 /* Return true iff basic block TEST_BB is valid for noce if-conversion.
    The condition used in this if-conversion is in COND.
    In practice, check that TEST_BB ends with a single set
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 302afc0..b9a7989 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -3090,6 +3090,7 @@  extern bool rtx_referenced_p (const_rtx, const_rtx);
 extern bool tablejump_p (const rtx_insn *, rtx_insn **, rtx_jump_table_data **);
 extern int computed_jump_p (const rtx_insn *);
 extern bool tls_referenced_p (const_rtx);
+extern bool contains_mem_rtx_p (rtx x);
 
 /* Overload for refers_to_regno_p for checking a single register.  */
 inline bool
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c
index ef93584..acb4230 100644
--- a/gcc/rtlanal.c
+++ b/gcc/rtlanal.c
@@ -685,6 +685,19 @@  rtx_addr_can_trap_p (const_rtx x)
   return rtx_addr_can_trap_p_1 (x, 0, 0, VOIDmode, false);
 }
 
+/* Return true if X contains a MEM subrtx.  */
+
+bool
+contains_mem_rtx_p (rtx x)
+{
+  subrtx_iterator::array_type array;
+  FOR_EACH_SUBRTX (iter, array, x, ALL)
+    if (MEM_P (*iter))
+      return true;
+
+  return false;
+}
+
 /* Return true if X is an address that is known to not be zero.  */
 
 bool
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 74e8d0d..16b27e6 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@ 
+2017-01-04  Jeff Law  <law@redhat.com>
+
+	PR tree-optimization/78812
+	* g++.dg/torture/pr78812.C: New test.
+
 2017-01-04  Michael Meissner  <meissner@linux.vnet.ibm.com>
 
 	PR target/71977
diff --git a/gcc/testsuite/g++.dg/torture/pr78812.C b/gcc/testsuite/g++.dg/torture/pr78812.C
new file mode 100644
index 0000000..efe0936
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/pr78812.C
@@ -0,0 +1,24 @@ 
+// { dg-do run } 
+// { dg-options "-fpic" { target fpic } }
+
+struct T
+{
+  bool a;
+  T () : a (false) {}
+  ~T () { if (!a) __builtin_abort (); }
+};
+
+__attribute__((noinline))
+void
+test (T &x)
+{
+  x.a = true;
+}
+
+int
+main ()
+{
+  T T;
+  test (T);
+}
+