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)