Hello,

On 2026-09-04 13:56, [email protected] wrote:
From: Kyrylo Tkachov <[email protected]>

A REFERENCE_TYPE parameter that refers to an object designates an object that
is at least as large as its referred-to type.  A method's this parameter
designates an object that is at least as large as TYPE_METHOD_BASETYPE.
tree_could_trap_p already uses this property for the this parameter, but not
for other reference parameters.

LIM therefore cannot move safe invariant loads through reference parameters.

GAPBS bfs contains this case in BUStep.  Without this change, the loads
remain below conditional guards in loop 1:

   <bb 6>  _30 = MEM[(const struct CSRGraph *)g_15(D)].in_index_;
   <bb 13> _38 = MEM[(const struct Bitmap *)front_22(D)].start_;

Factor the parameter object-size query into whole_object_param_size.
Handle reference parameters and this parameters there.  Use nonnull_arg_p
as the policy gate, in line with -fdelete-null-pointer-checks.  LIM can
then move both loads to the loop-1 preheader:

   <bb 12> _30 = MEM[(const struct CSRGraph *)g_15(D)].in_index_;
            _38 = MEM[(const struct Bitmap *)front_22(D)].start_;

Use the object bound only for rvalues.  A reference or this parameter can
designate read-only storage after const_cast, so its object bound does not
prove that a store is safe.

Add tests for load motion, access bounds, the null-pointer policy,
conditional store elimination, store motion, built-in memory attributes, and
strub watermark attributes.  Cover reference parameters and this parameters.

On Grace, serial GAPBS bfs with kron-23, -O3, and -mcpu=grace
reduces cycles by 6.2%.

Bootstrapped and tested on aarch64-unknown-linux-gnu.
Ok for trunk?
Thanks,
Kyrill

gcc/ChangeLog:

        * doc/generic.texi (REFERENCE_TYPE): Document the object contract
        for reference parameters.
        (METHOD_TYPE): Document the object contract for the this parameter.
        * tree-eh.cc (parm_decl_from_ptr): New function.
        (whole_object_param_size): New function.
        (tree_could_trap_1): Use whole-object parameter bounds for loads.

gcc/testsuite/ChangeLog:

        * c-c++-common/strub-mem-notrap.c: New test.

Both this test ...

        * g++.dg/tree-ssa/cselim-ref-1.C: New test.
        * g++.dg/tree-ssa/cselim-ref-2.C: New test.
        * g++.dg/tree-ssa/lim-ref-1.C: New test.
        * g++.dg/tree-ssa/lim-ref-2.C: New test.
        * g++.dg/tree-ssa/lim-ref-3.C: New test.
        * g++.dg/tree-ssa/lim-ref-4.C: New test.
        * g++.dg/tree-ssa/lim-this-1.C: New test.
        * g++.dg/tree-ssa/noncall-store-builtin.C: New test.

... and this test fails for all my tested targets on arm-none-eabi. Below are 
log entries for Cortex-M0.

Testing c-c++-common/strub-mem-notrap.c
doing compile
Executing on host: /build/r17-4165-gb5a11752dcb093/bin/arm-none-eabi-gcc  
/build/gcc_src/gcc/testsuite/c-c++-common/strub-mem-notrap.c  -mthumb 
-march=armv6s-m -mcpu=cortex-m0 -mfloat-abi=soft -mfpu=auto   
-fdiagnostics-plain-output  -Wc++-compat -O2 -fstrub=strict 
-fnon-call-exceptions -fdelete-null-pointer-checks -fdump-rtl-expand 
-ffat-lto-objects -S     -o strub-mem-notrap.s    (timeout = 800)
spawn -ignore SIGHUP /build/r17-4165-gb5a11752dcb093/bin/arm-none-eabi-gcc 
/build/gcc_src/gcc/testsuite/c-c++-common/strub-mem-notrap.c -mthumb 
-march=armv6s-m -mcpu=cortex-m0 -mfloat-abi=soft -mfpu=auto 
-fdiagnostics-plain-output -Wc++-compat -O2 -fstrub=strict 
-fnon-call-exceptions -fdelete-null-pointer-checks -fdump-rtl-expand 
-ffat-lto-objects -S -o strub-mem-notrap.s
pid is 180 -180
pid is -1
output is  status 0
PASS: c-c++-common/strub-mem-notrap.c  -Wc++-compat  (test for excess errors)
PASS: c-c++-common/strub-mem-notrap.c  -Wc++-compat   scan-rtl-dump expand 
"\\(mem/f/c:[^\\n]*watermark_ptr"
FAIL: c-c++-common/strub-mem-notrap.c  -Wc++-compat   scan-rtl-dump expand 
"\\(mem/f:[^\\n]*watermark_ptr"

Attached is strub-mem-notrap.c.273r.expand for this call.
This test fails in both C and C++ mode.


Testing tree-ssa/noncall-store-builtin.C,  -std=gnu++98
doing compile
Executing on host: /build/r17-4165-gb5a11752dcb093/bin/arm-none-eabi-g++  
/build/gcc_src/gcc/testsuite/g++.dg/tree-ssa/noncall-store-builtin.C  -mthumb 
-march=armv6s-m -mcpu=cortex-m0 -mfloat-abi=soft -mfpu=auto   
-fdiagnostics-plain-output   -fmessage-length=0 -std=gn
u++98 -O2 -fdelete-null-pointer-checks -fnon-call-exceptions 
-finline-stringops=memcpy -fdump-rtl-expand -ffat-lto-objects -fno-ident  -S    
 -o noncall-store-builtin.s    (timeout = 800)
