Re: [PATCH 2/2] Simplify and extend VRP edge-assertion code

2014-11-11 Thread Patrick Palka
This patch failed regtesting -- and on second thought I'm not too
confident that the refactoring is strictly an improvement so I will
try to fix the main issue (that is to make the test vrp-1.c fail to
compile) in a more direct way.


Re: [PATCH 2/2] Simplify and extend VRP edge-assertion code

2014-11-11 Thread Richard Biener
On Tue, Nov 11, 2014 at 4:52 AM, Patrick Palka patr...@parcs.ath.cx wrote:
 This patch refactors the VRP edge-assertion code to make it always
 traverse SSA-name definitions in order to find suitable edge assertions
 to insert.  Currently SSA-name definitions get traversed only when the
 LHS of the original conditional is a bitwise AND or OR operation which
 seems like a strange restriction.  We should always try to traverse
 the SSA-name definitions inside the conditional, in particular for
 conditionals with the form:

   int p = x COMP y;
   if (p != 0) -- edge assertion: x COMP y

Of course this specific case should have been simplified to

 if (x COMP y)

if that comparison cannot trap and -fnon-call-exceptions is in effect.

 To achieve this the patch merges the mutually recursive functions
 register_edge_assert_for_1() and register_edge_assert_for_2() into a
 single recursive function, register_edge_assert_for_1().  In doing so,
 code duplication can be reduced and at the same time the more general
 logic allows VRP to detect more useful edge assertions.

 The recursion of the function register_edge_assert_for_1() is bounded by
 a new 'limit' argument which is arbitrarily set to 4 so that at most 4
 levels of SSA-name definitions will be traversed per conditional.
 (Incidentally this hard recursion limit makes the related fix for PR
 57685 unnecessary.)

 A test in uninit-pred-9_b.c now has to be marked xfail because in it VRP
 (correctly) transforms the statement

   # prephitmp_35 = PHI pretmp_9(8), _28(10)
   into
   # prephitmp_35 = PHI pretmp_9(8), 1(10)

 and the uninit pass doesn't properly handle such PHIs containing a
 constant value as one of its arguments -- so a bogus uninit warning is
 now emitted.

Did you try fixing that?  It seems to me a constant should be easy
to handle?

 Full bootstrap + regtesting on x86_64-unknown-linux-gnu is in progress.
 Is it OK to commit if testing finishes with no new regressions?

Ok.

Thanks,
Richard.

 2014-11-11  Patrick Palka  patr...@parcs.ath.cx

 gcc/
 * tree-vrp.c (extract_code_and_val_from_cond_with_ops): Ensure
 that NAME always equals COND_OP0 or COND_OP1.
 (register_edge_assert_for, register_edge_assert_for_1,
 register_edge_assert_for_2): Refactor and consolidate
 edge-assertion logic into ...
 (register_edge_assert_for_2): ... here.  Add LIMIT parameter.
 Rename to ...
 (register_edge_assert_for_1): ... this.

 gcc/testsuite/
 * gcc.dg/vrp-1.c: New testcase.
 * gcc.dg/vrp-2.c: New testcase.
 * gcc.dg/uninit-pred-9_b.c: xfail test on line 24.
 ---
  gcc/testsuite/gcc.dg/uninit-pred-9_b.c |   2 +-
  gcc/testsuite/gcc.dg/vrp-1.c   |  31 
  gcc/testsuite/gcc.dg/vrp-2.c   |  78 ++
  gcc/tree-vrp.c | 261 
 +++--
  4 files changed, 231 insertions(+), 141 deletions(-)
  create mode 100644 gcc/testsuite/gcc.dg/vrp-1.c
  create mode 100644 gcc/testsuite/gcc.dg/vrp-2.c

 diff --git a/gcc/testsuite/gcc.dg/uninit-pred-9_b.c 
 b/gcc/testsuite/gcc.dg/uninit-pred-9_b.c
 index d9ae75e..555ec20 100644
 --- a/gcc/testsuite/gcc.dg/uninit-pred-9_b.c
 +++ b/gcc/testsuite/gcc.dg/uninit-pred-9_b.c
 @@ -21,7 +21,7 @@ int foo (int n, int l, int m, int r)
