Re: [PATCH 2/2] Simplify and extend VRP edge-assertion code
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
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
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
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
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
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 (); /* {