spawn -ignore SIGHUP /build/r17-4165-gb5a11752dcb093/bin/arm-none-eabi-g++ 
/build/gcc_src/gcc/testsuite/g++.dg/tree-ssa/noncall-store-builtin.C -mthumb 
-march=armv6s-m -mcpu=cortex-m0 -mfloat-abi=soft -mfpu=auto 
-fdiagnostics-plain-output -fmessage-length=0 -std=gnu++9
8 -O2 -fdelete-null-pointer-checks -fnon-call-exceptions 
-finline-stringops=memcpy -fdump-rtl-expand -ffat-lto-objects -fno-ident -S -o 
noncall-store-builtin.s
pid is 198 -198
pid is -1
output is  status 0
PASS: g++.dg/tree-ssa/noncall-store-builtin.C  -std=gnu++98 (test for excess 
errors)
PASS: g++.dg/tree-ssa/noncall-store-builtin.C  -std=gnu++98  scan-rtl-dump expand 
"\\(mem(?:/[a-z])*/c(?:/[a-z])*:"
PASS: g++.dg/tree-ssa/noncall-store-builtin.C  -std=gnu++98  scan-rtl-dump expand 
"\\(set[ \\t\\n]+\\(mem(?:/[a-z])*:"
FAIL: g++.dg/tree-ssa/noncall-store-builtin.C  -std=gnu++98  scan-rtl-dump-not expand 
"\\(set[ \\t\\n]+\\(mem(?:/[a-z])*/c(?:/[a-z])*:"
PASS: g++.dg/tree-ssa/noncall-store-builtin.C  -std=gnu++98  scan-assembler-not 
\\mmemcpy\\M

Attached is noncall-store-builtin.C.273r.expand for this call.

Are these two tests supposed to work for arm-none-eabi?

Kind regards,
Torbjörn


Signed-off-by: Kyrylo Tkachov <[email protected]>
---
  gcc/doc/generic.texi                          |  7 +-
  gcc/testsuite/c-c++-common/strub-mem-notrap.c | 21 ++++++
  gcc/testsuite/g++.dg/tree-ssa/cselim-ref-1.C  | 29 ++++++++
  gcc/testsuite/g++.dg/tree-ssa/cselim-ref-2.C  | 26 +++++++
  gcc/testsuite/g++.dg/tree-ssa/lim-ref-1.C     | 21 ++++++
  gcc/testsuite/g++.dg/tree-ssa/lim-ref-2.C     | 21 ++++++
  gcc/testsuite/g++.dg/tree-ssa/lim-ref-3.C     | 22 ++++++
  gcc/testsuite/g++.dg/tree-ssa/lim-ref-4.C     | 30 ++++++++
  gcc/testsuite/g++.dg/tree-ssa/lim-this-1.C    | 25 +++++++
  .../g++.dg/tree-ssa/noncall-store-builtin.C   | 20 +++++
  gcc/tree-eh.cc                                | 73 +++++++++++++++----
  11 files changed, 278 insertions(+), 17 deletions(-)
  create mode 100644 gcc/testsuite/c-c++-common/strub-mem-notrap.c
  create mode 100644 gcc/testsuite/g++.dg/tree-ssa/cselim-ref-1.C
  create mode 100644 gcc/testsuite/g++.dg/tree-ssa/cselim-ref-2.C
  create mode 100644 gcc/testsuite/g++.dg/tree-ssa/lim-ref-1.C
  create mode 100644 gcc/testsuite/g++.dg/tree-ssa/lim-ref-2.C
  create mode 100644 gcc/testsuite/g++.dg/tree-ssa/lim-ref-3.C
  create mode 100644 gcc/testsuite/g++.dg/tree-ssa/lim-ref-4.C
  create mode 100644 gcc/testsuite/g++.dg/tree-ssa/lim-this-1.C
  create mode 100644 gcc/testsuite/g++.dg/tree-ssa/noncall-store-builtin.C

diff --git a/gcc/doc/generic.texi b/gcc/doc/generic.texi
index 42a04e34eda..e61b151cd86 100644
--- a/gcc/doc/generic.texi
+++ b/gcc/doc/generic.texi
@@ -512,7 +512,10 @@ Used to represent pointer types, and pointer to data 
member types.  The
@item REFERENCE_TYPE
  Used to represent reference types.  The @code{TREE_TYPE} gives the type
-to which this type refers.
+to which this type refers.  A @code{PARM_DECL} whose reference type refers
+to an object type must designate an object whose size is at least that of
+the referred-to type.  Front ends must use @code{POINTER_TYPE} for a
+parameter that can be absent or otherwise fail to designate such an object.
@item FUNCTION_TYPE
  Used to represent the type of non-member functions and of static member