blah(v); /* { dg-bogus uninitialized bogus warning } */

if ( (n = 8)   (m  99)   (r  19) )
 -  blah(v); /* { dg-bogus uninitialized bogus warning } */
 +  blah(v); /* { dg-bogus uninitialized bogus warning { xfail *-*-* } 
 } */

return 0;
  }
 diff --git a/gcc/testsuite/gcc.dg/vrp-1.c b/gcc/testsuite/gcc.dg/vrp-1.c
 new file mode 100644
 index 000..df5334e
 --- /dev/null
 +++ b/gcc/testsuite/gcc.dg/vrp-1.c
 @@ -0,0 +1,31 @@
 +/* { dg-options -O2 } */
 +
 +void runtime_error (void) __attribute__ ((noreturn));
 +void compiletime_error (void) __attribute__ ((noreturn, error ()));
 +
 +static void
 +compiletime_check_equals_1 (int *x, int y)
 +{
 +  int __p = *x != y;
 +  if (__builtin_constant_p (__p)  __p)
 +compiletime_error ();
 +  if (__p)
 +runtime_error ();
 +}
 +
 +static void
 +compiletime_check_equals_2 (int *x, int y)
 +{
 +  int __p = *x != y;
 +  if (__builtin_constant_p (__p)  __p)
 +compiletime_error (); /* { dg-error call to } */
 +  if (__p)
 +runtime_error ();
 +}
 +
 +void
 +foo (int *x)
 +{
 +  compiletime_check_equals_1 (x, 5);
 +  compiletime_check_equals_2 (x, 10);
 +}
 diff --git a/gcc/testsuite/gcc.dg/vrp-2.c b/gcc/testsuite/gcc.dg/vrp-2.c
 new file mode 100644
 index 000..5757c2f
 --- /dev/null
 +++ b/gcc/testsuite/gcc.dg/vrp-2.c
 @@ -0,0 +1,78 @@
 +/* { dg-options -O2 } */
 +
 +void runtime_error (void) __attribute__ ((noreturn));
 +void compiletime_error (void) __attribute__ ((noreturn, error ()));
 +
 +void dummy (int x);
 +
 +void
 +bar (int x, int y, int z)
 +{
 +  int p = ~(x  y  z) == 37;
 +  if (p)
 +{
 +  if (!x || !y || !z)
 +   compiletime_error (); /* { 

Re: [PATCH 2/2] Simplify and extend VRP edge-assertion code

2014-11-11 Thread Andrew Pinski
On Tue, Nov 11, 2014 at 4:52 AM, Richard Biener
richard.guent...@gmail.com wrote:
 On Tue, Nov 11, 2014 at 4:52 AM, Patrick Palka patr...@parcs.ath.cx wrote:
 This patch refactors the VRP edge-assertion code to make it always
 traverse SSA-name definitions in order to find suitable edge assertions
 to insert.  Currently SSA-name definitions get traversed only when the
 LHS of the original conditional is a bitwise AND or OR operation which
 seems like a strange restriction.  We should always try to traverse
 the SSA-name definitions inside the conditional, in particular for
 conditionals with the form:

   int p = x COMP y;
   if (p != 0) -- edge assertion: x COMP y

 Of course this specific case should have been simplified to

  if (x COMP y)

 if that comparison cannot trap and -fnon-call-exceptions is in effect.

Except I have found that if p was used below also. We still have if(p
!= 0).  I just saw that recently when I was working on enhancing
PHI-opt.

Thanks,
Andrew Pinski


 To achieve this the patch merges the mutually recursive functions
 register_edge_assert_for_1() and register_edge_assert_for_2() into a
 single recursive function, register_edge_assert_for_1().  In doing so,
 code duplication can be reduced and at the same time the more general
 logic allows VRP to detect more useful edge assertions.

 The recursion of the function register_edge_assert_for_1() is bounded by
 a new 'limit' argument which is arbitrarily set to 4 so that at most 4
 levels of SSA-name definitions will be traversed per conditional.
 (Incidentally this hard recursion limit makes the related fix for PR
 57685 unnecessary.)

 A test in uninit-pred-9_b.c now has to be marked xfail because in it VRP
 (correctly) transforms the statement

   # prephitmp_35 = PHI pretmp_9(8), _28(10)
   into
   # prephitmp_35 = PHI pretmp_9(8), 1(10)

 and the uninit pass doesn't properly handle such PHIs containing a
 constant value as one of its arguments -- so a bogus uninit warning is
 now emitted.

 Did you try fixing that?  It seems to me a constant should be easy
 to handle?

 Full bootstrap + regtesting on x86_64-unknown-linux-gnu is in progress.
 Is it OK to commit if testing finishes with no new regressions?

 Ok.

 Thanks,
 Richard.

 2014-11-11  Patrick Palka  patr...@parcs.ath.cx

 gcc/
 * tree-vrp.c (extract_code_and_val_from_cond_with_ops): Ensure
 that NAME always equals COND_OP0 or COND_OP1.
 (register_edge_assert_for, register_edge_assert_for_1,
 register_edge_assert_for_2): Refactor and consolidate
 edge-assertion logic into ...
 (register_edge_assert_for_2): ... here.  Add LIMIT parameter.
 Rename to ...
 (register_edge_assert_for_1): ... this.

 gcc/testsuite/
 * gcc.dg/vrp-1.c: New testcase.
 * gcc.dg/vrp-2.c: New testcase.
 * gcc.dg/uninit-pred-9_b.c: xfail test on line 24.
 ---
  gcc/testsuite/gcc.dg/uninit-pred-9_b.c |   2 +-
  gcc/testsuite/gcc.dg/vrp-1.c   |  31 
  gcc/testsuite/gcc.dg/vrp-2.c   |  78 ++
  gcc/tree-vrp.c | 261 
 +++--
  4 files changed, 231 insertions(+), 141 deletions(-)
  create mode 100644 gcc/testsuite/gcc.dg/vrp-1.c
  create mode 100644 gcc/testsuite/gcc.dg/vrp-2.c

 diff --git a/gcc/testsuite/gcc.dg/uninit-pred-9_b.c 
 b/gcc/testsuite/gcc.dg/uninit-pred-9_b.c
 index d9ae75e..555ec20 100644
 --- a/gcc/testsuite/gcc.dg/uninit-pred-9_b.c
 +++ b/gcc/testsuite/gcc.dg/uninit-pred-9_b.c
 @@ -21,7 +21,7 @@ int foo (int n, int l, int m, int r)
blah(v); /* { dg-bogus uninitialized bogus warning } */

if ( (n = 8)   (m  99)   (r  19) )
 -  blah(v); /* { dg-bogus uninitialized bogus warning } */
 +  blah(v); /* { dg-bogus uninitialized bogus warning { xfail *-*-* 
 } } */

return 0;
  }
 diff --git a/gcc/testsuite/gcc.dg/vrp-1.c b/gcc/testsuite/gcc.dg/vrp-1.c
 new file mode 100644
 index 000..df5334e
 --- /dev/null
 +++ b/gcc/testsuite/gcc.dg/vrp-1.c
 @@ -0,0 +1,31 @@
 +/* { dg-options -O2 } */
 +
 +void runtime_error (void) __attribute__ ((noreturn));
 +void compiletime_error (void) __attribute__ ((noreturn, error ()));
 +
 +static void
 +compiletime_check_equals_1 (int *x, int y)
 +{
 +  int __p = *x != y;
 +  if (__builtin_constant_p (__p)  __p)
 +compiletime_error ();
 +  if (__p)
 +runtime_error ();
 +}
 +
 +static void
 +compiletime_check_equals_2 (int *x, int y)
 +{
 +  int __p = *x != y;
 +  if (__builtin_constant_p (__p)  __p)
 +compiletime_error (); /* { dg-error call to } */
 +  if (__p)
 +runtime_error ();
 +}
 +
 +void
 +foo (int *x)
 +{
 +  compiletime_check_equals_1 (x, 5);
 +  compiletime_check_equals_2 (x, 10);
 +}
 diff --git a/gcc/testsuite/gcc.dg/vrp-2.c b/gcc/testsuite/gcc.dg/vrp-2.c
 new file mode 100644
 index 000..5757c2f
 --- /dev/null
 +++ b/gcc/testsuite/gcc.dg/vrp-2.c
 @@ -0,0 +1,78 @@
 +/* { dg-options -O2 } */
 +
 +void runtime_error (void) __attribute__ 

Re: [PATCH 2/2] Simplify and extend VRP edge-assertion code

2014-11-11 Thread Richard Biener
On Tue, Nov 11, 2014 at 1:56 PM, Andrew Pinski pins...@gmail.com wrote:
 On Tue, Nov 11, 2014 at 4:52 AM, Richard Biener
 richard.guent...@gmail.com wrote:
 On Tue, Nov 11, 2014 at 4:52 AM, Patrick Palka patr...@parcs.ath.cx wrote:
 This patch refactors the VRP edge-assertion code to make it always
 traverse SSA-name definitions in order to find suitable edge assertions
 to insert.  Currently SSA-name definitions get traversed only when the
 LHS of the original conditional is a bitwise AND or OR operation which
 seems like a strange restriction.  We should always try to traverse
 the SSA-name definitions inside the conditional, in particular for
 conditionals with the form:

   int p = x COMP y;
   if (p != 0) -- edge assertion: x COMP y

 Of course this specific case should have been simplified to

  if (x COMP y)

 if that comparison cannot trap and -fnon-call-exceptions is in effect.

 Except I have found that if p was used below also. We still have if(p
 != 0).  I just saw that recently when I was working on enhancing
 PHI-opt.

Yeah - one of forwprop's single-use restrictions.  Definitely one
we don't want to preserve though.

Richard.

 Thanks,
 Andrew Pinski


 To achieve this the patch merges the mutually recursive functions
 register_edge_assert_for_1() and register_edge_assert_for_2() into a
 single recursive function, register_edge_assert_for_1().  In doing so,
 code duplication can be reduced and at the same time the more general
 logic allows VRP to detect more useful edge assertions.

 The recursion of the function register_edge_assert_for_1() is bounded by
 a new 'limit' argument which is arbitrarily set to 4 so that at most 4
 levels of SSA-name definitions will be traversed per conditional.
 (Incidentally this hard recursion limit makes the related fix for PR
 57685 unnecessary.)

 A test in uninit-pred-9_b.c now has to be marked xfail because in it VRP
 (correctly) transforms the statement

   # prephitmp_35 = PHI pretmp_9(8), _28(10)
   into
   # prephitmp_35 = PHI pretmp_9(8), 1(10)

 and the uninit pass doesn't properly handle such PHIs containing a
 constant value as one of its arguments -- so a bogus uninit warning is
 now emitted.

 Did you try fixing that?  It seems to me a constant should be easy
 to handle?

 Full bootstrap + regtesting on x86_64-unknown-linux-gnu is in progress.
 Is it OK to commit if testing finishes with no new regressions?

 Ok.

 Thanks,
 Richard.

 2014-11-11  Patrick Palka  patr...@parcs.ath.cx

 gcc/
 * tree-vrp.c (extract_code_and_val_from_cond_with_ops): Ensure
 that NAME always equals COND_OP0 or COND_OP1.
 (register_edge_assert_for, register_edge_assert_for_1,
 register_edge_assert_for_2): Refactor and consolidate
 edge-assertion logic into ...
 (register_edge_assert_for_2): ... here.  Add LIMIT parameter.
 Rename to ...
 (register_edge_assert_for_1): ... this.

 gcc/testsuite/
 * gcc.dg/vrp-1.c: New testcase.
 * gcc.dg/vrp-2.c: New testcase.
 * gcc.dg/uninit-pred-9_b.c: xfail test on line 24.
 ---
  gcc/testsuite/gcc.dg/uninit-pred-9_b.c |   2 +-
  gcc/testsuite/gcc.dg/vrp-1.c   |  31 
  gcc/testsuite/gcc.dg/vrp-2.c   |  78 ++
  gcc/tree-vrp.c | 261 
 +++--
  4 files changed, 231 insertions(+), 141 deletions(-)
  create mode 100644 gcc/testsuite/gcc.dg/vrp-1.c
  create mode 100644 gcc/testsuite/gcc.dg/vrp-2.c

 diff --git a/gcc/testsuite/gcc.dg/uninit-pred-9_b.c 
 b/gcc/testsuite/gcc.dg/uninit-pred-9_b.c
 index d9ae75e..555ec20 100644
 --- a/gcc/testsuite/gcc.dg/uninit-pred-9_b.c
 +++ b/gcc/testsuite/gcc.dg/uninit-pred-9_b.c
 @@ -21,7 +21,7 @@ int foo (int n, int l, int m, int r)
blah(v); /* { dg-bogus uninitialized bogus warning } */

if ( (n = 8)   (m  99)   (r  19) )
 -  blah(v); /* { dg-bogus uninitialized bogus warning } */
 +  blah(v); /* { dg-bogus uninitialized bogus warning { xfail *-*-* 
 } } */

return 0;
  }
 diff --git a/gcc/testsuite/gcc.dg/vrp-1.c b/gcc/testsuite/gcc.dg/vrp-1.c
 new file mode 100644
 index 000..df5334e
 --- /dev/null
 +++ b/gcc/testsuite/gcc.dg/vrp-1.c
 @@ -0,0 +1,31 @@
 +/* { dg-options -O2 } */
 +
 +void runtime_error (void) __attribute__ ((noreturn));
 +void compiletime_error (void) __attribute__ ((noreturn, error ()));
 +
 +static void
 +compiletime_check_equals_1 (int *x, int y)
 +{
 +  int __p = *x != y;
 +  if (__builtin_constant_p (__p)  __p)
 +compiletime_error ();
 +  if (__p)
 +runtime_error ();
 +}
 +
 +static void
 +compiletime_check_equals_2 (int *x, int y)
 +{
 +  int __p = *x != y;
 +  if (__builtin_constant_p (__p)  __p)
 +compiletime_error (); /* { dg-error call to } */
 +  if (__p)
 +runtime_error ();
 +}
 +
 +void
 +foo (int *x)
 +{
 +  compiletime_check_equals_1 (x, 5);
 +  compiletime_check_equals_2 (x, 10);
 +}
 diff --git a/gcc/testsuite/gcc.dg/vrp-2.c b/gcc/testsuite/gcc.dg/vrp-2.c
 

