+2017-08-24 Martin Sebor <msebor@redhat.com>
+
+ PR middle-end/81908
+ * gimple-fold.c (size_must_be_zero_p): New function.
+ (gimple_fold_builtin_memory_op): Call it.
+
2017-08-24 Steven Munroe <munroesj@gcc.gnu.org>
* config/rs6000/mm_malloc.h: New file.
return SSA_VAR_P (inner);
}
+/* If the SIZE argument representing the size of an object is in a range
+ of values of which exactly one is valid (and that is zero), return
+ true, otherwise false. */
+
+static bool
+size_must_be_zero_p (tree size)
+{
+ if (integer_zerop (size))
+ return true;
+
+ if (TREE_CODE (size) != SSA_NAME)
+ return false;
+
+ wide_int min, max;
+ enum value_range_type rtype = get_range_info (size, &min, &max);
+ if (rtype != VR_ANTI_RANGE)
+ return false;
+
+ tree type = TREE_TYPE (size);
+ int prec = TYPE_PRECISION (type);
+
+ wide_int wone = wi::one (prec);
+
+ /* Compute the value of SSIZE_MAX, the largest positive value that
+ can be stored in ssize_t, the signed counterpart of size_t. */
+ wide_int ssize_max = wi::lshift (wi::one (prec), prec - 1) - 1;
+
+ return wi::eq_p (min, wone) && wi::geu_p (max, ssize_max);
+}
+
/* Fold function call to builtin mem{{,p}cpy,move}. Return
false if no simplification can be made.
If ENDP is 0, return DEST (like memcpy).
tree destvar, srcvar;
location_t loc = gimple_location (stmt);
- /* If the LEN parameter is zero, return DEST. */
- if (integer_zerop (len))
+ /* If the LEN parameter is a constant zero or in range where
+ the only valid value is zero, return DEST. */
+ if (size_must_be_zero_p (len))
{
gimple *repl;
if (gimple_call_lhs (stmt))
+2017-08-24 Martin Sebor <msebor@redhat.com>
+
+ PR middle-end/81908
+ * gcc.dg/tree-ssa/builtins-folding-gimple-2.c: New test.
+ * gcc.dg/tree-ssa/builtins-folding-gimple-3.c: New test.
+ * gcc.dg/tree-ssa/pr81908.c: New test.
+
2017-08-24 Steven Munroe <munroesj@gcc.gnu.org>
* gcc.target/powerpc/mmx-packuswb-1.c [NO_WARN_X86_INTRINSICS]:
--- /dev/null
+/* PR 81908 - FAIL: gfortran.dg/alloc_comp_auto_array_2.f90 -O3 -g -m32
+ Test to verify that calls to memcpy et al. where the size is in a range
+ with just one valid value -- zero -- are eliminated.
+ { dg-do compile }
+ { dg-options "-O2 -Wall -fdump-tree-optimized" } */
+
+#define INT_MAX __INT_MAX__
+#define SHRT_MAX __SHRT_MAX__
+#define SIZE_MAX __SIZE_MAX__
+#define SSIZE_MAX (SIZE_MAX / 2)
+
+typedef __PTRDIFF_TYPE__ ssize_t;
+typedef __SIZE_TYPE__ size_t;
+
+#define UNIQUE_FUNCNAME(func, line) test_ ## func ## _ ## line
+#define FUNCNAME(func, line) UNIQUE_FUNCNAME (func, line)
+
+#define AR(func, type, min, max, val) \
+ void __attribute__ ((noclone, noinline)) \
+ FUNCNAME (func, __LINE__) (char *d, const char *s, type n) \
+ { \
+ if ((type)min <= n && n <= (type)max) \
+ n = val; \
+ __builtin_ ## func (d, s, n); \
+ } typedef void DummyType
+
+AR (memcpy, short, 1, SHRT_MAX, 0);
+AR (memcpy, int, 1, INT_MAX, 0);
+AR (memcpy, size_t, 1, SSIZE_MAX, 0);
+AR (memcpy, ssize_t, 1, SSIZE_MAX, 0);
+
+AR (memmove, short, 1, SHRT_MAX, 0);
+AR (memmove, int, 1, INT_MAX, 0);
+AR (memmove, ssize_t, 1, SSIZE_MAX, 0);
+AR (memmove, ssize_t, 1, SSIZE_MAX, 0);
+
+AR (mempcpy, short, 1, SHRT_MAX, 0);
+AR (mempcpy, int, 1, INT_MAX, 0);
+AR (mempcpy, size_t, 1, SSIZE_MAX, 0);
+AR (mempcpy, ssize_t, 1, SSIZE_MAX, 0);
+
+/* { dg-final { scan-tree-dump-not "builtin_memcpy" "optimized" } }
+ { dg-final { scan-tree-dump-not "builtin_memmove" "optimized" } }
+ { dg-final { scan-tree-dump-not "builtin_mempcpy" "optimized" } } */
--- /dev/null
+/* PR 81908 - FAIL: gfortran.dg/alloc_comp_auto_array_2.f90 -O3 -g -m32
+ Test to verify that calls to memcpy et al. where the size is in a range
+ with more than one valid value are not eliminated (this test complements
+ builtins-folding-gimple-2.c).
+ { dg-do compile }
+ { dg-options "-O2 -Wall -fdump-tree-optimized" } */
+
+#define SHRT_MAX __SHRT_MAX__
+#define SHRT_MIN (-SHRT_MAX - 1)
+#define INT_MAX __INT_MAX__
+#define INT_MIN (-INT_MAX - 1)
+
+#define UNIQUE_FUNCNAME(func, line) test_ ## func ## _ ## line
+#define FUNCNAME(func, line) UNIQUE_FUNCNAME (func, line)
+
+#define AR(func, type, min, max, val) \
+ void __attribute__ ((noclone, noinline)) \
+ FUNCNAME (func, __LINE__) (char *d, const char *s, type n) \
+ { \
+ if ((type)min <= n && n <= (type)max) \
+ n = val; \
+ __builtin_ ## func (d, s, n); \
+ } typedef void DummyType
+
+AR (memcpy, short, SHRT_MIN, 0, 1);
+AR (memcpy, short, SHRT_MIN, 1, 2);
+AR (memcpy, short, 2, SHRT_MAX, 1);
+
+AR (memcpy, int, INT_MIN, 0, 1);
+AR (memcpy, int, INT_MIN, 1, 2);
+AR (memcpy, int, INT_MIN, 2, 3);
+AR (memcpy, int, 2, INT_MAX, 1);
+AR (memcpy, int, 2, INT_MAX, 1);
+
+AR (memmove, short, 2, SHRT_MAX, 1);
+AR (memmove, int, 2, INT_MAX, 1);
+
+AR (mempcpy, short, 2, SHRT_MAX, 1);
+AR (mempcpy, int, 2, INT_MAX, 1);
+
+/* { dg-final { scan-tree-dump-times "builtin_memcpy" 8 "optimized" } }
+ { dg-final { scan-tree-dump-times "builtin_memmove" 2 "optimized" } }
+ { dg-final { scan-tree-dump-times "builtin_mempcpy" 2 "optimized" } } */
--- /dev/null
+/* PR 81908 - FAIL: gfortran.dg/alloc_comp_auto_array_2.f90 -O3 -g -m32
+ { dg-do compile }
+ { dg-options "-O2 -Wall" } */
+
+#define SIZE_MAX __SIZE_MAX__
+typedef __SIZE_TYPE__ size_t;
+
+void f0 (char *d, const char *s, size_t n)
+{
+ if (n > 0 && n <= SIZE_MAX / 2 - 1)
+ n = 0;
+
+ __builtin_memcpy (d, s, n);
+}
+
+void f1 (char *d, const char *s, size_t n)
+{
+ if (n > 0 && n <= SIZE_MAX / 2)
+ n = 0;
+
+ __builtin_memcpy (d, s, n); /* { dg-bogus "\\\[-Wstringop-overflow=]" } */
+}
+
+void f2 (char *d, const char *s, size_t n)
+{
+ if (n > 0 && n <= SIZE_MAX / 2 + 1)
+ n = 0;
+
+ __builtin_memcpy (d, s, n);
+}
+
+void f3 (char *d, const char *s, size_t n)
+{
+ if (n > 0 && n <= SIZE_MAX - 1)
+ n = 0;
+
+ __builtin_memcpy (d, s, n); /* { dg-bogus "\\\[-Wstringop-overflow=]" } */
+}
+
+void f4 (char *d, const char *s, size_t n)
+{
+ if (n > 0 && n <= SIZE_MAX)
+ n = 0;
+
+ __builtin_memcpy (d, s, n);
+}