@@ -537,6 +540,8 @@ The type of @code{*this}, i.e., the class of which 
functions of this
  type are a member, is given by the @code{TYPE_METHOD_BASETYPE}.  The
  @code{TYPE_ARG_TYPES} is the parameter list, as for a
  @code{FUNCTION_TYPE}, and includes the @code{this} argument.
+The @code{this} argument must designate an object whose size is at least
+that of @code{TYPE_METHOD_BASETYPE}.
@item ARRAY_TYPE
  Used to represent array types.  The @code{TREE_TYPE} gives the type of
diff --git a/gcc/testsuite/c-c++-common/strub-mem-notrap.c 
b/gcc/testsuite/c-c++-common/strub-mem-notrap.c
new file mode 100644
index 00000000000..ef9bbc39535
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-mem-notrap.c
@@ -0,0 +1,21 @@
+/* Keep read and write attributes separate for a strub watermark update.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrub=strict -fnon-call-exceptions" } */
+/* { dg-additional-options "-fdelete-null-pointer-checks -fdump-rtl-expand" } 
*/
+/* { dg-require-effective-target strub } */
+/* { dg-skip-if "" keeps_null_pointer_checks } */
+
+volatile int sink;
+
+__attribute__ ((__strub__ ("internal"), noinline))
+int
+scrubbed (int value)
+{
+  sink = value;
+  return sink;
+}
+
+/* The watermark load is nontrapping.  The conditional store can trap.  */
+/* { dg-final { scan-rtl-dump {\(mem/f/c:[^\n]*watermark_ptr} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(mem/f:[^\n]*watermark_ptr} "expand" } } */
diff --git a/gcc/testsuite/g++.dg/tree-ssa/cselim-ref-1.C 
b/gcc/testsuite/g++.dg/tree-ssa/cselim-ref-1.C
new file mode 100644
index 00000000000..ede771ecfc0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/cselim-ref-1.C
@@ -0,0 +1,29 @@
+// A reference parameter proves that an in-bounds load is safe.  It does not
+// prove that the referenced object is writable.  Keep the store conditional.
+
+// { dg-do compile }
+// { dg-options "-O2 -fdelete-null-pointer-checks -ftree-cselim 
-fdump-tree-phiopt1-details" }
+// { dg-additional-options "-fallow-store-data-races" }
+// { dg-skip-if "" keeps_null_pointer_checks }
+
+void
+f (const int &a, int b, int d)
+{
+  int &c = const_cast<int &> (a);
+  int p = a;
+  if (b)
+    c = d | p;
+}
+
+void
+g (int &a, int b, int d)
+{
+  // A non-const reference can designate a const object after const_cast.
+  // The path that does not store is still valid.
+  int p = a;
+  if (b)
+    a = d | p;
+}
+
+// { dg-final { scan-tree-dump-times "if \\(b_" 2 "phiopt1" } }
+// { dg-final { scan-tree-dump-not "Conditional store replacement happened" 
"phiopt1" } }
diff --git a/gcc/testsuite/g++.dg/tree-ssa/cselim-ref-2.C 
b/gcc/testsuite/g++.dg/tree-ssa/cselim-ref-2.C
new file mode 100644
index 00000000000..16aeceb6654
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/cselim-ref-2.C
@@ -0,0 +1,26 @@
+// Check the full conditional store replacement after disabling the early
+// phi optimization.
+
+// { dg-do compile }
+// { dg-options "-O2 -fdelete-null-pointer-checks -ftree-cselim -fno-ssa-phiopt 
-fdump-tree-cselim-details" }
+// { dg-additional-options "-fallow-store-data-races" }
+// { dg-skip-if "" keeps_null_pointer_checks }
+
+void
+f (const int &a, int b, int d)
+{
+  if (b)
+    const_cast<int &> (a) = d;
+}
+
+void
+g (int &a, int b, int d)
+{
+  // A non-const reference can designate a const object after const_cast.
+  // The path that does not store is still valid.
+  if (b)
+    a = d;
+}
+
+// { dg-final { scan-tree-dump-times "if \\(b_" 2 "cselim" } }
+// { dg-final { scan-tree-dump-not "Conditional store replacement happened" 
"cselim" } }
diff --git a/gcc/testsuite/g++.dg/tree-ssa/lim-ref-1.C 
b/gcc/testsuite/g++.dg/tree-ssa/lim-ref-1.C
new file mode 100644
index 00000000000..fcb9a7cbd7b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/lim-ref-1.C
@@ -0,0 +1,21 @@
+// A parameter of reference type is bound to a valid object of the referenced
+// type, so a load from it cannot trap and may be hoisted out of the loop even
+// though it is only executed on some iterations.
+
+// { dg-do compile }
+// { dg-options "-O2 -fdelete-null-pointer-checks -fdump-tree-lim2-details" }
+// { dg-skip-if "" keeps_null_pointer_checks }
+
+struct S { int n; int *p; };
+
+int
+f (S &s, int n)
+{
+  int r = 0;
+  for (int i = 0; i < n; ++i)
+    if (i & 1)
+      r += s.p[i];
+  return r;
+}
+
+// { dg-final { scan-tree-dump "Moving statement \[^\n\r]*->p;" "lim2" } }
diff --git a/gcc/testsuite/g++.dg/tree-ssa/lim-ref-2.C 
b/gcc/testsuite/g++.dg/tree-ssa/lim-ref-2.C
new file mode 100644
index 00000000000..e06cb512c1b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/lim-ref-2.C
@@ -0,0 +1,21 @@
+// -fno-delete-null-pointer-checks prevents nonnull_arg_p from using the
+// implicit nonnull property of a C++ reference, so the conditional load must
+// stay in the loop.
+
+// { dg-do compile }
+// { dg-options "-O2 -fno-delete-null-pointer-checks -fdump-tree-lim2-details" 
}
+
+struct S { int n; int *p; };
+
+int
+f (S &s, int n)
+{
+  int r = 0;
+  for (int i = 0; i < n; ++i)
+    if (i & 1)
+      r += s.p[i];
+  return r;
+}
+
+// { dg-final { scan-tree-dump "Memory reference \[^\n\r]*->p" "lim2" } }
+// { dg-final { scan-tree-dump-not "Moving statement \[^\n\r]*->p;" "lim2" } }
diff --git a/gcc/testsuite/g++.dg/tree-ssa/lim-ref-3.C 
b/gcc/testsuite/g++.dg/tree-ssa/lim-ref-3.C
new file mode 100644
index 00000000000..f4a611d9c47
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/lim-ref-3.C
@@ -0,0 +1,22 @@
+// The referenced type bounds what may be speculated: an access past the end
+// of the referenced object still counts as trapping and stays in the loop.
+
+// { dg-do compile }
+// { dg-options "-O2 -fdelete-null-pointer-checks -fdump-tree-lim2-details" }
+// { dg-skip-if "" keeps_null_pointer_checks }
+
+struct Small { int a; };
+struct Big { int a; long b[8]; };
+
+long
+g (Small &s, int n)
+{
+  long r = 0;
+  for (int i = 0; i < n; ++i)
+    if (i & 1)
+      r += reinterpret_cast<Big &> (s).b[3];
+  return r;
+}
+
+// { dg-final { scan-tree-dump "Memory reference \[^\n\r]*struct Big" "lim2" } 
}
+// { dg-final { scan-tree-dump-not "Moving statement \[^\n\r]*struct Big" 
"lim2" } }
diff --git a/gcc/testsuite/g++.dg/tree-ssa/lim-ref-4.C 
b/gcc/testsuite/g++.dg/tree-ssa/lim-ref-4.C
new file mode 100644
index 00000000000..9a9ac0b845a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/lim-ref-4.C
@@ -0,0 +1,30 @@
+// The object bound of a reference parameter does not make a conditional
+// store safe to execute outside its guard.
+
+// { dg-do compile }
+// { dg-options "-O2 -fdelete-null-pointer-checks -fno-tree-cselim -fno-ssa-phiopt 
-fdump-tree-lim2-details" }
+// { dg-additional-options "-fallow-store-data-races" }
+// { dg-skip-if "" keeps_null_pointer_checks }
+
+struct S { int value; };
+
+void
+f (const S &s, int n, int store)
+{
+  for (int i = 0; i < n; ++i)
+    if (store)
+      const_cast<S &> (s).value = 1;
+}
+
+void
+g (S &s, int n, int store)
+{
+  // A non-const reference can designate a const object after const_cast.
+  // The path that does not store is still valid.
+  for (int i = 0; i < n; ++i)
+    if (store)
+      s.value = 1;
+}
+
+// { dg-final { scan-tree-dump-times "Memory reference \[^\n\r]*value" 2 
"lim2" } }
+// { dg-final { scan-tree-dump-not "Executing store motion of \[^\n\r]*value" 
"lim2" } }
diff --git a/gcc/testsuite/g++.dg/tree-ssa/lim-this-1.C 
b/gcc/testsuite/g++.dg/tree-ssa/lim-this-1.C
new file mode 100644
index 00000000000..dbfd79a96b5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/lim-this-1.C
@@ -0,0 +1,25 @@
+// -fno-delete-null-pointer-checks prevents nonnull_arg_p from using the
+// implicit nonnull property of a method's this parameter, so the conditional
+// load must stay in the loop.
+
+// { dg-do compile }
+// { dg-options "-O2 -fno-delete-null-pointer-checks -fdump-tree-lim2-details" 
}
+
+struct S
+{
+  int *values;
+  int f (int);
+};
+
+int
+S::f (int n)
+{
+  int r = 0;
+  for (int i = 0; i < n; ++i)
+    if (i & 1)
+      r += values[i];
+  return r;
+}
+
+// { dg-final { scan-tree-dump "Memory reference \[^\n\r]*->values" "lim2" } }
+// { dg-final { scan-tree-dump-not "Moving statement \[^\n\r]*->values;" 
"lim2" } }
diff --git a/gcc/testsuite/g++.dg/tree-ssa/noncall-store-builtin.C 
b/gcc/testsuite/g++.dg/tree-ssa/noncall-store-builtin.C
new file mode 100644
index 00000000000..c99b3d7b3a0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/noncall-store-builtin.C
@@ -0,0 +1,20 @@
+// Keep the source load of an inline memcpy nontrapping, but not its
+// destination store.
+
+// { dg-do compile }
+// { dg-options "-O2 -fdelete-null-pointer-checks -fnon-call-exceptions 
-finline-stringops=memcpy -fdump-rtl-expand" }
+// { dg-require-effective-target ptr32plus }
+// { dg-skip-if "" keeps_null_pointer_checks }
+
+typedef unsigned char block[16384];
+
+void
+copy (block &dest, const block &src)
+{
+  __builtin_memcpy (dest, src, sizeof (block));
+}
+
+// { dg-final { scan-rtl-dump {\(mem(?:/[a-z])*/c(?:/[a-z])*:} "expand" } }
+// { dg-final { scan-rtl-dump {\(set[ \t\n]+\(mem(?:/[a-z])*:} "expand" } }
+// { dg-final { scan-rtl-dump-not {\(set[ \t\n]+\(mem(?:/[a-z])*/c(?:/[a-z])*:} 
"expand" } }
+// { dg-final { scan-assembler-not {\mmemcpy\M} } }
diff --git a/gcc/tree-eh.cc b/gcc/tree-eh.cc
index e48d9502fb0..e3b8db0b6d0 100644
--- a/gcc/tree-eh.cc
+++ b/gcc/tree-eh.cc
@@ -2752,6 +2752,54 @@ ref_outside_object_p (tree size, poly_offset_int off, 
tree refsz)
    return false;
  }