Re: [PATCH 2/2] Simplify and extend VRP edge-assertion code

2014-11-11 Thread Patrick Palka
On Tue, Nov 11, 2014 at 7:52 AM, Richard Biener
richard.guent...@gmail.com wrote:
 On Tue, Nov 11, 2014 at 4:52 AM, Patrick Palka patr...@parcs.ath.cx wrote:
 This patch refactors the VRP edge-assertion code to make it always
 traverse SSA-name definitions in order to find suitable edge assertions
 to insert.  Currently SSA-name definitions get traversed only when the
 LHS of the original conditional is a bitwise AND or OR operation which
 seems like a strange restriction.  We should always try to traverse
 the SSA-name definitions inside the conditional, in particular for
 conditionals with the form:

   int p = x COMP y;
   if (p != 0) -- edge assertion: x COMP y

 Of course this specific case should have been simplified to

  if (x COMP y)

 if that comparison cannot trap and -fnon-call-exceptions is in effect.

Like Andrew said, I noticed that if p is shared then such comparisons
don't get simplified.  And like in the case of uninit-pred-9_b.c it
seems that the compiler sometimes implicitly CSEs duplicate
conditionals.


 To achieve this the patch merges the mutually recursive functions
 register_edge_assert_for_1() and register_edge_assert_for_2() into a
 single recursive function, register_edge_assert_for_1().  In doing so,
 code duplication can be reduced and at the same time the more general
 logic allows VRP to detect more useful edge assertions.

 The recursion of the function register_edge_assert_for_1() is bounded by
 a new 'limit' argument which is arbitrarily set to 4 so that at most 4
 levels of SSA-name definitions will be traversed per conditional.
 (Incidentally this hard recursion limit makes the related fix for PR
 57685 unnecessary.)

 A test in uninit-pred-9_b.c now has to be marked xfail because in it VRP
 (correctly) transforms the statement

   # prephitmp_35 = PHI pretmp_9(8), _28(10)
   into
   # prephitmp_35 = PHI pretmp_9(8), 1(10)

 and the uninit pass doesn't properly handle such PHIs containing a
 constant value as one of its arguments -- so a bogus uninit warning is
 now emitted.

 Did you try fixing that?  It seems to me a constant should be easy
 to handle?

