diff mbox

Fix ICE during operand_equal_p hash checking (PR middle-end/70843)

Message ID 20160428155058.GT26501@tucnak.zalov.cz
State New
Headers show

Commit Message

Jakub Jelinek April 28, 2016, 3:50 p.m. UTC
Hi!

As reported in the PR and can be seen on this simplified testcase
everywhere, the FEs sometimes call operand_equal_p e.g. on a SAVE_EXPR
that contains a BIND_EXPR in it, and if arg0 == arg1, operand_equal_p
can return non-zero on it.
The ICE is because inchash::add_expr is unprepared to hash some trees,
it handles just tcc_declaration, selected specific trees and expressions of
all kinds, the last one usually by just recursing on all their operands.
For BIND_EXPR, the last operand is usually a BLOCK which we ICE on though,
and the middle argument usually a STATEMENT_LIST that we ICE on as well.

The first hunk is just an optimization (but fixes the ICE anyway),
I think we really don't need to verify that a hash function for the same
argument always returns the same value.  But I can imagine e.g.
a SAVE_EXPR of BIND_EXPR + var and var + the same SAVE_EXPR being compared
using operand_equal_p and there we wouldn't be equal at the top level and
still ICE.
The second hunk alone fixes the ICE too, by making sure we handle those
(just ignoring BLOCK and OMP_CLAUSE (the latter for now, if we find we want
to hash pre-OMP expansion trees too often we could adjust).

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2016-04-28  Jakub Jelinek  <jakub@redhat.com>

	PR middle-end/70843
	* fold-const.c (operand_equal_p): Don't verify hash value equality
	if arg0 == arg1.
	* tree.c (inchash::add_expr): Handle STATEMENT_LIST.  Ignore BLOCK
	and OMP_CLAUSE.

	* gcc.dg/pr70843.c: New test.


	Jakub

Comments

Jeff Law April 28, 2016, 10:18 p.m. UTC | #1
On 04/28/2016 09:50 AM, Jakub Jelinek wrote:
> Hi!
>
> As reported in the PR and can be seen on this simplified testcase
> everywhere, the FEs sometimes call operand_equal_p e.g. on a SAVE_EXPR
> that contains a BIND_EXPR in it, and if arg0 == arg1, operand_equal_p
> can return non-zero on it.
> The ICE is because inchash::add_expr is unprepared to hash some trees,
> it handles just tcc_declaration, selected specific trees and expressions of
> all kinds, the last one usually by just recursing on all their operands.
> For BIND_EXPR, the last operand is usually a BLOCK which we ICE on though,
> and the middle argument usually a STATEMENT_LIST that we ICE on as well.
>
> The first hunk is just an optimization (but fixes the ICE anyway),
> I think we really don't need to verify that a hash function for the same
> argument always returns the same value.  But I can imagine e.g.
> a SAVE_EXPR of BIND_EXPR + var and var + the same SAVE_EXPR being compared
> using operand_equal_p and there we wouldn't be equal at the top level and
> still ICE.
> The second hunk alone fixes the ICE too, by making sure we handle those
> (just ignoring BLOCK and OMP_CLAUSE (the latter for now, if we find we want
> to hash pre-OMP expansion trees too often we could adjust).
>
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
>
> 2016-04-28  Jakub Jelinek  <jakub@redhat.com>
>
> 	PR middle-end/70843
> 	* fold-const.c (operand_equal_p): Don't verify hash value equality
> 	if arg0 == arg1.
> 	* tree.c (inchash::add_expr): Handle STATEMENT_LIST.  Ignore BLOCK
> 	and OMP_CLAUSE.
>
> 	* gcc.dg/pr70843.c: New test.
OK.

Jeff
diff mbox

Patch

--- gcc/fold-const.c.jj	2016-04-27 15:29:05.000000000 +0200
+++ gcc/fold-const.c	2016-04-28 13:28:56.272276557 +0200
@@ -2756,12 +2756,15 @@  operand_equal_p (const_tree arg0, const_
     {
       if (operand_equal_p (arg0, arg1, flags | OEP_NO_HASH_CHECK))
 	{
-	  inchash::hash hstate0 (0), hstate1 (0);
-	  inchash::add_expr (arg0, hstate0, flags);
-	  inchash::add_expr (arg1, hstate1, flags);
-	  hashval_t h0 = hstate0.end ();
-	  hashval_t h1 = hstate1.end ();
-	  gcc_assert (h0 == h1);
+	  if (arg0 != arg1)
+	    {
+	      inchash::hash hstate0 (0), hstate1 (0);
+	      inchash::add_expr (arg0, hstate0, flags);
+	      inchash::add_expr (arg1, hstate1, flags);
+	      hashval_t h0 = hstate0.end ();
+	      hashval_t h1 = hstate1.end ();
+	      gcc_assert (h0 == h1);
+	    }
 	  return 1;
 	}
       else
--- gcc/tree.c.jj	2016-04-27 09:45:27.000000000 +0200
+++ gcc/tree.c	2016-04-28 13:24:01.770245254 +0200
@@ -7836,6 +7836,10 @@  add_expr (const_tree t, inchash::hash &h
     case PLACEHOLDER_EXPR:
       /* The node itself doesn't matter.  */
       return;
+    case BLOCK:
+    case OMP_CLAUSE:
+      /* Ignore.  */
+      return;
     case TREE_LIST:
       /* A list of expressions, for a CALL_EXPR or as the elements of a
 	 VECTOR_CST.  */
@@ -7854,6 +7858,14 @@  add_expr (const_tree t, inchash::hash &h
 	  }
 	return;
       }
+    case STATEMENT_LIST:
+      {
+	tree_stmt_iterator i;
+	for (i = tsi_start (CONST_CAST_TREE (t));
+	     !tsi_end_p (i); tsi_next (&i))
+	  inchash::add_expr (tsi_stmt (i), hstate, flags);
+	return;
+      }
     case FUNCTION_DECL:
       /* When referring to a built-in FUNCTION_DECL, use the __builtin__ form.
 	 Otherwise nodes that compare equal according to operand_equal_p might
--- gcc/testsuite/gcc.dg/pr70843.c.jj	2016-04-28 13:37:54.596022706 +0200
+++ gcc/testsuite/gcc.dg/pr70843.c	2016-04-28 13:37:38.000000000 +0200
@@ -0,0 +1,9 @@ 
+/* PR middle-end/70843 */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+int
+foo (int x, int y)
+{
+  return ({ int a = 5; a += x; a *= y; a; }) ? : 2;
+}