This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Fix kernel oops. PR 18241.



This fixes a problem with volatile operands. When we find a volatile operand, we mark the statement as having volatile operands to prevents optimizers from messing around with them. However, we also used to tell the operand scanner to not bother adding a virtual operand for volatiles.


This is all fine and good until you mix volatile storage with local variables. DCE was killing a store to a local variable that had no apparent uses:

int a;
volatile int *p = &a;
a = 3;
if (*p != 3)
   abort ();


The if() was not generating a VUSE for 'a', so DCE was removing 'a = 3'. This patch exposes the virtual operands and prevents such silliness.


At first we thought that this would require overhauling several optimizers but (a) we already have a statement annotation specifying that the statement has volatile operands which most/all optimizers check, and, (b) volatile variables are never GIMPLE registers, so they always end up in virtual operands.

The PR ended up having several variations of a similar failure. Since they would each fail with the different alternative patches we tried, I decided to keep all 5 of them.

Bootstrapped and tested on x86, x86-64, ppc, ia64 and alpha.


Diego.
2005-01-08  Jeff Law  <law@redhat.com>
	    Diego Novillo  <dnovillo@redhat.com>

	PR tree-optimization/18241
	* tree-nrv.c (tree_nrv): Ignore volatile return values.
	* tree-ssa-dse.c (dse_optimize_stmt): Do not optimize
	statements with volatile operands.
	* tree-ssa-operands.c (add_stmt_operand): Do add volatile
	operands after marking a statement with has_volatile_ops.

testsuite/ChangeLog:

2005-01-08  Diego Novillo  <dnovillo@redhat.com>

	PR tree-optimization/18241
	* gcc.dg/pr18241-1.c: New test.
	* gcc.dg/pr18241-2.c: New test.
	* gcc.dg/pr18241-3.c: New test.
	* gcc.dg/pr18241-4.c: New test.
	* gcc.dg/pr18241-5.c: New test.