I tried a couple months ago and I failed.  I might try again.


 Full bootstrap + regtesting on x86_64-unknown-linux-gnu is in progress.
 Is it OK to commit if testing finishes with no new regressions?

 Ok.

I decided to replace this refactoring patch with a simpler patch (sent
to the ML) that just changes (adds) about 20LOC to tree-vrp.c.  The
patch is not as extensive (a few of the tests in vrp-2.c still fail)
but I am more comfortable about the patch's correctness and its impact
on compile time.  Sorry, I should've been more clear about that.


[PATCH 2/2] Simplify and extend VRP edge-assertion code

2014-11-10 Thread Patrick Palka
This patch refactors the VRP edge-assertion code to make it always
traverse SSA-name definitions in order to find suitable edge assertions
to insert.  Currently SSA-name definitions get traversed only when the
LHS of the original conditional is a bitwise AND or OR operation which
seems like a strange restriction.  We should always try to traverse
the SSA-name definitions inside the conditional, in particular for
conditionals with the form:

  int p = x COMP y;
  if (p != 0) -- edge assertion: x COMP y

To achieve this the patch merges the mutually recursive functions
register_edge_assert_for_1() and register_edge_assert_for_2() into a
single recursive function, register_edge_assert_for_1().  In doing so,
code duplication can be reduced and at the same time the more general
logic allows VRP to detect more useful edge assertions.

