> 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>