+/* If PTR is a PARM_DECL or its default SSA definition, return the
+   PARM_DECL.  Otherwise return NULL_TREE.  */
+
+static tree
+parm_decl_from_ptr (tree ptr)
+{
+  if (TREE_CODE (ptr) == SSA_NAME)
+    {
+      if (!SSA_NAME_IS_DEFAULT_DEF (ptr))
+       return NULL_TREE;
+      ptr = SSA_NAME_VAR (ptr);
+    }
+
+  return ptr && TREE_CODE (ptr) == PARM_DECL ? ptr : NULL_TREE;
+}
+
+/* If PTR is a parameter of the current function, or the default definition
+   of one, that is known to designate a whole object, return the size of that
+   object in bytes.  Otherwise return NULL_TREE.
+
+   Two kinds of parameter qualify.  The this pointer of a method points to
+   an object of the method base type.  A parameter whose reference type
+   refers to an object type is bound to an object of the referenced type.
+   In both cases the pointed-to object is at least as large as that type.  */
+
+static tree
+whole_object_param_size (tree ptr)
+{
+  tree type;
+
+  if (!cfun)
+    return NULL_TREE;
+
+  ptr = parm_decl_from_ptr (ptr);
+  if (!ptr)
+    return NULL_TREE;
+
+  if (TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE)
+    type = TREE_TYPE (TREE_TYPE (ptr));
+  else if (TREE_CODE (TREE_TYPE (cfun->decl)) == METHOD_TYPE
+          && ptr == DECL_ARGUMENTS (cfun->decl))
+    type = TYPE_METHOD_BASETYPE (TREE_TYPE (cfun->decl));
+  else
+    return NULL_TREE;
+
+  return nonnull_arg_p (ptr) ? TYPE_SIZE_UNIT (type) : NULL_TREE;
+}
+
  /* Return true if EXPR can trap, as in dereferencing an invalid pointer
     location or evaluating floating-point arithmetic.  See may_trap_p for the
     RTL counterpart.  This routine expects only GIMPLE lhs or rhs input.  LHS
@@ -2852,23 +2900,16 @@ tree_could_trap_1 (tree expr, bool lhs)
          tree refsz = TYPE_SIZE_UNIT (TREE_TYPE (expr));
          return ref_outside_object_p (size, off, refsz);
        }
-      /* See if the base is this for C++ methods. For LHS, this can still
-        trap.  */
-      if (!lhs && cfun
-         && TREE_CODE (TREE_TYPE (cfun->decl)) == METHOD_TYPE
-         && ((TREE_CODE (TREE_OPERAND (expr, 0)) == SSA_NAME
-              && SSA_NAME_IS_DEFAULT_DEF (TREE_OPERAND (expr, 0))
-              && (SSA_NAME_VAR (TREE_OPERAND (expr, 0))
-                  == DECL_ARGUMENTS (cfun->decl)))
-             || TREE_OPERAND (expr, 0) == DECL_ARGUMENTS (cfun->decl)))
+      if (!lhs)
        {
-         poly_offset_int off = mem_ref_offset (expr);
-         if (maybe_lt (off, 0))
-           return true;
-         tree size = TYPE_SIZE_UNIT
-                       (TYPE_METHOD_BASETYPE (TREE_TYPE (cfun->decl)));
-         tree refsz = TYPE_SIZE_UNIT (TREE_TYPE (expr));
-         return ref_outside_object_p (size, off, refsz);
+         if (tree size = whole_object_param_size (TREE_OPERAND (expr, 0)))
+           {
+             poly_offset_int off = mem_ref_offset (expr);
+             if (maybe_lt (off, 0))
+               return true;
+             tree refsz = TYPE_SIZE_UNIT (TREE_TYPE (expr));
+             return ref_outside_object_p (size, off, refsz);
+           }
        }
        return true;