The recursion of the function register_edge_assert_for_1() is bounded by
a new 'limit' argument which is arbitrarily set to 4 so that at most 4
levels of SSA-name definitions will be traversed per conditional.
(Incidentally this hard recursion limit makes the related fix for PR
57685 unnecessary.)

A test in uninit-pred-9_b.c now has to be marked xfail because in it VRP
(correctly) transforms the statement

  # prephitmp_35 = PHI pretmp_9(8), _28(10)
  into
  # prephitmp_35 = PHI pretmp_9(8), 1(10)

and the uninit pass doesn't properly handle such PHIs containing a
constant value as one of its arguments -- so a bogus uninit warning is
now emitted.

Full bootstrap + regtesting on x86_64-unknown-linux-gnu is in progress.
Is it OK to commit if testing finishes with no new regressions?

2014-11-11  Patrick Palka  patr...@parcs.ath.cx

gcc/
* tree-vrp.c (extract_code_and_val_from_cond_with_ops): Ensure
that NAME always equals COND_OP0 or COND_OP1.
(register_edge_assert_for, register_edge_assert_for_1,
register_edge_assert_for_2): Refactor and consolidate
edge-assertion logic into ...
(register_edge_assert_for_2): ... here.  Add LIMIT parameter.
Rename to ...
(register_edge_assert_for_1): ... this.

