This fixes 2 related bugs. The user marks memmove as noreturn
so when we simplify the memmove to a memory load/store there
is no longer a statement that can alter the CFG and things go
down hill.
The same is true for removing the call in DSE.
So the fix is not to simplify/take into account the call from
gimple-fold and DSE.

Bootstrapped and tested on x86_64-linux-gnu.

        PR tree-optimization/121103

gcc/ChangeLog:

        * gimple-fold.cc (gimple_fold_call): Don't simplify
        noreturn functions.
        * tree-ssa-dse.cc (dse_optimize_stmt): Don't handle
        calls to noreturn functions.

gcc/testsuite/ChangeLog:

        * gcc.dg/torture/pr121103-1.c: New test.

Signed-off-by: Andrew Pinski <[email protected]>
---
 gcc/gimple-fold.cc                        |  4 +++
 gcc/testsuite/gcc.dg/torture/pr121103-1.c | 40 +++++++++++++++++++++++
 gcc/tree-ssa-dse.cc                       |  3 +-
 3 files changed, 46 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gcc.dg/torture/pr121103-1.c

diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
index ec6831a20a0..7ae5425376f 100644
--- a/gcc/gimple-fold.cc
+++ b/gcc/gimple-fold.cc
@@ -6068,6 +6068,10 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool 
inplace)
   if (inplace)
     return changed;
 
+  /* Don't constant fold functions which are marked as noreturn. */
+  if (gimple_call_flags (stmt) & ECF_NORETURN)
+    return changed;
+
   /* Check for builtins that CCP can handle using information not
      available in the generic fold routines.  */
   if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
diff --git a/gcc/testsuite/gcc.dg/torture/pr121103-1.c 
b/gcc/testsuite/gcc.dg/torture/pr121103-1.c
new file mode 100644
index 00000000000..22f76c528df
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr121103-1.c
@@ -0,0 +1,40 @@
+/* { dg-do compile } */
+/* PR tree-optimization/121103 */
+
+extern void *memmove(void *, const void *, __SIZE_TYPE__) 
__attribute__((noreturn));
+
+struct A {
+  const char *s;
+  int n;
+};
+
+void f(void *);
+
+struct B {
+  char d[5];
+  int n;
+};
+
+__attribute__((always_inline)) inline void g(struct B *p, struct A a) {
+  int i = a.n;
+  if (i <= 5)
+    p->n = i;
+  else {
+    p->n = -1;
+    f(p);
+  }
+
+  if (p->n >= 0)
+    memmove(p->d, a.s, a.n); /* { dg-bogus "\\\[-Warray-bounds" } */
+}
+
+void h(void) {
+  char c[8] = "";
+
+  struct A a;
+  a.s = c;
+  a.n = 8;
+
+  struct B b;
+  g(&b, a);
+}
diff --git a/gcc/tree-ssa-dse.cc b/gcc/tree-ssa-dse.cc
index 13266310ebe..10ae5d6e2ac 100644
--- a/gcc/tree-ssa-dse.cc
+++ b/gcc/tree-ssa-dse.cc
@@ -1501,7 +1501,8 @@ dse_optimize_stmt (function *fun, gimple_stmt_iterator 
*gsi, sbitmap live_bytes)
 
   /* We know we have virtual definitions.  We can handle assignments and
      some builtin calls.  */
-  if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
+  if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL)
+      && !(gimple_call_flags (stmt) & ECF_NORETURN))
     {
       tree fndecl = gimple_call_fndecl (stmt);
       switch (DECL_FUNCTION_CODE (fndecl))
-- 
2.43.0

Reply via email to