[RFA][PR tree-optimization/79095][PATCH 4/4] Tests
These are the tests. The tests in g++.dg start with a reduced test from Martin (pr79095-1.C) that includes a size check. With the size != 0 check this testcase should not issue any warnings as the path that turns into a __builtin_memset should get eliminated. pr79095-2.C is the same test, but without the size != test. This test should trigger an "exceeds maximum object size" warning. pr79095-3.C is the original test from the BZ, but with a proper size check on the vector. This test should not produce a warning. pr79095-4.C is the original test from the BZ, but without a size check on the vector. This should produce *one* warning (trunk currently generates 3). We verify that there's just one __builtin_memset by the time VRP2 is done and verify that we do get the desired warning. pr79095-5.C is another test from Martin which should not produce a warning. gcc-torture/execute/arith-1.c is updated to test a few more cases. This was mis-compiled at some point during patch development and at that time I added the additional tsts. gcc.dg/tree-ssa/pr79095.c is a new test to verify that VRP can propagate constants generated on the true/false arms of an overflow test and that constants to _not_ propagate into the wrong arm of the conditional. These were included in the bootstrap & regression testing of the prior patches. All the tests pass with the prior patches installed. OK for the trunk? * g++.dg/pr79095-1.C: New test * g++.dg/pr79095-2.C: New test * g++.dg/pr79095-3.C: New test * g++.dg/pr79095-4.C: New test * g++.dg/pr79095-5.C: New test * gcc.c-torture/execute/arith-1.c: Update with more cases. * gcc.dg/tree-ssa/pr79095-1.c: New test. diff --git a/gcc/testsuite/g++.dg/pr79095-1.C b/gcc/testsuite/g++.dg/pr79095-1.C new file mode 100644 index 000..4b8043c --- /dev/null +++ b/gcc/testsuite/g++.dg/pr79095-1.C @@ -0,0 +1,40 @@ +/* { dg-do compile } */ +/* { dg-options "-Wall -O3" } */ + +typedef long unsigned int size_t; + +inline void +fill (int *p, size_t n, int) +{ + while (n--) +*p++ = 0; +} + +struct B +{ + int* p0, *p1, *p2; + + size_t size () const { +return size_t (p1 - p0); + } + + void resize (size_t n) { +if (n > size()) + append (n - size()); + } + + void append (size_t n) + { +if (size_t (p2 - p1) >= n) { + fill (p1, n, 0); +} + } +}; + +void foo (B &b) +{ + if (b.size () != 0) +b.resize (b.size () - 1); +} + + diff --git a/gcc/testsuite/g++.dg/pr79095-2.C b/gcc/testsuite/g++.dg/pr79095-2.C new file mode 100644 index 000..9dabc7e --- /dev/null +++ b/gcc/testsuite/g++.dg/pr79095-2.C @@ -0,0 +1,46 @@ +/* { dg-do compile } */ +/* { dg-options "-Wall -O3" } */ + +typedef long unsigned int size_t; + +inline void +fill (int *p, size_t n, int) +{ + while (n--) +*p++ = 0; +} + +struct B +{ + int* p0, *p1, *p2; + + size_t size () const { +return size_t (p1 - p0); + } + + void resize (size_t n) { +if (n > size()) + append (n - size()); + } + + void append (size_t n) + { +if (size_t (p2 - p1) >= n) { + fill (p1, n, 0); +} + } +}; + +void foo (B &b) +{ +b.resize (b.size () - 1); +} + +/* If b.size() == 0, then the argument to b.resize is -1U (it overflowed). + This will result calling "fill" which turns into a memset with a bogus + length argument. We want to make sure we warn, which multiple + things. First the ldist pass converted the loop into a memset, + cprop and simplifications made the length a constant and the static + analysis pass determines it's a bogus size to pass to memset. */ +/* { dg-warning "exceeds maximum object size" "" { target *-*-* } 0 } */ + diff --git a/gcc/testsuite/g++.dg/pr79095-3.C b/gcc/testsuite/g++.dg/pr79095-3.C new file mode 100644 index 000..28c8a37 --- /dev/null +++ b/gcc/testsuite/g++.dg/pr79095-3.C @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-Wall -O3" } */ + +#include + +void foo(std::vector &v); + +void vtest() +{ + std::vector v; + foo (v); + if (v.size() > 0) + { +v.resize (v.size()-1); + } +} + diff --git a/gcc/testsuite/g++.dg/pr79095-4.C b/gcc/testsuite/g++.dg/pr79095-4.C new file mode 100644 index 000..df55025 --- /dev/null +++ b/gcc/testsuite/g++.dg/pr79095-4.C @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-Wall -O3 -fdump-tree-vrp2" } */ + +#include + +void foo(std::vector &v); + +void vtest() +{ + std::vector v; + foo (v); + { +v.resize (v.size()-1); + } +} + +/* As written this testcase should trigger a warning. We overflow to -1U + if v.size() == 0 in foo(). This results in bogus calls to memset. + + The number of clearing loops in the IL can vary depending on the C++ + mode used for the test. But by the end of VRP2, there should be a single + clearing loop left and it should be using memcpy. */ +/* { dg-final { scan-tree-dump-times "__builtin_memset \\(_\[0-9\]+, 0, \[0-9\]+\
[RFA][PR tree-optimization/79095][PATCH 4/4] Tests
This is unchanged from the original posting. Reposting to make review easier. The tests in g++.dg start with a reduced test from Martin (pr79095-1.C) that includes a size check. With the size != 0 check this testcase should not issue any warnings as the path that turns into a __builtin_memset should get eliminated. pr79095-2.C is the same test, but without the size != test. This test should trigger an "exceeds maximum object size" warning. pr79095-3.C is the original test from the BZ, but with a proper size check on the vector. This test should not produce a warning. pr79095-4.C is the original test from the BZ, but without a size check on the vector. This should produce *one* warning (trunk currently generates 3). We verify that there's just one __builtin_memset by the time VRP2 is done and verify that we do get the desired warning. pr79095-5.C is another test from Martin which should not produce a warning. gcc-torture/execute/arith-1.c is updated to test a few more cases. This was mis-compiled at some point during patch development and at that time I added the additional tsts. gcc.dg/tree-ssa/pr79095.c is a new test to verify that VRP can propagate constants generated on the true/false arms of an overflow test and that constants to _not_ propagate into the wrong arm of the conditional. These were included in the bootstrap & regression testing of the prior patches. All the tests pass with the prior patches installed. OK for the trunk? * g++.dg/pr79095-1.C: New test * g++.dg/pr79095-2.C: New test * g++.dg/pr79095-3.C: New test * g++.dg/pr79095-4.C: New test * g++.dg/pr79095-5.C: New test * gcc.c-torture/execute/arith-1.c: Update with more cases. * gcc.dg/tree-ssa/pr79095-1.c: New test. diff --git a/gcc/testsuite/g++.dg/pr79095-1.C b/gcc/testsuite/g++.dg/pr79095-1.C new file mode 100644 index 000..4b8043c --- /dev/null +++ b/gcc/testsuite/g++.dg/pr79095-1.C @@ -0,0 +1,40 @@ +/* { dg-do compile } */ +/* { dg-options "-Wall -O3" } */ + +typedef long unsigned int size_t; + +inline void +fill (int *p, size_t n, int) +{ + while (n--) +*p++ = 0; +} + +struct B +{ + int* p0, *p1, *p2; + + size_t size () const { +return size_t (p1 - p0); + } + + void resize (size_t n) { +if (n > size()) + append (n - size()); + } + + void append (size_t n) + { +if (size_t (p2 - p1) >= n) { + fill (p1, n, 0); +} + } +}; + +void foo (B &b) +{ + if (b.size () != 0) +b.resize (b.size () - 1); +} + + diff --git a/gcc/testsuite/g++.dg/pr79095-2.C b/gcc/testsuite/g++.dg/pr79095-2.C new file mode 100644 index 000..9dabc7e --- /dev/null +++ b/gcc/testsuite/g++.dg/pr79095-2.C @@ -0,0 +1,46 @@ +/* { dg-do compile } */ +/* { dg-options "-Wall -O3" } */ + +typedef long unsigned int size_t; + +inline void +fill (int *p, size_t n, int) +{ + while (n--) +*p++ = 0; +} + +struct B +{ + int* p0, *p1, *p2; + + size_t size () const { +return size_t (p1 - p0); + } + + void resize (size_t n) { +if (n > size()) + append (n - size()); + } + + void append (size_t n) + { +if (size_t (p2 - p1) >= n) { + fill (p1, n, 0); +} + } +}; + +void foo (B &b) +{ +b.resize (b.size () - 1); +} + +/* If b.size() == 0, then the argument to b.resize is -1U (it overflowed). + This will result calling "fill" which turns into a memset with a bogus + length argument. We want to make sure we warn, which multiple + things. First the ldist pass converted the loop into a memset, + cprop and simplifications made the length a constant and the static + analysis pass determines it's a bogus size to pass to memset. */ +/* { dg-warning "exceeds maximum object size" "" { target *-*-* } 0 } */ + diff --git a/gcc/testsuite/g++.dg/pr79095-3.C b/gcc/testsuite/g++.dg/pr79095-3.C new file mode 100644 index 000..28c8a37 --- /dev/null +++ b/gcc/testsuite/g++.dg/pr79095-3.C @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-Wall -O3" } */ + +#include + +void foo(std::vector &v); + +void vtest() +{ + std::vector v; + foo (v); + if (v.size() > 0) + { +v.resize (v.size()-1); + } +} + diff --git a/gcc/testsuite/g++.dg/pr79095-4.C b/gcc/testsuite/g++.dg/pr79095-4.C new file mode 100644 index 000..df55025 --- /dev/null +++ b/gcc/testsuite/g++.dg/pr79095-4.C @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-Wall -O3 -fdump-tree-vrp2" } */ + +#include + +void foo(std::vector &v); + +void vtest() +{ + std::vector v; + foo (v); + { +v.resize (v.size()-1); + } +} + +/* As written this testcase should trigger a warning. We overflow to -1U + if v.size() == 0 in foo(). This results in bogus calls to memset. + + The number of clearing loops in the IL can vary depending on the C++ + mode used for the test. But by the end of VRP2, there should be a single + clearing loop left and it should be using memcpy. */ +/* { dg-final { scan-t
Re: [RFA][PR tree-optimization/79095][PATCH 4/4] Tests
On Tue, Feb 7, 2017 at 7:32 PM, Jeff Law wrote: > > This is unchanged from the original posting. Reposting to make review > easier. > > > The tests in g++.dg start with a reduced test from Martin (pr79095-1.C) that > includes a size check. With the size != 0 check this testcase should not > issue any warnings as the path that turns into a __builtin_memset should get > eliminated. > > pr79095-2.C is the same test, but without the size != test. This test > should trigger an "exceeds maximum object size" warning. > > pr79095-3.C is the original test from the BZ, but with a proper size check > on the vector. This test should not produce a warning. > > pr79095-4.C is the original test from the BZ, but without a size check on > the vector. This should produce *one* warning (trunk currently generates > 3). We verify that there's just one __builtin_memset by the time VRP2 is > done and verify that we do get the desired warning. > > pr79095-5.C is another test from Martin which should not produce a warning. > > gcc-torture/execute/arith-1.c is updated to test a few more cases. This was > mis-compiled at some point during patch development and at that time I added > the additional tsts. > > gcc.dg/tree-ssa/pr79095.c is a new test to verify that VRP can propagate > constants generated on the true/false arms of an overflow test and that > constants to _not_ propagate into the wrong arm of the conditional. > > > These were included in the bootstrap & regression testing of the prior > patches. All the tests pass with the prior patches installed. OK for the > trunk? Ok. Richard. > > * g++.dg/pr79095-1.C: New test > * g++.dg/pr79095-2.C: New test > * g++.dg/pr79095-3.C: New test > * g++.dg/pr79095-4.C: New test > * g++.dg/pr79095-5.C: New test > * gcc.c-torture/execute/arith-1.c: Update with more cases. > * gcc.dg/tree-ssa/pr79095-1.c: New test. > > diff --git a/gcc/testsuite/g++.dg/pr79095-1.C > b/gcc/testsuite/g++.dg/pr79095-1.C > new file mode 100644 > index 000..4b8043c > --- /dev/null > +++ b/gcc/testsuite/g++.dg/pr79095-1.C > @@ -0,0 +1,40 @@ > +/* { dg-do compile } */ > +/* { dg-options "-Wall -O3" } */ > + > +typedef long unsigned int size_t; > + > +inline void > +fill (int *p, size_t n, int) > +{ > + while (n--) > +*p++ = 0; > +} > + > +struct B > +{ > + int* p0, *p1, *p2; > + > + size_t size () const { > +return size_t (p1 - p0); > + } > + > + void resize (size_t n) { > +if (n > size()) > + append (n - size()); > + } > + > + void append (size_t n) > + { > +if (size_t (p2 - p1) >= n) { > + fill (p1, n, 0); > +} > + } > +}; > + > +void foo (B &b) > +{ > + if (b.size () != 0) > +b.resize (b.size () - 1); > +} > + > + > diff --git a/gcc/testsuite/g++.dg/pr79095-2.C > b/gcc/testsuite/g++.dg/pr79095-2.C > new file mode 100644 > index 000..9dabc7e > --- /dev/null > +++ b/gcc/testsuite/g++.dg/pr79095-2.C > @@ -0,0 +1,46 @@ > +/* { dg-do compile } */ > +/* { dg-options "-Wall -O3" } */ > + > +typedef long unsigned int size_t; > + > +inline void > +fill (int *p, size_t n, int) > +{ > + while (n--) > +*p++ = 0; > +} > + > +struct B > +{ > + int* p0, *p1, *p2; > + > + size_t size () const { > +return size_t (p1 - p0); > + } > + > + void resize (size_t n) { > +if (n > size()) > + append (n - size()); > + } > + > + void append (size_t n) > + { > +if (size_t (p2 - p1) >= n) { > + fill (p1, n, 0); > +} > + } > +}; > + > +void foo (B &b) > +{ > +b.resize (b.size () - 1); > +} > + > +/* If b.size() == 0, then the argument to b.resize is -1U (it overflowed). > + This will result calling "fill" which turns into a memset with a bogus > + length argument. We want to make sure we warn, which multiple > + things. First the ldist pass converted the loop into a memset, > + cprop and simplifications made the length a constant and the static > + analysis pass determines it's a bogus size to pass to memset. */ > +/* { dg-warning "exceeds maximum object size" "" { target *-*-* } 0 } */ > + > diff --git a/gcc/testsuite/g++.dg/pr79095-3.C > b/gcc/testsuite/g++.dg/pr79095-3.C > new file mode 100644 > index 000..28c8a37 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/pr79095-3.C > @@ -0,0 +1,17 @@ > +/* { dg-do compile } */ > +/* { dg-options "-Wall -O3" } */ > + > +#include > + > +void foo(std::vector &v); > + > +void vtest() > +{ > + std::vector v; > + foo (v); > + if (v.size() > 0) > + { > +v.resize (v.size()-1); > + } > +} > + > diff --git a/gcc/testsuite/g++.dg/pr79095-4.C > b/gcc/testsuite/g++.dg/pr79095-4.C > new file mode 100644 > index 000..df55025 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/pr79095-4.C > @@ -0,0 +1,26 @@ > +/* { dg-do compile } */ > +/* { dg-options "-Wall -O3 -fdump-tree-vrp2" } */ > + > +#include > + > +void foo(std::vector &v); > + > +void vtest() > +{ > + std::vector v; > + foo (v); > + { > +v.resize