From: Kyrylo Tkachov <[email protected]>

expand_builtin_strub_update expands a watermark with EXPAND_MEMORY because
it needs a MEM.  The same MEM is first loaded for a comparison and can then
be the destination of a store.  EXPAND_MEMORY has conservative store
semantics, so the load loses its valid MEM_NOTRAP flag:

  (set (reg:DI ...)
       (mem/f:DI (... watermark_ptr ...)))
  (set (mem/f:DI (... watermark_ptr ...))
       (reg:DI ...))

Make a shallow copy for the load and derive its MEM_NOTRAP flag with load
trap semantics.  Keep the original MEM for the store:

  (set (reg:DI ...)
       (mem/f/c:DI (... watermark_ptr ...)))
  (set (mem/f:DI (... watermark_ptr ...))
       (reg:DI ...))

This keeps the memory-result requirement and does not mark the conditional
store as nontrapping.  Apply load trap semantics to the load-only watermarks
in expand_builtin_strub_leave as well.

Tighten the existing update test so that it identifies the load and store
positions independently of the target mode and MEM flag order.  Add a nested
at-calls test that checks the incoming watermark loads from both update and
leave.

Bootstrapped and tested on aarch64-unknown-linux-gnu.  Tested on
x86_64-pc-linux-gnu.

        PR middle-end/127185

gcc/ChangeLog:

        * builtins.cc (expand_builtin_strub_update): Use a separate MEM with
        load trap semantics for each watermark load.
        (expand_builtin_strub_leave): Use load trap semantics for watermark
        MEMs.

gcc/testsuite/ChangeLog:

        * c-c++-common/strub-mem-notrap.c: Tighten the load and store scans.
        * c-c++-common/strub-mem-notrap-leave.c: New test.

Signed-off-by: Kyrylo Tkachov <[email protected]>
---
 gcc/builtins.cc                               | 11 +++++++--
 .../c-c++-common/strub-mem-notrap-leave.c     | 23 +++++++++++++++++++
 gcc/testsuite/c-c++-common/strub-mem-notrap.c |  7 +++---
 3 files changed, 36 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/strub-mem-notrap-leave.c

diff --git a/gcc/builtins.cc b/gcc/builtins.cc
index 02170d74ae9..f2e21a57a59 100644
--- a/gcc/builtins.cc
+++ b/gcc/builtins.cc
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree.h"
 #include "memmodel.h"
 #include "gimple.h"
+#include "tree-eh.h"
 #include "predict.h"
 #include "tm_p.h"
 #include "stringpool.h"
@@ -5617,7 +5618,9 @@ expand_builtin_strub_update (tree exp)
                             build_int_cst (TREE_TYPE (wmptr), 0));
   rtx wmark = expand_expr (wmtree, NULL_RTX, ptr_mode, EXPAND_MEMORY);
 
-  rtx wmarkr = force_reg (ptr_mode, wmark);
+  rtx wmark_load = shallow_copy_rtx (wmark);
+  MEM_NOTRAP_P (wmark_load) = !tree_could_trap_p (wmtree);
+  rtx wmarkr = force_reg (ptr_mode, wmark_load);
 
   rtx_code_label *lab = gen_label_rtx ();
   do_compare_rtx_and_jump (stktop, wmarkr, STACK_TOPS, STACK_UNSIGNED,
@@ -5642,7 +5645,9 @@ expand_builtin_strub_update (tree exp)
       wmtree = fold_build2 (MEM_REF, wmtype, wmptr,
                            build_int_cst (TREE_TYPE (wmptr), 0));
       wmark = expand_expr (wmtree, NULL_RTX, ptr_mode, EXPAND_MEMORY);
-      wmarkr = force_reg (ptr_mode, wmark);
+      wmark_load = shallow_copy_rtx (wmark);
+      MEM_NOTRAP_P (wmark_load) = !tree_could_trap_p (wmtree);
+      wmarkr = force_reg (ptr_mode, wmark_load);
 
       do_compare_rtx_and_jump (stktop, wmarkr, STACK_TOPS, STACK_UNSIGNED,
                               ptr_mode, NULL_RTX, lab, NULL,
@@ -5677,6 +5682,7 @@ expand_builtin_strub_leave (tree exp)
       tree wmtree = fold_build2 (MEM_REF, wmtype, wmptr,
                                 build_int_cst (TREE_TYPE (wmptr), 0));
       rtx wmark = expand_expr (wmtree, NULL_RTX, ptr_mode, EXPAND_MEMORY);
+      MEM_NOTRAP_P (wmark) = !tree_could_trap_p (wmtree);
       stktop = force_reg (ptr_mode, wmark);
     }
 
@@ -5688,6 +5694,7 @@ expand_builtin_strub_leave (tree exp)
   tree wmtree = fold_build2 (MEM_REF, wmtype, wmptr,
                             build_int_cst (TREE_TYPE (wmptr), 0));
   rtx wmark = expand_expr (wmtree, NULL_RTX, ptr_mode, EXPAND_MEMORY);
+  MEM_NOTRAP_P (wmark) = !tree_could_trap_p (wmtree);
 
   rtx wmarkr = force_reg (ptr_mode, wmark);
 
diff --git a/gcc/testsuite/c-c++-common/strub-mem-notrap-leave.c 
b/gcc/testsuite/c-c++-common/strub-mem-notrap-leave.c
new file mode 100644
index 00000000000..246c4c2088f
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-mem-notrap-leave.c
@@ -0,0 +1,23 @@
+// Keep watermark loads nontrapping when a strub context calls another.
+
+// { 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 }
+
+extern int callee (int)
+  __attribute__ ((__strub__ ("at-calls"), __nothrow__));
+volatile int sink;
+
+__attribute__ ((__strub__ ("at-calls"), __noinline__))
+int
+caller (int value)
+{
+  int result = callee (value);
+  sink = result;
+  return result + 1;
+}
+
+// The incoming watermark is loaded once by update and once by leave.
+// { dg-final { scan-rtl-dump-times {\(set[ \t\n]+\(reg(?:/[a-z])*:[^\n\r]*\)[ 
\t\n]+\(mem(?:/[a-z])*/c(?:/[a-z])*:[^\n\r]*[*][.]strub[.]watermark_ptr} 2 
"expand" } }
diff --git a/gcc/testsuite/c-c++-common/strub-mem-notrap.c 
b/gcc/testsuite/c-c++-common/strub-mem-notrap.c
index ef9bbc39535..e0f4fe7b34d 100644
--- a/gcc/testsuite/c-c++-common/strub-mem-notrap.c
+++ b/gcc/testsuite/c-c++-common/strub-mem-notrap.c
@@ -16,6 +16,7 @@ scrubbed (int 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" } } */
+// The watermark load is nontrapping.  The conditional store can trap.
+// { dg-final { scan-rtl-dump {\(set[ \t\n]+\(reg(?:/[a-z])*:[^\n\r]*\)[ 
\t\n]+\(mem(?:/[a-z])*/c(?:/[a-z])*:[^\n\r]*[*][.]strub[.]watermark_ptr} 
"expand" } }
+// { dg-final { scan-rtl-dump {\(set[ 
\t\n]+\(mem(?:/[a-z])*:[^\n\r]*[*][.]strub[.]watermark_ptr} "expand" } }
+// { dg-final { scan-rtl-dump-not {\(set[ 
\t\n]+\(mem(?:/[a-z])*/c(?:/[a-z])*:[^\n\r]*[*][.]strub[.]watermark_ptr} 
"expand" } }
-- 
2.50.1 (Apple Git-155)

Reply via email to