gcc/testsuite/
* gcc.dg/vrp-1.c: New testcase.
* gcc.dg/vrp-2.c: New testcase.
* gcc.dg/uninit-pred-9_b.c: xfail test on line 24.
---
 gcc/testsuite/gcc.dg/uninit-pred-9_b.c |   2 +-
 gcc/testsuite/gcc.dg/vrp-1.c   |  31 
 gcc/testsuite/gcc.dg/vrp-2.c   |  78 ++
 gcc/tree-vrp.c | 261 +++--
 4 files changed, 231 insertions(+), 141 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/vrp-1.c
 create mode 100644 gcc/testsuite/gcc.dg/vrp-2.c

diff --git a/gcc/testsuite/gcc.dg/uninit-pred-9_b.c 
b/gcc/testsuite/gcc.dg/uninit-pred-9_b.c
index d9ae75e..555ec20 100644
--- a/gcc/testsuite/gcc.dg/uninit-pred-9_b.c
+++ b/gcc/testsuite/gcc.dg/uninit-pred-9_b.c
@@ -21,7 +21,7 @@ int foo (int n, int l, int m, int r)
   blah(v); /* { dg-bogus uninitialized bogus warning } */
 
   if ( (n = 8)   (m  99)   (r  19) )
-  blah(v); /* { dg-bogus uninitialized bogus warning } */
+  blah(v); /* { dg-bogus uninitialized bogus warning { xfail *-*-* } } 
*/
 
   return 0;
 }
