Message ID | 4998fc5c-9bd1-f2f0-282d-0c3c0b1fe808@gmail.com |
---|---|
State | New |
Headers | show |
Series | introduce effective-target fold_memcpy | expand |
On Sat, Jan 19, 2019 at 12:25 AM Martin Sebor <msebor@gmail.com> wrote: > > Some of the -Warray-bounds and -Wrestrict tests are prone to failing > on targets like arm-eabi and others that use different parameters to > decide which memcpy calls should be folded to MEM_REF (those that do > are copies of small power-of-two sizes where the power tends to vary > from target to target and may be as little as 1). The failures then > waste the time of those who maintain those secondary targets reporting > failures (see * below), as well as those who wrote the tests debugging > the problems and working around them. > > To reduce this effort (and ideally avoid these regressions going > forward) the attached patch adds a new effective-target to the test > harness: fold_memcpy_N. It detects the target's willingness to fold > memcpy call of the given size (N). While testing this with the arm > cross-compiler I also tweaked the tests that #include standard > headers to only do so when __has_include says the header exists. > This lets the tests pass even when using a cross-compiler without > library headers installed (my default MO). If/when the warnings > are improved to detect the problems regardless of the folding as > I'm hoping to eventually do, this new effective-target feature > can be removed. But all the memcpy folding does is see whether the target can access unaligned {2,4,8,<max-int-mode-size>} memory. So a effective target unaligned_move_{2,4,8...} would be better and possibly useful in other contexts? memcpy folding might be indeed a nice vehicle to test this property. Thus, I guess I'm only asking to rename the effective target keyword. Btw, new effective targets need documenting in sourcebuild.texi Richard. > Martin > > [*] https://gcc.gnu.org/ml/gcc-patches/2019-01/msg01056.html
On 1/21/19 1:18 AM, Richard Biener wrote: > On Sat, Jan 19, 2019 at 12:25 AM Martin Sebor <msebor@gmail.com> wrote: >> >> Some of the -Warray-bounds and -Wrestrict tests are prone to failing >> on targets like arm-eabi and others that use different parameters to >> decide which memcpy calls should be folded to MEM_REF (those that do >> are copies of small power-of-two sizes where the power tends to vary >> from target to target and may be as little as 1). The failures then >> waste the time of those who maintain those secondary targets reporting >> failures (see * below), as well as those who wrote the tests debugging >> the problems and working around them. >> >> To reduce this effort (and ideally avoid these regressions going >> forward) the attached patch adds a new effective-target to the test >> harness: fold_memcpy_N. It detects the target's willingness to fold >> memcpy call of the given size (N). While testing this with the arm >> cross-compiler I also tweaked the tests that #include standard >> headers to only do so when __has_include says the header exists. >> This lets the tests pass even when using a cross-compiler without >> library headers installed (my default MO). If/when the warnings >> are improved to detect the problems regardless of the folding as >> I'm hoping to eventually do, this new effective-target feature >> can be removed. > > But all the memcpy folding does is see whether the target can > access unaligned {2,4,8,<max-int-mode-size>} memory. So > a effective target unaligned_move_{2,4,8...} would be better and > possibly useful in other contexts? memcpy folding might be indeed > a nice vehicle to test this property. > > Thus, I guess I'm only asking to rename the effective target keyword. I did this but after some more reading I no longer think we need it. > Btw, new effective targets need documenting in sourcebuild.texi Thanks for the reminder! While adding the new keyword I came across non_strict_align. It looks like it's pretty much same thing as what I'm trying to add. It's used in gcc.dg/memmove-4.c and memcpy-3.c (besides a few other tests) to test the folding whose absence the warnings depend on. So I've simplified the patch to make use of non_strict_align instead. I've verified the tests pass with arm-eabi, sparc-solaris2.11, and x86_64. Martin > > Richard. > >> Martin >> >> [*] https://gcc.gnu.org/ml/gcc-patches/2019-01/msg01056.html gcc/testsuite/ChangeLog: * c-c++-common/Warray-bounds-2.c: Include headers only if they exist. * c-c++-common/Warray-bounds-3.c: Make xfails conditional on target non_strict_align. * c-c++-common/Wrestrict-2.c: Include headers only if they exist. * c-c++-common/Wrestrict.c: Make xfails conditional on target non_strict_align. Index: gcc/testsuite/c-c++-common/Warray-bounds-2.c =================================================================== --- gcc/testsuite/c-c++-common/Warray-bounds-2.c (revision 268086) +++ gcc/testsuite/c-c++-common/Warray-bounds-2.c (working copy) @@ -8,13 +8,28 @@ { dg-do compile } { dg-options "-O2 -Warray-bounds -Wno-stringop-overflow" } */ -#include <stddef.h> -#include <string.h> +#if __has_include (<stddef.h>) +# include <stddef.h> +#else +/* For cross-compilers. */ +typedef __PTRDIFF_TYPE__ ptrdiff_t; +typedef __SIZE_TYPE__ size_t; +#endif -#undef memcpy -#undef strcpy -#undef strncpy +#if __has_include (<string.h>) +# include <string.h> +# undef memcpy +# undef strcat +# undef strcpy +# undef strncpy +#else +extern void* memcpy (void*, const void*, size_t); +extern char* strcat (char*, const char*); +extern char* strcpy (char*, const char*); +extern char* strncpy (char*, const char*, size_t); +#endif + #define MAX (__SIZE_MAX__ / 2) void sink (void*); Index: gcc/testsuite/c-c++-common/Warray-bounds-3.c =================================================================== --- gcc/testsuite/c-c++-common/Warray-bounds-3.c (revision 268086) +++ gcc/testsuite/c-c++-common/Warray-bounds-3.c (working copy) @@ -158,7 +158,7 @@ void test_memcpy_overflow (char *d, const char *s, but known access size is detected. This works except with small sizes that are powers of 2 due to bug . */ T (char, 1, arr + SR (DIFF_MAX - 1, DIFF_MAX), s, 1); - T (char, 1, arr + SR (DIFF_MAX - 1, DIFF_MAX), s, 2); /* { dg-warning "pointer overflow between offset \\\[\[0-9\]+, \[0-9\]+] and size 2 accessing array " "bug " { xfail *-*-* } } */ + T (char, 1, arr + SR (DIFF_MAX - 1, DIFF_MAX), s, 2); /* { dg-warning "pointer overflow between offset \\\[\[0-9\]+, \[0-9\]+] and size 2 accessing array " "bug " { xfail non_strict_align } } */ T (char, 1, arr + SR (DIFF_MAX - 2, DIFF_MAX), s, 3); /* { dg-warning "pointer overflow between offset \\\[\[0-9\]+, \[0-9\]+] and size 3 accessing array " "memcpy" } */ T (char, 1, arr + SR (DIFF_MAX - 4, DIFF_MAX), s, 5); /* { dg-warning "pointer overflow between offset \\\[\[0-9\]+, \[0-9\]+] and size 5 accessing array " "memcpy" } */ } Index: gcc/testsuite/c-c++-common/Wrestrict-2.c =================================================================== --- gcc/testsuite/c-c++-common/Wrestrict-2.c (revision 268086) +++ gcc/testsuite/c-c++-common/Wrestrict-2.c (working copy) @@ -8,8 +8,30 @@ { dg-do compile } { dg-options "-O2 -Wrestrict" } */ -#include <string.h> +#if __has_include (<stddef.h>) +# include <stddef.h> +#else +/* For cross-compilers. */ +typedef __PTRDIFF_TYPE__ ptrdiff_t; +typedef __SIZE_TYPE__ size_t; +#endif +#if __has_include (<string.h>) +# include <string.h> +# undef memcpy +# undef strcat +# undef strcpy +# undef strncat +# undef strncpy +#else +extern void* memcpy (void*, const void*, size_t); +extern char* strcat (char*, const char*); +extern char* strcpy (char*, const char*); +extern char* strncat (char*, const char*, size_t); +extern char* strncpy (char*, const char*, size_t); +#endif + + static void wrap_memcpy (void *d, const void *s, size_t n) { memcpy (d, s, n); /* { dg-warning "accessing 2 bytes at offsets 0 and 1 overlaps 1 byte at offset 1" "memcpy" } */ Index: gcc/testsuite/c-c++-common/Wrestrict.c =================================================================== --- gcc/testsuite/c-c++-common/Wrestrict.c (revision 268086) +++ gcc/testsuite/c-c++-common/Wrestrict.c (working copy) @@ -53,8 +53,11 @@ void test_memcpy_cst (void *d, const void *s) T (a, a, 0); - /* This isn't detected because memcpy calls with small power-of-2 sizes - are intentionally folded into safe copies equivalent to memmove. + /* This isn't detected because memcpy calls with size of 1 are + intentionally folded into safe copies equivalent to memmove, + regardless of the target (larger power-of-2 copies may or + may not be folded depending on the target -- see non_strict_align + below, for example). It's marked xfail only because there is value in detecting such invalid calls for portability, and as a reminder of why it isn't diagnosed. */ @@ -192,7 +195,7 @@ void test_memcpy_range (char *d, size_t sz) T (a + ir, a, 2); T (a + ir, a, 3); /* The following fails because the size is a small power of 2. */ - T (a + ir, a, 4); /* { dg-warning "accessing 4 bytes at offsets \\\[2, 3] and 0 overlaps between 1 and 2 bytes at offset \\\[3, 2]" "memcpy" { xfail *-*-*} } */ + T (a + ir, a, 4); /* { dg-warning "accessing 4 bytes at offsets \\\[2, 3] and 0 overlaps between 1 and 2 bytes at offset \(\\\[3, 2]|\\\[2, 3]\)" "pr79220" { xfail non_strict_align } } */ T (a + ir, a, 5); /* { dg-warning "accessing 5 bytes at offsets \\\[2, 3] and 0 overlaps between 2 and 3 bytes at offset \\\[2, 3]" "memcpy" } */ T (d + ir, d, 0); @@ -199,12 +202,12 @@ void test_memcpy_range (char *d, size_t sz) T (d + ir, d, 1); T (d + ir, d, 2); T (d + ir, d, 3); - T (d + ir, d, 4); /* { dg-warning "accessing 4 bytes at offsets \\\[2, 3] and 0 overlaps 1 byte at offset 3" "bug 79220" { xfail *-*-* } } */ + T (d + ir, d, 4); /* { dg-warning "accessing 4 bytes at offsets \\\[2, 3] and 0 overlaps between 1 and 2 bytes at offset \\\[2, 3]" "pr79220" { xfail non_strict_align } } */ T (d + ir, d, 5); /* { dg-warning "accessing 5 bytes at offsets \\\[2, 3] and 0 overlaps between 2 and 3 bytes at offset \\\[2, 3]" "memcpy" } */ /* Because the size is constant and a power of 2 the following is folded too early to detect the overlap. */ - T (d + ir, d, 4); /* { dg-warning "accessing 4 bytes at offsets \\\[2, 3] and 0 overlaps 2 byte at offset 2" "memcpy" { xfail *-*-* } } */ + T (d + ir, d, 4); /* { dg-warning "accessing 4 bytes at offsets \\\[2, 3] and 0 overlaps between 1 and 2 bytes at offset \\\[2, 3]" "pr79220" { xfail non_strict_align } } */ T (d + ir, d, 5); /* { dg-warning "accessing 5 bytes at offsets \\\[2, 3] and 0 overlaps between 2 and 3 bytes at offset \\\[2, 3]" "memcpy" } */ /* Exercise the full range of size_t. */
On Mon, Jan 21, 2019 at 9:23 PM Martin Sebor <msebor@gmail.com> wrote: > > On 1/21/19 1:18 AM, Richard Biener wrote: > > On Sat, Jan 19, 2019 at 12:25 AM Martin Sebor <msebor@gmail.com> wrote: > >> > >> Some of the -Warray-bounds and -Wrestrict tests are prone to failing > >> on targets like arm-eabi and others that use different parameters to > >> decide which memcpy calls should be folded to MEM_REF (those that do > >> are copies of small power-of-two sizes where the power tends to vary > >> from target to target and may be as little as 1). The failures then > >> waste the time of those who maintain those secondary targets reporting > >> failures (see * below), as well as those who wrote the tests debugging > >> the problems and working around them. > >> > >> To reduce this effort (and ideally avoid these regressions going > >> forward) the attached patch adds a new effective-target to the test > >> harness: fold_memcpy_N. It detects the target's willingness to fold > >> memcpy call of the given size (N). While testing this with the arm > >> cross-compiler I also tweaked the tests that #include standard > >> headers to only do so when __has_include says the header exists. > >> This lets the tests pass even when using a cross-compiler without > >> library headers installed (my default MO). If/when the warnings > >> are improved to detect the problems regardless of the folding as > >> I'm hoping to eventually do, this new effective-target feature > >> can be removed. > > > > But all the memcpy folding does is see whether the target can > > access unaligned {2,4,8,<max-int-mode-size>} memory. So > > a effective target unaligned_move_{2,4,8...} would be better and > > possibly useful in other contexts? memcpy folding might be indeed > > a nice vehicle to test this property. > > > > Thus, I guess I'm only asking to rename the effective target keyword. > > I did this but after some more reading I no longer think we need it. > > > Btw, new effective targets need documenting in sourcebuild.texi > > Thanks for the reminder! While adding the new keyword I came across > non_strict_align. It looks like it's pretty much same thing as what > I'm trying to add. It's used in gcc.dg/memmove-4.c and memcpy-3.c > (besides a few other tests) to test the folding whose absence > the warnings depend on. > > So I've simplified the patch to make use of non_strict_align instead. > I've verified the tests pass with arm-eabi, sparc-solaris2.11, and > x86_64. OK. > Martin > > > > > Richard. > > > >> Martin > >> > >> [*] https://gcc.gnu.org/ml/gcc-patches/2019-01/msg01056.html >
gcc/testsuite/ChangeLog: * lib/target-supports.exp (check_compile): Support -ftree-dump-xxx options. (check_effective_target_fold_memcpy): New function. (check_effective_target_fold_memcpy_2): Same. (check_effective_target_fold_memcpy_4): Same. (check_effective_target_fold_memcpy_8): Same. * c-c++-common/Warray-bounds-2.c: Include headers only if they exist. * c-c++-common/Warray-bounds-3.c: Make xfails conditional on target fold_memcpy. * c-c++-common/Wrestrict-2.c: Include headers only if they exist. * c-c++-common/Wrestrict.c: Make xfails conditional on target fold_memcpy. Index: gcc/testsuite/lib/target-supports.exp =================================================================== --- gcc/testsuite/lib/target-supports.exp (revision 268082) +++ gcc/testsuite/lib/target-supports.exp (working copy) @@ -82,6 +82,11 @@ proc check_compile {basename type contents args} { lappend options "additional_flags=-fdump-$type" set compile_type assembly } + "tree-*" { + set output ${basename}[pid].s + lappend options "additional_flags=-fdump-$type" + set compile_type assembly + } } set f [open $src "w"] puts $f $contents @@ -95,6 +100,11 @@ proc check_compile {basename type contents args} { if [regexp "rtl-(.*)" $type dummy rtl_type] { set scan_output "[glob $src.\[0-9\]\[0-9\]\[0-9\]r.$rtl_type]" file delete $output + } else { + if [regexp "tree-(.*)" $type dummy tree_type] { + set scan_output "[glob $src.\[0-9\]\[0-9\]\[0-9\]t.$tree_type]" + file delete $output + } } # Restore additional_sources. @@ -9048,6 +9058,44 @@ proc check_effective_target_autoincdec { } { return 0 } +# Return 1 if the target folds memcpy calls with sizes of count bytes. +# The folding is done by the middle-end but targets have the ability +# to control the maximum size or to disable it altogether. +proc check_effective_target_fold_memcpy { count } { + set result [eval check_compile fold_memcpy tree-optimized { + "void test_fold_memcpy (void *d, const void *s) { __builtin_memcpy (d, s, $count); }" + } "-O2" ] + set lines [lindex $result 0] + set output [lindex $result 1] + set match 1 + + set file [open "$output" ] + set contents [read $file] + close $file + + if { [ regexp "__builtin_memcpy" $contents] } { + # Not folded. + set match 0 + } + remote_file build delete $output + return $match +} + +# Return 1 if the target folds memcpy calls with sizes of 2. +proc check_effective_target_fold_memcpy_2 { } { + return [check_effective_target_fold_memcpy { 2 }] +} + +# Return 1 if the target folds memcpy calls with sizes of 4. +proc check_effective_target_fold_memcpy_4 { } { + return [check_effective_target_fold_memcpy { 4 }] +} + +# Return 1 if the target folds memcpy calls with sizes of 8. +proc check_effective_target_fold_memcpy_8 { } { + return [check_effective_target_fold_memcpy { 8 }] +} + # Return 1 if the target has support for stack probing designed # to avoid stack-clash style attacks. # Index: gcc/testsuite/c-c++-common/Warray-bounds-2.c =================================================================== --- gcc/testsuite/c-c++-common/Warray-bounds-2.c (revision 268082) +++ gcc/testsuite/c-c++-common/Warray-bounds-2.c (working copy) @@ -8,13 +8,28 @@ { dg-do compile } { dg-options "-O2 -Warray-bounds -Wno-stringop-overflow" } */ -#include <stddef.h> -#include <string.h> +#if __has_include (<stddef.h>) +# include <stddef.h> +#else +/* For cross-compilers. */ +typedef __PTRDIFF_TYPE__ ptrdiff_t; +typedef __SIZE_TYPE__ size_t; +#endif -#undef memcpy -#undef strcpy -#undef strncpy +#if __has_include (<string.h>) +# include <string.h> +# undef memcpy +# undef strcat +# undef strcpy +# undef strncpy +#else +extern void* memcpy (void*, const void*, size_t); +extern char* strcat (char*, const char*); +extern char* strcpy (char*, const char*); +extern char* strncpy (char*, const char*, size_t); +#endif + #define MAX (__SIZE_MAX__ / 2) void sink (void*); Index: gcc/testsuite/c-c++-common/Warray-bounds-3.c =================================================================== --- gcc/testsuite/c-c++-common/Warray-bounds-3.c (revision 268082) +++ gcc/testsuite/c-c++-common/Warray-bounds-3.c (working copy) @@ -158,7 +158,7 @@ void test_memcpy_overflow (char *d, const char *s, but known access size is detected. This works except with small sizes that are powers of 2 due to bug . */ T (char, 1, arr + SR (DIFF_MAX - 1, DIFF_MAX), s, 1); - T (char, 1, arr + SR (DIFF_MAX - 1, DIFF_MAX), s, 2); /* { dg-warning "pointer overflow between offset \\\[\[0-9\]+, \[0-9\]+] and size 2 accessing array " "bug " { xfail *-*-* } } */ + T (char, 1, arr + SR (DIFF_MAX - 1, DIFF_MAX), s, 2); /* { dg-warning "pointer overflow between offset \\\[\[0-9\]+, \[0-9\]+] and size 2 accessing array " "bug " { xfail fold_memcpy_2 } } */ T (char, 1, arr + SR (DIFF_MAX - 2, DIFF_MAX), s, 3); /* { dg-warning "pointer overflow between offset \\\[\[0-9\]+, \[0-9\]+] and size 3 accessing array " "memcpy" } */ T (char, 1, arr + SR (DIFF_MAX - 4, DIFF_MAX), s, 5); /* { dg-warning "pointer overflow between offset \\\[\[0-9\]+, \[0-9\]+] and size 5 accessing array " "memcpy" } */ } Index: gcc/testsuite/c-c++-common/Wrestrict-2.c =================================================================== --- gcc/testsuite/c-c++-common/Wrestrict-2.c (revision 268082) +++ gcc/testsuite/c-c++-common/Wrestrict-2.c (working copy) @@ -8,8 +8,30 @@ { dg-do compile } { dg-options "-O2 -Wrestrict" } */ -#include <string.h> +#if __has_include (<stddef.h>) +# include <stddef.h> +#else +/* For cross-compilers. */ +typedef __PTRDIFF_TYPE__ ptrdiff_t; +typedef __SIZE_TYPE__ size_t; +#endif +#if __has_include (<string.h>) +# include <string.h> +# undef memcpy +# undef strcat +# undef strcpy +# undef strncat +# undef strncpy +#else +extern void* memcpy (void*, const void*, size_t); +extern char* strcat (char*, const char*); +extern char* strcpy (char*, const char*); +extern char* strncat (char*, const char*, size_t); +extern char* strncpy (char*, const char*, size_t); +#endif + + static void wrap_memcpy (void *d, const void *s, size_t n) { memcpy (d, s, n); /* { dg-warning "accessing 2 bytes at offsets 0 and 1 overlaps 1 byte at offset 1" "memcpy" } */ Index: gcc/testsuite/c-c++-common/Wrestrict.c =================================================================== --- gcc/testsuite/c-c++-common/Wrestrict.c (revision 268082) +++ gcc/testsuite/c-c++-common/Wrestrict.c (working copy) @@ -53,8 +53,11 @@ void test_memcpy_cst (void *d, const void *s) T (a, a, 0); - /* This isn't detected because memcpy calls with small power-of-2 sizes - are intentionally folded into safe copies equivalent to memmove. + /* This isn't detected because memcpy calls with size of 1 are + intentionally folded into safe copies equivalent to memmove, + regardless of the target (larger power-of-2 copies may or + may not be folded depending on the target -- see fold_memcpy_4 + below, for example). It's marked xfail only because there is value in detecting such invalid calls for portability, and as a reminder of why it isn't diagnosed. */ @@ -192,7 +195,7 @@ void test_memcpy_range (char *d, size_t sz) T (a + ir, a, 2); T (a + ir, a, 3); /* The following fails because the size is a small power of 2. */ - T (a + ir, a, 4); /* { dg-warning "accessing 4 bytes at offsets \\\[2, 3] and 0 overlaps between 1 and 2 bytes at offset \\\[3, 2]" "memcpy" { xfail *-*-*} } */ + T (a + ir, a, 4); /* { dg-warning "accessing 4 bytes at offsets \\\[2, 3] and 0 overlaps between 1 and 2 bytes at offset \(\\\[3, 2]|\\\[2, 3]\)" "pr79220" { xfail fold_memcpy_4 } } */ T (a + ir, a, 5); /* { dg-warning "accessing 5 bytes at offsets \\\[2, 3] and 0 overlaps between 2 and 3 bytes at offset \\\[2, 3]" "memcpy" } */ T (d + ir, d, 0); @@ -199,12 +202,12 @@ void test_memcpy_range (char *d, size_t sz) T (d + ir, d, 1); T (d + ir, d, 2); T (d + ir, d, 3); - T (d + ir, d, 4); /* { dg-warning "accessing 4 bytes at offsets \\\[2, 3] and 0 overlaps 1 byte at offset 3" "bug 79220" { xfail *-*-* } } */ + T (d + ir, d, 4); /* { dg-warning "accessing 4 bytes at offsets \\\[2, 3] and 0 overlaps between 1 and 2 bytes at offset \\\[2, 3]" "pr79220" { xfail fold_memcpy_4 } } */ T (d + ir, d, 5); /* { dg-warning "accessing 5 bytes at offsets \\\[2, 3] and 0 overlaps between 2 and 3 bytes at offset \\\[2, 3]" "memcpy" } */ /* Because the size is constant and a power of 2 the following is folded too early to detect the overlap. */ - T (d + ir, d, 4); /* { dg-warning "accessing 4 bytes at offsets \\\[2, 3] and 0 overlaps 2 byte at offset 2" "memcpy" { xfail *-*-* } } */ + T (d + ir, d, 4); /* { dg-warning "accessing 4 bytes at offsets \\\[2, 3] and 0 overlaps between 1 and 2 bytes at offset \\\[2, 3]" "pr79220" { xfail fold_memcpy_4 } } */ T (d + ir, d, 5); /* { dg-warning "accessing 5 bytes at offsets \\\[2, 3] and 0 overlaps between 2 and 3 bytes at offset \\\[2, 3]" "memcpy" } */ /* Exercise the full range of size_t. */