;; Function copy (_Z4copyRA16384_hRA16384_Kh, funcdef_no=0, decl_uid=4948, 
cgraph_uid=1, symbol_order=0)


;; Generating RTL for gimple basic block 2


try_optimize_cfg iteration 1

Merging block 3 into block 2...
Merged blocks 2 and 3.
Merged 2 and 3 without moving.
Merging block 7 into block 6...
Merged blocks 6 and 7.
Merged 6 and 7 without moving.


try_optimize_cfg iteration 2



;;
;; Full RTL generated for this function:
;;
(note 1 0 5 NOTE_INSN_DELETED)
(note 5 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
(insn 2 5 3 2 (set (reg/v/f:SI 94 [ dest ])
        (reg:SI 0 r0 [ dest ])) 
"/build/gcc_src/gcc/testsuite/g++.dg/tree-ssa/noncall-store-builtin.C":13:1 -1
     (nil))
(insn 3 2 4 2 (set (reg/v/f:SI 95 [ src ])
        (reg:SI 1 r1 [ src ])) 
"/build/gcc_src/gcc/testsuite/g++.dg/tree-ssa/noncall-store-builtin.C":13:1 -1
     (nil))
(note 4 3 7 2 NOTE_INSN_FUNCTION_BEG)
(insn 7 4 8 2 (set (reg:SI 96)
        (const_int 0 [0])) 
"/build/gcc_src/gcc/testsuite/g++.dg/tree-ssa/noncall-store-builtin.C":14:20 -1
     (nil))
(jump_insn 8 7 9 2 (set (pc)
        (label_ref 15)) 
"/build/gcc_src/gcc/testsuite/g++.dg/tree-ssa/noncall-store-builtin.C":14:20 -1
     (nil)
 -> 15)
(barrier 9 8 10)
(code_label 10 9 22 4 2 (nil) [1 uses])
(note 22 10 11 4 [bb 4] NOTE_INSN_BASIC_BLOCK)
(insn 11 22 12 4 (set (reg:SI 97)
        (zero_extend:SI (mem/c:QI (plus:SI (reg/v/f:SI 95 [ src ])
                    (reg:SI 96)) [0  S1 A8]))) 
"/build/gcc_src/gcc/testsuite/g++.dg/tree-ssa/noncall-store-builtin.C":14:20 -1
     (nil))
(insn 12 11 13 4 (set (reg:QI 98)
        (subreg:QI (reg:SI 97) 0)) 
"/build/gcc_src/gcc/testsuite/g++.dg/tree-ssa/noncall-store-builtin.C":14:20 -1
     (nil))
(insn 13 12 14 4 (set (mem/c:QI (plus:SI (reg/v/f:SI 94 [ dest ])
                (reg:SI 96)) [0  S1 A8])
        (reg:QI 98)) 
"/build/gcc_src/gcc/testsuite/g++.dg/tree-ssa/noncall-store-builtin.C":14:20 -1
     (nil))
(insn 14 13 15 4 (set (reg:SI 96)
        (plus:SI (reg:SI 96)
            (const_int 1 [0x1]))) 
"/build/gcc_src/gcc/testsuite/g++.dg/tree-ssa/noncall-store-builtin.C":14:20 -1
     (nil))
(code_label 15 14 23 5 3 (nil) [1 uses])
(note 23 15 16 5 [bb 5] NOTE_INSN_BASIC_BLOCK)
(insn 16 23 17 5 (set (reg:SI 99)
        (const_int 16384 [0x4000])) 
"/build/gcc_src/gcc/testsuite/g++.dg/tree-ssa/noncall-store-builtin.C":14:20 -1
     (nil))
(jump_insn 17 16 24 5 (set (pc)
        (if_then_else (ltu (reg:SI 96)
                (reg:SI 99))
            (label_ref 10)
            (pc))) 
"/build/gcc_src/gcc/testsuite/g++.dg/tree-ssa/noncall-store-builtin.C":14:20 -1
     (int_list:REG_BR_PROB 966367641 (nil))
 -> 10)
(note 24 17 18 6 [bb 6] NOTE_INSN_BASIC_BLOCK)
(insn 18 24 20 6 (set (reg:SI 100)
        (reg:SI 100)) 
"/build/gcc_src/gcc/testsuite/g++.dg/tree-ssa/noncall-store-builtin.C":15:1 -1
     (nil))
(insn 20 18 0 6 (unspec_volatile [
            (const_int 0 [0])
        ] VUNSPEC_BLOCKAGE) 
"/build/gcc_src/gcc/testsuite/g++.dg/tree-ssa/noncall-store-builtin.C":15:1 -1
     (nil))
;; Function scrubbed.strub.0 (scrubbed.strub.0, funcdef_no=1, decl_uid=4722, 
cgraph_uid=3, symbol_order=2)


;; Generating RTL for gimple basic block 2


try_optimize_cfg iteration 1

Merging block 3 into block 2...
Merged blocks 2 and 3.
Merged 2 and 3 without moving.
Removing jump 16.
Merging block 6 into block 5...
Merged blocks 5 and 6.
Merged 5 and 6 without moving.


try_optimize_cfg iteration 2



;;
;; Full RTL generated for this function:
;;
(note 1 0 5 NOTE_INSN_DELETED)
(note 5 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
(insn 2 5 3 2 (set (reg/v:SI 95 [ value ])
        (reg:SI 0 r0 [ value ])) 
"/build/gcc_src/gcc/testsuite/c-c++-common/strub-mem-notrap.c":13:1 -1
     (nil))
(insn 3 2 4 2 (set (reg/f:SI 96 [ .strub.watermark_ptr ])
        (reg:SI 1 r1 [ .strub.watermark_ptr ])) 
"/build/gcc_src/gcc/testsuite/c-c++-common/strub-mem-notrap.c":13:1 -1
     (nil))
(note 4 3 7 2 NOTE_INSN_FUNCTION_BEG)
(insn 7 4 8 2 (set (reg:SI 97)
        (reg/f:SI 13 sp)) 
"/build/gcc_src/gcc/testsuite/c-c++-common/strub-mem-notrap.c":13:1 -1
     (nil))
(insn 8 7 9 2 (set (reg/f:SI 98)
        (mem/f/c:SI (reg/f:SI 96 [ .strub.watermark_ptr ]) [2 
*.strub.watermark_ptr_5(D)+0 S4 A32])) 
"/build/gcc_src/gcc/testsuite/c-c++-common/strub-mem-notrap.c":13:1 -1
     (nil))
(jump_insn 9 8 23 2 (set (pc)
        (if_then_else (leu (reg/f:SI 98)
                (reg:SI 97))
            (label_ref 11)
            (pc))) 
"/build/gcc_src/gcc/testsuite/c-c++-common/strub-mem-notrap.c":13:1 -1
     (int_list:REG_BR_PROB 536865 (nil))
 -> 11)
(note 23 9 10 4 [bb 4] NOTE_INSN_BASIC_BLOCK)
(insn 10 23 11 4 (set (mem/f/c:SI (reg/f:SI 96 [ .strub.watermark_ptr ]) [2 
*.strub.watermark_ptr_5(D)+0 S4 A32])
        (reg:SI 97)) 
"/build/gcc_src/gcc/testsuite/c-c++-common/strub-mem-notrap.c":13:1 -1
     (nil))
(code_label 11 10 24 5 2 (nil) [1 uses])
(note 24 11 12 5 [bb 5] NOTE_INSN_BASIC_BLOCK)
(insn 12 24 13 5 (set (reg/f:SI 99)
        (mem/u/c:SI (symbol_ref/u:SI ("*.LC0") [flags 0x2]) [0  S4 A32])) 
"/build/gcc_src/gcc/testsuite/c-c++-common/strub-mem-notrap.c":15:8 -1
     (expr_list:REG_EQUAL (symbol_ref:SI ("*.LANCHOR0") [flags 0x182])
        (nil)))
(insn 13 12 14 5 (set (mem/v/c:SI (reg/f:SI 99) [1 sink+0 S4 A32])
        (reg/v:SI 95 [ value ])) 
"/build/gcc_src/gcc/testsuite/c-c++-common/strub-mem-notrap.c":15:8 -1
     (nil))
(insn 14 13 15 5 (set (reg/f:SI 100)
        (mem/u/c:SI (symbol_ref/u:SI ("*.LC0") [flags 0x2]) [0  S4 A32])) 
"/build/gcc_src/gcc/testsuite/c-c++-common/strub-mem-notrap.c":16:10 -1
     (expr_list:REG_EQUAL (symbol_ref:SI ("*.LANCHOR0") [flags 0x182])
        (nil)))
(insn 15 14 19 5 (set (reg:SI 94 [ <retval> ])
        (mem/v/c:SI (reg/f:SI 100) [1 sink+0 S4 A32])) 
"/build/gcc_src/gcc/testsuite/c-c++-common/strub-mem-notrap.c":16:10 -1
     (nil))
(insn 19 15 20 5 (set (reg/i:SI 0 r0)
        (reg:SI 94 [ <retval> ])) 
"/build/gcc_src/gcc/testsuite/c-c++-common/strub-mem-notrap.c":17:1 -1
     (nil))
(insn 20 19 21 5 (unspec_volatile [
            (const_int 0 [0])
        ] VUNSPEC_BLOCKAGE) 
"/build/gcc_src/gcc/testsuite/c-c++-common/strub-mem-notrap.c":17:1 -1
     (nil))
(insn 21 20 0 5 (use (reg/i:SI 0 r0)) 
"/build/gcc_src/gcc/testsuite/c-c++-common/strub-mem-notrap.c":17:1 -1
     (nil))

;; Function scrubbed (scrubbed, funcdef_no=3, decl_uid=4712, cgraph_uid=2, 
symbol_order=1)

Partition 0: size 4 align 4
        .strub.watermark.3

;; Generating RTL for gimple basic block 2


try_optimize_cfg iteration 1

Merging block 3 into block 2...
Merged blocks 2 and 3.
Merged 2 and 3 without moving.
Edge 2->5 redirected to 6
Merging block 5 into block 4...
Merged blocks 4 and 5.
Merged 4 and 5 without moving.
Removing jump 21.


try_optimize_cfg iteration 2



;;
;; Full RTL generated for this function:
;;
(note 1 0 4 NOTE_INSN_DELETED)
(note 4 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
(insn 2 4 3 2 (set (reg/v:SI 95 [ value ])
        (reg:SI 0 r0 [ value ])) 
"/build/gcc_src/gcc/testsuite/c-c++-common/strub-mem-notrap.c":13:1 -1
     (nil))
(note 3 2 6 2 NOTE_INSN_FUNCTION_BEG)
(insn 6 3 7 2 (set (reg:SI 96)
        (reg/f:SI 13 sp)) -1
     (nil))
(insn 7 6 8 2 (set (mem/f/c:SI (plus:SI (reg/f:SI 89 virtual-stack-vars)
                (const_int -4 [0xfffffffffffffffc])) [2 .strub.watermark.3+0 S4 
A32])
        (reg:SI 96)) -1
     (nil))
(insn 8 7 9 2 (set (reg:SI 97)
        (plus:SI (reg/f:SI 89 virtual-stack-vars)
            (const_int -4 [0xfffffffffffffffc]))) -1
     (nil))
(insn 9 8 10 2 (set (reg:SI 1 r1)
        (reg:SI 97)) -1
     (nil))
(insn 10 9 11 2 (set (reg:SI 0 r0)
        (reg/v:SI 95 [ value ])) -1
     (nil))
(call_insn 11 10 12 2 (parallel [
            (set (reg:SI 0 r0)
                (call (mem:SI (symbol_ref:SI ("scrubbed.strub.0") [flags 0x3]  
<function_decl 0x7c310ca93300 scrubbed.strub.0>) [0 scrubbed.strub.0 S4 A32])
                    (const_int 0 [0])))
            (use (const_int 0 [0]))
            (clobber (reg:SI 14 lr))
        ]) -1
     (expr_list:REG_CALL_DECL (symbol_ref:SI ("scrubbed.strub.0") [flags 0x3]  
<function_decl 0x7c310ca93300 scrubbed.strub.0>)
        (expr_list:REG_EH_REGION (const_int 0 [0])
            (nil)))
    (expr_list (clobber (reg:SI 12 ip))
        (expr_list:SI (use (reg:SI 0 r0))
            (expr_list:SI (use (reg:SI 1 r1))
                (nil)))) 0)
(insn 12 11 13 2 (set (reg:SI 94 [ <retval> ])
        (reg:SI 0 r0)) -1
     (nil))
(insn 13 12 14 2 (set (reg:SI 98)
        (reg/f:SI 13 sp)) -1
     (nil))
(insn 14 13 15 2 (set (reg/f:SI 99)
        (mem/f/c:SI (plus:SI (reg/f:SI 89 virtual-stack-vars)
                (const_int -4 [0xfffffffffffffffc])) [2 .strub.watermark.3+0 S4 
A32])) -1
     (nil))
(insn 15 14 16 2 (set (reg:SI 100)
        (reg/f:SI 99)) -1
     (nil))
(jump_insn 16 15 28 2 (set (pc)
        (if_then_else (geu (reg:SI 100)
                (reg:SI 98))
            (label_ref:SI 23)
            (pc))) 752 {cbranchsi4_insn}
     (int_list:REG_BR_PROB 536865 (nil))
 -> 23)
(note 28 16 17 4 [bb 4] NOTE_INSN_BASIC_BLOCK)
(insn 17 28 18 4 (set (reg:SI 101)
        (plus:SI (reg/f:SI 89 virtual-stack-vars)
            (const_int -4 [0xfffffffffffffffc]))) -1
     (nil))
(insn 18 17 19 4 (set (reg:SI 0 r0)
        (reg:SI 101)) -1
     (nil))
(call_insn 19 18 23 4 (parallel [
            (call (mem:SI (symbol_ref:SI ("__strub_leave") [flags 0x41]  
<function_decl 0x7c310ca93c00 __builtin___strub_leave>) [0 
__builtin___strub_leave S4 A32])
                (const_int 0 [0]))
            (use (const_int 0 [0]))
            (clobber (reg:SI 14 lr))
        ]) -1
     (expr_list:REG_CALL_DECL (symbol_ref:SI ("__strub_leave") [flags 0x41]  
<function_decl 0x7c310ca93c00 __builtin___strub_leave>)
        (expr_list:REG_EH_REGION (const_int 0 [0])
            (nil)))
    (expr_list (clobber (reg:SI 12 ip))
        (expr_list:SI (use (reg:SI 0 r0))
            (nil))) 0)
(code_label 23 19 27 6 6 (nil) [1 uses])
(note 27 23 24 6 [bb 6] NOTE_INSN_BASIC_BLOCK)
(insn 24 27 25 6 (set (reg/i:SI 0 r0)
        (reg:SI 94 [ <retval> ])) 
"/build/gcc_src/gcc/testsuite/c-c++-common/strub-mem-notrap.c":13:1 -1
     (nil))
(insn 25 24 26 6 (unspec_volatile [
            (const_int 0 [0])
        ] VUNSPEC_BLOCKAGE) 
"/build/gcc_src/gcc/testsuite/c-c++-common/strub-mem-notrap.c":13:1 -1
     (nil))
(insn 26 25 0 6 (use (reg/i:SI 0 r0)) 
"/build/gcc_src/gcc/testsuite/c-c++-common/strub-mem-notrap.c":13:1 -1
     (nil))

Reply via email to