diff --git a/gcc/testsuite/gcc.dg/vrp-1.c b/gcc/testsuite/gcc.dg/vrp-1.c
new file mode 100644
index 000..df5334e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vrp-1.c
@@ -0,0 +1,31 @@
+/* { dg-options -O2 } */
+
+void runtime_error (void) __attribute__ ((noreturn));
+void compiletime_error (void) __attribute__ ((noreturn, error ()));
+
+static void
+compiletime_check_equals_1 (int *x, int y)
+{
+  int __p = *x != y;
+  if (__builtin_constant_p (__p)  __p)
+compiletime_error ();
+  if (__p)
+runtime_error ();
+}
+
+static void
+compiletime_check_equals_2 (int *x, int y)
+{
+  int __p = *x != y;
+  if (__builtin_constant_p (__p)  __p)
+compiletime_error (); /* { dg-error call to } */
+  if (__p)
+runtime_error ();
+}
+
+void
+foo (int *x)
+{
+  compiletime_check_equals_1 (x, 5);
+  compiletime_check_equals_2 (x, 10);
+}
diff --git a/gcc/testsuite/gcc.dg/vrp-2.c b/gcc/testsuite/gcc.dg/vrp-2.c
new file mode 100644
index 000..5757c2f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vrp-2.c
@@ -0,0 +1,78 @@
+/* { dg-options -O2 } */
+
+void runtime_error (void) __attribute__ ((noreturn));
+void compiletime_error (void) __attribute__ ((noreturn, error ()));
+
+void dummy (int x);
+
+void
+bar (int x, int y, int z)
+{
+  int p = ~(x  y  z) == 37;
+  if (p)
+{
+  if (!x || !y || !z)
+   compiletime_error (); /* { dg-bogus call to } */
+}
+}
+
+void
+baz (int x)
+{
+  int y = ~x;
+  int p = y == 37;
+  dummy (y);
+  dummy (p);
+  if (p)
+{
+  int q = x != ~37;
+  dummy (q);
+  if (q)
+   compiletime_error (); /* { dg-bogus call to } */
+}
+}
+
+void
+blah_1 (char x)
+{
+  int y = x;
+  int p = y == 10;
+  dummy (p);
+  if (p)
+{
+  int q = x != 10;
+  dummy (q);
+  if (q)
+   compiletime_error (); /* {