> On 14 Sep 2026, at 08:13, Torbjorn SVENSSON <[email protected]> 
> wrote:
> 
> 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.

My bad, I was hasty in pushing the optimization patch and forgot that these 
tests depend on the prerequisites from the series at:
https://gcc.gnu.org/pipermail/gcc-patches/2026-September/730714.html
landing.
Though the strub test does need some extra handling, which I’ve added in the 
respun series at:
https://gcc.gnu.org/pipermail/gcc-patches/2026-September/731206.html
These patches should fix these two tests (though in hindsight I shouldn’t have 
pushed them with this patch).
Thanks,
Kyrill


> 
> 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;
>>  
> <noncall-store-builtin.C.273r.expand><strub-mem-notrap.c.273r.expand>

Reply via email to