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.

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.  */

Reply via email to