Index: tree-nrv.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-nrv.c,v
retrieving revision 2.5
diff -d -c -p -u -r2.5 tree-nrv.c
--- tree-nrv.c	6 Sep 2004 10:08:02 -0000	2.5
+++ tree-nrv.c	8 Jan 2005 15:15:43 -0000
@@ -154,6 +154,7 @@ tree_nrv (void)
 	  /* The returned value must be a local automatic variable of the
 	     same type and alignment as the function's result.  */
 	  if (TREE_CODE (found) != VAR_DECL
+	      || TREE_THIS_VOLATILE (found)
 	      || DECL_CONTEXT (found) != current_function_decl
 	      || TREE_STATIC (found)
 	      || TREE_ADDRESSABLE (found)
Index: tree-ssa-dse.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-dse.c,v
retrieving revision 2.12
diff -d -c -p -u -r2.12 tree-ssa-dse.c
--- tree-ssa-dse.c	26 Sep 2004 19:53:13 -0000	2.12
+++ tree-ssa-dse.c	8 Jan 2005 15:15:44 -0000
@@ -259,6 +259,10 @@ dse_optimize_stmt (struct dom_walk_data 
      not also a function call, then record it into our table.  */
   if (get_call_expr_in (stmt))
     return;
+
+  if (ann->has_volatile_ops)
+    return;
+
   if (TREE_CODE (stmt) == MODIFY_EXPR)
     {
       dataflow_t df = get_immediate_uses (stmt);
Index: tree-ssa-operands.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-operands.c,v
retrieving revision 2.60
diff -d -c -p -u -r2.60 tree-ssa-operands.c
--- tree-ssa-operands.c	10 Dec 2004 17:28:32 -0000	2.60
+++ tree-ssa-operands.c	8 Jan 2005 15:15:44 -0000
@@ -1520,13 +1520,10 @@ add_stmt_operand (tree *var_p, stmt_ann_
   sym = (TREE_CODE (var) == SSA_NAME ? SSA_NAME_VAR (var) : var);
   v_ann = var_ann (sym);
 
-  /* Don't expose volatile variables to the optimizers.  */
-  if (TREE_THIS_VOLATILE (sym))
-    {
-      if (s_ann)
-	s_ann->has_volatile_ops = true;
-      return;
-    }
+  /* Mark statements with volatile operands.  Optimizers should back
+     off from statements having volatile operands.  */
+  if (TREE_THIS_VOLATILE (sym) && s_ann)
+    s_ann->has_volatile_ops = true;
 
   if (is_real_op)
     {
Index: testsuite/gcc.dg/pr18241-1.c
===================================================================
RCS file: testsuite/gcc.dg/pr18241-1.c
diff -N testsuite/gcc.dg/pr18241-1.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gcc.dg/pr18241-1.c	8 Jan 2005 15:15:46 -0000
@@ -0,0 +1,107 @@
+/* { dg-do execute } */
+/* { dg-options "-std=gnu99 -Wall -Wextra -O1" } */ 
+
+extern void *memset (void*, int, unsigned long);
+extern void abort (void);
+
+struct radix_tree_root {
+	unsigned int height;
+	struct radix_tree_node *rnode;
+};
+
+struct radix_tree_node {
+	unsigned int count;
+	void *slots[64];
+	unsigned long tags[2][2];
+};
+
+struct radix_tree_path {
+	struct radix_tree_node *node, **slot;
+	int offset;
+};
+
+static unsigned long height_to_maxindex[7] =
+{0, 63, 4095, 262143, 16777215, 1073741823, 4294967295};
+
+static inline void tag_clear(struct radix_tree_node *node, int tag, int offset)
+{
+	int nr;
+	volatile unsigned long *addr;
+	int mask;
+	
+	nr = offset;
+	addr = &node->tags[tag][0];
+
+	addr += nr >> 5;
+	mask = 1 << (nr & 0x1f);
+	*addr &= ~mask;
+}
+
+void *radix_tree_tag_clear(struct radix_tree_root *root, unsigned long index, int tag)
+{
+	struct radix_tree_path path[7], *pathp = path;
+	unsigned int height, shift;
+	void *ret = 0;
+	
+	height = root->height;
+	if (index > height_to_maxindex[height])
+		goto out;
+	
+	shift = (height - 1) * 6;
+	pathp->node = 0;
+	pathp->slot = &root->rnode;
+	
+	while (height > 0) {
+		int offset;
+		
+		if (*pathp->slot == 0)
+			goto out;
+		
+		offset = (index >> shift) & (64-1);
+		pathp[1].offset = offset;
+		pathp[1].node = *pathp[0].slot;
+		pathp[1].slot = (struct radix_tree_node **)
+			(pathp[1].node->slots + offset);
+		pathp++;
+		shift -= 6;
+		height--;
+	}
+	
+	ret = *pathp[0].slot;
+	if (ret == 0)
+		goto out;
+	
+	do {
+		int idx;
+		
+		tag_clear(pathp[0].node, tag, pathp[0].offset);
+		for (idx = 0; idx < 2; idx++) {
+			if (pathp[0].node->tags[tag][idx])
+				goto out;
+		}
+		pathp--;
+	} while (pathp[0].node);
+out:
+	return ret;
+}
+
+int main ()
+{
+	struct radix_tree_root r;
+	struct radix_tree_node node;
+	void *p = (void *) 0xdeadbeef;
+	
+  	r.height = 1;
+	r.rnode = &node;
+	
+	memset (&node, 0, sizeof (node));
+	
+	node.count = 1;
+	node.slots [13] = p;
+	
+	radix_tree_tag_clear (&r, 13, 1);
+	
+	if (r.rnode->slots[13] != p)
+		abort ();
+	return 0;
+}
Index: testsuite/gcc.dg/pr18241-2.c
===================================================================
RCS file: testsuite/gcc.dg/pr18241-2.c
diff -N testsuite/gcc.dg/pr18241-2.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gcc.dg/pr18241-2.c	8 Jan 2005 15:15:46 -0000
@@ -0,0 +1,65 @@
+/* { dg-do execute } */
+/* { dg-options "-std=gnu99 -Wall -Wextra -O1" } */ 
+
+extern void *memset (void*, int, unsigned long);
+extern void abort (void);
+
+struct radix_tree_root {
+	unsigned int height;
+	struct radix_tree_node *rnode;
+};
+
+struct radix_tree_node {
+	unsigned int count;
+	void *slots[64];
+	unsigned long tags[2];
+};
+
+struct radix_tree_path {
+	struct radix_tree_node *node, **slot;
+	int offset;
+};
+
+void radix_tree_tag_clear(struct radix_tree_root *root, unsigned long index)
+{
+	struct radix_tree_path path[7], *pathp = path;
+	unsigned int height, shift;
+	volatile unsigned long *addr;
+	
+	height = root->height;
+	
+	shift = (height - 1) * 6;
+	path[0].slot = &root->rnode;
+	
+	while (height > 0) {
+		int offset;
+		
+		offset = (index >> shift) & (64-1);
+		pathp[1].offset = offset;
+		pathp[1].node = *pathp[0].slot;
+		pathp[1].slot = (struct radix_tree_node **)
+			(pathp[1].node->slots + offset);
+		pathp++;
+		shift -= 6;
+		height--;
+	}
+	
+	addr = &(pathp->node->tags[0]) + 1;
+	*addr = 574;
+}
+
+struct radix_tree_root r;
+struct radix_tree_node node;
+
+int main ()
+{
+  	r.height = 1;
+	r.rnode = &node;
+	
+	memset (&node, 0, sizeof (node));
+	
+	node.count = 1;
+	
+	radix_tree_tag_clear (&r, 13);
+	return 0;
+}
Index: testsuite/gcc.dg/pr18241-3.c
===================================================================
RCS file: testsuite/gcc.dg/pr18241-3.c
diff -N testsuite/gcc.dg/pr18241-3.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gcc.dg/pr18241-3.c	8 Jan 2005 15:15:46 -0000
@@ -0,0 +1,31 @@
+/* { dg-do execute } */
+/* { dg-options "-O1" } */ 
+
+void abort (void);
+
+void radix_tree_tag_clear (int *node)
+{
+	int *path[2], **pathp = path, height;
+	volatile int *addr;
+	
+	height = 1;
+	pathp[0] = node;
+	
+	while (height > 0) {
+		pathp[1] = pathp[0];
+		pathp++;
+		height--;
+	}
+	
+	addr = pathp[0];
+	*addr = 1;
+}
+
+int main ()
+{
+	int n;
+	radix_tree_tag_clear (&n);
+	if (n != 1)
+		abort ();
+	return 0;
+}
Index: testsuite/gcc.dg/pr18241-4.c
===================================================================
RCS file: testsuite/gcc.dg/pr18241-4.c
diff -N testsuite/gcc.dg/pr18241-4.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gcc.dg/pr18241-4.c	8 Jan 2005 15:15:46 -0000
@@ -0,0 +1,22 @@
+/* { dg-do execute } */
+/* { dg-options "-O1" } */ 
+
+void abort (void);
+
+int f(int i1243)
+{
+  int i[2], *i1 = i;
+  i[0] = 1;
+  volatile int *i2 = i1;
+  i2[1] = 1;
+  i1243 = 0;
+  return i2[1]+i2[0];
+}
+
+
+int main(void)
+{
+  if( f(100) != 2)
+   abort ();
+  return 0;
+}
Index: testsuite/gcc.dg/pr18241-5.c
===================================================================
RCS file: testsuite/gcc.dg/pr18241-5.c
diff -N testsuite/gcc.dg/pr18241-5.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gcc.dg/pr18241-5.c	8 Jan 2005 15:15:46 -0000
@@ -0,0 +1,14 @@
+/* { dg-do execute } */
+/* { dg-options "-O1" } */ 
+
+void abort (void);
+
+int main ()
+{
+  int a;
+  volatile int *b = &a;
+  a = 1;
+  if (*b != 1)
+    abort ();
+  return 0;
+}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]