public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/users/aoliva/heads/testme)] strub: enable conditional support
@ 2023-12-07  0:02 Alexandre Oliva
  0 siblings, 0 replies; 25+ messages in thread
From: Alexandre Oliva @ 2023-12-07  0:02 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:54341700b55497f725f2366269bd0b2b62f4a34b

commit 54341700b55497f725f2366269bd0b2b62f4a34b
Author: Alexandre Oliva <oliva@gnu.org>
Date:   Wed Dec 6 19:36:02 2023 -0300

    strub: enable conditional support

Diff:
---
 gcc/config/nvptx/nvptx.cc                          |  3 ++
 gcc/doc/tm.texi                                    |  6 +++
 gcc/doc/tm.texi.in                                 |  2 +
 gcc/ipa-strub.cc                                   | 54 +++++++++++++++++++++-
 gcc/target.def                                     |  8 ++++
 gcc/testsuite/c-c++-common/strub-O0.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O1.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O2.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O2fni.c           |  1 +
 gcc/testsuite/c-c++-common/strub-O3.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O3fni.c           |  1 +
 gcc/testsuite/c-c++-common/strub-Og.c              |  1 +
 gcc/testsuite/c-c++-common/strub-Os.c              |  1 +
 gcc/testsuite/c-c++-common/strub-all1.c            |  1 +
 gcc/testsuite/c-c++-common/strub-all2.c            |  1 +
 gcc/testsuite/c-c++-common/strub-apply1.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply2.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply3.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply4.c          |  1 +
 gcc/testsuite/c-c++-common/strub-at-calls1.c       |  1 +
 gcc/testsuite/c-c++-common/strub-at-calls2.c       |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O3.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-Os.c        |  1 +
 gcc/testsuite/c-c++-common/strub-internal1.c       |  1 +
 gcc/testsuite/c-c++-common/strub-internal2.c       |  1 +
 gcc/testsuite/c-c++-common/strub-parms1.c          |  1 +
 gcc/testsuite/c-c++-common/strub-parms2.c          |  1 +
 gcc/testsuite/c-c++-common/strub-parms3.c          |  1 +
 gcc/testsuite/c-c++-common/strub-relaxed1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-relaxed2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O0-exc.c    |  1 +
 gcc/testsuite/c-c++-common/strub-short-O0.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O3.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-Os.c        |  1 +
 gcc/testsuite/c-c++-common/strub-strict1.c         |  1 +
 gcc/testsuite/c-c++-common/strub-strict2.c         |  1 +
 gcc/testsuite/c-c++-common/strub-tail-O1.c         |  1 +
 gcc/testsuite/c-c++-common/strub-tail-O2.c         |  1 +
 gcc/testsuite/c-c++-common/strub-var1.c            |  1 +
 .../c-c++-common/torture/strub-callable1.c         |  1 +
 .../c-c++-common/torture/strub-callable2.c         |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const1.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const2.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const3.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const4.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data1.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data2.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data3.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data4.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data5.c   |  1 +
 .../c-c++-common/torture/strub-indcall1.c          |  1 +
 .../c-c++-common/torture/strub-indcall2.c          |  1 +
 .../c-c++-common/torture/strub-indcall3.c          |  1 +
 .../c-c++-common/torture/strub-inlinable1.c        |  1 +
 .../c-c++-common/torture/strub-inlinable2.c        |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure1.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure2.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure3.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure4.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run1.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run2.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run3.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4c.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4d.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4i.c   |  1 +
 gcc/testsuite/g++.dg/strub-run1.C                  |  1 +
 gcc/testsuite/g++.dg/torture/strub-init1.C         |  1 +
 gcc/testsuite/g++.dg/torture/strub-init2.C         |  1 +
 gcc/testsuite/g++.dg/torture/strub-init3.C         |  1 +
 gcc/testsuite/gnat.dg/strub_access.adb             |  1 +
 gcc/testsuite/gnat.dg/strub_access1.adb            |  1 +
 gcc/testsuite/gnat.dg/strub_attr.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_disp.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_disp1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_ind.adb                |  1 +
 gcc/testsuite/gnat.dg/strub_ind1.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_ind2.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_intf.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_intf1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_intf2.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_renm.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_renm1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_renm2.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_var.adb                |  1 +
 gcc/testsuite/gnat.dg/strub_var1.adb               |  1 +
 gcc/testsuite/lib/target-supports.exp              |  7 +++
 libgcc/Makefile.in                                 |  2 +-
 libgcc/configure                                   | 26 +++++++++++
 libgcc/configure.ac                                | 13 ++++++
 98 files changed, 207 insertions(+), 3 deletions(-)

diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc
index ae20802c879..3fb1deb70fd 100644
--- a/gcc/config/nvptx/nvptx.cc
+++ b/gcc/config/nvptx/nvptx.cc
@@ -7789,6 +7789,9 @@ nvptx_asm_output_def_from_decls (FILE *stream, tree name, tree value)
 #undef TARGET_LIBC_HAS_FUNCTION
 #define TARGET_LIBC_HAS_FUNCTION nvptx_libc_has_function
 
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-nvptx.h"
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 89a1735dd79..768ada0af52 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -3450,6 +3450,12 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@deftypefn {Target Hook} bool TARGET_HAVE_STRUB_SUPPORT_FOR (tree)
+Returns true if the target supports stack scrubbing for the given function
+or type, otherwise return false.  The default implementation always returns
+true.
+@end deftypefn
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index ebc1d3de5ca..4fe0805394e 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2686,6 +2686,8 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@hook TARGET_HAVE_STRUB_SUPPORT_FOR
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
index 293bec132b8..f3100bb1d44 100644
--- a/gcc/ipa-strub.cc
+++ b/gcc/ipa-strub.cc
@@ -60,6 +60,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-strub.h"
 #include "symtab-thunks.h"
 #include "attr-fnspec.h"
+#include "target.h"
 
 /* This file introduces two passes that, together, implement
    machine-independent stack scrubbing, strub for short.  It arranges
@@ -631,17 +632,60 @@ strub_always_inline_p (cgraph_node *node)
   return lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl));
 }
 
+/* Return TRUE iff the target has strub support for T, a function decl
+   or a type, and optionally REPORT thereasons for ineligibility.  If
+   T is a type and error REPORTing is enabled, the LOCation (e.g. of
+   the indirect call) should be given in LOC.  */
+static inline bool
+strub_target_support_p (tree t, bool report = false,
+			location_t loc = UNKNOWN_LOCATION)
+{
+  bool result = true;
+
+  if (!targetm.have_strub_support_for (t))
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      if (DECL_P (t))
+	sorry_at (DECL_SOURCE_LOCATION (t),
+		  "%qD is not eligible for %<strub%>"
+		  " on the target system", t);
+      else
+	sorry_at (loc,
+		  "%qT is not an eligible type for %<strub%>"
+		  " on the target system", t);
+    }
+
+  return result;
+}
+
 /* Return TRUE iff NODE is potentially eligible for any strub-enabled mode, and
    optionally REPORT the reasons for ineligibility.  */
 
 static inline bool
 can_strub_p (cgraph_node *node, bool report = false)
 {
-  bool result = true;
+  bool result = strub_target_support_p (node->decl, report);
 
-  if (!report && strub_always_inline_p (node))
+  if (!report && (!result || strub_always_inline_p (node)))
     return result;
 
+  if (flag_split_stack)
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (node->decl),
+		"%qD is not eligible for %<strub%>"
+		" because %<-fsplit-stack%> is enabled",
+		node->decl);
+    }
+
   if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
     {
       result = false;
@@ -2417,6 +2461,12 @@ pass_ipa_strub::adjust_at_calls_call (cgraph_edge *e, int named_args,
 			 && (TREE_TYPE (gimple_call_arg (ocall, named_args))
 			     == get_pwmt ())));
 
+  tree tsup;
+  if (!(tsup = gimple_call_fndecl (ocall)))
+    tsup = TREE_TYPE (TREE_TYPE (gimple_call_fn (ocall)));
+  if (!strub_target_support_p (tsup, true, gimple_location (ocall)))
+    return;
+
   /* If we're already within a strub context, pass on the incoming watermark
      pointer, and omit the enter and leave calls around the modified call, as an
      optimization, or as a means to satisfy a tail-call requirement.  */
diff --git a/gcc/target.def b/gcc/target.def
index 52b83e091b9..08218f3a42a 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4457,6 +4457,14 @@ otherwise return false.  The default implementation always returns true.",
  bool, (void),
  hook_bool_void_true)
 
+DEFHOOK
+(have_strub_support_for,
+ "Returns true if the target supports stack scrubbing for the given function\n\
+or type, otherwise return false.  The default implementation always returns\n\
+true.",
+ bool, (tree),
+ hook_bool_tree_true)
+
 DEFHOOK
 (have_speculation_safe_value,
 "This hook is used to determine the level of target support for\n\
diff --git a/gcc/testsuite/c-c++-common/strub-O0.c b/gcc/testsuite/c-c++-common/strub-O0.c
index c7a79a6ea0d..cb61af2d425 100644
--- a/gcc/testsuite/c-c++-common/strub-O0.c
+++ b/gcc/testsuite/c-c++-common/strub-O0.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fdump-rtl-expand" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O1.c b/gcc/testsuite/c-c++-common/strub-O1.c
index 96285c975d9..9c8e36ccf56 100644
--- a/gcc/testsuite/c-c++-common/strub-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-O1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fdump-rtl-expand" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O2.c b/gcc/testsuite/c-c++-common/strub-O2.c
index 8edc0d8aa13..0775c8354f8 100644
--- a/gcc/testsuite/c-c++-common/strub-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-O2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O2fni.c b/gcc/testsuite/c-c++-common/strub-O2fni.c
index c6d900cf3c4..ea1effc09c7 100644
--- a/gcc/testsuite/c-c++-common/strub-O2fni.c
+++ b/gcc/testsuite/c-c++-common/strub-O2fni.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O3.c b/gcc/testsuite/c-c++-common/strub-O3.c
index 33ee465e51c..909aac313e2 100644
--- a/gcc/testsuite/c-c++-common/strub-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-O3.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O3fni.c b/gcc/testsuite/c-c++-common/strub-O3fni.c
index 2936f82079e..acf68f02eed 100644
--- a/gcc/testsuite/c-c++-common/strub-O3fni.c
+++ b/gcc/testsuite/c-c++-common/strub-O3fni.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-Og.c b/gcc/testsuite/c-c++-common/strub-Og.c
index 479746e57d8..8e5bab12936 100644
--- a/gcc/testsuite/c-c++-common/strub-Og.c
+++ b/gcc/testsuite/c-c++-common/strub-Og.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-Og -fstrub=strict -fdump-rtl-expand" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-Os.c b/gcc/testsuite/c-c++-common/strub-Os.c
index 2241d4ea07f..14199e0aa8c 100644
--- a/gcc/testsuite/c-c++-common/strub-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-Os.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-Os -fstrub=strict -fdump-rtl-expand" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-all1.c b/gcc/testsuite/c-c++-common/strub-all1.c
index a322bcc5da6..04328515764 100644
--- a/gcc/testsuite/c-c++-common/strub-all1.c
+++ b/gcc/testsuite/c-c++-common/strub-all1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-all2.c b/gcc/testsuite/c-c++-common/strub-all2.c
index db60026d0e0..3f3304c2512 100644
--- a/gcc/testsuite/c-c++-common/strub-all2.c
+++ b/gcc/testsuite/c-c++-common/strub-all2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-apply1.c b/gcc/testsuite/c-c++-common/strub-apply1.c
index 2f462adc1ef..21b706abc5a 100644
--- a/gcc/testsuite/c-c++-common/strub-apply1.c
+++ b/gcc/testsuite/c-c++-common/strub-apply1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-apply2.c b/gcc/testsuite/c-c++-common/strub-apply2.c
index a5d7551f5da..bec9707f015 100644
--- a/gcc/testsuite/c-c++-common/strub-apply2.c
+++ b/gcc/testsuite/c-c++-common/strub-apply2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-apply3.c b/gcc/testsuite/c-c++-common/strub-apply3.c
index 64422a0d1e8..e94cfcf5972 100644
--- a/gcc/testsuite/c-c++-common/strub-apply3.c
+++ b/gcc/testsuite/c-c++-common/strub-apply3.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-apply4.c b/gcc/testsuite/c-c++-common/strub-apply4.c
index 15ffaa031b8..56021c573ff 100644
--- a/gcc/testsuite/c-c++-common/strub-apply4.c
+++ b/gcc/testsuite/c-c++-common/strub-apply4.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-ipa-strubm" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls1.c b/gcc/testsuite/c-c++-common/strub-at-calls1.c
index b70843b4215..7cfae001db3 100644
--- a/gcc/testsuite/c-c++-common/strub-at-calls1.c
+++ b/gcc/testsuite/c-c++-common/strub-at-calls1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls2.c b/gcc/testsuite/c-c++-common/strub-at-calls2.c
index 97a3988a6b9..d26ce9be856 100644
--- a/gcc/testsuite/c-c++-common/strub-at-calls2.c
+++ b/gcc/testsuite/c-c++-common/strub-at-calls2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O1.c b/gcc/testsuite/c-c++-common/strub-defer-O1.c
index 3d73431b3dc..147c938145c 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O1" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O2.c b/gcc/testsuite/c-c++-common/strub-defer-O2.c
index fddf3c745e7..c12d50ff051 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O2" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O3.c b/gcc/testsuite/c-c++-common/strub-defer-O3.c
index 7ebc65b58dd..7a5f2a9e084 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O3.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O3" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-defer-Os.c b/gcc/testsuite/c-c++-common/strub-defer-Os.c
index fbaf85fe0fa..ce868bd7694 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-Os.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -Os" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-internal1.c b/gcc/testsuite/c-c++-common/strub-internal1.c
index e9d7b7b9ee0..47ed5b60c46 100644
--- a/gcc/testsuite/c-c++-common/strub-internal1.c
+++ b/gcc/testsuite/c-c++-common/strub-internal1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-internal2.c b/gcc/testsuite/c-c++-common/strub-internal2.c
index 8b8e15a51c7..ca6b3a3a3e2 100644
--- a/gcc/testsuite/c-c++-common/strub-internal2.c
+++ b/gcc/testsuite/c-c++-common/strub-internal2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-parms1.c b/gcc/testsuite/c-c++-common/strub-parms1.c
index 0a4a7539d34..66f3eba8433 100644
--- a/gcc/testsuite/c-c++-common/strub-parms1.c
+++ b/gcc/testsuite/c-c++-common/strub-parms1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-parms2.c b/gcc/testsuite/c-c++-common/strub-parms2.c
index 147171d96d5..4f676ecd962 100644
--- a/gcc/testsuite/c-c++-common/strub-parms2.c
+++ b/gcc/testsuite/c-c++-common/strub-parms2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-parms3.c b/gcc/testsuite/c-c++-common/strub-parms3.c
index 4e92682895a..fbef0c76bd4 100644
--- a/gcc/testsuite/c-c++-common/strub-parms3.c
+++ b/gcc/testsuite/c-c++-common/strub-parms3.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed1.c b/gcc/testsuite/c-c++-common/strub-relaxed1.c
index e2f9d8aebca..152f2cc6731 100644
--- a/gcc/testsuite/c-c++-common/strub-relaxed1.c
+++ b/gcc/testsuite/c-c++-common/strub-relaxed1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed2.c b/gcc/testsuite/c-c++-common/strub-relaxed2.c
index 98474435d2e..af77224b54e 100644
--- a/gcc/testsuite/c-c++-common/strub-relaxed2.c
+++ b/gcc/testsuite/c-c++-common/strub-relaxed2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
index 1de15342595..8d46c8c1596 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fexceptions -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0.c b/gcc/testsuite/c-c++-common/strub-short-O0.c
index f9209c81900..c0a124de21e 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O0.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O0.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O1.c b/gcc/testsuite/c-c++-common/strub-short-O1.c
index bed1dcfb54a..52aa2525502 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O2.c b/gcc/testsuite/c-c++-common/strub-short-O2.c
index 6bf0071f52b..6735756dcdc 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O3.c b/gcc/testsuite/c-c++-common/strub-short-O3.c
index 4732f515bf7..efcc29b7049 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O3.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-Os.c b/gcc/testsuite/c-c++-common/strub-short-Os.c
index 8d6424c479a..c5dc7884ef4 100644
--- a/gcc/testsuite/c-c++-common/strub-short-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-short-Os.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-Os -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-strict1.c b/gcc/testsuite/c-c++-common/strub-strict1.c
index 36852244206..783f19a1571 100644
--- a/gcc/testsuite/c-c++-common/strub-strict1.c
+++ b/gcc/testsuite/c-c++-common/strub-strict1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-strict2.c b/gcc/testsuite/c-c++-common/strub-strict2.c
index b4f28883218..f7a51f0ce78 100644
--- a/gcc/testsuite/c-c++-common/strub-strict2.c
+++ b/gcc/testsuite/c-c++-common/strub-strict2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O1.c b/gcc/testsuite/c-c++-common/strub-tail-O1.c
index e48e0610e07..bb4c567384b 100644
--- a/gcc/testsuite/c-c++-common/strub-tail-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-tail-O1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O2.c b/gcc/testsuite/c-c++-common/strub-tail-O2.c
index 87cda7ab21b..6e23d7cc223 100644
--- a/gcc/testsuite/c-c++-common/strub-tail-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-tail-O2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-var1.c b/gcc/testsuite/c-c++-common/strub-var1.c
index eb6250fd39c..f321cf754a8 100644
--- a/gcc/testsuite/c-c++-common/strub-var1.c
+++ b/gcc/testsuite/c-c++-common/strub-var1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 
 int __attribute__ ((strub)) x;
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable1.c b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
index b5e45ab0525..bfcee855b4f 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-callable1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable2.c b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
index 96aa7fe4b07..066136df80e 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-callable2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const1.c b/gcc/testsuite/c-c++-common/torture/strub-const1.c
index 5e956cb1a9b..248d55a7f7a 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const2.c b/gcc/testsuite/c-c++-common/torture/strub-const2.c
index 73d650292df..57ef0efa777 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const3.c b/gcc/testsuite/c-c++-common/torture/strub-const3.c
index 2584f1f974a..cacfbe99cb4 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const3.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const4.c b/gcc/testsuite/c-c++-common/torture/strub-const4.c
index d819f54ec02..0ec152006d3 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const4.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data1.c b/gcc/testsuite/c-c++-common/torture/strub-data1.c
index 7c27a2a1a6d..e693e8cebc6 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data2.c b/gcc/testsuite/c-c++-common/torture/strub-data2.c
index e66d903780a..d42cbe67399 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data3.c b/gcc/testsuite/c-c++-common/torture/strub-data3.c
index 5e08e0e58c6..eb1c2c88c94 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data3.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data4.c b/gcc/testsuite/c-c++-common/torture/strub-data4.c
index a818e7a38bb..579906e5ba2 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data4.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data5.c b/gcc/testsuite/c-c++-common/torture/strub-data5.c
index ddb0b5c0543..6591253a23c 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data5.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data5.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
index c165f312f16..37a9385d1b0 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
index 69fcff8d376..67237561742 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
index ff006224909..16906e49eb8 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
index 614b02228ba..b242ceecdd0 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
index f9a6b4a16fa..479b72024f2 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
index b4a7f3992bb..002e70a25d9 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
index ef634d35126..e9201951cd4 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -Wpedantic" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
index e1f179e160e..d8efccb782b 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -Wpedantic -fpermissive" } */
 /* { dg-prune-output "command-line option .-fpermissive." } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
index 70b558afad0..0fa81d6aee0 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure1.c b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
index a262a086837..2cb46429417 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure2.c b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
index 4c4bd50c209..f79e77e5881 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure3.c b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
index ce195c6b1f1..ff8ff280572 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure4.c b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
index 75cd54ccb5b..d45ded73468 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run1.c b/gcc/testsuite/c-c++-common/torture/strub-run1.c
index 7458b3fb54d..15918ee50c6 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run2.c b/gcc/testsuite/c-c++-common/torture/strub-run2.c
index 5d60a7775f4..19595b1d7ea 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run3.c b/gcc/testsuite/c-c++-common/torture/strub-run3.c
index c2ad710858e..6f7d46f70c6 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run3.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 /* { dg-require-effective-target alloca } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4.c b/gcc/testsuite/c-c++-common/torture/strub-run4.c
index 3b36b8e5d68..4dab4cefde1 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=all" } */
 /* { dg-require-effective-target alloca } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4c.c b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
index 57f9baf758d..2bba2c31184 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4c.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=at-calls" } */
 /* { dg-require-effective-target alloca } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4d.c b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
index 08de3f1c3b1..978f5c5f7ba 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4d.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 /* { dg-require-effective-target alloca } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4i.c b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
index 459f6886c54..02e695563a4 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4i.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=internal" } */
 /* { dg-require-effective-target alloca } */
diff --git a/gcc/testsuite/g++.dg/strub-run1.C b/gcc/testsuite/g++.dg/strub-run1.C
index 0d367fb83d0..3e4ec3038e3 100644
--- a/gcc/testsuite/g++.dg/strub-run1.C
+++ b/gcc/testsuite/g++.dg/strub-run1.C
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 // { dg-do run }
 // { dg-options "-fstrub=internal" }
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init1.C b/gcc/testsuite/g++.dg/torture/strub-init1.C
index c226ab10ff6..e6eb7830f51 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init1.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init1.C
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init2.C b/gcc/testsuite/g++.dg/torture/strub-init2.C
index a7911f1fa72..df72880382b 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init2.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init2.C
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init3.C b/gcc/testsuite/g++.dg/torture/strub-init3.C
index 6ebebcd01e8..f47613ccda7 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init3.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init3.C
@@ -1,3 +1,4 @@
+/* { dg-skip-if { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/gnat.dg/strub_access.adb b/gcc/testsuite/gnat.dg/strub_access.adb
index 29e6996ecf6..c74710d3954 100644
--- a/gcc/testsuite/gnat.dg/strub_access.adb
+++ b/gcc/testsuite/gnat.dg/strub_access.adb
@@ -1,3 +1,4 @@
+--  { dg-skip-if { ! strub } }
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed -fdump-ipa-strubm" }
 
diff --git a/gcc/testsuite/gnat.dg/strub_access1.adb b/gcc/testsuite/gnat.dg/strub_access1.adb
index dae47060164..4c63577eca6 100644
--- a/gcc/testsuite/gnat.dg/strub_access1.adb
+++ b/gcc/testsuite/gnat.dg/strub_access1.adb
@@ -1,3 +1,4 @@
+--  { dg-skip-if { ! strub } }
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed" }
 
diff --git a/gcc/testsuite/gnat.dg/strub_attr.adb b/gcc/testsuite/gnat.dg/strub_attr.adb
index 10445d7cf84..d896aa45623 100644
--- a/gcc/testsuite/gnat.dg/strub_attr.adb
+++ b/gcc/testsuite/gnat.dg/strub_attr.adb
@@ -1,3 +1,4 @@
+--  { dg-skip-if { ! strub } }
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm -fdump-ipa-strub" }
 
diff --git a/gcc/testsuite/gnat.dg/strub_disp.adb b/gcc/testsuite/gnat.dg/strub_disp.adb
index 3dbcc4a357c..a142cc88371 100644
--- a/gcc/testsuite/gnat.dg/strub_disp.adb
+++ b/gcc/testsuite/gnat.dg/strub_disp.adb
@@ -1,3 +1,4 @@
+--  { dg-skip-if { ! strub } }
 --  { dg-do compile }
 
 procedure Strub_Disp is
diff --git a/gcc/testsuite/gnat.dg/strub_disp1.adb b/gcc/testsuite/gnat.dg/strub_disp1.adb
index 09756a74b7d..6cf53fee1f5 100644
--- a/gcc/testsuite/gnat.dg/strub_disp1.adb
+++ b/gcc/testsuite/gnat.dg/strub_disp1.adb
@@ -1,3 +1,4 @@
+--  { dg-skip-if { ! strub } }
 --  { dg-do compile }
 --  { dg-options "-fdump-ipa-strub" }
 
diff --git a/gcc/testsuite/gnat.dg/strub_ind.adb b/gcc/testsuite/gnat.dg/strub_ind.adb
index da56acaa957..538fc98ad04 100644
--- a/gcc/testsuite/gnat.dg/strub_ind.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind.adb
@@ -1,3 +1,4 @@
+--  { dg-skip-if { ! strub } }
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict" }
 
diff --git a/gcc/testsuite/gnat.dg/strub_ind1.adb b/gcc/testsuite/gnat.dg/strub_ind1.adb
index 825e395e681..8f0202aff54 100644
--- a/gcc/testsuite/gnat.dg/strub_ind1.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind1.adb
@@ -1,3 +1,4 @@
+--  { dg-skip-if { ! strub } }
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm" }
 
diff --git a/gcc/testsuite/gnat.dg/strub_ind2.adb b/gcc/testsuite/gnat.dg/strub_ind2.adb
index e918b392631..8bfebb30aa4 100644
--- a/gcc/testsuite/gnat.dg/strub_ind2.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind2.adb
@@ -1,3 +1,4 @@
+--  { dg-skip-if { ! strub } }
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict" }
 
diff --git a/gcc/testsuite/gnat.dg/strub_intf.adb b/gcc/testsuite/gnat.dg/strub_intf.adb
index 8f0212a7586..fd41def99fd 100644
--- a/gcc/testsuite/gnat.dg/strub_intf.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf.adb
@@ -1,3 +1,4 @@
+--  { dg-skip-if { ! strub } }
 --  { dg-do compile }
 
 --  Check that strub mode mismatches between overrider and overridden
diff --git a/gcc/testsuite/gnat.dg/strub_intf1.adb b/gcc/testsuite/gnat.dg/strub_intf1.adb
index bf77321cef7..2b5a1341769 100644
--- a/gcc/testsuite/gnat.dg/strub_intf1.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf1.adb
@@ -1,3 +1,4 @@
+--  { dg-skip-if { ! strub } }
 --  { dg-do compile }
 --  { dg-options "-fdump-ipa-strub" }
 
diff --git a/gcc/testsuite/gnat.dg/strub_intf2.adb b/gcc/testsuite/gnat.dg/strub_intf2.adb
index e8880dbc437..256ae44dcdc 100644
--- a/gcc/testsuite/gnat.dg/strub_intf2.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf2.adb
@@ -1,3 +1,4 @@
+--  { dg-skip-if { ! strub } }
 --  { dg-do compile }
 
 --  Check that strub mode mismatches between overrider and overridden
diff --git a/gcc/testsuite/gnat.dg/strub_renm.adb b/gcc/testsuite/gnat.dg/strub_renm.adb
index 217367e712d..9fadac72bb2 100644
--- a/gcc/testsuite/gnat.dg/strub_renm.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm.adb
@@ -1,3 +1,4 @@
+--  { dg-skip-if { ! strub } }
 --  { dg-do compile }
 
 procedure Strub_Renm is
diff --git a/gcc/testsuite/gnat.dg/strub_renm1.adb b/gcc/testsuite/gnat.dg/strub_renm1.adb
index a11adbfb5a9..f5d3415ee9d 100644
--- a/gcc/testsuite/gnat.dg/strub_renm1.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm1.adb
@@ -1,3 +1,4 @@
+--  { dg-skip-if { ! strub } }
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed -fdump-ipa-strub" }
 
diff --git a/gcc/testsuite/gnat.dg/strub_renm2.adb b/gcc/testsuite/gnat.dg/strub_renm2.adb
index c488c20826f..957ab052752 100644
--- a/gcc/testsuite/gnat.dg/strub_renm2.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm2.adb
@@ -1,3 +1,4 @@
+--  { dg-skip-if { ! strub } }
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strub" }
 
diff --git a/gcc/testsuite/gnat.dg/strub_var.adb b/gcc/testsuite/gnat.dg/strub_var.adb
index 3d158de2803..88d1ff6905a 100644
--- a/gcc/testsuite/gnat.dg/strub_var.adb
+++ b/gcc/testsuite/gnat.dg/strub_var.adb
@@ -1,3 +1,4 @@
+--  { dg-skip-if { ! strub } }
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm" }
 
diff --git a/gcc/testsuite/gnat.dg/strub_var1.adb b/gcc/testsuite/gnat.dg/strub_var1.adb
index 6a504e09198..98d7ac8042b 100644
--- a/gcc/testsuite/gnat.dg/strub_var1.adb
+++ b/gcc/testsuite/gnat.dg/strub_var1.adb
@@ -1,3 +1,4 @@
+--  { dg-skip-if { ! strub } }
 --  { dg-do compile }
 
 with Strub_Attr;
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 3fcce6be49d..daf1d259aae 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -1302,6 +1302,13 @@ proc check_stack_check_available { stack_kind } {
     } "$stack_opt"]
 }
 
+# Return 1 if the target supports stack scrubbing.
+proc check_effective_target_strub {} {
+    return [check_no_compiler_messages strub assembly {
+	int __attribute__ ((__strub__)) fn () {}
+    } ""]
+}
+
 # Return 1 if compilation with -freorder-blocks-and-partition is error-free
 # for trivial code, 0 otherwise.  As some targets (ARM for example) only
 # warn when -fprofile-use is also supplied we test that combination too.
diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in
index d8163c5af99..3f77283490e 100644
--- a/libgcc/Makefile.in
+++ b/libgcc/Makefile.in
@@ -434,7 +434,7 @@ LIB2ADD += enable-execute-stack.c
 LIB2ADD += $(srcdir)/hardcfr.c
 
 # Stack scrubbing infrastructure.
-LIB2ADD += $(srcdir)/strub.c
+@HAVE_STRUB_SUPPORT@LIB2ADD += $(srcdir)/strub.c
 
 # While emutls.c has nothing to do with EH, it is in LIB2ADDEH*
 # instead of LIB2ADD because that's the way to be sure on some targets
diff --git a/libgcc/configure b/libgcc/configure
index cf149209652..f77d39df625 100755
--- a/libgcc/configure
+++ b/libgcc/configure
@@ -593,6 +593,7 @@ asm_hidden_op
 extra_parts
 cpu_type
 get_gcc_base_ver
+HAVE_STRUB_SUPPORT
 thread_header
 tm_defines
 tm_file
@@ -5702,6 +5703,31 @@ esac
 
 
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for strub support" >&5
+$as_echo_n "checking for strub support... " >&6; }
+if ${libgcc_cv_strub_support+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int __attribute__ ((__strub__)) fn () {}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  libgcc_cv_strub_support=yes
+else
+  libgcc_cv_strub_support=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgcc_cv_strub_support" >&5
+$as_echo "$libgcc_cv_strub_support" >&6; }
+if test "x$libgcc_cv_strub_support" != xno; then
+  HAVE_STRUB_SUPPORT=
+else
+  HAVE_STRUB_SUPPORT='# '
+fi
+
+
 # Determine what GCC version number to use in filesystem paths.
 
   get_gcc_base_ver="cat"
diff --git a/libgcc/configure.ac b/libgcc/configure.ac
index 2fc9d5d7c93..a8def244998 100644
--- a/libgcc/configure.ac
+++ b/libgcc/configure.ac
@@ -694,6 +694,19 @@ AC_SUBST(tm_defines)
 # Map from thread model to thread header.
 GCC_AC_THREAD_HEADER([$target_thread_file])
 
+AC_CACHE_CHECK([for strub support],
+  [libgcc_cv_strub_support],
+  [AC_COMPILE_IFELSE(
+    [AC_LANG_SOURCE([int __attribute__ ((__strub__)) fn () {}])],
+    [libgcc_cv_strub_support=yes],
+    [libgcc_cv_strub_support=no])])
+if test "x$libgcc_cv_strub_support" != xno; then
+  HAVE_STRUB_SUPPORT=
+else
+  HAVE_STRUB_SUPPORT='# '
+fi
+AC_SUBST(HAVE_STRUB_SUPPORT)
+
 # Determine what GCC version number to use in filesystem paths.
 GCC_BASE_VER

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [gcc(refs/users/aoliva/heads/testme)] strub: enable conditional support
@ 2023-12-07  1:48 Alexandre Oliva
  0 siblings, 0 replies; 25+ messages in thread
From: Alexandre Oliva @ 2023-12-07  1:48 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:015082195d5223ce14421ba747ebbc4028b0fc84

commit 015082195d5223ce14421ba747ebbc4028b0fc84
Author: Alexandre Oliva <oliva@adacore.com>
Date:   Wed Dec 6 19:36:02 2023 -0300

    strub: enable conditional support
    
    Targets that don't expose callee stacks to callers, such as nvptx, as
    well as -fsplit-stack compilations, violate fundamental assumptions of
    the current strub implementation.  This patch enables targets to
    disable strub, and disables it when -fsplit-stack is enabled.
    
    When strub support is disabled, the testsuite will now skip strub
    tests, and libgcc will not build the strub runtime components.
    
    
    for  gcc/ChangeLog
    
            * target.def (have_strub_support_for): New hook.
            * doc/tm.texi.in: Document it.
            * doc/tm.texi: Rebuild.
            * ipa-strub.cc: Include target.h.
            (strub_target_support_p): New.
            (can_strub_p): Call it.  Test for no flag_split_stack.
            (pass_ipa_strub::adjust_at_calls_call): Check for target
            support.
            * config/nvptx/nvptx.cc (TARGET_HAVE_STRUB_SUPPORT_FOR):
            Disable.
            * doc/sourcebuild.texi (strub): Document new effective
            target.
    
    for  gcc/testsuite/ChangeLog
    
            * gcc.dg/strub-split-stack.c: New.
            * gcc.dg/strub-unsupported.c: New.
            * gcc.dg/strub-unsupported-2.c: New.
            * gcc.dg/strub-unsupported-3.c: New.
            * lib/target-supports.exp (check_effective_target_strub): New.
            * c-c++-common/strub-O0.c: Require effective target strub.
            * c-c++-common/strub-O1.c: Likewise.
            * c-c++-common/strub-O2.c: Likewise.
            * c-c++-common/strub-O2fni.c: Likewise.
            * c-c++-common/strub-O3.c: Likewise.
            * c-c++-common/strub-O3fni.c: Likewise.
            * c-c++-common/strub-Og.c: Likewise.
            * c-c++-common/strub-Os.c: Likewise.
            * c-c++-common/strub-all1.c: Likewise.
            * c-c++-common/strub-all2.c: Likewise.
            * c-c++-common/strub-apply1.c: Likewise.
            * c-c++-common/strub-apply2.c: Likewise.
            * c-c++-common/strub-apply3.c: Likewise.
            * c-c++-common/strub-apply4.c: Likewise.
            * c-c++-common/strub-at-calls1.c: Likewise.
            * c-c++-common/strub-at-calls2.c: Likewise.
            * c-c++-common/strub-defer-O1.c: Likewise.
            * c-c++-common/strub-defer-O2.c: Likewise.
            * c-c++-common/strub-defer-O3.c: Likewise.
            * c-c++-common/strub-defer-Os.c: Likewise.
            * c-c++-common/strub-internal1.c: Likewise.
            * c-c++-common/strub-internal2.c: Likewise.
            * c-c++-common/strub-parms1.c: Likewise.
            * c-c++-common/strub-parms2.c: Likewise.
            * c-c++-common/strub-parms3.c: Likewise.
            * c-c++-common/strub-relaxed1.c: Likewise.
            * c-c++-common/strub-relaxed2.c: Likewise.
            * c-c++-common/strub-short-O0-exc.c: Likewise.
            * c-c++-common/strub-short-O0.c: Likewise.
            * c-c++-common/strub-short-O1.c: Likewise.
            * c-c++-common/strub-short-O2.c: Likewise.
            * c-c++-common/strub-short-O3.c: Likewise.
            * c-c++-common/strub-short-Os.c: Likewise.
            * c-c++-common/strub-strict1.c: Likewise.
            * c-c++-common/strub-strict2.c: Likewise.
            * c-c++-common/strub-tail-O1.c: Likewise.
            * c-c++-common/strub-tail-O2.c: Likewise.
            * c-c++-common/strub-var1.c: Likewise.
            * c-c++-common/torture/strub-callable1.c: Likewise.
            * c-c++-common/torture/strub-callable2.c: Likewise.
            * c-c++-common/torture/strub-const1.c: Likewise.
            * c-c++-common/torture/strub-const2.c: Likewise.
            * c-c++-common/torture/strub-const3.c: Likewise.
            * c-c++-common/torture/strub-const4.c: Likewise.
            * c-c++-common/torture/strub-data1.c: Likewise.
            * c-c++-common/torture/strub-data2.c: Likewise.
            * c-c++-common/torture/strub-data3.c: Likewise.
            * c-c++-common/torture/strub-data4.c: Likewise.
            * c-c++-common/torture/strub-data5.c: Likewise.
            * c-c++-common/torture/strub-indcall1.c: Likewise.
            * c-c++-common/torture/strub-indcall2.c: Likewise.
            * c-c++-common/torture/strub-indcall3.c: Likewise.
            * c-c++-common/torture/strub-inlinable1.c: Likewise.
            * c-c++-common/torture/strub-inlinable2.c: Likewise.
            * c-c++-common/torture/strub-ptrfn1.c: Likewise.
            * c-c++-common/torture/strub-ptrfn2.c: Likewise.
            * c-c++-common/torture/strub-ptrfn3.c: Likewise.
            * c-c++-common/torture/strub-ptrfn4.c: Likewise.
            * c-c++-common/torture/strub-pure1.c: Likewise.
            * c-c++-common/torture/strub-pure2.c: Likewise.
            * c-c++-common/torture/strub-pure3.c: Likewise.
            * c-c++-common/torture/strub-pure4.c: Likewise.
            * c-c++-common/torture/strub-run1.c: Likewise.
            * c-c++-common/torture/strub-run2.c: Likewise.
            * c-c++-common/torture/strub-run3.c: Likewise.
            * c-c++-common/torture/strub-run4.c: Likewise.
            * c-c++-common/torture/strub-run4c.c: Likewise.
            * c-c++-common/torture/strub-run4d.c: Likewise.
            * c-c++-common/torture/strub-run4i.c: Likewise.
            * g++.dg/strub-run1.C: Likewise.
            * g++.dg/torture/strub-init1.C: Likewise.
            * g++.dg/torture/strub-init2.C: Likewise.
            * g++.dg/torture/strub-init3.C: Likewise.
            * gnat.dg/strub_attr.adb: Likewise.
            * gnat.dg/strub_ind.adb: Likewise.
            * gnat.dg/strub_access.adb: Likewise.
            * gnat.dg/strub_access1.adb: Likewise.
            * gnat.dg/strub_disp.adb: Likewise.
            * gnat.dg/strub_disp1.adb: Likewise.
            * gnat.dg/strub_ind1.adb: Likewise.
            * gnat.dg/strub_ind2.adb: Likewise.
            * gnat.dg/strub_intf.adb: Likewise.
            * gnat.dg/strub_intf1.adb: Likewise.
            * gnat.dg/strub_intf2.adb: Likewise.
            * gnat.dg/strub_renm.adb: Likewise.
            * gnat.dg/strub_renm1.adb: Likewise.
            * gnat.dg/strub_renm2.adb: Likewise.
            * gnat.dg/strub_var.adb: Likewise.
            * gnat.dg/strub_var1.adb: Likewise.
    
    for  libgcc/ChangeLog
    
            * configure.ac: Check for strub support.
            * configure: Rebuilt.
            * Makefile.in: Compile strub.c conditionally.

Diff:
---
 gcc/config/nvptx/nvptx.cc                          |  3 ++
 gcc/doc/sourcebuild.texi                           |  3 ++
 gcc/doc/tm.texi                                    |  6 +++
 gcc/doc/tm.texi.in                                 |  2 +
 gcc/ipa-strub.cc                                   | 54 +++++++++++++++++++++-
 gcc/target.def                                     |  8 ++++
 gcc/testsuite/c-c++-common/strub-O0.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O1.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O2.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O2fni.c           |  1 +
 gcc/testsuite/c-c++-common/strub-O3.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O3fni.c           |  1 +
 gcc/testsuite/c-c++-common/strub-Og.c              |  1 +
 gcc/testsuite/c-c++-common/strub-Os.c              |  1 +
 gcc/testsuite/c-c++-common/strub-all1.c            |  1 +
 gcc/testsuite/c-c++-common/strub-all2.c            |  1 +
 gcc/testsuite/c-c++-common/strub-apply1.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply2.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply3.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply4.c          |  1 +
 gcc/testsuite/c-c++-common/strub-at-calls1.c       |  1 +
 gcc/testsuite/c-c++-common/strub-at-calls2.c       |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O3.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-Os.c        |  1 +
 gcc/testsuite/c-c++-common/strub-internal1.c       |  1 +
 gcc/testsuite/c-c++-common/strub-internal2.c       |  1 +
 gcc/testsuite/c-c++-common/strub-parms1.c          |  1 +
 gcc/testsuite/c-c++-common/strub-parms2.c          |  1 +
 gcc/testsuite/c-c++-common/strub-parms3.c          |  1 +
 gcc/testsuite/c-c++-common/strub-relaxed1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-relaxed2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O0-exc.c    |  1 +
 gcc/testsuite/c-c++-common/strub-short-O0.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O3.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-Os.c        |  1 +
 gcc/testsuite/c-c++-common/strub-split-stack.c     | 10 ++++
 gcc/testsuite/c-c++-common/strub-strict1.c         |  1 +
 gcc/testsuite/c-c++-common/strub-strict2.c         |  1 +
 gcc/testsuite/c-c++-common/strub-tail-O1.c         |  1 +
 gcc/testsuite/c-c++-common/strub-tail-O2.c         |  1 +
 gcc/testsuite/c-c++-common/strub-unsupported-2.c   | 13 ++++++
 gcc/testsuite/c-c++-common/strub-unsupported-3.c   | 18 ++++++++
 gcc/testsuite/c-c++-common/strub-unsupported.c     | 21 +++++++++
 gcc/testsuite/c-c++-common/strub-var1.c            |  1 +
 .../c-c++-common/torture/strub-callable1.c         |  1 +
 .../c-c++-common/torture/strub-callable2.c         |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const1.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const2.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const3.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const4.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data1.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data2.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data3.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data4.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data5.c   |  1 +
 .../c-c++-common/torture/strub-indcall1.c          |  1 +
 .../c-c++-common/torture/strub-indcall2.c          |  1 +
 .../c-c++-common/torture/strub-indcall3.c          |  1 +
 .../c-c++-common/torture/strub-inlinable1.c        |  1 +
 .../c-c++-common/torture/strub-inlinable2.c        |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure1.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure2.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure3.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure4.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run1.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run2.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run3.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4c.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4d.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4i.c   |  1 +
 gcc/testsuite/g++.dg/strub-run1.C                  |  1 +
 gcc/testsuite/g++.dg/torture/strub-init1.C         |  1 +
 gcc/testsuite/g++.dg/torture/strub-init2.C         |  1 +
 gcc/testsuite/g++.dg/torture/strub-init3.C         |  1 +
 gcc/testsuite/gnat.dg/strub_access.adb             |  1 +
 gcc/testsuite/gnat.dg/strub_access1.adb            |  1 +
 gcc/testsuite/gnat.dg/strub_attr.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_disp.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_disp1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_ind.adb                |  1 +
 gcc/testsuite/gnat.dg/strub_ind1.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_ind2.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_intf.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_intf1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_intf2.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_renm.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_renm1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_renm2.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_var.adb                |  1 +
 gcc/testsuite/gnat.dg/strub_var1.adb               |  1 +
 gcc/testsuite/lib/target-supports.exp              |  7 +++
 libgcc/Makefile.in                                 |  2 +-
 libgcc/configure                                   | 26 +++++++++++
 libgcc/configure.ac                                | 13 ++++++
 103 files changed, 272 insertions(+), 3 deletions(-)

diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc
index ae20802c879..3fb1deb70fd 100644
--- a/gcc/config/nvptx/nvptx.cc
+++ b/gcc/config/nvptx/nvptx.cc
@@ -7789,6 +7789,9 @@ nvptx_asm_output_def_from_decls (FILE *stream, tree name, tree value)
 #undef TARGET_LIBC_HAS_FUNCTION
 #define TARGET_LIBC_HAS_FUNCTION nvptx_libc_has_function
 
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-nvptx.h"
diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi
index c9909026854..26a7e9c3507 100644
--- a/gcc/doc/sourcebuild.texi
+++ b/gcc/doc/sourcebuild.texi
@@ -2983,6 +2983,9 @@ Target supports statically linking @samp{libgfortran}.
 @item string_merging
 Target supports merging string constants at link time.
 
+@item strub
+Target supports attribute @code{strub} for stack scrubbing.
+
 @item ucn
 Target supports compiling and assembling UCN.
 
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 89a1735dd79..768ada0af52 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -3450,6 +3450,12 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@deftypefn {Target Hook} bool TARGET_HAVE_STRUB_SUPPORT_FOR (tree)
+Returns true if the target supports stack scrubbing for the given function
+or type, otherwise return false.  The default implementation always returns
+true.
+@end deftypefn
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index ebc1d3de5ca..4fe0805394e 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2686,6 +2686,8 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@hook TARGET_HAVE_STRUB_SUPPORT_FOR
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
index 293bec132b8..2afb7a45575 100644
--- a/gcc/ipa-strub.cc
+++ b/gcc/ipa-strub.cc
@@ -60,6 +60,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-strub.h"
 #include "symtab-thunks.h"
 #include "attr-fnspec.h"
+#include "target.h"
 
 /* This file introduces two passes that, together, implement
    machine-independent stack scrubbing, strub for short.  It arranges
@@ -631,17 +632,60 @@ strub_always_inline_p (cgraph_node *node)
   return lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl));
 }
 
+/* Return TRUE iff the target has strub support for T, a function
+   decl, or a type used in an indirect call, and optionally REPORT the
+   reasons for ineligibility.  If T is a type and error REPORTing is
+   enabled, the LOCation (of the indirect call) should be provided.  */
+static inline bool
+strub_target_support_p (tree t, bool report = false,
+			location_t loc = UNKNOWN_LOCATION)
+{
+  bool result = true;
+
+  if (!targetm.have_strub_support_for (t))
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      if (DECL_P (t))
+	sorry_at (DECL_SOURCE_LOCATION (t),
+		  "%qD is not eligible for %<strub%>"
+		  " on the target system", t);
+      else
+	sorry_at (loc,
+		  "unsupported %<strub%> call"
+		  " on the target system");
+    }
+
+  return result;
+}
+
 /* Return TRUE iff NODE is potentially eligible for any strub-enabled mode, and
    optionally REPORT the reasons for ineligibility.  */
 
 static inline bool
 can_strub_p (cgraph_node *node, bool report = false)
 {
-  bool result = true;
+  bool result = strub_target_support_p (node->decl, report);
 
-  if (!report && strub_always_inline_p (node))
+  if (!report && (!result || strub_always_inline_p (node)))
     return result;
 
+  if (flag_split_stack)
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (node->decl),
+		"%qD is not eligible for %<strub%>"
+		" because %<-fsplit-stack%> is enabled",
+		node->decl);
+    }
+
   if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
     {
       result = false;
@@ -2417,6 +2461,12 @@ pass_ipa_strub::adjust_at_calls_call (cgraph_edge *e, int named_args,
 			 && (TREE_TYPE (gimple_call_arg (ocall, named_args))
 			     == get_pwmt ())));
 
+  tree tsup;
+  if (!(tsup = gimple_call_fndecl (ocall)))
+    tsup = TREE_TYPE (TREE_TYPE (gimple_call_fn (ocall)));
+  if (!strub_target_support_p (tsup, true, gimple_location (ocall)))
+    return;
+
   /* If we're already within a strub context, pass on the incoming watermark
      pointer, and omit the enter and leave calls around the modified call, as an
      optimization, or as a means to satisfy a tail-call requirement.  */
diff --git a/gcc/target.def b/gcc/target.def
index 52b83e091b9..08218f3a42a 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4457,6 +4457,14 @@ otherwise return false.  The default implementation always returns true.",
  bool, (void),
  hook_bool_void_true)
 
+DEFHOOK
+(have_strub_support_for,
+ "Returns true if the target supports stack scrubbing for the given function\n\
+or type, otherwise return false.  The default implementation always returns\n\
+true.",
+ bool, (tree),
+ hook_bool_tree_true)
+
 DEFHOOK
 (have_speculation_safe_value,
 "This hook is used to determine the level of target support for\n\
diff --git a/gcc/testsuite/c-c++-common/strub-O0.c b/gcc/testsuite/c-c++-common/strub-O0.c
index c7a79a6ea0d..f0a3f7b4c6f 100644
--- a/gcc/testsuite/c-c++-common/strub-O0.c
+++ b/gcc/testsuite/c-c++-common/strub-O0.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -O0, none of the strub builtins are expanded inline.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O1.c b/gcc/testsuite/c-c++-common/strub-O1.c
index 96285c975d9..50403426b18 100644
--- a/gcc/testsuite/c-c++-common/strub-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -O1, without -fno-inline, we fully expand enter, but neither update nor
    leave.  */
diff --git a/gcc/testsuite/c-c++-common/strub-O2.c b/gcc/testsuite/c-c++-common/strub-O2.c
index 8edc0d8aa13..37e02998e31 100644
--- a/gcc/testsuite/c-c++-common/strub-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -O2, without -fno-inline, we fully expand enter and update, and add a test
    around the leave call.  */
diff --git a/gcc/testsuite/c-c++-common/strub-O2fni.c b/gcc/testsuite/c-c++-common/strub-O2fni.c
index c6d900cf3c4..905e2c6b2ff 100644
--- a/gcc/testsuite/c-c++-common/strub-O2fni.c
+++ b/gcc/testsuite/c-c++-common/strub-O2fni.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
+/* { dg-require-effective-target strub } */
 
 /* With -fno-inline, none of the strub builtins are inlined.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O3.c b/gcc/testsuite/c-c++-common/strub-O3.c
index 33ee465e51c..3bbf132bdf1 100644
--- a/gcc/testsuite/c-c++-common/strub-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-O3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 int __attribute__ ((__strub__)) var;
 
diff --git a/gcc/testsuite/c-c++-common/strub-O3fni.c b/gcc/testsuite/c-c++-common/strub-O3fni.c
index 2936f82079e..c46fce38e5c 100644
--- a/gcc/testsuite/c-c++-common/strub-O3fni.c
+++ b/gcc/testsuite/c-c++-common/strub-O3fni.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
+/* { dg-require-effective-target strub } */
 
 /* With -fno-inline, none of the strub builtins are inlined.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-Og.c b/gcc/testsuite/c-c++-common/strub-Og.c
index 479746e57d8..3b8eb19765c 100644
--- a/gcc/testsuite/c-c++-common/strub-Og.c
+++ b/gcc/testsuite/c-c++-common/strub-Og.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-Og -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -Og, without -fno-inline, we fully expand enter, but neither update nor
    leave.  */
diff --git a/gcc/testsuite/c-c++-common/strub-Os.c b/gcc/testsuite/c-c++-common/strub-Os.c
index 2241d4ea07f..8cfb253d676 100644
--- a/gcc/testsuite/c-c++-common/strub-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-Os.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-Os -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -Os, without -fno-inline, we fully expand enter, and also update.  The
    expanded update might be larger than a call proper, but argument saving and
diff --git a/gcc/testsuite/c-c++-common/strub-all1.c b/gcc/testsuite/c-c++-common/strub-all1.c
index a322bcc5da6..2037f681f29 100644
--- a/gcc/testsuite/c-c++-common/strub-all1.c
+++ b/gcc/testsuite/c-c++-common/strub-all1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
    strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub.  */
diff --git a/gcc/testsuite/c-c++-common/strub-all2.c b/gcc/testsuite/c-c++-common/strub-all2.c
index db60026d0e0..c026e7d9d28 100644
--- a/gcc/testsuite/c-c++-common/strub-all2.c
+++ b/gcc/testsuite/c-c++-common/strub-all2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* g becomes STRUB_INTERNAL, because of the flag.  Without inline, force_output
    is set for static non-inline functions when not optimizing, and that keeps
diff --git a/gcc/testsuite/c-c++-common/strub-apply1.c b/gcc/testsuite/c-c++-common/strub-apply1.c
index 2f462adc1ef..3edc89c54ee 100644
--- a/gcc/testsuite/c-c++-common/strub-apply1.c
+++ b/gcc/testsuite/c-c++-common/strub-apply1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 void __attribute__ ((__strub__ ("callable")))
 apply_function (void *args)
diff --git a/gcc/testsuite/c-c++-common/strub-apply2.c b/gcc/testsuite/c-c++-common/strub-apply2.c
index a5d7551f5da..838fc752734 100644
--- a/gcc/testsuite/c-c++-common/strub-apply2.c
+++ b/gcc/testsuite/c-c++-common/strub-apply2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 extern void __attribute__ ((__strub__))
 apply_function (void *args);
diff --git a/gcc/testsuite/c-c++-common/strub-apply3.c b/gcc/testsuite/c-c++-common/strub-apply3.c
index 64422a0d1e8..0206e4d930e 100644
--- a/gcc/testsuite/c-c++-common/strub-apply3.c
+++ b/gcc/testsuite/c-c++-common/strub-apply3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 void __attribute__ ((__strub__))
 apply_function (void *args)
diff --git a/gcc/testsuite/c-c++-common/strub-apply4.c b/gcc/testsuite/c-c++-common/strub-apply4.c
index 15ffaa031b8..e82504728b2 100644
--- a/gcc/testsuite/c-c++-common/strub-apply4.c
+++ b/gcc/testsuite/c-c++-common/strub-apply4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that implicit enabling of strub mode selects internal strub when the
    function uses __builtin_apply_args, that prevents the optimization to
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls1.c b/gcc/testsuite/c-c++-common/strub-at-calls1.c
index b70843b4215..a20acc0a48a 100644
--- a/gcc/testsuite/c-c++-common/strub-at-calls1.c
+++ b/gcc/testsuite/c-c++-common/strub-at-calls1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
    strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub.  */
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls2.c b/gcc/testsuite/c-c++-common/strub-at-calls2.c
index 97a3988a6b9..7915b33a39a 100644
--- a/gcc/testsuite/c-c++-common/strub-at-calls2.c
+++ b/gcc/testsuite/c-c++-common/strub-at-calls2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* g does NOT become STRUB_AT_CALLS because it's not viable.  Without inline,
    force_output is set for static non-inline functions when not optimizing, and
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O1.c b/gcc/testsuite/c-c++-common/strub-defer-O1.c
index 3d73431b3dc..3689998b5a3 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O1" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function does NOT defer
    the strubbing to its caller at -O1.  */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O2.c b/gcc/testsuite/c-c++-common/strub-defer-O2.c
index fddf3c745e7..9e01949db6b 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O2" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function does NOT defer
    the strubbing to its caller at -O2.  */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O3.c b/gcc/testsuite/c-c++-common/strub-defer-O3.c
index 7ebc65b58dd..40ee8edd1e0 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O3.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O3" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function defers the
    strubbing to its caller at -O3.  */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-Os.c b/gcc/testsuite/c-c++-common/strub-defer-Os.c
index fbaf85fe0fa..67ea9f04639 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-Os.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -Os" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function defers the
    strubbing to its caller at -Os.  */
diff --git a/gcc/testsuite/c-c++-common/strub-internal1.c b/gcc/testsuite/c-c++-common/strub-internal1.c
index e9d7b7b9ee0..d17254904e5 100644
--- a/gcc/testsuite/c-c++-common/strub-internal1.c
+++ b/gcc/testsuite/c-c++-common/strub-internal1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
    strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub.  */
diff --git a/gcc/testsuite/c-c++-common/strub-internal2.c b/gcc/testsuite/c-c++-common/strub-internal2.c
index 8b8e15a51c7..afc9189701f 100644
--- a/gcc/testsuite/c-c++-common/strub-internal2.c
+++ b/gcc/testsuite/c-c++-common/strub-internal2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* g becomes STRUB_INTERNAL, because of the flag.  */
 static void
diff --git a/gcc/testsuite/c-c++-common/strub-parms1.c b/gcc/testsuite/c-c++-common/strub-parms1.c
index 0a4a7539d34..f410b268971 100644
--- a/gcc/testsuite/c-c++-common/strub-parms1.c
+++ b/gcc/testsuite/c-c++-common/strub-parms1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 #include <stdarg.h>
 
diff --git a/gcc/testsuite/c-c++-common/strub-parms2.c b/gcc/testsuite/c-c++-common/strub-parms2.c
index 147171d96d5..6f572115a88 100644
--- a/gcc/testsuite/c-c++-common/strub-parms2.c
+++ b/gcc/testsuite/c-c++-common/strub-parms2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 #include <stdarg.h>
 
diff --git a/gcc/testsuite/c-c++-common/strub-parms3.c b/gcc/testsuite/c-c++-common/strub-parms3.c
index 4e92682895a..7383fea9ce8 100644
--- a/gcc/testsuite/c-c++-common/strub-parms3.c
+++ b/gcc/testsuite/c-c++-common/strub-parms3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that uses of a strub variable implicitly enables internal strub for
    publicly-visible functions, and causes the same transformations to their
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed1.c b/gcc/testsuite/c-c++-common/strub-relaxed1.c
index e2f9d8aebca..d2b4b52c51e 100644
--- a/gcc/testsuite/c-c++-common/strub-relaxed1.c
+++ b/gcc/testsuite/c-c++-common/strub-relaxed1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The difference between relaxed and strict in this case is that we accept the
    call from one internal-strub function to another.  Without the error,
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed2.c b/gcc/testsuite/c-c++-common/strub-relaxed2.c
index 98474435d2e..9e5a8e76b6c 100644
--- a/gcc/testsuite/c-c++-common/strub-relaxed2.c
+++ b/gcc/testsuite/c-c++-common/strub-relaxed2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The difference between relaxed and strict in this case is that we accept the
    call from one internal-strub function to another.  */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
index 1de15342595..aaeba2a2159 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fexceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0.c b/gcc/testsuite/c-c++-common/strub-short-O0.c
index f9209c81900..30cbdd819f1 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O0.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O0.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O1.c b/gcc/testsuite/c-c++-common/strub-short-O1.c
index bed1dcfb54a..911fdfb6db9 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O2.c b/gcc/testsuite/c-c++-common/strub-short-O2.c
index 6bf0071f52b..9b23ee3ac33 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O3.c b/gcc/testsuite/c-c++-common/strub-short-O3.c
index 4732f515bf7..4b3a8f843ea 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  At -O3 and -Os, we omit
    enter and leave calls within strub contexts, passing on the enclosing
diff --git a/gcc/testsuite/c-c++-common/strub-short-Os.c b/gcc/testsuite/c-c++-common/strub-short-Os.c
index 8d6424c479a..3627a240600 100644
--- a/gcc/testsuite/c-c++-common/strub-short-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-short-Os.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-Os -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  At -O3 and -Os, we omit
    enter and leave calls within strub contexts, passing on the enclosing
diff --git a/gcc/testsuite/c-c++-common/strub-split-stack.c b/gcc/testsuite/c-c++-common/strub-split-stack.c
new file mode 100644
index 00000000000..7a030cdb9e9
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-split-stack.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-fsplit-stack" } */
+/* { dg-require-effective-target strub } */
+/* { dg-require-effective-target split_stack } */
+
+void __attribute__ ((__strub__))
+f () {} /* { dg-message "not eligible|requested" } */
+
+void __attribute__ ((__strub__ ("internal")))
+g () {} /* { dg-message "not eligible|requested" } */
diff --git a/gcc/testsuite/c-c++-common/strub-strict1.c b/gcc/testsuite/c-c++-common/strub-strict1.c
index 36852244206..503eb1734e3 100644
--- a/gcc/testsuite/c-c++-common/strub-strict1.c
+++ b/gcc/testsuite/c-c++-common/strub-strict1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
 
 static int __attribute__ ((__strub__)) var;
 
diff --git a/gcc/testsuite/c-c++-common/strub-strict2.c b/gcc/testsuite/c-c++-common/strub-strict2.c
index b4f28883218..3bf1aa30b4a 100644
--- a/gcc/testsuite/c-c++-common/strub-strict2.c
+++ b/gcc/testsuite/c-c++-common/strub-strict2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
 
 static int __attribute__ ((__strub__)) var;
 
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O1.c b/gcc/testsuite/c-c++-common/strub-tail-O1.c
index e48e0610e07..ba4b1623e28 100644
--- a/gcc/testsuite/c-c++-common/strub-tail-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-tail-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-tail-O2.c"
 
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O2.c b/gcc/testsuite/c-c++-common/strub-tail-O2.c
index 87cda7ab21b..043813b1de4 100644
--- a/gcc/testsuite/c-c++-common/strub-tail-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-tail-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.
    Tail calls are short-circuited at -O2+.  */
diff --git a/gcc/testsuite/c-c++-common/strub-unsupported-2.c b/gcc/testsuite/c-c++-common/strub-unsupported-2.c
new file mode 100644
index 00000000000..3586f4f679d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-unsupported-2.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+
+/* Check that, when strub is not supported (so no dg-required-effective-target
+   strub above), we report when pointers to strub functions are called.  This
+   cannot be part of strub-unsupported.c because errors in the strub-mode pass
+   prevent the main strub pass, where errors at calls are detected, from
+   running.  */
+
+void __attribute__ ((__strub__ ("at-calls"))) (*p) (void);
+
+void m () {
+  p (); /* { dg-message "unsupported" "" { target { ! strub } } } */
+}
diff --git a/gcc/testsuite/c-c++-common/strub-unsupported-3.c b/gcc/testsuite/c-c++-common/strub-unsupported-3.c
new file mode 100644
index 00000000000..d6fb4c525c4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-unsupported-3.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+
+/* Check that, when strub is not supported (so no dg-required-effective-target
+   strub above), we report when strub functions that are not defined are
+   called.  This cannot be part of strub-unsupported-2.c because errors in the
+   strub-mode pass prevent the main strub pass, where errors at calls are
+   detected, from running.  */
+
+extern void __attribute__ ((__strub__))
+s (void); /* { dg-message "not eligible|requested" "" { target { ! strub } } } */
+
+extern void __attribute__ ((__strub__ ("internal")))
+t (void); /* { dg-message "not eligible|requested" "" { target { ! strub } } } */
+
+void m () {
+  s ();
+  t ();
+}
diff --git a/gcc/testsuite/c-c++-common/strub-unsupported.c b/gcc/testsuite/c-c++-common/strub-unsupported.c
new file mode 100644
index 00000000000..cb5c4049495
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-unsupported.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+
+/* Check that, when strub is not supported (so no dg-required-effective-target
+   strub above), we report when strub functions are defined, and when they're
+   called in ways that would require changes.  */
+
+void __attribute__ ((__strub__))
+f (void) {} /* { dg-message "not eligible|requested" "" { target { ! strub } } } */
+
+void __attribute__ ((__strub__ ("internal")))
+g (void) {} /* { dg-message "not eligible|requested" "" { target { ! strub } } } */
+
+/* This only gets an error when called, see strub-unsupported-2.c.  */
+void __attribute__ ((__strub__ ("at-calls"))) (*p) (void);
+
+/* These too, see strub-unsupported-3.c.  */
+extern void __attribute__ ((__strub__))
+s (void);
+
+extern void __attribute__ ((__strub__ ("internal")))
+t (void);
diff --git a/gcc/testsuite/c-c++-common/strub-var1.c b/gcc/testsuite/c-c++-common/strub-var1.c
index eb6250fd39c..67014aa5de8 100644
--- a/gcc/testsuite/c-c++-common/strub-var1.c
+++ b/gcc/testsuite/c-c++-common/strub-var1.c
@@ -1,4 +1,5 @@
 /* { dg-do compile } */
+/* { dg-require-effective-target strub } */
 
 int __attribute__ ((strub)) x;
 float __attribute__ ((strub)) f;
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable1.c b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
index b5e45ab0525..86dbee6746d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-callable1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that strub and non-strub functions can be called from non-strub
    contexts, and that strub and callable functions can be called from strub
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable2.c b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
index 96aa7fe4b07..9da120f6156 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-callable2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that impermissible (cross-strub-context) calls are reported.  */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const1.c b/gcc/testsuite/c-c++-common/torture/strub-const1.c
index 5e956cb1a9b..22056713cce 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub const function call, we issue an asm
    statement to make sure the watermark passed to it is held in memory before
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const2.c b/gcc/testsuite/c-c++-common/torture/strub-const2.c
index 73d650292df..a105c66d7a9 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-const function call, we issue an
    asm statement to make sure the watermark passed to it is held in memory
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const3.c b/gcc/testsuite/c-c++-common/torture/strub-const3.c
index 2584f1f974a..386200c2784 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub const wrapping call, we issue an asm statement
    to make sure the watermark passed to it is held in memory before the call,
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const4.c b/gcc/testsuite/c-c++-common/torture/strub-const4.c
index d819f54ec02..817e9fa2118 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-const wrapping call, we issue an
    asm statement to make sure the watermark passed to it is held in memory
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data1.c b/gcc/testsuite/c-c++-common/torture/strub-data1.c
index 7c27a2a1a6d..132ab63ef73 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointed-to data enables strubbing if accessed.  */
 int __attribute__ ((__strub__)) var;
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data2.c b/gcc/testsuite/c-c++-common/torture/strub-data2.c
index e66d903780a..b660702d26e 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointer itself is a strub variable, enabling internal strubbing when
    its value is used.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data3.c b/gcc/testsuite/c-c++-common/torture/strub-data3.c
index 5e08e0e58c6..fc44eef6f8f 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointer itself is a strub variable, that would enable internal strubbing
    if its value was used.  Here, it's only overwritten, so no strub.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data4.c b/gcc/testsuite/c-c++-common/torture/strub-data4.c
index a818e7a38bb..85e2f59055b 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointer itself is a strub variable, that would enable internal strubbing
    if its value was used.  Here, it's only overwritten, so no strub.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data5.c b/gcc/testsuite/c-c++-common/torture/strub-data5.c
index ddb0b5c0543..0a5edac414d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data5.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data5.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* It would be desirable to issue at least warnings for these.  */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
index c165f312f16..988954e7ed6 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 typedef void __attribute__ ((__strub__)) fntype ();
 fntype (*ptr);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
index 69fcff8d376..d3ca91389a7 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 typedef void __attribute__ ((__strub__)) fntype (int, int);
 fntype (*ptr);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
index ff006224909..89b5979cf7b 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 typedef void __attribute__ ((__strub__)) fntype (int, int, ...);
 fntype (*ptr);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
index 614b02228ba..4917dda8826 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed" } */
+/* { dg-require-effective-target strub } */
 
 inline void __attribute__ ((strub ("internal"), always_inline))
 inl_int_ali (void)
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
index f9a6b4a16fa..c45903856d4 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all" } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-inlinable1.c"
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
index b4a7f3992bb..b0d6139f0a8 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 typedef void ft (void);
 typedef void ft2 (int, int);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
index ef634d35126..1148c246f20 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -Wpedantic" } */
+/* { dg-require-effective-target strub } */
 
 /* C++ does not warn about the partial incompatibilities.
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
index e1f179e160e..06a72d86d2c 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
@@ -1,6 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -Wpedantic -fpermissive" } */
 /* { dg-prune-output "command-line option .-fpermissive." } */
+/* { dg-require-effective-target strub } */
 
 /* See strub-ptrfn2.c.  */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
index 70b558afad0..83ea1af7056 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed" } */
+/* { dg-require-effective-target strub } */
 
 /* This is strub-ptrfn2.c without -Wpedantic.
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure1.c b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
index a262a086837..2643136f178 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub pure function call, we issue an asm statement
    to make sure the watermark passed to it is not assumed to be unchanged.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure2.c b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
index 4c4bd50c209..8bda129b77d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-pure function call, we issue an asm
    statement to make sure the watermark passed to it is not assumed to be
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure3.c b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
index ce195c6b1f1..00bcbdd097a 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub pure wrapping call, we issue an asm statement
    to make sure the watermark passed to it is not assumed to be unchanged.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure4.c b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
index 75cd54ccb5b..ea7c40e7912 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-pure wrapping call, we issue an asm
    statement to make sure the watermark passed to it is not assumed to be
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run1.c b/gcc/testsuite/c-c++-common/torture/strub-run1.c
index 7458b3fb54d..fdf10042863 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run1.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a non-strub function leaves a string behind in the stack, and that
    equivalent strub functions don't.  Avoid the use of red zones by avoiding
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run2.c b/gcc/testsuite/c-c++-common/torture/strub-run2.c
index 5d60a7775f4..1228a665997 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run2.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a non-strub function leaves a string behind in the stack, and that
    equivalent strub functions don't.  Allow red zones to be used.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run3.c b/gcc/testsuite/c-c++-common/torture/strub-run3.c
index c2ad710858e..e5047a988f5 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run3.c
@@ -1,6 +1,7 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a non-strub function leaves a string behind in the stack, and that
    equivalent strub functions don't.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4.c b/gcc/testsuite/c-c++-common/torture/strub-run4.c
index 3b36b8e5d68..0e84a4bab80 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4.c
@@ -1,6 +1,7 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=all" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 /* Check that multi-level, multi-inlined functions still get cleaned up as
    expected, without overwriting temporary stack allocations while they should
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4c.c b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
index 57f9baf758d..edc98486dc9 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4c.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=at-calls" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-run4.c"
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4d.c b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
index 08de3f1c3b1..487ed08bb66 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4d.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
@@ -1,6 +1,7 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 #define ATTR_STRUB_AT_CALLS __attribute__ ((__strub__ ("at-calls")))
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4i.c b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
index 459f6886c54..a85447ffabf 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4i.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=internal" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-run4.c"
diff --git a/gcc/testsuite/g++.dg/strub-run1.C b/gcc/testsuite/g++.dg/strub-run1.C
index 0d367fb83d0..beb8b811f8f 100644
--- a/gcc/testsuite/g++.dg/strub-run1.C
+++ b/gcc/testsuite/g++.dg/strub-run1.C
@@ -1,5 +1,6 @@
 // { dg-do run }
 // { dg-options "-fstrub=internal" }
+// { dg-require-effective-target strub }
 
 // Check that we don't get extra copies.
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init1.C b/gcc/testsuite/g++.dg/torture/strub-init1.C
index c226ab10ff6..6ae45fadd70 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init1.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init1.C
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
 
 extern int __attribute__((__strub__)) initializer ();
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init2.C b/gcc/testsuite/g++.dg/torture/strub-init2.C
index a7911f1fa72..8f4849c7fde 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init2.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init2.C
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
 
 extern int __attribute__((__strub__)) initializer ();
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init3.C b/gcc/testsuite/g++.dg/torture/strub-init3.C
index 6ebebcd01e8..14f28e3c276 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init3.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init3.C
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
 
 extern int __attribute__((__strub__)) initializer ();
 
diff --git a/gcc/testsuite/gnat.dg/strub_access.adb b/gcc/testsuite/gnat.dg/strub_access.adb
index 29e6996ecf6..488a2d64afe 100644
--- a/gcc/testsuite/gnat.dg/strub_access.adb
+++ b/gcc/testsuite/gnat.dg/strub_access.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed -fdump-ipa-strubm" }
+--  { dg-require-effective-target strub }
 
 --  The main subprogram doesn't read from the automatic variable, but
 --  being an automatic variable, its presence should be enough for the
diff --git a/gcc/testsuite/gnat.dg/strub_access1.adb b/gcc/testsuite/gnat.dg/strub_access1.adb
index dae47060164..4a8653c4d84 100644
--- a/gcc/testsuite/gnat.dg/strub_access1.adb
+++ b/gcc/testsuite/gnat.dg/strub_access1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed" }
+--  { dg-require-effective-target strub }
 
 --  Check that we reject 'Access of a strub variable whose type does
 --  not carry a strub modifier.
diff --git a/gcc/testsuite/gnat.dg/strub_attr.adb b/gcc/testsuite/gnat.dg/strub_attr.adb
index 10445d7cf84..eb7826dc990 100644
--- a/gcc/testsuite/gnat.dg/strub_attr.adb
+++ b/gcc/testsuite/gnat.dg/strub_attr.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm -fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 package body Strub_Attr is
    E : exception;
diff --git a/gcc/testsuite/gnat.dg/strub_disp.adb b/gcc/testsuite/gnat.dg/strub_disp.adb
index 3dbcc4a357c..f23d4675def 100644
--- a/gcc/testsuite/gnat.dg/strub_disp.adb
+++ b/gcc/testsuite/gnat.dg/strub_disp.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Disp is
    package Foo is
diff --git a/gcc/testsuite/gnat.dg/strub_disp1.adb b/gcc/testsuite/gnat.dg/strub_disp1.adb
index 09756a74b7d..9c4c7f69637 100644
--- a/gcc/testsuite/gnat.dg/strub_disp1.adb
+++ b/gcc/testsuite/gnat.dg/strub_disp1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 -- Check that at-calls dispatching calls are transformed.
 
diff --git a/gcc/testsuite/gnat.dg/strub_ind.adb b/gcc/testsuite/gnat.dg/strub_ind.adb
index da56acaa957..613db69305e 100644
--- a/gcc/testsuite/gnat.dg/strub_ind.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict" }
+--  { dg-require-effective-target strub }
 
 --  This is essentially the same test as strub_attr.adb, 
 --  but applying attributes to access types as well.
diff --git a/gcc/testsuite/gnat.dg/strub_ind1.adb b/gcc/testsuite/gnat.dg/strub_ind1.adb
index 825e395e681..245b0a830f6 100644
--- a/gcc/testsuite/gnat.dg/strub_ind1.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm" }
+--  { dg-require-effective-target strub }
 
 --  This is essentially the same test as strub_attr.adb, 
 --  but with an explicit conversion.
diff --git a/gcc/testsuite/gnat.dg/strub_ind2.adb b/gcc/testsuite/gnat.dg/strub_ind2.adb
index e918b392631..b9bfe50e929 100644
--- a/gcc/testsuite/gnat.dg/strub_ind2.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind2.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict" }
+--  { dg-require-effective-target strub }
 
 --  This is essentially the same test as strub_attr.adb, 
 --  but with an explicit conversion.
diff --git a/gcc/testsuite/gnat.dg/strub_intf.adb b/gcc/testsuite/gnat.dg/strub_intf.adb
index 8f0212a7586..f43854705d0 100644
--- a/gcc/testsuite/gnat.dg/strub_intf.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 --  Check that strub mode mismatches between overrider and overridden
 --  subprograms are reported.
diff --git a/gcc/testsuite/gnat.dg/strub_intf1.adb b/gcc/testsuite/gnat.dg/strub_intf1.adb
index bf77321cef7..7a38a4c49ba 100644
--- a/gcc/testsuite/gnat.dg/strub_intf1.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 -- Check that at-calls dispatching calls to interfaces are transformed.
 
diff --git a/gcc/testsuite/gnat.dg/strub_intf2.adb b/gcc/testsuite/gnat.dg/strub_intf2.adb
index e8880dbc437..7992b7344fb 100644
--- a/gcc/testsuite/gnat.dg/strub_intf2.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf2.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 --  Check that strub mode mismatches between overrider and overridden
 --  subprograms are reported even when the overriders for an
diff --git a/gcc/testsuite/gnat.dg/strub_renm.adb b/gcc/testsuite/gnat.dg/strub_renm.adb
index 217367e712d..abfb120b514 100644
--- a/gcc/testsuite/gnat.dg/strub_renm.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Renm is
    procedure P (X : Integer);
diff --git a/gcc/testsuite/gnat.dg/strub_renm1.adb b/gcc/testsuite/gnat.dg/strub_renm1.adb
index a11adbfb5a9..68d3230b535 100644
--- a/gcc/testsuite/gnat.dg/strub_renm1.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed -fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Renm1 is
    V : Integer := 0;
diff --git a/gcc/testsuite/gnat.dg/strub_renm2.adb b/gcc/testsuite/gnat.dg/strub_renm2.adb
index c488c20826f..3cb81ea03f7 100644
--- a/gcc/testsuite/gnat.dg/strub_renm2.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm2.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Renm2 is
    V : Integer := 0;
diff --git a/gcc/testsuite/gnat.dg/strub_var.adb b/gcc/testsuite/gnat.dg/strub_var.adb
index 3d158de2803..7c6affa06d4 100644
--- a/gcc/testsuite/gnat.dg/strub_var.adb
+++ b/gcc/testsuite/gnat.dg/strub_var.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm" }
+--  { dg-require-effective-target strub }
 
 -- We don't read from the automatic variable, but being an automatic
 --  variable, its presence should be enough for the procedure to get
diff --git a/gcc/testsuite/gnat.dg/strub_var1.adb b/gcc/testsuite/gnat.dg/strub_var1.adb
index 6a504e09198..64b7e65fe9b 100644
--- a/gcc/testsuite/gnat.dg/strub_var1.adb
+++ b/gcc/testsuite/gnat.dg/strub_var1.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 with Strub_Attr;
 procedure Strub_Var1 is
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 3fcce6be49d..40a60c198cf 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -1302,6 +1302,13 @@ proc check_stack_check_available { stack_kind } {
     } "$stack_opt"]
 }
 
+# Return 1 if the target supports stack scrubbing.
+proc check_effective_target_strub {} {
+    return [check_no_compiler_messages strub assembly {
+	void __attribute__ ((__strub__)) fn (void) {}
+    } ""]
+}
+
 # Return 1 if compilation with -freorder-blocks-and-partition is error-free
 # for trivial code, 0 otherwise.  As some targets (ARM for example) only
 # warn when -fprofile-use is also supplied we test that combination too.
diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in
index d8163c5af99..3f77283490e 100644
--- a/libgcc/Makefile.in
+++ b/libgcc/Makefile.in
@@ -434,7 +434,7 @@ LIB2ADD += enable-execute-stack.c
 LIB2ADD += $(srcdir)/hardcfr.c
 
 # Stack scrubbing infrastructure.
-LIB2ADD += $(srcdir)/strub.c
+@HAVE_STRUB_SUPPORT@LIB2ADD += $(srcdir)/strub.c
 
 # While emutls.c has nothing to do with EH, it is in LIB2ADDEH*
 # instead of LIB2ADD because that's the way to be sure on some targets
diff --git a/libgcc/configure b/libgcc/configure
index cf149209652..567158955a3 100755
--- a/libgcc/configure
+++ b/libgcc/configure
@@ -593,6 +593,7 @@ asm_hidden_op
 extra_parts
 cpu_type
 get_gcc_base_ver
+HAVE_STRUB_SUPPORT
 thread_header
 tm_defines
 tm_file
@@ -5702,6 +5703,31 @@ esac
 
 
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for strub support" >&5
+$as_echo_n "checking for strub support... " >&6; }
+if ${libgcc_cv_strub_support+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+void __attribute__ ((__strub__)) fn (void) {}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  libgcc_cv_strub_support=yes
+else
+  libgcc_cv_strub_support=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgcc_cv_strub_support" >&5
+$as_echo "$libgcc_cv_strub_support" >&6; }
+if test "x$libgcc_cv_strub_support" != xno; then
+  HAVE_STRUB_SUPPORT=
+else
+  HAVE_STRUB_SUPPORT='# '
+fi
+
+
 # Determine what GCC version number to use in filesystem paths.
 
   get_gcc_base_ver="cat"
diff --git a/libgcc/configure.ac b/libgcc/configure.ac
index 2fc9d5d7c93..9c0e415501a 100644
--- a/libgcc/configure.ac
+++ b/libgcc/configure.ac
@@ -694,6 +694,19 @@ AC_SUBST(tm_defines)
 # Map from thread model to thread header.
 GCC_AC_THREAD_HEADER([$target_thread_file])
 
+AC_CACHE_CHECK([for strub support],
+  [libgcc_cv_strub_support],
+  [AC_COMPILE_IFELSE(
+    [AC_LANG_SOURCE([void __attribute__ ((__strub__)) fn (void) {}])],
+    [libgcc_cv_strub_support=yes],
+    [libgcc_cv_strub_support=no])])
+if test "x$libgcc_cv_strub_support" != xno; then
+  HAVE_STRUB_SUPPORT=
+else
+  HAVE_STRUB_SUPPORT='# '
+fi
+AC_SUBST(HAVE_STRUB_SUPPORT)
+
 # Determine what GCC version number to use in filesystem paths.
 GCC_BASE_VER

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [gcc(refs/users/aoliva/heads/testme)] strub: enable conditional support
@ 2023-12-07  1:45 Alexandre Oliva
  0 siblings, 0 replies; 25+ messages in thread
From: Alexandre Oliva @ 2023-12-07  1:45 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:3c01ffb70a6605523830ea1c0d25d23690a8ac04

commit 3c01ffb70a6605523830ea1c0d25d23690a8ac04
Author: Alexandre Oliva <oliva@adacore.com>
Date:   Wed Dec 6 19:36:02 2023 -0300

    strub: enable conditional support
    
    Targets that don't expose callee stacks to callers, such as nvptx, as
    well as -fsplit-stack compilations, violate fundamental assumptions of
    the current strub implementation.  This patch enables targets to
    disable strub, and disables it when -fsplit-stack is enabled.
    
    When strub support is disabled, the testsuite will now skip strub
    tests, and libgcc will not build the strub runtime components.
    
    
    for  gcc/ChangeLog
    
            * target.def (have_strub_support_for): New hook.
            * doc/tm.texi.in: Document it.
            * doc/tm.texi: Rebuild.
            * ipa-strub.cc: Include target.h.
            (strub_target_support_p): New.
            (can_strub_p): Call it.  Test for no flag_split_stack.
            (pass_ipa_strub::adjust_at_calls_call): Check for target
            support.
            * config/nvptx/nvptx.cc (TARGET_HAVE_STRUB_SUPPORT_FOR):
            Disable.
            * doc/sourcebuild.texi (strub): Document new effective
            target.
    
    for  gcc/testsuite/ChangeLog
    
            * gcc.dg/strub-split-stack.c: New.
            * gcc.dg/strub-unsupported.c: New.
            * gcc.dg/strub-unsupported-2.c: New.
            * gcc.dg/strub-unsupported-3.c: New.
            * lib/target-supports.exp (check_effective_target_strub): New.
            * c-c++-common/strub-O0.c: Require effective target strub.
            * c-c++-common/strub-O1.c: Likewise.
            * c-c++-common/strub-O2.c: Likewise.
            * c-c++-common/strub-O2fni.c: Likewise.
            * c-c++-common/strub-O3.c: Likewise.
            * c-c++-common/strub-O3fni.c: Likewise.
            * c-c++-common/strub-Og.c: Likewise.
            * c-c++-common/strub-Os.c: Likewise.
            * c-c++-common/strub-all1.c: Likewise.
            * c-c++-common/strub-all2.c: Likewise.
            * c-c++-common/strub-apply1.c: Likewise.
            * c-c++-common/strub-apply2.c: Likewise.
            * c-c++-common/strub-apply3.c: Likewise.
            * c-c++-common/strub-apply4.c: Likewise.
            * c-c++-common/strub-at-calls1.c: Likewise.
            * c-c++-common/strub-at-calls2.c: Likewise.
            * c-c++-common/strub-defer-O1.c: Likewise.
            * c-c++-common/strub-defer-O2.c: Likewise.
            * c-c++-common/strub-defer-O3.c: Likewise.
            * c-c++-common/strub-defer-Os.c: Likewise.
            * c-c++-common/strub-internal1.c: Likewise.
            * c-c++-common/strub-internal2.c: Likewise.
            * c-c++-common/strub-parms1.c: Likewise.
            * c-c++-common/strub-parms2.c: Likewise.
            * c-c++-common/strub-parms3.c: Likewise.
            * c-c++-common/strub-relaxed1.c: Likewise.
            * c-c++-common/strub-relaxed2.c: Likewise.
            * c-c++-common/strub-short-O0-exc.c: Likewise.
            * c-c++-common/strub-short-O0.c: Likewise.
            * c-c++-common/strub-short-O1.c: Likewise.
            * c-c++-common/strub-short-O2.c: Likewise.
            * c-c++-common/strub-short-O3.c: Likewise.
            * c-c++-common/strub-short-Os.c: Likewise.
            * c-c++-common/strub-strict1.c: Likewise.
            * c-c++-common/strub-strict2.c: Likewise.
            * c-c++-common/strub-tail-O1.c: Likewise.
            * c-c++-common/strub-tail-O2.c: Likewise.
            * c-c++-common/strub-var1.c: Likewise.
            * c-c++-common/torture/strub-callable1.c: Likewise.
            * c-c++-common/torture/strub-callable2.c: Likewise.
            * c-c++-common/torture/strub-const1.c: Likewise.
            * c-c++-common/torture/strub-const2.c: Likewise.
            * c-c++-common/torture/strub-const3.c: Likewise.
            * c-c++-common/torture/strub-const4.c: Likewise.
            * c-c++-common/torture/strub-data1.c: Likewise.
            * c-c++-common/torture/strub-data2.c: Likewise.
            * c-c++-common/torture/strub-data3.c: Likewise.
            * c-c++-common/torture/strub-data4.c: Likewise.
            * c-c++-common/torture/strub-data5.c: Likewise.
            * c-c++-common/torture/strub-indcall1.c: Likewise.
            * c-c++-common/torture/strub-indcall2.c: Likewise.
            * c-c++-common/torture/strub-indcall3.c: Likewise.
            * c-c++-common/torture/strub-inlinable1.c: Likewise.
            * c-c++-common/torture/strub-inlinable2.c: Likewise.
            * c-c++-common/torture/strub-ptrfn1.c: Likewise.
            * c-c++-common/torture/strub-ptrfn2.c: Likewise.
            * c-c++-common/torture/strub-ptrfn3.c: Likewise.
            * c-c++-common/torture/strub-ptrfn4.c: Likewise.
            * c-c++-common/torture/strub-pure1.c: Likewise.
            * c-c++-common/torture/strub-pure2.c: Likewise.
            * c-c++-common/torture/strub-pure3.c: Likewise.
            * c-c++-common/torture/strub-pure4.c: Likewise.
            * c-c++-common/torture/strub-run1.c: Likewise.
            * c-c++-common/torture/strub-run2.c: Likewise.
            * c-c++-common/torture/strub-run3.c: Likewise.
            * c-c++-common/torture/strub-run4.c: Likewise.
            * c-c++-common/torture/strub-run4c.c: Likewise.
            * c-c++-common/torture/strub-run4d.c: Likewise.
            * c-c++-common/torture/strub-run4i.c: Likewise.
            * g++.dg/strub-run1.C: Likewise.
            * g++.dg/torture/strub-init1.C: Likewise.
            * g++.dg/torture/strub-init2.C: Likewise.
            * g++.dg/torture/strub-init3.C: Likewise.
            * gnat.dg/strub_attr.adb: Likewise.
            * gnat.dg/strub_ind.adb: Likewise.
            * gnat.dg/strub_access.adb: Likewise.
            * gnat.dg/strub_access1.adb: Likewise.
            * gnat.dg/strub_disp.adb: Likewise.
            * gnat.dg/strub_disp1.adb: Likewise.
            * gnat.dg/strub_ind1.adb: Likewise.
            * gnat.dg/strub_ind2.adb: Likewise.
            * gnat.dg/strub_intf.adb: Likewise.
            * gnat.dg/strub_intf1.adb: Likewise.
            * gnat.dg/strub_intf2.adb: Likewise.
            * gnat.dg/strub_renm.adb: Likewise.
            * gnat.dg/strub_renm1.adb: Likewise.
            * gnat.dg/strub_renm2.adb: Likewise.
            * gnat.dg/strub_var.adb: Likewise.
            * gnat.dg/strub_var1.adb: Likewise.
    
    for  libgcc/ChangeLog
    
            * configure.ac: Check for strub support.
            * configure: Rebuilt.
            * Makefile.in: Compile strub.c conditionally.

Diff:
---
 gcc/config/nvptx/nvptx.cc                          |  3 ++
 gcc/doc/sourcebuild.texi                           |  3 ++
 gcc/doc/tm.texi                                    |  6 +++
 gcc/doc/tm.texi.in                                 |  2 +
 gcc/ipa-strub.cc                                   | 54 +++++++++++++++++++++-
 gcc/target.def                                     |  8 ++++
 gcc/testsuite/c-c++-common/strub-O0.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O1.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O2.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O2fni.c           |  1 +
 gcc/testsuite/c-c++-common/strub-O3.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O3fni.c           |  1 +
 gcc/testsuite/c-c++-common/strub-Og.c              |  1 +
 gcc/testsuite/c-c++-common/strub-Os.c              |  1 +
 gcc/testsuite/c-c++-common/strub-all1.c            |  1 +
 gcc/testsuite/c-c++-common/strub-all2.c            |  1 +
 gcc/testsuite/c-c++-common/strub-apply1.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply2.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply3.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply4.c          |  1 +
 gcc/testsuite/c-c++-common/strub-at-calls1.c       |  1 +
 gcc/testsuite/c-c++-common/strub-at-calls2.c       |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O3.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-Os.c        |  1 +
 gcc/testsuite/c-c++-common/strub-internal1.c       |  1 +
 gcc/testsuite/c-c++-common/strub-internal2.c       |  1 +
 gcc/testsuite/c-c++-common/strub-parms1.c          |  1 +
 gcc/testsuite/c-c++-common/strub-parms2.c          |  1 +
 gcc/testsuite/c-c++-common/strub-parms3.c          |  1 +
 gcc/testsuite/c-c++-common/strub-relaxed1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-relaxed2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O0-exc.c    |  1 +
 gcc/testsuite/c-c++-common/strub-short-O0.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O3.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-Os.c        |  1 +
 gcc/testsuite/c-c++-common/strub-split-stack.c     | 10 ++++
 gcc/testsuite/c-c++-common/strub-strict1.c         |  1 +
 gcc/testsuite/c-c++-common/strub-strict2.c         |  1 +
 gcc/testsuite/c-c++-common/strub-tail-O1.c         |  1 +
 gcc/testsuite/c-c++-common/strub-tail-O2.c         |  1 +
 gcc/testsuite/c-c++-common/strub-unsupported-2.c   | 13 ++++++
 gcc/testsuite/c-c++-common/strub-unsupported-3.c   | 18 ++++++++
 gcc/testsuite/c-c++-common/strub-unsupported.c     | 21 +++++++++
 gcc/testsuite/c-c++-common/strub-var1.c            |  1 +
 .../c-c++-common/torture/strub-callable1.c         |  1 +
 .../c-c++-common/torture/strub-callable2.c         |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const1.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const2.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const3.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const4.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data1.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data2.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data3.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data4.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data5.c   |  1 +
 .../c-c++-common/torture/strub-indcall1.c          |  1 +
 .../c-c++-common/torture/strub-indcall2.c          |  1 +
 .../c-c++-common/torture/strub-indcall3.c          |  1 +
 .../c-c++-common/torture/strub-inlinable1.c        |  1 +
 .../c-c++-common/torture/strub-inlinable2.c        |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure1.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure2.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure3.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure4.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run1.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run2.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run3.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4c.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4d.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4i.c   |  1 +
 gcc/testsuite/g++.dg/strub-run1.C                  |  1 +
 gcc/testsuite/g++.dg/torture/strub-init1.C         |  1 +
 gcc/testsuite/g++.dg/torture/strub-init2.C         |  1 +
 gcc/testsuite/g++.dg/torture/strub-init3.C         |  1 +
 gcc/testsuite/gnat.dg/strub_access.adb             |  1 +
 gcc/testsuite/gnat.dg/strub_access1.adb            |  1 +
 gcc/testsuite/gnat.dg/strub_attr.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_disp.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_disp1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_ind.adb                |  1 +
 gcc/testsuite/gnat.dg/strub_ind1.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_ind2.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_intf.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_intf1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_intf2.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_renm.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_renm1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_renm2.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_var.adb                |  1 +
 gcc/testsuite/gnat.dg/strub_var1.adb               |  1 +
 gcc/testsuite/lib/target-supports.exp              |  7 +++
 libgcc/Makefile.in                                 |  2 +-
 libgcc/configure                                   | 26 +++++++++++
 libgcc/configure.ac                                | 13 ++++++
 103 files changed, 272 insertions(+), 3 deletions(-)

diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc
index ae20802c879..3fb1deb70fd 100644
--- a/gcc/config/nvptx/nvptx.cc
+++ b/gcc/config/nvptx/nvptx.cc
@@ -7789,6 +7789,9 @@ nvptx_asm_output_def_from_decls (FILE *stream, tree name, tree value)
 #undef TARGET_LIBC_HAS_FUNCTION
 #define TARGET_LIBC_HAS_FUNCTION nvptx_libc_has_function
 
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-nvptx.h"
diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi
index c9909026854..26a7e9c3507 100644
--- a/gcc/doc/sourcebuild.texi
+++ b/gcc/doc/sourcebuild.texi
@@ -2983,6 +2983,9 @@ Target supports statically linking @samp{libgfortran}.
 @item string_merging
 Target supports merging string constants at link time.
 
+@item strub
+Target supports attribute @code{strub} for stack scrubbing.
+
 @item ucn
 Target supports compiling and assembling UCN.
 
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 89a1735dd79..768ada0af52 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -3450,6 +3450,12 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@deftypefn {Target Hook} bool TARGET_HAVE_STRUB_SUPPORT_FOR (tree)
+Returns true if the target supports stack scrubbing for the given function
+or type, otherwise return false.  The default implementation always returns
+true.
+@end deftypefn
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index ebc1d3de5ca..4fe0805394e 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2686,6 +2686,8 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@hook TARGET_HAVE_STRUB_SUPPORT_FOR
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
index 293bec132b8..2afb7a45575 100644
--- a/gcc/ipa-strub.cc
+++ b/gcc/ipa-strub.cc
@@ -60,6 +60,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-strub.h"
 #include "symtab-thunks.h"
 #include "attr-fnspec.h"
+#include "target.h"
 
 /* This file introduces two passes that, together, implement
    machine-independent stack scrubbing, strub for short.  It arranges
@@ -631,17 +632,60 @@ strub_always_inline_p (cgraph_node *node)
   return lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl));
 }
 
+/* Return TRUE iff the target has strub support for T, a function
+   decl, or a type used in an indirect call, and optionally REPORT the
+   reasons for ineligibility.  If T is a type and error REPORTing is
+   enabled, the LOCation (of the indirect call) should be provided.  */
+static inline bool
+strub_target_support_p (tree t, bool report = false,
+			location_t loc = UNKNOWN_LOCATION)
+{
+  bool result = true;
+
+  if (!targetm.have_strub_support_for (t))
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      if (DECL_P (t))
+	sorry_at (DECL_SOURCE_LOCATION (t),
+		  "%qD is not eligible for %<strub%>"
+		  " on the target system", t);
+      else
+	sorry_at (loc,
+		  "unsupported %<strub%> call"
+		  " on the target system");
+    }
+
+  return result;
+}
+
 /* Return TRUE iff NODE is potentially eligible for any strub-enabled mode, and
    optionally REPORT the reasons for ineligibility.  */
 
 static inline bool
 can_strub_p (cgraph_node *node, bool report = false)
 {
-  bool result = true;
+  bool result = strub_target_support_p (node->decl, report);
 
-  if (!report && strub_always_inline_p (node))
+  if (!report && (!result || strub_always_inline_p (node)))
     return result;
 
+  if (flag_split_stack)
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (node->decl),
+		"%qD is not eligible for %<strub%>"
+		" because %<-fsplit-stack%> is enabled",
+		node->decl);
+    }
+
   if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
     {
       result = false;
@@ -2417,6 +2461,12 @@ pass_ipa_strub::adjust_at_calls_call (cgraph_edge *e, int named_args,
 			 && (TREE_TYPE (gimple_call_arg (ocall, named_args))
 			     == get_pwmt ())));
 
+  tree tsup;
+  if (!(tsup = gimple_call_fndecl (ocall)))
+    tsup = TREE_TYPE (TREE_TYPE (gimple_call_fn (ocall)));
+  if (!strub_target_support_p (tsup, true, gimple_location (ocall)))
+    return;
+
   /* If we're already within a strub context, pass on the incoming watermark
      pointer, and omit the enter and leave calls around the modified call, as an
      optimization, or as a means to satisfy a tail-call requirement.  */
diff --git a/gcc/target.def b/gcc/target.def
index 52b83e091b9..08218f3a42a 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4457,6 +4457,14 @@ otherwise return false.  The default implementation always returns true.",
  bool, (void),
  hook_bool_void_true)
 
+DEFHOOK
+(have_strub_support_for,
+ "Returns true if the target supports stack scrubbing for the given function\n\
+or type, otherwise return false.  The default implementation always returns\n\
+true.",
+ bool, (tree),
+ hook_bool_tree_true)
+
 DEFHOOK
 (have_speculation_safe_value,
 "This hook is used to determine the level of target support for\n\
diff --git a/gcc/testsuite/c-c++-common/strub-O0.c b/gcc/testsuite/c-c++-common/strub-O0.c
index c7a79a6ea0d..f0a3f7b4c6f 100644
--- a/gcc/testsuite/c-c++-common/strub-O0.c
+++ b/gcc/testsuite/c-c++-common/strub-O0.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -O0, none of the strub builtins are expanded inline.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O1.c b/gcc/testsuite/c-c++-common/strub-O1.c
index 96285c975d9..50403426b18 100644
--- a/gcc/testsuite/c-c++-common/strub-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -O1, without -fno-inline, we fully expand enter, but neither update nor
    leave.  */
diff --git a/gcc/testsuite/c-c++-common/strub-O2.c b/gcc/testsuite/c-c++-common/strub-O2.c
index 8edc0d8aa13..37e02998e31 100644
--- a/gcc/testsuite/c-c++-common/strub-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -O2, without -fno-inline, we fully expand enter and update, and add a test
    around the leave call.  */
diff --git a/gcc/testsuite/c-c++-common/strub-O2fni.c b/gcc/testsuite/c-c++-common/strub-O2fni.c
index c6d900cf3c4..905e2c6b2ff 100644
--- a/gcc/testsuite/c-c++-common/strub-O2fni.c
+++ b/gcc/testsuite/c-c++-common/strub-O2fni.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
+/* { dg-require-effective-target strub } */
 
 /* With -fno-inline, none of the strub builtins are inlined.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O3.c b/gcc/testsuite/c-c++-common/strub-O3.c
index 33ee465e51c..3bbf132bdf1 100644
--- a/gcc/testsuite/c-c++-common/strub-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-O3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 int __attribute__ ((__strub__)) var;
 
diff --git a/gcc/testsuite/c-c++-common/strub-O3fni.c b/gcc/testsuite/c-c++-common/strub-O3fni.c
index 2936f82079e..c46fce38e5c 100644
--- a/gcc/testsuite/c-c++-common/strub-O3fni.c
+++ b/gcc/testsuite/c-c++-common/strub-O3fni.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
+/* { dg-require-effective-target strub } */
 
 /* With -fno-inline, none of the strub builtins are inlined.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-Og.c b/gcc/testsuite/c-c++-common/strub-Og.c
index 479746e57d8..3b8eb19765c 100644
--- a/gcc/testsuite/c-c++-common/strub-Og.c
+++ b/gcc/testsuite/c-c++-common/strub-Og.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-Og -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -Og, without -fno-inline, we fully expand enter, but neither update nor
    leave.  */
diff --git a/gcc/testsuite/c-c++-common/strub-Os.c b/gcc/testsuite/c-c++-common/strub-Os.c
index 2241d4ea07f..8cfb253d676 100644
--- a/gcc/testsuite/c-c++-common/strub-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-Os.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-Os -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -Os, without -fno-inline, we fully expand enter, and also update.  The
    expanded update might be larger than a call proper, but argument saving and
diff --git a/gcc/testsuite/c-c++-common/strub-all1.c b/gcc/testsuite/c-c++-common/strub-all1.c
index a322bcc5da6..2037f681f29 100644
--- a/gcc/testsuite/c-c++-common/strub-all1.c
+++ b/gcc/testsuite/c-c++-common/strub-all1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
    strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub.  */
diff --git a/gcc/testsuite/c-c++-common/strub-all2.c b/gcc/testsuite/c-c++-common/strub-all2.c
index db60026d0e0..c026e7d9d28 100644
--- a/gcc/testsuite/c-c++-common/strub-all2.c
+++ b/gcc/testsuite/c-c++-common/strub-all2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* g becomes STRUB_INTERNAL, because of the flag.  Without inline, force_output
    is set for static non-inline functions when not optimizing, and that keeps
diff --git a/gcc/testsuite/c-c++-common/strub-apply1.c b/gcc/testsuite/c-c++-common/strub-apply1.c
index 2f462adc1ef..3edc89c54ee 100644
--- a/gcc/testsuite/c-c++-common/strub-apply1.c
+++ b/gcc/testsuite/c-c++-common/strub-apply1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 void __attribute__ ((__strub__ ("callable")))
 apply_function (void *args)
diff --git a/gcc/testsuite/c-c++-common/strub-apply2.c b/gcc/testsuite/c-c++-common/strub-apply2.c
index a5d7551f5da..838fc752734 100644
--- a/gcc/testsuite/c-c++-common/strub-apply2.c
+++ b/gcc/testsuite/c-c++-common/strub-apply2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 extern void __attribute__ ((__strub__))
 apply_function (void *args);
diff --git a/gcc/testsuite/c-c++-common/strub-apply3.c b/gcc/testsuite/c-c++-common/strub-apply3.c
index 64422a0d1e8..0206e4d930e 100644
--- a/gcc/testsuite/c-c++-common/strub-apply3.c
+++ b/gcc/testsuite/c-c++-common/strub-apply3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 void __attribute__ ((__strub__))
 apply_function (void *args)
diff --git a/gcc/testsuite/c-c++-common/strub-apply4.c b/gcc/testsuite/c-c++-common/strub-apply4.c
index 15ffaa031b8..e82504728b2 100644
--- a/gcc/testsuite/c-c++-common/strub-apply4.c
+++ b/gcc/testsuite/c-c++-common/strub-apply4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that implicit enabling of strub mode selects internal strub when the
    function uses __builtin_apply_args, that prevents the optimization to
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls1.c b/gcc/testsuite/c-c++-common/strub-at-calls1.c
index b70843b4215..a20acc0a48a 100644
--- a/gcc/testsuite/c-c++-common/strub-at-calls1.c
+++ b/gcc/testsuite/c-c++-common/strub-at-calls1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
    strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub.  */
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls2.c b/gcc/testsuite/c-c++-common/strub-at-calls2.c
index 97a3988a6b9..7915b33a39a 100644
--- a/gcc/testsuite/c-c++-common/strub-at-calls2.c
+++ b/gcc/testsuite/c-c++-common/strub-at-calls2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* g does NOT become STRUB_AT_CALLS because it's not viable.  Without inline,
    force_output is set for static non-inline functions when not optimizing, and
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O1.c b/gcc/testsuite/c-c++-common/strub-defer-O1.c
index 3d73431b3dc..3689998b5a3 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O1" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function does NOT defer
    the strubbing to its caller at -O1.  */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O2.c b/gcc/testsuite/c-c++-common/strub-defer-O2.c
index fddf3c745e7..9e01949db6b 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O2" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function does NOT defer
    the strubbing to its caller at -O2.  */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O3.c b/gcc/testsuite/c-c++-common/strub-defer-O3.c
index 7ebc65b58dd..40ee8edd1e0 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O3.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O3" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function defers the
    strubbing to its caller at -O3.  */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-Os.c b/gcc/testsuite/c-c++-common/strub-defer-Os.c
index fbaf85fe0fa..67ea9f04639 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-Os.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -Os" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function defers the
    strubbing to its caller at -Os.  */
diff --git a/gcc/testsuite/c-c++-common/strub-internal1.c b/gcc/testsuite/c-c++-common/strub-internal1.c
index e9d7b7b9ee0..d17254904e5 100644
--- a/gcc/testsuite/c-c++-common/strub-internal1.c
+++ b/gcc/testsuite/c-c++-common/strub-internal1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
    strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub.  */
diff --git a/gcc/testsuite/c-c++-common/strub-internal2.c b/gcc/testsuite/c-c++-common/strub-internal2.c
index 8b8e15a51c7..afc9189701f 100644
--- a/gcc/testsuite/c-c++-common/strub-internal2.c
+++ b/gcc/testsuite/c-c++-common/strub-internal2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* g becomes STRUB_INTERNAL, because of the flag.  */
 static void
diff --git a/gcc/testsuite/c-c++-common/strub-parms1.c b/gcc/testsuite/c-c++-common/strub-parms1.c
index 0a4a7539d34..f410b268971 100644
--- a/gcc/testsuite/c-c++-common/strub-parms1.c
+++ b/gcc/testsuite/c-c++-common/strub-parms1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 #include <stdarg.h>
 
diff --git a/gcc/testsuite/c-c++-common/strub-parms2.c b/gcc/testsuite/c-c++-common/strub-parms2.c
index 147171d96d5..6f572115a88 100644
--- a/gcc/testsuite/c-c++-common/strub-parms2.c
+++ b/gcc/testsuite/c-c++-common/strub-parms2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 #include <stdarg.h>
 
diff --git a/gcc/testsuite/c-c++-common/strub-parms3.c b/gcc/testsuite/c-c++-common/strub-parms3.c
index 4e92682895a..7383fea9ce8 100644
--- a/gcc/testsuite/c-c++-common/strub-parms3.c
+++ b/gcc/testsuite/c-c++-common/strub-parms3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that uses of a strub variable implicitly enables internal strub for
    publicly-visible functions, and causes the same transformations to their
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed1.c b/gcc/testsuite/c-c++-common/strub-relaxed1.c
index e2f9d8aebca..d2b4b52c51e 100644
--- a/gcc/testsuite/c-c++-common/strub-relaxed1.c
+++ b/gcc/testsuite/c-c++-common/strub-relaxed1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The difference between relaxed and strict in this case is that we accept the
    call from one internal-strub function to another.  Without the error,
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed2.c b/gcc/testsuite/c-c++-common/strub-relaxed2.c
index 98474435d2e..9e5a8e76b6c 100644
--- a/gcc/testsuite/c-c++-common/strub-relaxed2.c
+++ b/gcc/testsuite/c-c++-common/strub-relaxed2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The difference between relaxed and strict in this case is that we accept the
    call from one internal-strub function to another.  */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
index 1de15342595..aaeba2a2159 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fexceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0.c b/gcc/testsuite/c-c++-common/strub-short-O0.c
index f9209c81900..30cbdd819f1 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O0.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O0.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O1.c b/gcc/testsuite/c-c++-common/strub-short-O1.c
index bed1dcfb54a..911fdfb6db9 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O2.c b/gcc/testsuite/c-c++-common/strub-short-O2.c
index 6bf0071f52b..9b23ee3ac33 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O3.c b/gcc/testsuite/c-c++-common/strub-short-O3.c
index 4732f515bf7..4b3a8f843ea 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  At -O3 and -Os, we omit
    enter and leave calls within strub contexts, passing on the enclosing
diff --git a/gcc/testsuite/c-c++-common/strub-short-Os.c b/gcc/testsuite/c-c++-common/strub-short-Os.c
index 8d6424c479a..3627a240600 100644
--- a/gcc/testsuite/c-c++-common/strub-short-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-short-Os.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-Os -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  At -O3 and -Os, we omit
    enter and leave calls within strub contexts, passing on the enclosing
diff --git a/gcc/testsuite/c-c++-common/strub-split-stack.c b/gcc/testsuite/c-c++-common/strub-split-stack.c
new file mode 100644
index 00000000000..024f06ec98f
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-split-stack.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-fsplit-stack" } */
+/* { dg-require-effective-target strub } */
+/* { dg-require-effective-target split_stack } */
+
+void __attribute__ ((__strub__))
+f {} /* { dg-message "not eligible" }
+
+void __attribute__ ((__strub__ ("internal")))
+g {} /* { dg-message "not eligible" }
diff --git a/gcc/testsuite/c-c++-common/strub-strict1.c b/gcc/testsuite/c-c++-common/strub-strict1.c
index 36852244206..503eb1734e3 100644
--- a/gcc/testsuite/c-c++-common/strub-strict1.c
+++ b/gcc/testsuite/c-c++-common/strub-strict1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
 
 static int __attribute__ ((__strub__)) var;
 
diff --git a/gcc/testsuite/c-c++-common/strub-strict2.c b/gcc/testsuite/c-c++-common/strub-strict2.c
index b4f28883218..3bf1aa30b4a 100644
--- a/gcc/testsuite/c-c++-common/strub-strict2.c
+++ b/gcc/testsuite/c-c++-common/strub-strict2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
 
 static int __attribute__ ((__strub__)) var;
 
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O1.c b/gcc/testsuite/c-c++-common/strub-tail-O1.c
index e48e0610e07..ba4b1623e28 100644
--- a/gcc/testsuite/c-c++-common/strub-tail-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-tail-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-tail-O2.c"
 
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O2.c b/gcc/testsuite/c-c++-common/strub-tail-O2.c
index 87cda7ab21b..043813b1de4 100644
--- a/gcc/testsuite/c-c++-common/strub-tail-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-tail-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.
    Tail calls are short-circuited at -O2+.  */
diff --git a/gcc/testsuite/c-c++-common/strub-unsupported-2.c b/gcc/testsuite/c-c++-common/strub-unsupported-2.c
new file mode 100644
index 00000000000..3586f4f679d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-unsupported-2.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+
+/* Check that, when strub is not supported (so no dg-required-effective-target
+   strub above), we report when pointers to strub functions are called.  This
+   cannot be part of strub-unsupported.c because errors in the strub-mode pass
+   prevent the main strub pass, where errors at calls are detected, from
+   running.  */
+
+void __attribute__ ((__strub__ ("at-calls"))) (*p) (void);
+
+void m () {
+  p (); /* { dg-message "unsupported" "" { target { ! strub } } } */
+}
diff --git a/gcc/testsuite/c-c++-common/strub-unsupported-3.c b/gcc/testsuite/c-c++-common/strub-unsupported-3.c
new file mode 100644
index 00000000000..d6fb4c525c4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-unsupported-3.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+
+/* Check that, when strub is not supported (so no dg-required-effective-target
+   strub above), we report when strub functions that are not defined are
+   called.  This cannot be part of strub-unsupported-2.c because errors in the
+   strub-mode pass prevent the main strub pass, where errors at calls are
+   detected, from running.  */
+
+extern void __attribute__ ((__strub__))
+s (void); /* { dg-message "not eligible|requested" "" { target { ! strub } } } */
+
+extern void __attribute__ ((__strub__ ("internal")))
+t (void); /* { dg-message "not eligible|requested" "" { target { ! strub } } } */
+
+void m () {
+  s ();
+  t ();
+}
diff --git a/gcc/testsuite/c-c++-common/strub-unsupported.c b/gcc/testsuite/c-c++-common/strub-unsupported.c
new file mode 100644
index 00000000000..cb5c4049495
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-unsupported.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+
+/* Check that, when strub is not supported (so no dg-required-effective-target
+   strub above), we report when strub functions are defined, and when they're
+   called in ways that would require changes.  */
+
+void __attribute__ ((__strub__))
+f (void) {} /* { dg-message "not eligible|requested" "" { target { ! strub } } } */
+
+void __attribute__ ((__strub__ ("internal")))
+g (void) {} /* { dg-message "not eligible|requested" "" { target { ! strub } } } */
+
+/* This only gets an error when called, see strub-unsupported-2.c.  */
+void __attribute__ ((__strub__ ("at-calls"))) (*p) (void);
+
+/* These too, see strub-unsupported-3.c.  */
+extern void __attribute__ ((__strub__))
+s (void);
+
+extern void __attribute__ ((__strub__ ("internal")))
+t (void);
diff --git a/gcc/testsuite/c-c++-common/strub-var1.c b/gcc/testsuite/c-c++-common/strub-var1.c
index eb6250fd39c..67014aa5de8 100644
--- a/gcc/testsuite/c-c++-common/strub-var1.c
+++ b/gcc/testsuite/c-c++-common/strub-var1.c
@@ -1,4 +1,5 @@
 /* { dg-do compile } */
+/* { dg-require-effective-target strub } */
 
 int __attribute__ ((strub)) x;
 float __attribute__ ((strub)) f;
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable1.c b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
index b5e45ab0525..86dbee6746d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-callable1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that strub and non-strub functions can be called from non-strub
    contexts, and that strub and callable functions can be called from strub
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable2.c b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
index 96aa7fe4b07..9da120f6156 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-callable2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that impermissible (cross-strub-context) calls are reported.  */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const1.c b/gcc/testsuite/c-c++-common/torture/strub-const1.c
index 5e956cb1a9b..22056713cce 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub const function call, we issue an asm
    statement to make sure the watermark passed to it is held in memory before
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const2.c b/gcc/testsuite/c-c++-common/torture/strub-const2.c
index 73d650292df..a105c66d7a9 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-const function call, we issue an
    asm statement to make sure the watermark passed to it is held in memory
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const3.c b/gcc/testsuite/c-c++-common/torture/strub-const3.c
index 2584f1f974a..386200c2784 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub const wrapping call, we issue an asm statement
    to make sure the watermark passed to it is held in memory before the call,
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const4.c b/gcc/testsuite/c-c++-common/torture/strub-const4.c
index d819f54ec02..817e9fa2118 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-const wrapping call, we issue an
    asm statement to make sure the watermark passed to it is held in memory
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data1.c b/gcc/testsuite/c-c++-common/torture/strub-data1.c
index 7c27a2a1a6d..132ab63ef73 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointed-to data enables strubbing if accessed.  */
 int __attribute__ ((__strub__)) var;
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data2.c b/gcc/testsuite/c-c++-common/torture/strub-data2.c
index e66d903780a..b660702d26e 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointer itself is a strub variable, enabling internal strubbing when
    its value is used.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data3.c b/gcc/testsuite/c-c++-common/torture/strub-data3.c
index 5e08e0e58c6..fc44eef6f8f 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointer itself is a strub variable, that would enable internal strubbing
    if its value was used.  Here, it's only overwritten, so no strub.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data4.c b/gcc/testsuite/c-c++-common/torture/strub-data4.c
index a818e7a38bb..85e2f59055b 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointer itself is a strub variable, that would enable internal strubbing
    if its value was used.  Here, it's only overwritten, so no strub.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data5.c b/gcc/testsuite/c-c++-common/torture/strub-data5.c
index ddb0b5c0543..0a5edac414d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data5.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data5.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* It would be desirable to issue at least warnings for these.  */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
index c165f312f16..988954e7ed6 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 typedef void __attribute__ ((__strub__)) fntype ();
 fntype (*ptr);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
index 69fcff8d376..d3ca91389a7 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 typedef void __attribute__ ((__strub__)) fntype (int, int);
 fntype (*ptr);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
index ff006224909..89b5979cf7b 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 typedef void __attribute__ ((__strub__)) fntype (int, int, ...);
 fntype (*ptr);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
index 614b02228ba..4917dda8826 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed" } */
+/* { dg-require-effective-target strub } */
 
 inline void __attribute__ ((strub ("internal"), always_inline))
 inl_int_ali (void)
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
index f9a6b4a16fa..c45903856d4 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all" } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-inlinable1.c"
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
index b4a7f3992bb..b0d6139f0a8 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 typedef void ft (void);
 typedef void ft2 (int, int);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
index ef634d35126..1148c246f20 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -Wpedantic" } */
+/* { dg-require-effective-target strub } */
 
 /* C++ does not warn about the partial incompatibilities.
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
index e1f179e160e..06a72d86d2c 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
@@ -1,6 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -Wpedantic -fpermissive" } */
 /* { dg-prune-output "command-line option .-fpermissive." } */
+/* { dg-require-effective-target strub } */
 
 /* See strub-ptrfn2.c.  */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
index 70b558afad0..83ea1af7056 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed" } */
+/* { dg-require-effective-target strub } */
 
 /* This is strub-ptrfn2.c without -Wpedantic.
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure1.c b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
index a262a086837..2643136f178 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub pure function call, we issue an asm statement
    to make sure the watermark passed to it is not assumed to be unchanged.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure2.c b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
index 4c4bd50c209..8bda129b77d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-pure function call, we issue an asm
    statement to make sure the watermark passed to it is not assumed to be
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure3.c b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
index ce195c6b1f1..00bcbdd097a 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub pure wrapping call, we issue an asm statement
    to make sure the watermark passed to it is not assumed to be unchanged.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure4.c b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
index 75cd54ccb5b..ea7c40e7912 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-pure wrapping call, we issue an asm
    statement to make sure the watermark passed to it is not assumed to be
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run1.c b/gcc/testsuite/c-c++-common/torture/strub-run1.c
index 7458b3fb54d..fdf10042863 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run1.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a non-strub function leaves a string behind in the stack, and that
    equivalent strub functions don't.  Avoid the use of red zones by avoiding
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run2.c b/gcc/testsuite/c-c++-common/torture/strub-run2.c
index 5d60a7775f4..1228a665997 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run2.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a non-strub function leaves a string behind in the stack, and that
    equivalent strub functions don't.  Allow red zones to be used.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run3.c b/gcc/testsuite/c-c++-common/torture/strub-run3.c
index c2ad710858e..e5047a988f5 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run3.c
@@ -1,6 +1,7 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a non-strub function leaves a string behind in the stack, and that
    equivalent strub functions don't.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4.c b/gcc/testsuite/c-c++-common/torture/strub-run4.c
index 3b36b8e5d68..0e84a4bab80 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4.c
@@ -1,6 +1,7 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=all" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 /* Check that multi-level, multi-inlined functions still get cleaned up as
    expected, without overwriting temporary stack allocations while they should
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4c.c b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
index 57f9baf758d..edc98486dc9 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4c.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=at-calls" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-run4.c"
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4d.c b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
index 08de3f1c3b1..487ed08bb66 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4d.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
@@ -1,6 +1,7 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 #define ATTR_STRUB_AT_CALLS __attribute__ ((__strub__ ("at-calls")))
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4i.c b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
index 459f6886c54..a85447ffabf 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4i.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=internal" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-run4.c"
diff --git a/gcc/testsuite/g++.dg/strub-run1.C b/gcc/testsuite/g++.dg/strub-run1.C
index 0d367fb83d0..beb8b811f8f 100644
--- a/gcc/testsuite/g++.dg/strub-run1.C
+++ b/gcc/testsuite/g++.dg/strub-run1.C
@@ -1,5 +1,6 @@
 // { dg-do run }
 // { dg-options "-fstrub=internal" }
+// { dg-require-effective-target strub }
 
 // Check that we don't get extra copies.
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init1.C b/gcc/testsuite/g++.dg/torture/strub-init1.C
index c226ab10ff6..6ae45fadd70 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init1.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init1.C
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
 
 extern int __attribute__((__strub__)) initializer ();
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init2.C b/gcc/testsuite/g++.dg/torture/strub-init2.C
index a7911f1fa72..8f4849c7fde 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init2.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init2.C
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
 
 extern int __attribute__((__strub__)) initializer ();
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init3.C b/gcc/testsuite/g++.dg/torture/strub-init3.C
index 6ebebcd01e8..14f28e3c276 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init3.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init3.C
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
 
 extern int __attribute__((__strub__)) initializer ();
 
diff --git a/gcc/testsuite/gnat.dg/strub_access.adb b/gcc/testsuite/gnat.dg/strub_access.adb
index 29e6996ecf6..488a2d64afe 100644
--- a/gcc/testsuite/gnat.dg/strub_access.adb
+++ b/gcc/testsuite/gnat.dg/strub_access.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed -fdump-ipa-strubm" }
+--  { dg-require-effective-target strub }
 
 --  The main subprogram doesn't read from the automatic variable, but
 --  being an automatic variable, its presence should be enough for the
diff --git a/gcc/testsuite/gnat.dg/strub_access1.adb b/gcc/testsuite/gnat.dg/strub_access1.adb
index dae47060164..4a8653c4d84 100644
--- a/gcc/testsuite/gnat.dg/strub_access1.adb
+++ b/gcc/testsuite/gnat.dg/strub_access1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed" }
+--  { dg-require-effective-target strub }
 
 --  Check that we reject 'Access of a strub variable whose type does
 --  not carry a strub modifier.
diff --git a/gcc/testsuite/gnat.dg/strub_attr.adb b/gcc/testsuite/gnat.dg/strub_attr.adb
index 10445d7cf84..eb7826dc990 100644
--- a/gcc/testsuite/gnat.dg/strub_attr.adb
+++ b/gcc/testsuite/gnat.dg/strub_attr.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm -fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 package body Strub_Attr is
    E : exception;
diff --git a/gcc/testsuite/gnat.dg/strub_disp.adb b/gcc/testsuite/gnat.dg/strub_disp.adb
index 3dbcc4a357c..f23d4675def 100644
--- a/gcc/testsuite/gnat.dg/strub_disp.adb
+++ b/gcc/testsuite/gnat.dg/strub_disp.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Disp is
    package Foo is
diff --git a/gcc/testsuite/gnat.dg/strub_disp1.adb b/gcc/testsuite/gnat.dg/strub_disp1.adb
index 09756a74b7d..9c4c7f69637 100644
--- a/gcc/testsuite/gnat.dg/strub_disp1.adb
+++ b/gcc/testsuite/gnat.dg/strub_disp1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 -- Check that at-calls dispatching calls are transformed.
 
diff --git a/gcc/testsuite/gnat.dg/strub_ind.adb b/gcc/testsuite/gnat.dg/strub_ind.adb
index da56acaa957..613db69305e 100644
--- a/gcc/testsuite/gnat.dg/strub_ind.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict" }
+--  { dg-require-effective-target strub }
 
 --  This is essentially the same test as strub_attr.adb, 
 --  but applying attributes to access types as well.
diff --git a/gcc/testsuite/gnat.dg/strub_ind1.adb b/gcc/testsuite/gnat.dg/strub_ind1.adb
index 825e395e681..245b0a830f6 100644
--- a/gcc/testsuite/gnat.dg/strub_ind1.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm" }
+--  { dg-require-effective-target strub }
 
 --  This is essentially the same test as strub_attr.adb, 
 --  but with an explicit conversion.
diff --git a/gcc/testsuite/gnat.dg/strub_ind2.adb b/gcc/testsuite/gnat.dg/strub_ind2.adb
index e918b392631..b9bfe50e929 100644
--- a/gcc/testsuite/gnat.dg/strub_ind2.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind2.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict" }
+--  { dg-require-effective-target strub }
 
 --  This is essentially the same test as strub_attr.adb, 
 --  but with an explicit conversion.
diff --git a/gcc/testsuite/gnat.dg/strub_intf.adb b/gcc/testsuite/gnat.dg/strub_intf.adb
index 8f0212a7586..f43854705d0 100644
--- a/gcc/testsuite/gnat.dg/strub_intf.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 --  Check that strub mode mismatches between overrider and overridden
 --  subprograms are reported.
diff --git a/gcc/testsuite/gnat.dg/strub_intf1.adb b/gcc/testsuite/gnat.dg/strub_intf1.adb
index bf77321cef7..7a38a4c49ba 100644
--- a/gcc/testsuite/gnat.dg/strub_intf1.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 -- Check that at-calls dispatching calls to interfaces are transformed.
 
diff --git a/gcc/testsuite/gnat.dg/strub_intf2.adb b/gcc/testsuite/gnat.dg/strub_intf2.adb
index e8880dbc437..7992b7344fb 100644
--- a/gcc/testsuite/gnat.dg/strub_intf2.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf2.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 --  Check that strub mode mismatches between overrider and overridden
 --  subprograms are reported even when the overriders for an
diff --git a/gcc/testsuite/gnat.dg/strub_renm.adb b/gcc/testsuite/gnat.dg/strub_renm.adb
index 217367e712d..abfb120b514 100644
--- a/gcc/testsuite/gnat.dg/strub_renm.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Renm is
    procedure P (X : Integer);
diff --git a/gcc/testsuite/gnat.dg/strub_renm1.adb b/gcc/testsuite/gnat.dg/strub_renm1.adb
index a11adbfb5a9..68d3230b535 100644
--- a/gcc/testsuite/gnat.dg/strub_renm1.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed -fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Renm1 is
    V : Integer := 0;
diff --git a/gcc/testsuite/gnat.dg/strub_renm2.adb b/gcc/testsuite/gnat.dg/strub_renm2.adb
index c488c20826f..3cb81ea03f7 100644
--- a/gcc/testsuite/gnat.dg/strub_renm2.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm2.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Renm2 is
    V : Integer := 0;
diff --git a/gcc/testsuite/gnat.dg/strub_var.adb b/gcc/testsuite/gnat.dg/strub_var.adb
index 3d158de2803..7c6affa06d4 100644
--- a/gcc/testsuite/gnat.dg/strub_var.adb
+++ b/gcc/testsuite/gnat.dg/strub_var.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm" }
+--  { dg-require-effective-target strub }
 
 -- We don't read from the automatic variable, but being an automatic
 --  variable, its presence should be enough for the procedure to get
diff --git a/gcc/testsuite/gnat.dg/strub_var1.adb b/gcc/testsuite/gnat.dg/strub_var1.adb
index 6a504e09198..64b7e65fe9b 100644
--- a/gcc/testsuite/gnat.dg/strub_var1.adb
+++ b/gcc/testsuite/gnat.dg/strub_var1.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 with Strub_Attr;
 procedure Strub_Var1 is
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 3fcce6be49d..40a60c198cf 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -1302,6 +1302,13 @@ proc check_stack_check_available { stack_kind } {
     } "$stack_opt"]
 }
 
+# Return 1 if the target supports stack scrubbing.
+proc check_effective_target_strub {} {
+    return [check_no_compiler_messages strub assembly {
+	void __attribute__ ((__strub__)) fn (void) {}
+    } ""]
+}
+
 # Return 1 if compilation with -freorder-blocks-and-partition is error-free
 # for trivial code, 0 otherwise.  As some targets (ARM for example) only
 # warn when -fprofile-use is also supplied we test that combination too.
diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in
index d8163c5af99..3f77283490e 100644
--- a/libgcc/Makefile.in
+++ b/libgcc/Makefile.in
@@ -434,7 +434,7 @@ LIB2ADD += enable-execute-stack.c
 LIB2ADD += $(srcdir)/hardcfr.c
 
 # Stack scrubbing infrastructure.
-LIB2ADD += $(srcdir)/strub.c
+@HAVE_STRUB_SUPPORT@LIB2ADD += $(srcdir)/strub.c
 
 # While emutls.c has nothing to do with EH, it is in LIB2ADDEH*
 # instead of LIB2ADD because that's the way to be sure on some targets
diff --git a/libgcc/configure b/libgcc/configure
index cf149209652..567158955a3 100755
--- a/libgcc/configure
+++ b/libgcc/configure
@@ -593,6 +593,7 @@ asm_hidden_op
 extra_parts
 cpu_type
 get_gcc_base_ver
+HAVE_STRUB_SUPPORT
 thread_header
 tm_defines
 tm_file
@@ -5702,6 +5703,31 @@ esac
 
 
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for strub support" >&5
+$as_echo_n "checking for strub support... " >&6; }
+if ${libgcc_cv_strub_support+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+void __attribute__ ((__strub__)) fn (void) {}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  libgcc_cv_strub_support=yes
+else
+  libgcc_cv_strub_support=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgcc_cv_strub_support" >&5
+$as_echo "$libgcc_cv_strub_support" >&6; }
+if test "x$libgcc_cv_strub_support" != xno; then
+  HAVE_STRUB_SUPPORT=
+else
+  HAVE_STRUB_SUPPORT='# '
+fi
+
+
 # Determine what GCC version number to use in filesystem paths.
 
   get_gcc_base_ver="cat"
diff --git a/libgcc/configure.ac b/libgcc/configure.ac
index 2fc9d5d7c93..9c0e415501a 100644
--- a/libgcc/configure.ac
+++ b/libgcc/configure.ac
@@ -694,6 +694,19 @@ AC_SUBST(tm_defines)
 # Map from thread model to thread header.
 GCC_AC_THREAD_HEADER([$target_thread_file])
 
+AC_CACHE_CHECK([for strub support],
+  [libgcc_cv_strub_support],
+  [AC_COMPILE_IFELSE(
+    [AC_LANG_SOURCE([void __attribute__ ((__strub__)) fn (void) {}])],
+    [libgcc_cv_strub_support=yes],
+    [libgcc_cv_strub_support=no])])
+if test "x$libgcc_cv_strub_support" != xno; then
+  HAVE_STRUB_SUPPORT=
+else
+  HAVE_STRUB_SUPPORT='# '
+fi
+AC_SUBST(HAVE_STRUB_SUPPORT)
+
 # Determine what GCC version number to use in filesystem paths.
 GCC_BASE_VER

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [gcc(refs/users/aoliva/heads/testme)] strub: enable conditional support
@ 2023-12-07  1:43 Alexandre Oliva
  0 siblings, 0 replies; 25+ messages in thread
From: Alexandre Oliva @ 2023-12-07  1:43 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:4f9417cbb0c8e36f4c0f24c4821b16a1d3fd0f32

commit 4f9417cbb0c8e36f4c0f24c4821b16a1d3fd0f32
Author: Alexandre Oliva <oliva@adacore.com>
Date:   Wed Dec 6 19:36:02 2023 -0300

    strub: enable conditional support
    
    Targets that don't expose callee stacks to callers, such as nvptx, as
    well as -fsplit-stack compilations, violate fundamental assumptions of
    the current strub implementation.  This patch enables targets to
    disable strub, and disables it when -fsplit-stack is enabled.
    
    When strub support is disabled, the testsuite will now skip strub
    tests, and libgcc will not build the strub runtime components.
    
    
    for  gcc/ChangeLog
    
            * target.def (have_strub_support_for): New hook.
            * doc/tm.texi.in: Document it.
            * doc/tm.texi: Rebuild.
            * ipa-strub.cc: Include target.h.
            (strub_target_support_p): New.
            (can_strub_p): Call it.  Test for no flag_split_stack.
            (pass_ipa_strub::adjust_at_calls_call): Check for target
            support.
            * config/nvptx/nvptx.cc (TARGET_HAVE_STRUB_SUPPORT_FOR):
            Disable.
            * doc/sourcebuild.texi (strub): Document new effective
            target.
    
    for  gcc/testsuite/ChangeLog
    
            * gcc.dg/strub-split-stack.c: New.
            * gcc.dg/strub-unsupported.c: New.
            * gcc.dg/strub-unsupported-2.c: New.
            * gcc.dg/strub-unsupported-3.c: New.
            * lib/target-supports.exp (check_effective_target_strub): New.
            * c-c++-common/strub-O0.c: Require effective target strub.
            * c-c++-common/strub-O1.c: Likewise.
            * c-c++-common/strub-O2.c: Likewise.
            * c-c++-common/strub-O2fni.c: Likewise.
            * c-c++-common/strub-O3.c: Likewise.
            * c-c++-common/strub-O3fni.c: Likewise.
            * c-c++-common/strub-Og.c: Likewise.
            * c-c++-common/strub-Os.c: Likewise.
            * c-c++-common/strub-all1.c: Likewise.
            * c-c++-common/strub-all2.c: Likewise.
            * c-c++-common/strub-apply1.c: Likewise.
            * c-c++-common/strub-apply2.c: Likewise.
            * c-c++-common/strub-apply3.c: Likewise.
            * c-c++-common/strub-apply4.c: Likewise.
            * c-c++-common/strub-at-calls1.c: Likewise.
            * c-c++-common/strub-at-calls2.c: Likewise.
            * c-c++-common/strub-defer-O1.c: Likewise.
            * c-c++-common/strub-defer-O2.c: Likewise.
            * c-c++-common/strub-defer-O3.c: Likewise.
            * c-c++-common/strub-defer-Os.c: Likewise.
            * c-c++-common/strub-internal1.c: Likewise.
            * c-c++-common/strub-internal2.c: Likewise.
            * c-c++-common/strub-parms1.c: Likewise.
            * c-c++-common/strub-parms2.c: Likewise.
            * c-c++-common/strub-parms3.c: Likewise.
            * c-c++-common/strub-relaxed1.c: Likewise.
            * c-c++-common/strub-relaxed2.c: Likewise.
            * c-c++-common/strub-short-O0-exc.c: Likewise.
            * c-c++-common/strub-short-O0.c: Likewise.
            * c-c++-common/strub-short-O1.c: Likewise.
            * c-c++-common/strub-short-O2.c: Likewise.
            * c-c++-common/strub-short-O3.c: Likewise.
            * c-c++-common/strub-short-Os.c: Likewise.
            * c-c++-common/strub-strict1.c: Likewise.
            * c-c++-common/strub-strict2.c: Likewise.
            * c-c++-common/strub-tail-O1.c: Likewise.
            * c-c++-common/strub-tail-O2.c: Likewise.
            * c-c++-common/strub-var1.c: Likewise.
            * c-c++-common/torture/strub-callable1.c: Likewise.
            * c-c++-common/torture/strub-callable2.c: Likewise.
            * c-c++-common/torture/strub-const1.c: Likewise.
            * c-c++-common/torture/strub-const2.c: Likewise.
            * c-c++-common/torture/strub-const3.c: Likewise.
            * c-c++-common/torture/strub-const4.c: Likewise.
            * c-c++-common/torture/strub-data1.c: Likewise.
            * c-c++-common/torture/strub-data2.c: Likewise.
            * c-c++-common/torture/strub-data3.c: Likewise.
            * c-c++-common/torture/strub-data4.c: Likewise.
            * c-c++-common/torture/strub-data5.c: Likewise.
            * c-c++-common/torture/strub-indcall1.c: Likewise.
            * c-c++-common/torture/strub-indcall2.c: Likewise.
            * c-c++-common/torture/strub-indcall3.c: Likewise.
            * c-c++-common/torture/strub-inlinable1.c: Likewise.
            * c-c++-common/torture/strub-inlinable2.c: Likewise.
            * c-c++-common/torture/strub-ptrfn1.c: Likewise.
            * c-c++-common/torture/strub-ptrfn2.c: Likewise.
            * c-c++-common/torture/strub-ptrfn3.c: Likewise.
            * c-c++-common/torture/strub-ptrfn4.c: Likewise.
            * c-c++-common/torture/strub-pure1.c: Likewise.
            * c-c++-common/torture/strub-pure2.c: Likewise.
            * c-c++-common/torture/strub-pure3.c: Likewise.
            * c-c++-common/torture/strub-pure4.c: Likewise.
            * c-c++-common/torture/strub-run1.c: Likewise.
            * c-c++-common/torture/strub-run2.c: Likewise.
            * c-c++-common/torture/strub-run3.c: Likewise.
            * c-c++-common/torture/strub-run4.c: Likewise.
            * c-c++-common/torture/strub-run4c.c: Likewise.
            * c-c++-common/torture/strub-run4d.c: Likewise.
            * c-c++-common/torture/strub-run4i.c: Likewise.
            * g++.dg/strub-run1.C: Likewise.
            * g++.dg/torture/strub-init1.C: Likewise.
            * g++.dg/torture/strub-init2.C: Likewise.
            * g++.dg/torture/strub-init3.C: Likewise.
            * gnat.dg/strub_attr.adb: Likewise.
            * gnat.dg/strub_ind.adb: Likewise.
            * gnat.dg/strub_access.adb: Likewise.
            * gnat.dg/strub_access1.adb: Likewise.
            * gnat.dg/strub_disp.adb: Likewise.
            * gnat.dg/strub_disp1.adb: Likewise.
            * gnat.dg/strub_ind1.adb: Likewise.
            * gnat.dg/strub_ind2.adb: Likewise.
            * gnat.dg/strub_intf.adb: Likewise.
            * gnat.dg/strub_intf1.adb: Likewise.
            * gnat.dg/strub_intf2.adb: Likewise.
            * gnat.dg/strub_renm.adb: Likewise.
            * gnat.dg/strub_renm1.adb: Likewise.
            * gnat.dg/strub_renm2.adb: Likewise.
            * gnat.dg/strub_var.adb: Likewise.
            * gnat.dg/strub_var1.adb: Likewise.
    
    for  libgcc/ChangeLog
    
            * configure.ac: Check for strub support.
            * configure: Rebuilt.
            * Makefile.in: Compile strub.c conditionally.

Diff:
---
 gcc/config/nvptx/nvptx.cc                          |  3 ++
 gcc/doc/sourcebuild.texi                           |  3 ++
 gcc/doc/tm.texi                                    |  6 +++
 gcc/doc/tm.texi.in                                 |  2 +
 gcc/ipa-strub.cc                                   | 54 +++++++++++++++++++++-
 gcc/target.def                                     |  8 ++++
 gcc/testsuite/c-c++-common/strub-O0.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O1.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O2.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O2fni.c           |  1 +
 gcc/testsuite/c-c++-common/strub-O3.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O3fni.c           |  1 +
 gcc/testsuite/c-c++-common/strub-Og.c              |  1 +
 gcc/testsuite/c-c++-common/strub-Os.c              |  1 +
 gcc/testsuite/c-c++-common/strub-all1.c            |  1 +
 gcc/testsuite/c-c++-common/strub-all2.c            |  1 +
 gcc/testsuite/c-c++-common/strub-apply1.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply2.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply3.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply4.c          |  1 +
 gcc/testsuite/c-c++-common/strub-at-calls1.c       |  1 +
 gcc/testsuite/c-c++-common/strub-at-calls2.c       |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O3.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-Os.c        |  1 +
 gcc/testsuite/c-c++-common/strub-internal1.c       |  1 +
 gcc/testsuite/c-c++-common/strub-internal2.c       |  1 +
 gcc/testsuite/c-c++-common/strub-parms1.c          |  1 +
 gcc/testsuite/c-c++-common/strub-parms2.c          |  1 +
 gcc/testsuite/c-c++-common/strub-parms3.c          |  1 +
 gcc/testsuite/c-c++-common/strub-relaxed1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-relaxed2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O0-exc.c    |  1 +
 gcc/testsuite/c-c++-common/strub-short-O0.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O3.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-Os.c        |  1 +
 gcc/testsuite/c-c++-common/strub-split-stack.c     | 10 ++++
 gcc/testsuite/c-c++-common/strub-strict1.c         |  1 +
 gcc/testsuite/c-c++-common/strub-strict2.c         |  1 +
 gcc/testsuite/c-c++-common/strub-tail-O1.c         |  1 +
 gcc/testsuite/c-c++-common/strub-tail-O2.c         |  1 +
 gcc/testsuite/c-c++-common/strub-unsupported-2.c   | 13 ++++++
 gcc/testsuite/c-c++-common/strub-unsupported-3.c   | 18 ++++++++
 gcc/testsuite/c-c++-common/strub-unsupported.c     | 21 +++++++++
 gcc/testsuite/c-c++-common/strub-var1.c            |  1 +
 .../c-c++-common/torture/strub-callable1.c         |  1 +
 .../c-c++-common/torture/strub-callable2.c         |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const1.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const2.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const3.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const4.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data1.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data2.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data3.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data4.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data5.c   |  1 +
 .../c-c++-common/torture/strub-indcall1.c          |  1 +
 .../c-c++-common/torture/strub-indcall2.c          |  1 +
 .../c-c++-common/torture/strub-indcall3.c          |  1 +
 .../c-c++-common/torture/strub-inlinable1.c        |  1 +
 .../c-c++-common/torture/strub-inlinable2.c        |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure1.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure2.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure3.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure4.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run1.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run2.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run3.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4c.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4d.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4i.c   |  1 +
 gcc/testsuite/g++.dg/strub-run1.C                  |  1 +
 gcc/testsuite/g++.dg/torture/strub-init1.C         |  1 +
 gcc/testsuite/g++.dg/torture/strub-init2.C         |  1 +
 gcc/testsuite/g++.dg/torture/strub-init3.C         |  1 +
 gcc/testsuite/gnat.dg/strub_access.adb             |  1 +
 gcc/testsuite/gnat.dg/strub_access1.adb            |  1 +
 gcc/testsuite/gnat.dg/strub_attr.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_disp.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_disp1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_ind.adb                |  1 +
 gcc/testsuite/gnat.dg/strub_ind1.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_ind2.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_intf.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_intf1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_intf2.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_renm.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_renm1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_renm2.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_var.adb                |  1 +
 gcc/testsuite/gnat.dg/strub_var1.adb               |  1 +
 gcc/testsuite/lib/target-supports.exp              |  7 +++
 libgcc/Makefile.in                                 |  2 +-
 libgcc/configure                                   | 26 +++++++++++
 libgcc/configure.ac                                | 13 ++++++
 103 files changed, 272 insertions(+), 3 deletions(-)

diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc
index ae20802c879..3fb1deb70fd 100644
--- a/gcc/config/nvptx/nvptx.cc
+++ b/gcc/config/nvptx/nvptx.cc
@@ -7789,6 +7789,9 @@ nvptx_asm_output_def_from_decls (FILE *stream, tree name, tree value)
 #undef TARGET_LIBC_HAS_FUNCTION
 #define TARGET_LIBC_HAS_FUNCTION nvptx_libc_has_function
 
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-nvptx.h"
diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi
index c9909026854..26a7e9c3507 100644
--- a/gcc/doc/sourcebuild.texi
+++ b/gcc/doc/sourcebuild.texi
@@ -2983,6 +2983,9 @@ Target supports statically linking @samp{libgfortran}.
 @item string_merging
 Target supports merging string constants at link time.
 
+@item strub
+Target supports attribute @code{strub} for stack scrubbing.
+
 @item ucn
 Target supports compiling and assembling UCN.
 
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 89a1735dd79..768ada0af52 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -3450,6 +3450,12 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@deftypefn {Target Hook} bool TARGET_HAVE_STRUB_SUPPORT_FOR (tree)
+Returns true if the target supports stack scrubbing for the given function
+or type, otherwise return false.  The default implementation always returns
+true.
+@end deftypefn
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index ebc1d3de5ca..4fe0805394e 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2686,6 +2686,8 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@hook TARGET_HAVE_STRUB_SUPPORT_FOR
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
index 293bec132b8..2afb7a45575 100644
--- a/gcc/ipa-strub.cc
+++ b/gcc/ipa-strub.cc
@@ -60,6 +60,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-strub.h"
 #include "symtab-thunks.h"
 #include "attr-fnspec.h"
+#include "target.h"
 
 /* This file introduces two passes that, together, implement
    machine-independent stack scrubbing, strub for short.  It arranges
@@ -631,17 +632,60 @@ strub_always_inline_p (cgraph_node *node)
   return lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl));
 }
 
+/* Return TRUE iff the target has strub support for T, a function
+   decl, or a type used in an indirect call, and optionally REPORT the
+   reasons for ineligibility.  If T is a type and error REPORTing is
+   enabled, the LOCation (of the indirect call) should be provided.  */
+static inline bool
+strub_target_support_p (tree t, bool report = false,
+			location_t loc = UNKNOWN_LOCATION)
+{
+  bool result = true;
+
+  if (!targetm.have_strub_support_for (t))
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      if (DECL_P (t))
+	sorry_at (DECL_SOURCE_LOCATION (t),
+		  "%qD is not eligible for %<strub%>"
+		  " on the target system", t);
+      else
+	sorry_at (loc,
+		  "unsupported %<strub%> call"
+		  " on the target system");
+    }
+
+  return result;
+}
+
 /* Return TRUE iff NODE is potentially eligible for any strub-enabled mode, and
    optionally REPORT the reasons for ineligibility.  */
 
 static inline bool
 can_strub_p (cgraph_node *node, bool report = false)
 {
-  bool result = true;
+  bool result = strub_target_support_p (node->decl, report);
 
-  if (!report && strub_always_inline_p (node))
+  if (!report && (!result || strub_always_inline_p (node)))
     return result;
 
+  if (flag_split_stack)
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (node->decl),
+		"%qD is not eligible for %<strub%>"
+		" because %<-fsplit-stack%> is enabled",
+		node->decl);
+    }
+
   if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
     {
       result = false;
@@ -2417,6 +2461,12 @@ pass_ipa_strub::adjust_at_calls_call (cgraph_edge *e, int named_args,
 			 && (TREE_TYPE (gimple_call_arg (ocall, named_args))
 			     == get_pwmt ())));
 
+  tree tsup;
+  if (!(tsup = gimple_call_fndecl (ocall)))
+    tsup = TREE_TYPE (TREE_TYPE (gimple_call_fn (ocall)));
+  if (!strub_target_support_p (tsup, true, gimple_location (ocall)))
+    return;
+
   /* If we're already within a strub context, pass on the incoming watermark
      pointer, and omit the enter and leave calls around the modified call, as an
      optimization, or as a means to satisfy a tail-call requirement.  */
diff --git a/gcc/target.def b/gcc/target.def
index 52b83e091b9..08218f3a42a 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4457,6 +4457,14 @@ otherwise return false.  The default implementation always returns true.",
  bool, (void),
  hook_bool_void_true)
 
+DEFHOOK
+(have_strub_support_for,
+ "Returns true if the target supports stack scrubbing for the given function\n\
+or type, otherwise return false.  The default implementation always returns\n\
+true.",
+ bool, (tree),
+ hook_bool_tree_true)
+
 DEFHOOK
 (have_speculation_safe_value,
 "This hook is used to determine the level of target support for\n\
diff --git a/gcc/testsuite/c-c++-common/strub-O0.c b/gcc/testsuite/c-c++-common/strub-O0.c
index c7a79a6ea0d..f0a3f7b4c6f 100644
--- a/gcc/testsuite/c-c++-common/strub-O0.c
+++ b/gcc/testsuite/c-c++-common/strub-O0.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -O0, none of the strub builtins are expanded inline.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O1.c b/gcc/testsuite/c-c++-common/strub-O1.c
index 96285c975d9..50403426b18 100644
--- a/gcc/testsuite/c-c++-common/strub-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -O1, without -fno-inline, we fully expand enter, but neither update nor
    leave.  */
diff --git a/gcc/testsuite/c-c++-common/strub-O2.c b/gcc/testsuite/c-c++-common/strub-O2.c
index 8edc0d8aa13..37e02998e31 100644
--- a/gcc/testsuite/c-c++-common/strub-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -O2, without -fno-inline, we fully expand enter and update, and add a test
    around the leave call.  */
diff --git a/gcc/testsuite/c-c++-common/strub-O2fni.c b/gcc/testsuite/c-c++-common/strub-O2fni.c
index c6d900cf3c4..905e2c6b2ff 100644
--- a/gcc/testsuite/c-c++-common/strub-O2fni.c
+++ b/gcc/testsuite/c-c++-common/strub-O2fni.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
+/* { dg-require-effective-target strub } */
 
 /* With -fno-inline, none of the strub builtins are inlined.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O3.c b/gcc/testsuite/c-c++-common/strub-O3.c
index 33ee465e51c..3bbf132bdf1 100644
--- a/gcc/testsuite/c-c++-common/strub-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-O3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 int __attribute__ ((__strub__)) var;
 
diff --git a/gcc/testsuite/c-c++-common/strub-O3fni.c b/gcc/testsuite/c-c++-common/strub-O3fni.c
index 2936f82079e..c46fce38e5c 100644
--- a/gcc/testsuite/c-c++-common/strub-O3fni.c
+++ b/gcc/testsuite/c-c++-common/strub-O3fni.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
+/* { dg-require-effective-target strub } */
 
 /* With -fno-inline, none of the strub builtins are inlined.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-Og.c b/gcc/testsuite/c-c++-common/strub-Og.c
index 479746e57d8..3b8eb19765c 100644
--- a/gcc/testsuite/c-c++-common/strub-Og.c
+++ b/gcc/testsuite/c-c++-common/strub-Og.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-Og -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -Og, without -fno-inline, we fully expand enter, but neither update nor
    leave.  */
diff --git a/gcc/testsuite/c-c++-common/strub-Os.c b/gcc/testsuite/c-c++-common/strub-Os.c
index 2241d4ea07f..8cfb253d676 100644
--- a/gcc/testsuite/c-c++-common/strub-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-Os.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-Os -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -Os, without -fno-inline, we fully expand enter, and also update.  The
    expanded update might be larger than a call proper, but argument saving and
diff --git a/gcc/testsuite/c-c++-common/strub-all1.c b/gcc/testsuite/c-c++-common/strub-all1.c
index a322bcc5da6..2037f681f29 100644
--- a/gcc/testsuite/c-c++-common/strub-all1.c
+++ b/gcc/testsuite/c-c++-common/strub-all1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
    strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub.  */
diff --git a/gcc/testsuite/c-c++-common/strub-all2.c b/gcc/testsuite/c-c++-common/strub-all2.c
index db60026d0e0..c026e7d9d28 100644
--- a/gcc/testsuite/c-c++-common/strub-all2.c
+++ b/gcc/testsuite/c-c++-common/strub-all2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* g becomes STRUB_INTERNAL, because of the flag.  Without inline, force_output
    is set for static non-inline functions when not optimizing, and that keeps
diff --git a/gcc/testsuite/c-c++-common/strub-apply1.c b/gcc/testsuite/c-c++-common/strub-apply1.c
index 2f462adc1ef..3edc89c54ee 100644
--- a/gcc/testsuite/c-c++-common/strub-apply1.c
+++ b/gcc/testsuite/c-c++-common/strub-apply1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 void __attribute__ ((__strub__ ("callable")))
 apply_function (void *args)
diff --git a/gcc/testsuite/c-c++-common/strub-apply2.c b/gcc/testsuite/c-c++-common/strub-apply2.c
index a5d7551f5da..838fc752734 100644
--- a/gcc/testsuite/c-c++-common/strub-apply2.c
+++ b/gcc/testsuite/c-c++-common/strub-apply2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 extern void __attribute__ ((__strub__))
 apply_function (void *args);
diff --git a/gcc/testsuite/c-c++-common/strub-apply3.c b/gcc/testsuite/c-c++-common/strub-apply3.c
index 64422a0d1e8..0206e4d930e 100644
--- a/gcc/testsuite/c-c++-common/strub-apply3.c
+++ b/gcc/testsuite/c-c++-common/strub-apply3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 void __attribute__ ((__strub__))
 apply_function (void *args)
diff --git a/gcc/testsuite/c-c++-common/strub-apply4.c b/gcc/testsuite/c-c++-common/strub-apply4.c
index 15ffaa031b8..e82504728b2 100644
--- a/gcc/testsuite/c-c++-common/strub-apply4.c
+++ b/gcc/testsuite/c-c++-common/strub-apply4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that implicit enabling of strub mode selects internal strub when the
    function uses __builtin_apply_args, that prevents the optimization to
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls1.c b/gcc/testsuite/c-c++-common/strub-at-calls1.c
index b70843b4215..a20acc0a48a 100644
--- a/gcc/testsuite/c-c++-common/strub-at-calls1.c
+++ b/gcc/testsuite/c-c++-common/strub-at-calls1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
    strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub.  */
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls2.c b/gcc/testsuite/c-c++-common/strub-at-calls2.c
index 97a3988a6b9..7915b33a39a 100644
--- a/gcc/testsuite/c-c++-common/strub-at-calls2.c
+++ b/gcc/testsuite/c-c++-common/strub-at-calls2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* g does NOT become STRUB_AT_CALLS because it's not viable.  Without inline,
    force_output is set for static non-inline functions when not optimizing, and
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O1.c b/gcc/testsuite/c-c++-common/strub-defer-O1.c
index 3d73431b3dc..3689998b5a3 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O1" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function does NOT defer
    the strubbing to its caller at -O1.  */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O2.c b/gcc/testsuite/c-c++-common/strub-defer-O2.c
index fddf3c745e7..9e01949db6b 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O2" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function does NOT defer
    the strubbing to its caller at -O2.  */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O3.c b/gcc/testsuite/c-c++-common/strub-defer-O3.c
index 7ebc65b58dd..40ee8edd1e0 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O3.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O3" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function defers the
    strubbing to its caller at -O3.  */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-Os.c b/gcc/testsuite/c-c++-common/strub-defer-Os.c
index fbaf85fe0fa..67ea9f04639 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-Os.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -Os" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function defers the
    strubbing to its caller at -Os.  */
diff --git a/gcc/testsuite/c-c++-common/strub-internal1.c b/gcc/testsuite/c-c++-common/strub-internal1.c
index e9d7b7b9ee0..d17254904e5 100644
--- a/gcc/testsuite/c-c++-common/strub-internal1.c
+++ b/gcc/testsuite/c-c++-common/strub-internal1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
    strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub.  */
diff --git a/gcc/testsuite/c-c++-common/strub-internal2.c b/gcc/testsuite/c-c++-common/strub-internal2.c
index 8b8e15a51c7..afc9189701f 100644
--- a/gcc/testsuite/c-c++-common/strub-internal2.c
+++ b/gcc/testsuite/c-c++-common/strub-internal2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* g becomes STRUB_INTERNAL, because of the flag.  */
 static void
diff --git a/gcc/testsuite/c-c++-common/strub-parms1.c b/gcc/testsuite/c-c++-common/strub-parms1.c
index 0a4a7539d34..f410b268971 100644
--- a/gcc/testsuite/c-c++-common/strub-parms1.c
+++ b/gcc/testsuite/c-c++-common/strub-parms1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 #include <stdarg.h>
 
diff --git a/gcc/testsuite/c-c++-common/strub-parms2.c b/gcc/testsuite/c-c++-common/strub-parms2.c
index 147171d96d5..6f572115a88 100644
--- a/gcc/testsuite/c-c++-common/strub-parms2.c
+++ b/gcc/testsuite/c-c++-common/strub-parms2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 #include <stdarg.h>
 
diff --git a/gcc/testsuite/c-c++-common/strub-parms3.c b/gcc/testsuite/c-c++-common/strub-parms3.c
index 4e92682895a..7383fea9ce8 100644
--- a/gcc/testsuite/c-c++-common/strub-parms3.c
+++ b/gcc/testsuite/c-c++-common/strub-parms3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that uses of a strub variable implicitly enables internal strub for
    publicly-visible functions, and causes the same transformations to their
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed1.c b/gcc/testsuite/c-c++-common/strub-relaxed1.c
index e2f9d8aebca..d2b4b52c51e 100644
--- a/gcc/testsuite/c-c++-common/strub-relaxed1.c
+++ b/gcc/testsuite/c-c++-common/strub-relaxed1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The difference between relaxed and strict in this case is that we accept the
    call from one internal-strub function to another.  Without the error,
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed2.c b/gcc/testsuite/c-c++-common/strub-relaxed2.c
index 98474435d2e..9e5a8e76b6c 100644
--- a/gcc/testsuite/c-c++-common/strub-relaxed2.c
+++ b/gcc/testsuite/c-c++-common/strub-relaxed2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The difference between relaxed and strict in this case is that we accept the
    call from one internal-strub function to another.  */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
index 1de15342595..aaeba2a2159 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fexceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0.c b/gcc/testsuite/c-c++-common/strub-short-O0.c
index f9209c81900..30cbdd819f1 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O0.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O0.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O1.c b/gcc/testsuite/c-c++-common/strub-short-O1.c
index bed1dcfb54a..911fdfb6db9 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O2.c b/gcc/testsuite/c-c++-common/strub-short-O2.c
index 6bf0071f52b..9b23ee3ac33 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O3.c b/gcc/testsuite/c-c++-common/strub-short-O3.c
index 4732f515bf7..4b3a8f843ea 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  At -O3 and -Os, we omit
    enter and leave calls within strub contexts, passing on the enclosing
diff --git a/gcc/testsuite/c-c++-common/strub-short-Os.c b/gcc/testsuite/c-c++-common/strub-short-Os.c
index 8d6424c479a..3627a240600 100644
--- a/gcc/testsuite/c-c++-common/strub-short-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-short-Os.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-Os -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  At -O3 and -Os, we omit
    enter and leave calls within strub contexts, passing on the enclosing
diff --git a/gcc/testsuite/c-c++-common/strub-split-stack.c b/gcc/testsuite/c-c++-common/strub-split-stack.c
new file mode 100644
index 00000000000..acbd750c3cd
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-split-stack.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-fsplit-stack" } */
+/* { dg-require-effective-target strub } */
+/* { dg-require-effective-target split-stack } */
+
+void __attribute__ ((__strub__))
+f {} /* { dg-message "not eligible" }
+
+void __attribute__ ((__strub__ ("internal")))
+g {} /* { dg-message "not eligible" }
diff --git a/gcc/testsuite/c-c++-common/strub-strict1.c b/gcc/testsuite/c-c++-common/strub-strict1.c
index 36852244206..503eb1734e3 100644
--- a/gcc/testsuite/c-c++-common/strub-strict1.c
+++ b/gcc/testsuite/c-c++-common/strub-strict1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
 
 static int __attribute__ ((__strub__)) var;
 
diff --git a/gcc/testsuite/c-c++-common/strub-strict2.c b/gcc/testsuite/c-c++-common/strub-strict2.c
index b4f28883218..3bf1aa30b4a 100644
--- a/gcc/testsuite/c-c++-common/strub-strict2.c
+++ b/gcc/testsuite/c-c++-common/strub-strict2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
 
 static int __attribute__ ((__strub__)) var;
 
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O1.c b/gcc/testsuite/c-c++-common/strub-tail-O1.c
index e48e0610e07..ba4b1623e28 100644
--- a/gcc/testsuite/c-c++-common/strub-tail-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-tail-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-tail-O2.c"
 
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O2.c b/gcc/testsuite/c-c++-common/strub-tail-O2.c
index 87cda7ab21b..043813b1de4 100644
--- a/gcc/testsuite/c-c++-common/strub-tail-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-tail-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.
    Tail calls are short-circuited at -O2+.  */
diff --git a/gcc/testsuite/c-c++-common/strub-unsupported-2.c b/gcc/testsuite/c-c++-common/strub-unsupported-2.c
new file mode 100644
index 00000000000..3586f4f679d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-unsupported-2.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+
+/* Check that, when strub is not supported (so no dg-required-effective-target
+   strub above), we report when pointers to strub functions are called.  This
+   cannot be part of strub-unsupported.c because errors in the strub-mode pass
+   prevent the main strub pass, where errors at calls are detected, from
+   running.  */
+
+void __attribute__ ((__strub__ ("at-calls"))) (*p) (void);
+
+void m () {
+  p (); /* { dg-message "unsupported" "" { target { ! strub } } } */
+}
diff --git a/gcc/testsuite/c-c++-common/strub-unsupported-3.c b/gcc/testsuite/c-c++-common/strub-unsupported-3.c
new file mode 100644
index 00000000000..d6fb4c525c4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-unsupported-3.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+
+/* Check that, when strub is not supported (so no dg-required-effective-target
+   strub above), we report when strub functions that are not defined are
+   called.  This cannot be part of strub-unsupported-2.c because errors in the
+   strub-mode pass prevent the main strub pass, where errors at calls are
+   detected, from running.  */
+
+extern void __attribute__ ((__strub__))
+s (void); /* { dg-message "not eligible|requested" "" { target { ! strub } } } */
+
+extern void __attribute__ ((__strub__ ("internal")))
+t (void); /* { dg-message "not eligible|requested" "" { target { ! strub } } } */
+
+void m () {
+  s ();
+  t ();
+}
diff --git a/gcc/testsuite/c-c++-common/strub-unsupported.c b/gcc/testsuite/c-c++-common/strub-unsupported.c
new file mode 100644
index 00000000000..cb5c4049495
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-unsupported.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+
+/* Check that, when strub is not supported (so no dg-required-effective-target
+   strub above), we report when strub functions are defined, and when they're
+   called in ways that would require changes.  */
+
+void __attribute__ ((__strub__))
+f (void) {} /* { dg-message "not eligible|requested" "" { target { ! strub } } } */
+
+void __attribute__ ((__strub__ ("internal")))
+g (void) {} /* { dg-message "not eligible|requested" "" { target { ! strub } } } */
+
+/* This only gets an error when called, see strub-unsupported-2.c.  */
+void __attribute__ ((__strub__ ("at-calls"))) (*p) (void);
+
+/* These too, see strub-unsupported-3.c.  */
+extern void __attribute__ ((__strub__))
+s (void);
+
+extern void __attribute__ ((__strub__ ("internal")))
+t (void);
diff --git a/gcc/testsuite/c-c++-common/strub-var1.c b/gcc/testsuite/c-c++-common/strub-var1.c
index eb6250fd39c..67014aa5de8 100644
--- a/gcc/testsuite/c-c++-common/strub-var1.c
+++ b/gcc/testsuite/c-c++-common/strub-var1.c
@@ -1,4 +1,5 @@
 /* { dg-do compile } */
+/* { dg-require-effective-target strub } */
 
 int __attribute__ ((strub)) x;
 float __attribute__ ((strub)) f;
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable1.c b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
index b5e45ab0525..86dbee6746d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-callable1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that strub and non-strub functions can be called from non-strub
    contexts, and that strub and callable functions can be called from strub
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable2.c b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
index 96aa7fe4b07..9da120f6156 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-callable2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that impermissible (cross-strub-context) calls are reported.  */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const1.c b/gcc/testsuite/c-c++-common/torture/strub-const1.c
index 5e956cb1a9b..22056713cce 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub const function call, we issue an asm
    statement to make sure the watermark passed to it is held in memory before
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const2.c b/gcc/testsuite/c-c++-common/torture/strub-const2.c
index 73d650292df..a105c66d7a9 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-const function call, we issue an
    asm statement to make sure the watermark passed to it is held in memory
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const3.c b/gcc/testsuite/c-c++-common/torture/strub-const3.c
index 2584f1f974a..386200c2784 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub const wrapping call, we issue an asm statement
    to make sure the watermark passed to it is held in memory before the call,
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const4.c b/gcc/testsuite/c-c++-common/torture/strub-const4.c
index d819f54ec02..817e9fa2118 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-const wrapping call, we issue an
    asm statement to make sure the watermark passed to it is held in memory
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data1.c b/gcc/testsuite/c-c++-common/torture/strub-data1.c
index 7c27a2a1a6d..132ab63ef73 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointed-to data enables strubbing if accessed.  */
 int __attribute__ ((__strub__)) var;
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data2.c b/gcc/testsuite/c-c++-common/torture/strub-data2.c
index e66d903780a..b660702d26e 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointer itself is a strub variable, enabling internal strubbing when
    its value is used.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data3.c b/gcc/testsuite/c-c++-common/torture/strub-data3.c
index 5e08e0e58c6..fc44eef6f8f 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointer itself is a strub variable, that would enable internal strubbing
    if its value was used.  Here, it's only overwritten, so no strub.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data4.c b/gcc/testsuite/c-c++-common/torture/strub-data4.c
index a818e7a38bb..85e2f59055b 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointer itself is a strub variable, that would enable internal strubbing
    if its value was used.  Here, it's only overwritten, so no strub.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data5.c b/gcc/testsuite/c-c++-common/torture/strub-data5.c
index ddb0b5c0543..0a5edac414d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data5.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data5.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* It would be desirable to issue at least warnings for these.  */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
index c165f312f16..988954e7ed6 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 typedef void __attribute__ ((__strub__)) fntype ();
 fntype (*ptr);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
index 69fcff8d376..d3ca91389a7 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 typedef void __attribute__ ((__strub__)) fntype (int, int);
 fntype (*ptr);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
index ff006224909..89b5979cf7b 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 typedef void __attribute__ ((__strub__)) fntype (int, int, ...);
 fntype (*ptr);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
index 614b02228ba..4917dda8826 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed" } */
+/* { dg-require-effective-target strub } */
 
 inline void __attribute__ ((strub ("internal"), always_inline))
 inl_int_ali (void)
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
index f9a6b4a16fa..c45903856d4 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all" } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-inlinable1.c"
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
index b4a7f3992bb..b0d6139f0a8 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 typedef void ft (void);
 typedef void ft2 (int, int);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
index ef634d35126..1148c246f20 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -Wpedantic" } */
+/* { dg-require-effective-target strub } */
 
 /* C++ does not warn about the partial incompatibilities.
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
index e1f179e160e..06a72d86d2c 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
@@ -1,6 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -Wpedantic -fpermissive" } */
 /* { dg-prune-output "command-line option .-fpermissive." } */
+/* { dg-require-effective-target strub } */
 
 /* See strub-ptrfn2.c.  */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
index 70b558afad0..83ea1af7056 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed" } */
+/* { dg-require-effective-target strub } */
 
 /* This is strub-ptrfn2.c without -Wpedantic.
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure1.c b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
index a262a086837..2643136f178 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub pure function call, we issue an asm statement
    to make sure the watermark passed to it is not assumed to be unchanged.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure2.c b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
index 4c4bd50c209..8bda129b77d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-pure function call, we issue an asm
    statement to make sure the watermark passed to it is not assumed to be
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure3.c b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
index ce195c6b1f1..00bcbdd097a 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub pure wrapping call, we issue an asm statement
    to make sure the watermark passed to it is not assumed to be unchanged.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure4.c b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
index 75cd54ccb5b..ea7c40e7912 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-pure wrapping call, we issue an asm
    statement to make sure the watermark passed to it is not assumed to be
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run1.c b/gcc/testsuite/c-c++-common/torture/strub-run1.c
index 7458b3fb54d..fdf10042863 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run1.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a non-strub function leaves a string behind in the stack, and that
    equivalent strub functions don't.  Avoid the use of red zones by avoiding
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run2.c b/gcc/testsuite/c-c++-common/torture/strub-run2.c
index 5d60a7775f4..1228a665997 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run2.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a non-strub function leaves a string behind in the stack, and that
    equivalent strub functions don't.  Allow red zones to be used.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run3.c b/gcc/testsuite/c-c++-common/torture/strub-run3.c
index c2ad710858e..e5047a988f5 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run3.c
@@ -1,6 +1,7 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a non-strub function leaves a string behind in the stack, and that
    equivalent strub functions don't.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4.c b/gcc/testsuite/c-c++-common/torture/strub-run4.c
index 3b36b8e5d68..0e84a4bab80 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4.c
@@ -1,6 +1,7 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=all" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 /* Check that multi-level, multi-inlined functions still get cleaned up as
    expected, without overwriting temporary stack allocations while they should
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4c.c b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
index 57f9baf758d..edc98486dc9 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4c.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=at-calls" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-run4.c"
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4d.c b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
index 08de3f1c3b1..487ed08bb66 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4d.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
@@ -1,6 +1,7 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 #define ATTR_STRUB_AT_CALLS __attribute__ ((__strub__ ("at-calls")))
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4i.c b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
index 459f6886c54..a85447ffabf 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4i.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=internal" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-run4.c"
diff --git a/gcc/testsuite/g++.dg/strub-run1.C b/gcc/testsuite/g++.dg/strub-run1.C
index 0d367fb83d0..beb8b811f8f 100644
--- a/gcc/testsuite/g++.dg/strub-run1.C
+++ b/gcc/testsuite/g++.dg/strub-run1.C
@@ -1,5 +1,6 @@
 // { dg-do run }
 // { dg-options "-fstrub=internal" }
+// { dg-require-effective-target strub }
 
 // Check that we don't get extra copies.
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init1.C b/gcc/testsuite/g++.dg/torture/strub-init1.C
index c226ab10ff6..6ae45fadd70 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init1.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init1.C
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
 
 extern int __attribute__((__strub__)) initializer ();
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init2.C b/gcc/testsuite/g++.dg/torture/strub-init2.C
index a7911f1fa72..8f4849c7fde 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init2.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init2.C
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
 
 extern int __attribute__((__strub__)) initializer ();
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init3.C b/gcc/testsuite/g++.dg/torture/strub-init3.C
index 6ebebcd01e8..14f28e3c276 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init3.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init3.C
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
 
 extern int __attribute__((__strub__)) initializer ();
 
diff --git a/gcc/testsuite/gnat.dg/strub_access.adb b/gcc/testsuite/gnat.dg/strub_access.adb
index 29e6996ecf6..488a2d64afe 100644
--- a/gcc/testsuite/gnat.dg/strub_access.adb
+++ b/gcc/testsuite/gnat.dg/strub_access.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed -fdump-ipa-strubm" }
+--  { dg-require-effective-target strub }
 
 --  The main subprogram doesn't read from the automatic variable, but
 --  being an automatic variable, its presence should be enough for the
diff --git a/gcc/testsuite/gnat.dg/strub_access1.adb b/gcc/testsuite/gnat.dg/strub_access1.adb
index dae47060164..4a8653c4d84 100644
--- a/gcc/testsuite/gnat.dg/strub_access1.adb
+++ b/gcc/testsuite/gnat.dg/strub_access1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed" }
+--  { dg-require-effective-target strub }
 
 --  Check that we reject 'Access of a strub variable whose type does
 --  not carry a strub modifier.
diff --git a/gcc/testsuite/gnat.dg/strub_attr.adb b/gcc/testsuite/gnat.dg/strub_attr.adb
index 10445d7cf84..eb7826dc990 100644
--- a/gcc/testsuite/gnat.dg/strub_attr.adb
+++ b/gcc/testsuite/gnat.dg/strub_attr.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm -fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 package body Strub_Attr is
    E : exception;
diff --git a/gcc/testsuite/gnat.dg/strub_disp.adb b/gcc/testsuite/gnat.dg/strub_disp.adb
index 3dbcc4a357c..f23d4675def 100644
--- a/gcc/testsuite/gnat.dg/strub_disp.adb
+++ b/gcc/testsuite/gnat.dg/strub_disp.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Disp is
    package Foo is
diff --git a/gcc/testsuite/gnat.dg/strub_disp1.adb b/gcc/testsuite/gnat.dg/strub_disp1.adb
index 09756a74b7d..9c4c7f69637 100644
--- a/gcc/testsuite/gnat.dg/strub_disp1.adb
+++ b/gcc/testsuite/gnat.dg/strub_disp1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 -- Check that at-calls dispatching calls are transformed.
 
diff --git a/gcc/testsuite/gnat.dg/strub_ind.adb b/gcc/testsuite/gnat.dg/strub_ind.adb
index da56acaa957..613db69305e 100644
--- a/gcc/testsuite/gnat.dg/strub_ind.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict" }
+--  { dg-require-effective-target strub }
 
 --  This is essentially the same test as strub_attr.adb, 
 --  but applying attributes to access types as well.
diff --git a/gcc/testsuite/gnat.dg/strub_ind1.adb b/gcc/testsuite/gnat.dg/strub_ind1.adb
index 825e395e681..245b0a830f6 100644
--- a/gcc/testsuite/gnat.dg/strub_ind1.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm" }
+--  { dg-require-effective-target strub }
 
 --  This is essentially the same test as strub_attr.adb, 
 --  but with an explicit conversion.
diff --git a/gcc/testsuite/gnat.dg/strub_ind2.adb b/gcc/testsuite/gnat.dg/strub_ind2.adb
index e918b392631..b9bfe50e929 100644
--- a/gcc/testsuite/gnat.dg/strub_ind2.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind2.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict" }
+--  { dg-require-effective-target strub }
 
 --  This is essentially the same test as strub_attr.adb, 
 --  but with an explicit conversion.
diff --git a/gcc/testsuite/gnat.dg/strub_intf.adb b/gcc/testsuite/gnat.dg/strub_intf.adb
index 8f0212a7586..f43854705d0 100644
--- a/gcc/testsuite/gnat.dg/strub_intf.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 --  Check that strub mode mismatches between overrider and overridden
 --  subprograms are reported.
diff --git a/gcc/testsuite/gnat.dg/strub_intf1.adb b/gcc/testsuite/gnat.dg/strub_intf1.adb
index bf77321cef7..7a38a4c49ba 100644
--- a/gcc/testsuite/gnat.dg/strub_intf1.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 -- Check that at-calls dispatching calls to interfaces are transformed.
 
diff --git a/gcc/testsuite/gnat.dg/strub_intf2.adb b/gcc/testsuite/gnat.dg/strub_intf2.adb
index e8880dbc437..7992b7344fb 100644
--- a/gcc/testsuite/gnat.dg/strub_intf2.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf2.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 --  Check that strub mode mismatches between overrider and overridden
 --  subprograms are reported even when the overriders for an
diff --git a/gcc/testsuite/gnat.dg/strub_renm.adb b/gcc/testsuite/gnat.dg/strub_renm.adb
index 217367e712d..abfb120b514 100644
--- a/gcc/testsuite/gnat.dg/strub_renm.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Renm is
    procedure P (X : Integer);
diff --git a/gcc/testsuite/gnat.dg/strub_renm1.adb b/gcc/testsuite/gnat.dg/strub_renm1.adb
index a11adbfb5a9..68d3230b535 100644
--- a/gcc/testsuite/gnat.dg/strub_renm1.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed -fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Renm1 is
    V : Integer := 0;
diff --git a/gcc/testsuite/gnat.dg/strub_renm2.adb b/gcc/testsuite/gnat.dg/strub_renm2.adb
index c488c20826f..3cb81ea03f7 100644
--- a/gcc/testsuite/gnat.dg/strub_renm2.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm2.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Renm2 is
    V : Integer := 0;
diff --git a/gcc/testsuite/gnat.dg/strub_var.adb b/gcc/testsuite/gnat.dg/strub_var.adb
index 3d158de2803..7c6affa06d4 100644
--- a/gcc/testsuite/gnat.dg/strub_var.adb
+++ b/gcc/testsuite/gnat.dg/strub_var.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm" }
+--  { dg-require-effective-target strub }
 
 -- We don't read from the automatic variable, but being an automatic
 --  variable, its presence should be enough for the procedure to get
diff --git a/gcc/testsuite/gnat.dg/strub_var1.adb b/gcc/testsuite/gnat.dg/strub_var1.adb
index 6a504e09198..64b7e65fe9b 100644
--- a/gcc/testsuite/gnat.dg/strub_var1.adb
+++ b/gcc/testsuite/gnat.dg/strub_var1.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 with Strub_Attr;
 procedure Strub_Var1 is
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 3fcce6be49d..40a60c198cf 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -1302,6 +1302,13 @@ proc check_stack_check_available { stack_kind } {
     } "$stack_opt"]
 }
 
+# Return 1 if the target supports stack scrubbing.
+proc check_effective_target_strub {} {
+    return [check_no_compiler_messages strub assembly {
+	void __attribute__ ((__strub__)) fn (void) {}
+    } ""]
+}
+
 # Return 1 if compilation with -freorder-blocks-and-partition is error-free
 # for trivial code, 0 otherwise.  As some targets (ARM for example) only
 # warn when -fprofile-use is also supplied we test that combination too.
diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in
index d8163c5af99..3f77283490e 100644
--- a/libgcc/Makefile.in
+++ b/libgcc/Makefile.in
@@ -434,7 +434,7 @@ LIB2ADD += enable-execute-stack.c
 LIB2ADD += $(srcdir)/hardcfr.c
 
 # Stack scrubbing infrastructure.
-LIB2ADD += $(srcdir)/strub.c
+@HAVE_STRUB_SUPPORT@LIB2ADD += $(srcdir)/strub.c
 
 # While emutls.c has nothing to do with EH, it is in LIB2ADDEH*
 # instead of LIB2ADD because that's the way to be sure on some targets
diff --git a/libgcc/configure b/libgcc/configure
index cf149209652..567158955a3 100755
--- a/libgcc/configure
+++ b/libgcc/configure
@@ -593,6 +593,7 @@ asm_hidden_op
 extra_parts
 cpu_type
 get_gcc_base_ver
+HAVE_STRUB_SUPPORT
 thread_header
 tm_defines
 tm_file
@@ -5702,6 +5703,31 @@ esac
 
 
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for strub support" >&5
+$as_echo_n "checking for strub support... " >&6; }
+if ${libgcc_cv_strub_support+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+void __attribute__ ((__strub__)) fn (void) {}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  libgcc_cv_strub_support=yes
+else
+  libgcc_cv_strub_support=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgcc_cv_strub_support" >&5
+$as_echo "$libgcc_cv_strub_support" >&6; }
+if test "x$libgcc_cv_strub_support" != xno; then
+  HAVE_STRUB_SUPPORT=
+else
+  HAVE_STRUB_SUPPORT='# '
+fi
+
+
 # Determine what GCC version number to use in filesystem paths.
 
   get_gcc_base_ver="cat"
diff --git a/libgcc/configure.ac b/libgcc/configure.ac
index 2fc9d5d7c93..9c0e415501a 100644
--- a/libgcc/configure.ac
+++ b/libgcc/configure.ac
@@ -694,6 +694,19 @@ AC_SUBST(tm_defines)
 # Map from thread model to thread header.
 GCC_AC_THREAD_HEADER([$target_thread_file])
 
+AC_CACHE_CHECK([for strub support],
+  [libgcc_cv_strub_support],
+  [AC_COMPILE_IFELSE(
+    [AC_LANG_SOURCE([void __attribute__ ((__strub__)) fn (void) {}])],
+    [libgcc_cv_strub_support=yes],
+    [libgcc_cv_strub_support=no])])
+if test "x$libgcc_cv_strub_support" != xno; then
+  HAVE_STRUB_SUPPORT=
+else
+  HAVE_STRUB_SUPPORT='# '
+fi
+AC_SUBST(HAVE_STRUB_SUPPORT)
+
 # Determine what GCC version number to use in filesystem paths.
 GCC_BASE_VER

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [gcc(refs/users/aoliva/heads/testme)] strub: enable conditional support
@ 2023-12-07  1:42 Alexandre Oliva
  0 siblings, 0 replies; 25+ messages in thread
From: Alexandre Oliva @ 2023-12-07  1:42 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:2936565c8c0ab56ce1b0aa418c1c5488f18f54d9

commit 2936565c8c0ab56ce1b0aa418c1c5488f18f54d9
Author: Alexandre Oliva <oliva@adacore.com>
Date:   Wed Dec 6 19:36:02 2023 -0300

    strub: enable conditional support
    
    Targets that don't expose callee stacks to callers, such as nvptx, as
    well as -fsplit-stack compilations, violate fundamental assumptions of
    the current strub implementation.  This patch enables targets to
    disable strub, and disables it when -fsplit-stack is enabled.
    
    When strub support is disabled, the testsuite will now skip strub
    tests, and libgcc will not build the strub runtime components.
    
    
    for  gcc/ChangeLog
    
            * target.def (have_strub_support_for): New hook.
            * doc/tm.texi.in: Document it.
            * doc/tm.texi: Rebuild.
            * ipa-strub.cc: Include target.h.
            (strub_target_support_p): New.
            (can_strub_p): Call it.  Test for no flag_split_stack.
            (pass_ipa_strub::adjust_at_calls_call): Check for target
            support.
            * config/nvptx/nvptx.cc (TARGET_HAVE_STRUB_SUPPORT_FOR):
            Disable.
            * doc/sourcebuild.texi (strub): Document new effective
            target.
    
    for  gcc/testsuite/ChangeLog
    
            * gcc.dg/strub-split-stack.c: New.
            * gcc.dg/strub-unsupported.c: New.
            * gcc.dg/strub-unsupported-2.c: New.
            * gcc.dg/strub-unsupported-3.c: New.
            * lib/target-supports.exp (check_effective_target_strub): New.
            * c-c++-common/strub-O0.c: Require effective target strub.
            * c-c++-common/strub-O1.c: Likewise.
            * c-c++-common/strub-O2.c: Likewise.
            * c-c++-common/strub-O2fni.c: Likewise.
            * c-c++-common/strub-O3.c: Likewise.
            * c-c++-common/strub-O3fni.c: Likewise.
            * c-c++-common/strub-Og.c: Likewise.
            * c-c++-common/strub-Os.c: Likewise.
            * c-c++-common/strub-all1.c: Likewise.
            * c-c++-common/strub-all2.c: Likewise.
            * c-c++-common/strub-apply1.c: Likewise.
            * c-c++-common/strub-apply2.c: Likewise.
            * c-c++-common/strub-apply3.c: Likewise.
            * c-c++-common/strub-apply4.c: Likewise.
            * c-c++-common/strub-at-calls1.c: Likewise.
            * c-c++-common/strub-at-calls2.c: Likewise.
            * c-c++-common/strub-defer-O1.c: Likewise.
            * c-c++-common/strub-defer-O2.c: Likewise.
            * c-c++-common/strub-defer-O3.c: Likewise.
            * c-c++-common/strub-defer-Os.c: Likewise.
            * c-c++-common/strub-internal1.c: Likewise.
            * c-c++-common/strub-internal2.c: Likewise.
            * c-c++-common/strub-parms1.c: Likewise.
            * c-c++-common/strub-parms2.c: Likewise.
            * c-c++-common/strub-parms3.c: Likewise.
            * c-c++-common/strub-relaxed1.c: Likewise.
            * c-c++-common/strub-relaxed2.c: Likewise.
            * c-c++-common/strub-short-O0-exc.c: Likewise.
            * c-c++-common/strub-short-O0.c: Likewise.
            * c-c++-common/strub-short-O1.c: Likewise.
            * c-c++-common/strub-short-O2.c: Likewise.
            * c-c++-common/strub-short-O3.c: Likewise.
            * c-c++-common/strub-short-Os.c: Likewise.
            * c-c++-common/strub-strict1.c: Likewise.
            * c-c++-common/strub-strict2.c: Likewise.
            * c-c++-common/strub-tail-O1.c: Likewise.
            * c-c++-common/strub-tail-O2.c: Likewise.
            * c-c++-common/strub-var1.c: Likewise.
            * c-c++-common/torture/strub-callable1.c: Likewise.
            * c-c++-common/torture/strub-callable2.c: Likewise.
            * c-c++-common/torture/strub-const1.c: Likewise.
            * c-c++-common/torture/strub-const2.c: Likewise.
            * c-c++-common/torture/strub-const3.c: Likewise.
            * c-c++-common/torture/strub-const4.c: Likewise.
            * c-c++-common/torture/strub-data1.c: Likewise.
            * c-c++-common/torture/strub-data2.c: Likewise.
            * c-c++-common/torture/strub-data3.c: Likewise.
            * c-c++-common/torture/strub-data4.c: Likewise.
            * c-c++-common/torture/strub-data5.c: Likewise.
            * c-c++-common/torture/strub-indcall1.c: Likewise.
            * c-c++-common/torture/strub-indcall2.c: Likewise.
            * c-c++-common/torture/strub-indcall3.c: Likewise.
            * c-c++-common/torture/strub-inlinable1.c: Likewise.
            * c-c++-common/torture/strub-inlinable2.c: Likewise.
            * c-c++-common/torture/strub-ptrfn1.c: Likewise.
            * c-c++-common/torture/strub-ptrfn2.c: Likewise.
            * c-c++-common/torture/strub-ptrfn3.c: Likewise.
            * c-c++-common/torture/strub-ptrfn4.c: Likewise.
            * c-c++-common/torture/strub-pure1.c: Likewise.
            * c-c++-common/torture/strub-pure2.c: Likewise.
            * c-c++-common/torture/strub-pure3.c: Likewise.
            * c-c++-common/torture/strub-pure4.c: Likewise.
            * c-c++-common/torture/strub-run1.c: Likewise.
            * c-c++-common/torture/strub-run2.c: Likewise.
            * c-c++-common/torture/strub-run3.c: Likewise.
            * c-c++-common/torture/strub-run4.c: Likewise.
            * c-c++-common/torture/strub-run4c.c: Likewise.
            * c-c++-common/torture/strub-run4d.c: Likewise.
            * c-c++-common/torture/strub-run4i.c: Likewise.
            * g++.dg/strub-run1.C: Likewise.
            * g++.dg/torture/strub-init1.C: Likewise.
            * g++.dg/torture/strub-init2.C: Likewise.
            * g++.dg/torture/strub-init3.C: Likewise.
            * gnat.dg/strub_attr.adb: Likewise.
            * gnat.dg/strub_ind.adb: Likewise.
            * gnat.dg/strub_access.adb: Likewise.
            * gnat.dg/strub_access1.adb: Likewise.
            * gnat.dg/strub_disp.adb: Likewise.
            * gnat.dg/strub_disp1.adb: Likewise.
            * gnat.dg/strub_ind1.adb: Likewise.
            * gnat.dg/strub_ind2.adb: Likewise.
            * gnat.dg/strub_intf.adb: Likewise.
            * gnat.dg/strub_intf1.adb: Likewise.
            * gnat.dg/strub_intf2.adb: Likewise.
            * gnat.dg/strub_renm.adb: Likewise.
            * gnat.dg/strub_renm1.adb: Likewise.
            * gnat.dg/strub_renm2.adb: Likewise.
            * gnat.dg/strub_var.adb: Likewise.
            * gnat.dg/strub_var1.adb: Likewise.
    
    for  libgcc/ChangeLog
    
            * configure.ac: Check for strub support.
            * configure: Rebuilt.
            * Makefile.in: Compile strub.c conditionally.

Diff:
---
 gcc/config/i386/i386.cc                            |  4 ++
 gcc/config/nvptx/nvptx.cc                          |  3 ++
 gcc/doc/sourcebuild.texi                           |  3 ++
 gcc/doc/tm.texi                                    |  6 +++
 gcc/doc/tm.texi.in                                 |  2 +
 gcc/ipa-strub.cc                                   | 54 +++++++++++++++++++++-
 gcc/target.def                                     |  8 ++++
 gcc/testsuite/c-c++-common/strub-O0.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O1.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O2.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O2fni.c           |  1 +
 gcc/testsuite/c-c++-common/strub-O3.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O3fni.c           |  1 +
 gcc/testsuite/c-c++-common/strub-Og.c              |  1 +
 gcc/testsuite/c-c++-common/strub-Os.c              |  1 +
 gcc/testsuite/c-c++-common/strub-all1.c            |  1 +
 gcc/testsuite/c-c++-common/strub-all2.c            |  1 +
 gcc/testsuite/c-c++-common/strub-apply1.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply2.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply3.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply4.c          |  1 +
 gcc/testsuite/c-c++-common/strub-at-calls1.c       |  1 +
 gcc/testsuite/c-c++-common/strub-at-calls2.c       |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O3.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-Os.c        |  1 +
 gcc/testsuite/c-c++-common/strub-internal1.c       |  1 +
 gcc/testsuite/c-c++-common/strub-internal2.c       |  1 +
 gcc/testsuite/c-c++-common/strub-parms1.c          |  1 +
 gcc/testsuite/c-c++-common/strub-parms2.c          |  1 +
 gcc/testsuite/c-c++-common/strub-parms3.c          |  1 +
 gcc/testsuite/c-c++-common/strub-relaxed1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-relaxed2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O0-exc.c    |  1 +
 gcc/testsuite/c-c++-common/strub-short-O0.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O3.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-Os.c        |  1 +
 gcc/testsuite/c-c++-common/strub-split-stack.c     | 10 ++++
 gcc/testsuite/c-c++-common/strub-strict1.c         |  1 +
 gcc/testsuite/c-c++-common/strub-strict2.c         |  1 +
 gcc/testsuite/c-c++-common/strub-tail-O1.c         |  1 +
 gcc/testsuite/c-c++-common/strub-tail-O2.c         |  1 +
 gcc/testsuite/c-c++-common/strub-unsupported-2.c   | 13 ++++++
 gcc/testsuite/c-c++-common/strub-unsupported-3.c   | 18 ++++++++
 gcc/testsuite/c-c++-common/strub-unsupported.c     | 21 +++++++++
 gcc/testsuite/c-c++-common/strub-var1.c            |  1 +
 .../c-c++-common/torture/strub-callable1.c         |  1 +
 .../c-c++-common/torture/strub-callable2.c         |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const1.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const2.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const3.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const4.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data1.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data2.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data3.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data4.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data5.c   |  1 +
 .../c-c++-common/torture/strub-indcall1.c          |  1 +
 .../c-c++-common/torture/strub-indcall2.c          |  1 +
 .../c-c++-common/torture/strub-indcall3.c          |  1 +
 .../c-c++-common/torture/strub-inlinable1.c        |  1 +
 .../c-c++-common/torture/strub-inlinable2.c        |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure1.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure2.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure3.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure4.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run1.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run2.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run3.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4c.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4d.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4i.c   |  1 +
 gcc/testsuite/g++.dg/strub-run1.C                  |  1 +
 gcc/testsuite/g++.dg/torture/strub-init1.C         |  1 +
 gcc/testsuite/g++.dg/torture/strub-init2.C         |  1 +
 gcc/testsuite/g++.dg/torture/strub-init3.C         |  1 +
 gcc/testsuite/gnat.dg/strub_access.adb             |  1 +
 gcc/testsuite/gnat.dg/strub_access1.adb            |  1 +
 gcc/testsuite/gnat.dg/strub_attr.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_disp.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_disp1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_ind.adb                |  1 +
 gcc/testsuite/gnat.dg/strub_ind1.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_ind2.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_intf.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_intf1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_intf2.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_renm.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_renm1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_renm2.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_var.adb                |  1 +
 gcc/testsuite/gnat.dg/strub_var1.adb               |  1 +
 gcc/testsuite/lib/target-supports.exp              |  7 +++
 libgcc/Makefile.in                                 |  2 +-
 libgcc/configure                                   | 26 +++++++++++
 libgcc/configure.ac                                | 13 ++++++
 104 files changed, 276 insertions(+), 3 deletions(-)

diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 7c5cab4e2c6..f933c9c23c7 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -26658,6 +26658,10 @@ ix86_libm_function_max_error (unsigned cfn, machine_mode mode,
 #define TARGET_RUN_TARGET_SELFTESTS selftest::ix86_run_selftests
 #endif /* #if CHECKING_P */
 
+// ??? for testing only
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 #include "gt-i386.h"
diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc
index ae20802c879..3fb1deb70fd 100644
--- a/gcc/config/nvptx/nvptx.cc
+++ b/gcc/config/nvptx/nvptx.cc
@@ -7789,6 +7789,9 @@ nvptx_asm_output_def_from_decls (FILE *stream, tree name, tree value)
 #undef TARGET_LIBC_HAS_FUNCTION
 #define TARGET_LIBC_HAS_FUNCTION nvptx_libc_has_function
 
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-nvptx.h"
diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi
index c9909026854..26a7e9c3507 100644
--- a/gcc/doc/sourcebuild.texi
+++ b/gcc/doc/sourcebuild.texi
@@ -2983,6 +2983,9 @@ Target supports statically linking @samp{libgfortran}.
 @item string_merging
 Target supports merging string constants at link time.
 
+@item strub
+Target supports attribute @code{strub} for stack scrubbing.
+
 @item ucn
 Target supports compiling and assembling UCN.
 
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 89a1735dd79..768ada0af52 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -3450,6 +3450,12 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@deftypefn {Target Hook} bool TARGET_HAVE_STRUB_SUPPORT_FOR (tree)
+Returns true if the target supports stack scrubbing for the given function
+or type, otherwise return false.  The default implementation always returns
+true.
+@end deftypefn
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index ebc1d3de5ca..4fe0805394e 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2686,6 +2686,8 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@hook TARGET_HAVE_STRUB_SUPPORT_FOR
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
index 293bec132b8..2afb7a45575 100644
--- a/gcc/ipa-strub.cc
+++ b/gcc/ipa-strub.cc
@@ -60,6 +60,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-strub.h"
 #include "symtab-thunks.h"
 #include "attr-fnspec.h"
+#include "target.h"
 
 /* This file introduces two passes that, together, implement
    machine-independent stack scrubbing, strub for short.  It arranges
@@ -631,17 +632,60 @@ strub_always_inline_p (cgraph_node *node)
   return lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl));
 }
 
+/* Return TRUE iff the target has strub support for T, a function
+   decl, or a type used in an indirect call, and optionally REPORT the
+   reasons for ineligibility.  If T is a type and error REPORTing is
+   enabled, the LOCation (of the indirect call) should be provided.  */
+static inline bool
+strub_target_support_p (tree t, bool report = false,
+			location_t loc = UNKNOWN_LOCATION)
+{
+  bool result = true;
+
+  if (!targetm.have_strub_support_for (t))
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      if (DECL_P (t))
+	sorry_at (DECL_SOURCE_LOCATION (t),
+		  "%qD is not eligible for %<strub%>"
+		  " on the target system", t);
+      else
+	sorry_at (loc,
+		  "unsupported %<strub%> call"
+		  " on the target system");
+    }
+
+  return result;
+}
+
 /* Return TRUE iff NODE is potentially eligible for any strub-enabled mode, and
    optionally REPORT the reasons for ineligibility.  */
 
 static inline bool
 can_strub_p (cgraph_node *node, bool report = false)
 {
-  bool result = true;
+  bool result = strub_target_support_p (node->decl, report);
 
-  if (!report && strub_always_inline_p (node))
+  if (!report && (!result || strub_always_inline_p (node)))
     return result;
 
+  if (flag_split_stack)
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (node->decl),
+		"%qD is not eligible for %<strub%>"
+		" because %<-fsplit-stack%> is enabled",
+		node->decl);
+    }
+
   if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
     {
       result = false;
@@ -2417,6 +2461,12 @@ pass_ipa_strub::adjust_at_calls_call (cgraph_edge *e, int named_args,
 			 && (TREE_TYPE (gimple_call_arg (ocall, named_args))
 			     == get_pwmt ())));
 
+  tree tsup;
+  if (!(tsup = gimple_call_fndecl (ocall)))
+    tsup = TREE_TYPE (TREE_TYPE (gimple_call_fn (ocall)));
+  if (!strub_target_support_p (tsup, true, gimple_location (ocall)))
+    return;
+
   /* If we're already within a strub context, pass on the incoming watermark
      pointer, and omit the enter and leave calls around the modified call, as an
      optimization, or as a means to satisfy a tail-call requirement.  */
diff --git a/gcc/target.def b/gcc/target.def
index 52b83e091b9..08218f3a42a 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4457,6 +4457,14 @@ otherwise return false.  The default implementation always returns true.",
  bool, (void),
  hook_bool_void_true)
 
+DEFHOOK
+(have_strub_support_for,
+ "Returns true if the target supports stack scrubbing for the given function\n\
+or type, otherwise return false.  The default implementation always returns\n\
+true.",
+ bool, (tree),
+ hook_bool_tree_true)
+
 DEFHOOK
 (have_speculation_safe_value,
 "This hook is used to determine the level of target support for\n\
diff --git a/gcc/testsuite/c-c++-common/strub-O0.c b/gcc/testsuite/c-c++-common/strub-O0.c
index c7a79a6ea0d..f0a3f7b4c6f 100644
--- a/gcc/testsuite/c-c++-common/strub-O0.c
+++ b/gcc/testsuite/c-c++-common/strub-O0.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -O0, none of the strub builtins are expanded inline.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O1.c b/gcc/testsuite/c-c++-common/strub-O1.c
index 96285c975d9..50403426b18 100644
--- a/gcc/testsuite/c-c++-common/strub-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -O1, without -fno-inline, we fully expand enter, but neither update nor
    leave.  */
diff --git a/gcc/testsuite/c-c++-common/strub-O2.c b/gcc/testsuite/c-c++-common/strub-O2.c
index 8edc0d8aa13..37e02998e31 100644
--- a/gcc/testsuite/c-c++-common/strub-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -O2, without -fno-inline, we fully expand enter and update, and add a test
    around the leave call.  */
diff --git a/gcc/testsuite/c-c++-common/strub-O2fni.c b/gcc/testsuite/c-c++-common/strub-O2fni.c
index c6d900cf3c4..905e2c6b2ff 100644
--- a/gcc/testsuite/c-c++-common/strub-O2fni.c
+++ b/gcc/testsuite/c-c++-common/strub-O2fni.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
+/* { dg-require-effective-target strub } */
 
 /* With -fno-inline, none of the strub builtins are inlined.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O3.c b/gcc/testsuite/c-c++-common/strub-O3.c
index 33ee465e51c..3bbf132bdf1 100644
--- a/gcc/testsuite/c-c++-common/strub-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-O3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 int __attribute__ ((__strub__)) var;
 
diff --git a/gcc/testsuite/c-c++-common/strub-O3fni.c b/gcc/testsuite/c-c++-common/strub-O3fni.c
index 2936f82079e..c46fce38e5c 100644
--- a/gcc/testsuite/c-c++-common/strub-O3fni.c
+++ b/gcc/testsuite/c-c++-common/strub-O3fni.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
+/* { dg-require-effective-target strub } */
 
 /* With -fno-inline, none of the strub builtins are inlined.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-Og.c b/gcc/testsuite/c-c++-common/strub-Og.c
index 479746e57d8..3b8eb19765c 100644
--- a/gcc/testsuite/c-c++-common/strub-Og.c
+++ b/gcc/testsuite/c-c++-common/strub-Og.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-Og -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -Og, without -fno-inline, we fully expand enter, but neither update nor
    leave.  */
diff --git a/gcc/testsuite/c-c++-common/strub-Os.c b/gcc/testsuite/c-c++-common/strub-Os.c
index 2241d4ea07f..8cfb253d676 100644
--- a/gcc/testsuite/c-c++-common/strub-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-Os.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-Os -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -Os, without -fno-inline, we fully expand enter, and also update.  The
    expanded update might be larger than a call proper, but argument saving and
diff --git a/gcc/testsuite/c-c++-common/strub-all1.c b/gcc/testsuite/c-c++-common/strub-all1.c
index a322bcc5da6..2037f681f29 100644
--- a/gcc/testsuite/c-c++-common/strub-all1.c
+++ b/gcc/testsuite/c-c++-common/strub-all1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
    strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub.  */
diff --git a/gcc/testsuite/c-c++-common/strub-all2.c b/gcc/testsuite/c-c++-common/strub-all2.c
index db60026d0e0..c026e7d9d28 100644
--- a/gcc/testsuite/c-c++-common/strub-all2.c
+++ b/gcc/testsuite/c-c++-common/strub-all2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* g becomes STRUB_INTERNAL, because of the flag.  Without inline, force_output
    is set for static non-inline functions when not optimizing, and that keeps
diff --git a/gcc/testsuite/c-c++-common/strub-apply1.c b/gcc/testsuite/c-c++-common/strub-apply1.c
index 2f462adc1ef..3edc89c54ee 100644
--- a/gcc/testsuite/c-c++-common/strub-apply1.c
+++ b/gcc/testsuite/c-c++-common/strub-apply1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 void __attribute__ ((__strub__ ("callable")))
 apply_function (void *args)
diff --git a/gcc/testsuite/c-c++-common/strub-apply2.c b/gcc/testsuite/c-c++-common/strub-apply2.c
index a5d7551f5da..838fc752734 100644
--- a/gcc/testsuite/c-c++-common/strub-apply2.c
+++ b/gcc/testsuite/c-c++-common/strub-apply2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 extern void __attribute__ ((__strub__))
 apply_function (void *args);
diff --git a/gcc/testsuite/c-c++-common/strub-apply3.c b/gcc/testsuite/c-c++-common/strub-apply3.c
index 64422a0d1e8..0206e4d930e 100644
--- a/gcc/testsuite/c-c++-common/strub-apply3.c
+++ b/gcc/testsuite/c-c++-common/strub-apply3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 void __attribute__ ((__strub__))
 apply_function (void *args)
diff --git a/gcc/testsuite/c-c++-common/strub-apply4.c b/gcc/testsuite/c-c++-common/strub-apply4.c
index 15ffaa031b8..e82504728b2 100644
--- a/gcc/testsuite/c-c++-common/strub-apply4.c
+++ b/gcc/testsuite/c-c++-common/strub-apply4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that implicit enabling of strub mode selects internal strub when the
    function uses __builtin_apply_args, that prevents the optimization to
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls1.c b/gcc/testsuite/c-c++-common/strub-at-calls1.c
index b70843b4215..a20acc0a48a 100644
--- a/gcc/testsuite/c-c++-common/strub-at-calls1.c
+++ b/gcc/testsuite/c-c++-common/strub-at-calls1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
    strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub.  */
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls2.c b/gcc/testsuite/c-c++-common/strub-at-calls2.c
index 97a3988a6b9..7915b33a39a 100644
--- a/gcc/testsuite/c-c++-common/strub-at-calls2.c
+++ b/gcc/testsuite/c-c++-common/strub-at-calls2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* g does NOT become STRUB_AT_CALLS because it's not viable.  Without inline,
    force_output is set for static non-inline functions when not optimizing, and
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O1.c b/gcc/testsuite/c-c++-common/strub-defer-O1.c
index 3d73431b3dc..3689998b5a3 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O1" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function does NOT defer
    the strubbing to its caller at -O1.  */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O2.c b/gcc/testsuite/c-c++-common/strub-defer-O2.c
index fddf3c745e7..9e01949db6b 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O2" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function does NOT defer
    the strubbing to its caller at -O2.  */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O3.c b/gcc/testsuite/c-c++-common/strub-defer-O3.c
index 7ebc65b58dd..40ee8edd1e0 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O3.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O3" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function defers the
    strubbing to its caller at -O3.  */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-Os.c b/gcc/testsuite/c-c++-common/strub-defer-Os.c
index fbaf85fe0fa..67ea9f04639 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-Os.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -Os" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function defers the
    strubbing to its caller at -Os.  */
diff --git a/gcc/testsuite/c-c++-common/strub-internal1.c b/gcc/testsuite/c-c++-common/strub-internal1.c
index e9d7b7b9ee0..d17254904e5 100644
--- a/gcc/testsuite/c-c++-common/strub-internal1.c
+++ b/gcc/testsuite/c-c++-common/strub-internal1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
    strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub.  */
diff --git a/gcc/testsuite/c-c++-common/strub-internal2.c b/gcc/testsuite/c-c++-common/strub-internal2.c
index 8b8e15a51c7..afc9189701f 100644
--- a/gcc/testsuite/c-c++-common/strub-internal2.c
+++ b/gcc/testsuite/c-c++-common/strub-internal2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* g becomes STRUB_INTERNAL, because of the flag.  */
 static void
diff --git a/gcc/testsuite/c-c++-common/strub-parms1.c b/gcc/testsuite/c-c++-common/strub-parms1.c
index 0a4a7539d34..f410b268971 100644
--- a/gcc/testsuite/c-c++-common/strub-parms1.c
+++ b/gcc/testsuite/c-c++-common/strub-parms1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 #include <stdarg.h>
 
diff --git a/gcc/testsuite/c-c++-common/strub-parms2.c b/gcc/testsuite/c-c++-common/strub-parms2.c
index 147171d96d5..6f572115a88 100644
--- a/gcc/testsuite/c-c++-common/strub-parms2.c
+++ b/gcc/testsuite/c-c++-common/strub-parms2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 #include <stdarg.h>
 
diff --git a/gcc/testsuite/c-c++-common/strub-parms3.c b/gcc/testsuite/c-c++-common/strub-parms3.c
index 4e92682895a..7383fea9ce8 100644
--- a/gcc/testsuite/c-c++-common/strub-parms3.c
+++ b/gcc/testsuite/c-c++-common/strub-parms3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that uses of a strub variable implicitly enables internal strub for
    publicly-visible functions, and causes the same transformations to their
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed1.c b/gcc/testsuite/c-c++-common/strub-relaxed1.c
index e2f9d8aebca..d2b4b52c51e 100644
--- a/gcc/testsuite/c-c++-common/strub-relaxed1.c
+++ b/gcc/testsuite/c-c++-common/strub-relaxed1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The difference between relaxed and strict in this case is that we accept the
    call from one internal-strub function to another.  Without the error,
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed2.c b/gcc/testsuite/c-c++-common/strub-relaxed2.c
index 98474435d2e..9e5a8e76b6c 100644
--- a/gcc/testsuite/c-c++-common/strub-relaxed2.c
+++ b/gcc/testsuite/c-c++-common/strub-relaxed2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The difference between relaxed and strict in this case is that we accept the
    call from one internal-strub function to another.  */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
index 1de15342595..aaeba2a2159 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fexceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0.c b/gcc/testsuite/c-c++-common/strub-short-O0.c
index f9209c81900..30cbdd819f1 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O0.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O0.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O1.c b/gcc/testsuite/c-c++-common/strub-short-O1.c
index bed1dcfb54a..911fdfb6db9 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O2.c b/gcc/testsuite/c-c++-common/strub-short-O2.c
index 6bf0071f52b..9b23ee3ac33 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O3.c b/gcc/testsuite/c-c++-common/strub-short-O3.c
index 4732f515bf7..4b3a8f843ea 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  At -O3 and -Os, we omit
    enter and leave calls within strub contexts, passing on the enclosing
diff --git a/gcc/testsuite/c-c++-common/strub-short-Os.c b/gcc/testsuite/c-c++-common/strub-short-Os.c
index 8d6424c479a..3627a240600 100644
--- a/gcc/testsuite/c-c++-common/strub-short-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-short-Os.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-Os -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  At -O3 and -Os, we omit
    enter and leave calls within strub contexts, passing on the enclosing
diff --git a/gcc/testsuite/c-c++-common/strub-split-stack.c b/gcc/testsuite/c-c++-common/strub-split-stack.c
new file mode 100644
index 00000000000..acbd750c3cd
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-split-stack.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-fsplit-stack" } */
+/* { dg-require-effective-target strub } */
+/* { dg-require-effective-target split-stack } */
+
+void __attribute__ ((__strub__))
+f {} /* { dg-message "not eligible" }
+
+void __attribute__ ((__strub__ ("internal")))
+g {} /* { dg-message "not eligible" }
diff --git a/gcc/testsuite/c-c++-common/strub-strict1.c b/gcc/testsuite/c-c++-common/strub-strict1.c
index 36852244206..503eb1734e3 100644
--- a/gcc/testsuite/c-c++-common/strub-strict1.c
+++ b/gcc/testsuite/c-c++-common/strub-strict1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
 
 static int __attribute__ ((__strub__)) var;
 
diff --git a/gcc/testsuite/c-c++-common/strub-strict2.c b/gcc/testsuite/c-c++-common/strub-strict2.c
index b4f28883218..3bf1aa30b4a 100644
--- a/gcc/testsuite/c-c++-common/strub-strict2.c
+++ b/gcc/testsuite/c-c++-common/strub-strict2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
 
 static int __attribute__ ((__strub__)) var;
 
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O1.c b/gcc/testsuite/c-c++-common/strub-tail-O1.c
index e48e0610e07..ba4b1623e28 100644
--- a/gcc/testsuite/c-c++-common/strub-tail-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-tail-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-tail-O2.c"
 
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O2.c b/gcc/testsuite/c-c++-common/strub-tail-O2.c
index 87cda7ab21b..043813b1de4 100644
--- a/gcc/testsuite/c-c++-common/strub-tail-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-tail-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.
    Tail calls are short-circuited at -O2+.  */
diff --git a/gcc/testsuite/c-c++-common/strub-unsupported-2.c b/gcc/testsuite/c-c++-common/strub-unsupported-2.c
new file mode 100644
index 00000000000..3586f4f679d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-unsupported-2.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+
+/* Check that, when strub is not supported (so no dg-required-effective-target
+   strub above), we report when pointers to strub functions are called.  This
+   cannot be part of strub-unsupported.c because errors in the strub-mode pass
+   prevent the main strub pass, where errors at calls are detected, from
+   running.  */
+
+void __attribute__ ((__strub__ ("at-calls"))) (*p) (void);
+
+void m () {
+  p (); /* { dg-message "unsupported" "" { target { ! strub } } } */
+}
diff --git a/gcc/testsuite/c-c++-common/strub-unsupported-3.c b/gcc/testsuite/c-c++-common/strub-unsupported-3.c
new file mode 100644
index 00000000000..d6fb4c525c4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-unsupported-3.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+
+/* Check that, when strub is not supported (so no dg-required-effective-target
+   strub above), we report when strub functions that are not defined are
+   called.  This cannot be part of strub-unsupported-2.c because errors in the
+   strub-mode pass prevent the main strub pass, where errors at calls are
+   detected, from running.  */
+
+extern void __attribute__ ((__strub__))
+s (void); /* { dg-message "not eligible|requested" "" { target { ! strub } } } */
+
+extern void __attribute__ ((__strub__ ("internal")))
+t (void); /* { dg-message "not eligible|requested" "" { target { ! strub } } } */
+
+void m () {
+  s ();
+  t ();
+}
diff --git a/gcc/testsuite/c-c++-common/strub-unsupported.c b/gcc/testsuite/c-c++-common/strub-unsupported.c
new file mode 100644
index 00000000000..cb5c4049495
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-unsupported.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+
+/* Check that, when strub is not supported (so no dg-required-effective-target
+   strub above), we report when strub functions are defined, and when they're
+   called in ways that would require changes.  */
+
+void __attribute__ ((__strub__))
+f (void) {} /* { dg-message "not eligible|requested" "" { target { ! strub } } } */
+
+void __attribute__ ((__strub__ ("internal")))
+g (void) {} /* { dg-message "not eligible|requested" "" { target { ! strub } } } */
+
+/* This only gets an error when called, see strub-unsupported-2.c.  */
+void __attribute__ ((__strub__ ("at-calls"))) (*p) (void);
+
+/* These too, see strub-unsupported-3.c.  */
+extern void __attribute__ ((__strub__))
+s (void);
+
+extern void __attribute__ ((__strub__ ("internal")))
+t (void);
diff --git a/gcc/testsuite/c-c++-common/strub-var1.c b/gcc/testsuite/c-c++-common/strub-var1.c
index eb6250fd39c..67014aa5de8 100644
--- a/gcc/testsuite/c-c++-common/strub-var1.c
+++ b/gcc/testsuite/c-c++-common/strub-var1.c
@@ -1,4 +1,5 @@
 /* { dg-do compile } */
+/* { dg-require-effective-target strub } */
 
 int __attribute__ ((strub)) x;
 float __attribute__ ((strub)) f;
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable1.c b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
index b5e45ab0525..86dbee6746d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-callable1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that strub and non-strub functions can be called from non-strub
    contexts, and that strub and callable functions can be called from strub
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable2.c b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
index 96aa7fe4b07..9da120f6156 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-callable2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that impermissible (cross-strub-context) calls are reported.  */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const1.c b/gcc/testsuite/c-c++-common/torture/strub-const1.c
index 5e956cb1a9b..22056713cce 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub const function call, we issue an asm
    statement to make sure the watermark passed to it is held in memory before
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const2.c b/gcc/testsuite/c-c++-common/torture/strub-const2.c
index 73d650292df..a105c66d7a9 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-const function call, we issue an
    asm statement to make sure the watermark passed to it is held in memory
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const3.c b/gcc/testsuite/c-c++-common/torture/strub-const3.c
index 2584f1f974a..386200c2784 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub const wrapping call, we issue an asm statement
    to make sure the watermark passed to it is held in memory before the call,
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const4.c b/gcc/testsuite/c-c++-common/torture/strub-const4.c
index d819f54ec02..817e9fa2118 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-const wrapping call, we issue an
    asm statement to make sure the watermark passed to it is held in memory
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data1.c b/gcc/testsuite/c-c++-common/torture/strub-data1.c
index 7c27a2a1a6d..132ab63ef73 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointed-to data enables strubbing if accessed.  */
 int __attribute__ ((__strub__)) var;
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data2.c b/gcc/testsuite/c-c++-common/torture/strub-data2.c
index e66d903780a..b660702d26e 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointer itself is a strub variable, enabling internal strubbing when
    its value is used.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data3.c b/gcc/testsuite/c-c++-common/torture/strub-data3.c
index 5e08e0e58c6..fc44eef6f8f 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointer itself is a strub variable, that would enable internal strubbing
    if its value was used.  Here, it's only overwritten, so no strub.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data4.c b/gcc/testsuite/c-c++-common/torture/strub-data4.c
index a818e7a38bb..85e2f59055b 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointer itself is a strub variable, that would enable internal strubbing
    if its value was used.  Here, it's only overwritten, so no strub.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data5.c b/gcc/testsuite/c-c++-common/torture/strub-data5.c
index ddb0b5c0543..0a5edac414d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data5.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data5.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* It would be desirable to issue at least warnings for these.  */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
index c165f312f16..988954e7ed6 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 typedef void __attribute__ ((__strub__)) fntype ();
 fntype (*ptr);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
index 69fcff8d376..d3ca91389a7 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 typedef void __attribute__ ((__strub__)) fntype (int, int);
 fntype (*ptr);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
index ff006224909..89b5979cf7b 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 typedef void __attribute__ ((__strub__)) fntype (int, int, ...);
 fntype (*ptr);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
index 614b02228ba..4917dda8826 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed" } */
+/* { dg-require-effective-target strub } */
 
 inline void __attribute__ ((strub ("internal"), always_inline))
 inl_int_ali (void)
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
index f9a6b4a16fa..c45903856d4 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all" } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-inlinable1.c"
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
index b4a7f3992bb..b0d6139f0a8 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 typedef void ft (void);
 typedef void ft2 (int, int);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
index ef634d35126..1148c246f20 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -Wpedantic" } */
+/* { dg-require-effective-target strub } */
 
 /* C++ does not warn about the partial incompatibilities.
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
index e1f179e160e..06a72d86d2c 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
@@ -1,6 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -Wpedantic -fpermissive" } */
 /* { dg-prune-output "command-line option .-fpermissive." } */
+/* { dg-require-effective-target strub } */
 
 /* See strub-ptrfn2.c.  */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
index 70b558afad0..83ea1af7056 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed" } */
+/* { dg-require-effective-target strub } */
 
 /* This is strub-ptrfn2.c without -Wpedantic.
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure1.c b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
index a262a086837..2643136f178 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub pure function call, we issue an asm statement
    to make sure the watermark passed to it is not assumed to be unchanged.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure2.c b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
index 4c4bd50c209..8bda129b77d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-pure function call, we issue an asm
    statement to make sure the watermark passed to it is not assumed to be
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure3.c b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
index ce195c6b1f1..00bcbdd097a 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub pure wrapping call, we issue an asm statement
    to make sure the watermark passed to it is not assumed to be unchanged.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure4.c b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
index 75cd54ccb5b..ea7c40e7912 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-pure wrapping call, we issue an asm
    statement to make sure the watermark passed to it is not assumed to be
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run1.c b/gcc/testsuite/c-c++-common/torture/strub-run1.c
index 7458b3fb54d..fdf10042863 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run1.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a non-strub function leaves a string behind in the stack, and that
    equivalent strub functions don't.  Avoid the use of red zones by avoiding
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run2.c b/gcc/testsuite/c-c++-common/torture/strub-run2.c
index 5d60a7775f4..1228a665997 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run2.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a non-strub function leaves a string behind in the stack, and that
    equivalent strub functions don't.  Allow red zones to be used.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run3.c b/gcc/testsuite/c-c++-common/torture/strub-run3.c
index c2ad710858e..e5047a988f5 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run3.c
@@ -1,6 +1,7 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a non-strub function leaves a string behind in the stack, and that
    equivalent strub functions don't.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4.c b/gcc/testsuite/c-c++-common/torture/strub-run4.c
index 3b36b8e5d68..0e84a4bab80 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4.c
@@ -1,6 +1,7 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=all" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 /* Check that multi-level, multi-inlined functions still get cleaned up as
    expected, without overwriting temporary stack allocations while they should
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4c.c b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
index 57f9baf758d..edc98486dc9 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4c.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=at-calls" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-run4.c"
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4d.c b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
index 08de3f1c3b1..487ed08bb66 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4d.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
@@ -1,6 +1,7 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 #define ATTR_STRUB_AT_CALLS __attribute__ ((__strub__ ("at-calls")))
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4i.c b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
index 459f6886c54..a85447ffabf 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4i.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=internal" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-run4.c"
diff --git a/gcc/testsuite/g++.dg/strub-run1.C b/gcc/testsuite/g++.dg/strub-run1.C
index 0d367fb83d0..beb8b811f8f 100644
--- a/gcc/testsuite/g++.dg/strub-run1.C
+++ b/gcc/testsuite/g++.dg/strub-run1.C
@@ -1,5 +1,6 @@
 // { dg-do run }
 // { dg-options "-fstrub=internal" }
+// { dg-require-effective-target strub }
 
 // Check that we don't get extra copies.
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init1.C b/gcc/testsuite/g++.dg/torture/strub-init1.C
index c226ab10ff6..6ae45fadd70 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init1.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init1.C
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
 
 extern int __attribute__((__strub__)) initializer ();
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init2.C b/gcc/testsuite/g++.dg/torture/strub-init2.C
index a7911f1fa72..8f4849c7fde 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init2.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init2.C
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
 
 extern int __attribute__((__strub__)) initializer ();
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init3.C b/gcc/testsuite/g++.dg/torture/strub-init3.C
index 6ebebcd01e8..14f28e3c276 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init3.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init3.C
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
 
 extern int __attribute__((__strub__)) initializer ();
 
diff --git a/gcc/testsuite/gnat.dg/strub_access.adb b/gcc/testsuite/gnat.dg/strub_access.adb
index 29e6996ecf6..488a2d64afe 100644
--- a/gcc/testsuite/gnat.dg/strub_access.adb
+++ b/gcc/testsuite/gnat.dg/strub_access.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed -fdump-ipa-strubm" }
+--  { dg-require-effective-target strub }
 
 --  The main subprogram doesn't read from the automatic variable, but
 --  being an automatic variable, its presence should be enough for the
diff --git a/gcc/testsuite/gnat.dg/strub_access1.adb b/gcc/testsuite/gnat.dg/strub_access1.adb
index dae47060164..4a8653c4d84 100644
--- a/gcc/testsuite/gnat.dg/strub_access1.adb
+++ b/gcc/testsuite/gnat.dg/strub_access1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed" }
+--  { dg-require-effective-target strub }
 
 --  Check that we reject 'Access of a strub variable whose type does
 --  not carry a strub modifier.
diff --git a/gcc/testsuite/gnat.dg/strub_attr.adb b/gcc/testsuite/gnat.dg/strub_attr.adb
index 10445d7cf84..eb7826dc990 100644
--- a/gcc/testsuite/gnat.dg/strub_attr.adb
+++ b/gcc/testsuite/gnat.dg/strub_attr.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm -fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 package body Strub_Attr is
    E : exception;
diff --git a/gcc/testsuite/gnat.dg/strub_disp.adb b/gcc/testsuite/gnat.dg/strub_disp.adb
index 3dbcc4a357c..f23d4675def 100644
--- a/gcc/testsuite/gnat.dg/strub_disp.adb
+++ b/gcc/testsuite/gnat.dg/strub_disp.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Disp is
    package Foo is
diff --git a/gcc/testsuite/gnat.dg/strub_disp1.adb b/gcc/testsuite/gnat.dg/strub_disp1.adb
index 09756a74b7d..9c4c7f69637 100644
--- a/gcc/testsuite/gnat.dg/strub_disp1.adb
+++ b/gcc/testsuite/gnat.dg/strub_disp1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 -- Check that at-calls dispatching calls are transformed.
 
diff --git a/gcc/testsuite/gnat.dg/strub_ind.adb b/gcc/testsuite/gnat.dg/strub_ind.adb
index da56acaa957..613db69305e 100644
--- a/gcc/testsuite/gnat.dg/strub_ind.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict" }
+--  { dg-require-effective-target strub }
 
 --  This is essentially the same test as strub_attr.adb, 
 --  but applying attributes to access types as well.
diff --git a/gcc/testsuite/gnat.dg/strub_ind1.adb b/gcc/testsuite/gnat.dg/strub_ind1.adb
index 825e395e681..245b0a830f6 100644
--- a/gcc/testsuite/gnat.dg/strub_ind1.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm" }
+--  { dg-require-effective-target strub }
 
 --  This is essentially the same test as strub_attr.adb, 
 --  but with an explicit conversion.
diff --git a/gcc/testsuite/gnat.dg/strub_ind2.adb b/gcc/testsuite/gnat.dg/strub_ind2.adb
index e918b392631..b9bfe50e929 100644
--- a/gcc/testsuite/gnat.dg/strub_ind2.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind2.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict" }
+--  { dg-require-effective-target strub }
 
 --  This is essentially the same test as strub_attr.adb, 
 --  but with an explicit conversion.
diff --git a/gcc/testsuite/gnat.dg/strub_intf.adb b/gcc/testsuite/gnat.dg/strub_intf.adb
index 8f0212a7586..f43854705d0 100644
--- a/gcc/testsuite/gnat.dg/strub_intf.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 --  Check that strub mode mismatches between overrider and overridden
 --  subprograms are reported.
diff --git a/gcc/testsuite/gnat.dg/strub_intf1.adb b/gcc/testsuite/gnat.dg/strub_intf1.adb
index bf77321cef7..7a38a4c49ba 100644
--- a/gcc/testsuite/gnat.dg/strub_intf1.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 -- Check that at-calls dispatching calls to interfaces are transformed.
 
diff --git a/gcc/testsuite/gnat.dg/strub_intf2.adb b/gcc/testsuite/gnat.dg/strub_intf2.adb
index e8880dbc437..7992b7344fb 100644
--- a/gcc/testsuite/gnat.dg/strub_intf2.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf2.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 --  Check that strub mode mismatches between overrider and overridden
 --  subprograms are reported even when the overriders for an
diff --git a/gcc/testsuite/gnat.dg/strub_renm.adb b/gcc/testsuite/gnat.dg/strub_renm.adb
index 217367e712d..abfb120b514 100644
--- a/gcc/testsuite/gnat.dg/strub_renm.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Renm is
    procedure P (X : Integer);
diff --git a/gcc/testsuite/gnat.dg/strub_renm1.adb b/gcc/testsuite/gnat.dg/strub_renm1.adb
index a11adbfb5a9..68d3230b535 100644
--- a/gcc/testsuite/gnat.dg/strub_renm1.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed -fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Renm1 is
    V : Integer := 0;
diff --git a/gcc/testsuite/gnat.dg/strub_renm2.adb b/gcc/testsuite/gnat.dg/strub_renm2.adb
index c488c20826f..3cb81ea03f7 100644
--- a/gcc/testsuite/gnat.dg/strub_renm2.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm2.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Renm2 is
    V : Integer := 0;
diff --git a/gcc/testsuite/gnat.dg/strub_var.adb b/gcc/testsuite/gnat.dg/strub_var.adb
index 3d158de2803..7c6affa06d4 100644
--- a/gcc/testsuite/gnat.dg/strub_var.adb
+++ b/gcc/testsuite/gnat.dg/strub_var.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm" }
+--  { dg-require-effective-target strub }
 
 -- We don't read from the automatic variable, but being an automatic
 --  variable, its presence should be enough for the procedure to get
diff --git a/gcc/testsuite/gnat.dg/strub_var1.adb b/gcc/testsuite/gnat.dg/strub_var1.adb
index 6a504e09198..64b7e65fe9b 100644
--- a/gcc/testsuite/gnat.dg/strub_var1.adb
+++ b/gcc/testsuite/gnat.dg/strub_var1.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 with Strub_Attr;
 procedure Strub_Var1 is
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 3fcce6be49d..40a60c198cf 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -1302,6 +1302,13 @@ proc check_stack_check_available { stack_kind } {
     } "$stack_opt"]
 }
 
+# Return 1 if the target supports stack scrubbing.
+proc check_effective_target_strub {} {
+    return [check_no_compiler_messages strub assembly {
+	void __attribute__ ((__strub__)) fn (void) {}
+    } ""]
+}
+
 # Return 1 if compilation with -freorder-blocks-and-partition is error-free
 # for trivial code, 0 otherwise.  As some targets (ARM for example) only
 # warn when -fprofile-use is also supplied we test that combination too.
diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in
index d8163c5af99..3f77283490e 100644
--- a/libgcc/Makefile.in
+++ b/libgcc/Makefile.in
@@ -434,7 +434,7 @@ LIB2ADD += enable-execute-stack.c
 LIB2ADD += $(srcdir)/hardcfr.c
 
 # Stack scrubbing infrastructure.
-LIB2ADD += $(srcdir)/strub.c
+@HAVE_STRUB_SUPPORT@LIB2ADD += $(srcdir)/strub.c
 
 # While emutls.c has nothing to do with EH, it is in LIB2ADDEH*
 # instead of LIB2ADD because that's the way to be sure on some targets
diff --git a/libgcc/configure b/libgcc/configure
index cf149209652..567158955a3 100755
--- a/libgcc/configure
+++ b/libgcc/configure
@@ -593,6 +593,7 @@ asm_hidden_op
 extra_parts
 cpu_type
 get_gcc_base_ver
+HAVE_STRUB_SUPPORT
 thread_header
 tm_defines
 tm_file
@@ -5702,6 +5703,31 @@ esac
 
 
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for strub support" >&5
+$as_echo_n "checking for strub support... " >&6; }
+if ${libgcc_cv_strub_support+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+void __attribute__ ((__strub__)) fn (void) {}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  libgcc_cv_strub_support=yes
+else
+  libgcc_cv_strub_support=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgcc_cv_strub_support" >&5
+$as_echo "$libgcc_cv_strub_support" >&6; }
+if test "x$libgcc_cv_strub_support" != xno; then
+  HAVE_STRUB_SUPPORT=
+else
+  HAVE_STRUB_SUPPORT='# '
+fi
+
+
 # Determine what GCC version number to use in filesystem paths.
 
   get_gcc_base_ver="cat"
diff --git a/libgcc/configure.ac b/libgcc/configure.ac
index 2fc9d5d7c93..9c0e415501a 100644
--- a/libgcc/configure.ac
+++ b/libgcc/configure.ac
@@ -694,6 +694,19 @@ AC_SUBST(tm_defines)
 # Map from thread model to thread header.
 GCC_AC_THREAD_HEADER([$target_thread_file])
 
+AC_CACHE_CHECK([for strub support],
+  [libgcc_cv_strub_support],
+  [AC_COMPILE_IFELSE(
+    [AC_LANG_SOURCE([void __attribute__ ((__strub__)) fn (void) {}])],
+    [libgcc_cv_strub_support=yes],
+    [libgcc_cv_strub_support=no])])
+if test "x$libgcc_cv_strub_support" != xno; then
+  HAVE_STRUB_SUPPORT=
+else
+  HAVE_STRUB_SUPPORT='# '
+fi
+AC_SUBST(HAVE_STRUB_SUPPORT)
+
 # Determine what GCC version number to use in filesystem paths.
 GCC_BASE_VER

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [gcc(refs/users/aoliva/heads/testme)] strub: enable conditional support
@ 2023-12-07  1:40 Alexandre Oliva
  0 siblings, 0 replies; 25+ messages in thread
From: Alexandre Oliva @ 2023-12-07  1:40 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:a53d1430060c6e1d731c96ee68cbf897a57f2d75

commit a53d1430060c6e1d731c96ee68cbf897a57f2d75
Author: Alexandre Oliva <oliva@adacore.com>
Date:   Wed Dec 6 19:36:02 2023 -0300

    strub: enable conditional support
    
    Targets that don't expose callee stacks to callers, such as nvptx, as
    well as -fsplit-stack compilations, violate fundamental assumptions of
    the current strub implementation.  This patch enables targets to
    disable strub, and disables it when -fsplit-stack is enabled.
    
    When strub support is disabled, the testsuite will now skip strub
    tests, and libgcc will not build the strub runtime components.
    
    
    for  gcc/ChangeLog
    
            * target.def (have_strub_support_for): New hook.
            * doc/tm.texi.in: Document it.
            * doc/tm.texi: Rebuild.
            * ipa-strub.cc: Include target.h.
            (strub_target_support_p): New.
            (can_strub_p): Call it.  Test for no flag_split_stack.
            (pass_ipa_strub::adjust_at_calls_call): Check for target
            support.
            * config/nvptx/nvptx.cc (TARGET_HAVE_STRUB_SUPPORT_FOR):
            Disable.
            * doc/sourcebuild.texi (strub): Document new effective
            target.
    
    for  gcc/testsuite/ChangeLog
    
            * gcc.dg/strub-split-stack.c: New.
            * gcc.dg/strub-unsupported.c: New.
            * gcc.dg/strub-unsupported-2.c: New.
            * gcc.dg/strub-unsupported-3.c: New.
            * lib/target-supports.exp (check_effective_target_strub): New.
            * c-c++-common/strub-O0.c: Require effective target strub.
            * c-c++-common/strub-O1.c: Likewise.
            * c-c++-common/strub-O2.c: Likewise.
            * c-c++-common/strub-O2fni.c: Likewise.
            * c-c++-common/strub-O3.c: Likewise.
            * c-c++-common/strub-O3fni.c: Likewise.
            * c-c++-common/strub-Og.c: Likewise.
            * c-c++-common/strub-Os.c: Likewise.
            * c-c++-common/strub-all1.c: Likewise.
            * c-c++-common/strub-all2.c: Likewise.
            * c-c++-common/strub-apply1.c: Likewise.
            * c-c++-common/strub-apply2.c: Likewise.
            * c-c++-common/strub-apply3.c: Likewise.
            * c-c++-common/strub-apply4.c: Likewise.
            * c-c++-common/strub-at-calls1.c: Likewise.
            * c-c++-common/strub-at-calls2.c: Likewise.
            * c-c++-common/strub-defer-O1.c: Likewise.
            * c-c++-common/strub-defer-O2.c: Likewise.
            * c-c++-common/strub-defer-O3.c: Likewise.
            * c-c++-common/strub-defer-Os.c: Likewise.
            * c-c++-common/strub-internal1.c: Likewise.
            * c-c++-common/strub-internal2.c: Likewise.
            * c-c++-common/strub-parms1.c: Likewise.
            * c-c++-common/strub-parms2.c: Likewise.
            * c-c++-common/strub-parms3.c: Likewise.
            * c-c++-common/strub-relaxed1.c: Likewise.
            * c-c++-common/strub-relaxed2.c: Likewise.
            * c-c++-common/strub-short-O0-exc.c: Likewise.
            * c-c++-common/strub-short-O0.c: Likewise.
            * c-c++-common/strub-short-O1.c: Likewise.
            * c-c++-common/strub-short-O2.c: Likewise.
            * c-c++-common/strub-short-O3.c: Likewise.
            * c-c++-common/strub-short-Os.c: Likewise.
            * c-c++-common/strub-strict1.c: Likewise.
            * c-c++-common/strub-strict2.c: Likewise.
            * c-c++-common/strub-tail-O1.c: Likewise.
            * c-c++-common/strub-tail-O2.c: Likewise.
            * c-c++-common/strub-var1.c: Likewise.
            * c-c++-common/torture/strub-callable1.c: Likewise.
            * c-c++-common/torture/strub-callable2.c: Likewise.
            * c-c++-common/torture/strub-const1.c: Likewise.
            * c-c++-common/torture/strub-const2.c: Likewise.
            * c-c++-common/torture/strub-const3.c: Likewise.
            * c-c++-common/torture/strub-const4.c: Likewise.
            * c-c++-common/torture/strub-data1.c: Likewise.
            * c-c++-common/torture/strub-data2.c: Likewise.
            * c-c++-common/torture/strub-data3.c: Likewise.
            * c-c++-common/torture/strub-data4.c: Likewise.
            * c-c++-common/torture/strub-data5.c: Likewise.
            * c-c++-common/torture/strub-indcall1.c: Likewise.
            * c-c++-common/torture/strub-indcall2.c: Likewise.
            * c-c++-common/torture/strub-indcall3.c: Likewise.
            * c-c++-common/torture/strub-inlinable1.c: Likewise.
            * c-c++-common/torture/strub-inlinable2.c: Likewise.
            * c-c++-common/torture/strub-ptrfn1.c: Likewise.
            * c-c++-common/torture/strub-ptrfn2.c: Likewise.
            * c-c++-common/torture/strub-ptrfn3.c: Likewise.
            * c-c++-common/torture/strub-ptrfn4.c: Likewise.
            * c-c++-common/torture/strub-pure1.c: Likewise.
            * c-c++-common/torture/strub-pure2.c: Likewise.
            * c-c++-common/torture/strub-pure3.c: Likewise.
            * c-c++-common/torture/strub-pure4.c: Likewise.
            * c-c++-common/torture/strub-run1.c: Likewise.
            * c-c++-common/torture/strub-run2.c: Likewise.
            * c-c++-common/torture/strub-run3.c: Likewise.
            * c-c++-common/torture/strub-run4.c: Likewise.
            * c-c++-common/torture/strub-run4c.c: Likewise.
            * c-c++-common/torture/strub-run4d.c: Likewise.
            * c-c++-common/torture/strub-run4i.c: Likewise.
            * g++.dg/strub-run1.C: Likewise.
            * g++.dg/torture/strub-init1.C: Likewise.
            * g++.dg/torture/strub-init2.C: Likewise.
            * g++.dg/torture/strub-init3.C: Likewise.
            * gnat.dg/strub_attr.adb: Likewise.
            * gnat.dg/strub_ind.adb: Likewise.
            * gnat.dg/strub_access.adb: Likewise.
            * gnat.dg/strub_access1.adb: Likewise.
            * gnat.dg/strub_disp.adb: Likewise.
            * gnat.dg/strub_disp1.adb: Likewise.
            * gnat.dg/strub_ind1.adb: Likewise.
            * gnat.dg/strub_ind2.adb: Likewise.
            * gnat.dg/strub_intf.adb: Likewise.
            * gnat.dg/strub_intf1.adb: Likewise.
            * gnat.dg/strub_intf2.adb: Likewise.
            * gnat.dg/strub_renm.adb: Likewise.
            * gnat.dg/strub_renm1.adb: Likewise.
            * gnat.dg/strub_renm2.adb: Likewise.
            * gnat.dg/strub_var.adb: Likewise.
            * gnat.dg/strub_var1.adb: Likewise.
    
    for  libgcc/ChangeLog
    
            * configure.ac: Check for strub support.
            * configure: Rebuilt.
            * Makefile.in: Compile strub.c conditionally.

Diff:
---
 gcc/config/i386/i386.cc                            |  4 ++
 gcc/config/nvptx/nvptx.cc                          |  3 ++
 gcc/doc/sourcebuild.texi                           |  3 ++
 gcc/doc/tm.texi                                    |  6 +++
 gcc/doc/tm.texi.in                                 |  2 +
 gcc/ipa-strub.cc                                   | 54 +++++++++++++++++++++-
 gcc/target.def                                     |  8 ++++
 gcc/testsuite/c-c++-common/strub-O0.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O1.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O2.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O2fni.c           |  1 +
 gcc/testsuite/c-c++-common/strub-O3.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O3fni.c           |  1 +
 gcc/testsuite/c-c++-common/strub-Og.c              |  1 +
 gcc/testsuite/c-c++-common/strub-Os.c              |  1 +
 gcc/testsuite/c-c++-common/strub-all1.c            |  1 +
 gcc/testsuite/c-c++-common/strub-all2.c            |  1 +
 gcc/testsuite/c-c++-common/strub-apply1.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply2.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply3.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply4.c          |  1 +
 gcc/testsuite/c-c++-common/strub-at-calls1.c       |  1 +
 gcc/testsuite/c-c++-common/strub-at-calls2.c       |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O3.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-Os.c        |  1 +
 gcc/testsuite/c-c++-common/strub-internal1.c       |  1 +
 gcc/testsuite/c-c++-common/strub-internal2.c       |  1 +
 gcc/testsuite/c-c++-common/strub-parms1.c          |  1 +
 gcc/testsuite/c-c++-common/strub-parms2.c          |  1 +
 gcc/testsuite/c-c++-common/strub-parms3.c          |  1 +
 gcc/testsuite/c-c++-common/strub-relaxed1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-relaxed2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O0-exc.c    |  1 +
 gcc/testsuite/c-c++-common/strub-short-O0.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O3.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-Os.c        |  1 +
 gcc/testsuite/c-c++-common/strub-split-stack.c     | 10 ++++
 gcc/testsuite/c-c++-common/strub-strict1.c         |  1 +
 gcc/testsuite/c-c++-common/strub-strict2.c         |  1 +
 gcc/testsuite/c-c++-common/strub-tail-O1.c         |  1 +
 gcc/testsuite/c-c++-common/strub-tail-O2.c         |  1 +
 gcc/testsuite/c-c++-common/strub-unsupported-2.c   | 13 ++++++
 gcc/testsuite/c-c++-common/strub-unsupported-3.c   | 18 ++++++++
 gcc/testsuite/c-c++-common/strub-unsupported.c     | 21 +++++++++
 gcc/testsuite/c-c++-common/strub-var1.c            |  1 +
 .../c-c++-common/torture/strub-callable1.c         |  1 +
 .../c-c++-common/torture/strub-callable2.c         |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const1.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const2.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const3.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const4.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data1.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data2.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data3.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data4.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data5.c   |  1 +
 .../c-c++-common/torture/strub-indcall1.c          |  1 +
 .../c-c++-common/torture/strub-indcall2.c          |  1 +
 .../c-c++-common/torture/strub-indcall3.c          |  1 +
 .../c-c++-common/torture/strub-inlinable1.c        |  1 +
 .../c-c++-common/torture/strub-inlinable2.c        |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure1.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure2.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure3.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure4.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run1.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run2.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run3.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4c.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4d.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4i.c   |  1 +
 gcc/testsuite/g++.dg/strub-run1.C                  |  1 +
 gcc/testsuite/g++.dg/torture/strub-init1.C         |  1 +
 gcc/testsuite/g++.dg/torture/strub-init2.C         |  1 +
 gcc/testsuite/g++.dg/torture/strub-init3.C         |  1 +
 gcc/testsuite/gnat.dg/strub_access.adb             |  1 +
 gcc/testsuite/gnat.dg/strub_access1.adb            |  1 +
 gcc/testsuite/gnat.dg/strub_attr.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_disp.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_disp1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_ind.adb                |  1 +
 gcc/testsuite/gnat.dg/strub_ind1.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_ind2.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_intf.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_intf1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_intf2.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_renm.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_renm1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_renm2.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_var.adb                |  1 +
 gcc/testsuite/gnat.dg/strub_var1.adb               |  1 +
 gcc/testsuite/lib/target-supports.exp              |  7 +++
 libgcc/Makefile.in                                 |  2 +-
 libgcc/configure                                   | 26 +++++++++++
 libgcc/configure.ac                                | 13 ++++++
 104 files changed, 276 insertions(+), 3 deletions(-)

diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 7c5cab4e2c6..f933c9c23c7 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -26658,6 +26658,10 @@ ix86_libm_function_max_error (unsigned cfn, machine_mode mode,
 #define TARGET_RUN_TARGET_SELFTESTS selftest::ix86_run_selftests
 #endif /* #if CHECKING_P */
 
+// ??? for testing only
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 #include "gt-i386.h"
diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc
index ae20802c879..3fb1deb70fd 100644
--- a/gcc/config/nvptx/nvptx.cc
+++ b/gcc/config/nvptx/nvptx.cc
@@ -7789,6 +7789,9 @@ nvptx_asm_output_def_from_decls (FILE *stream, tree name, tree value)
 #undef TARGET_LIBC_HAS_FUNCTION
 #define TARGET_LIBC_HAS_FUNCTION nvptx_libc_has_function
 
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-nvptx.h"
diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi
index c9909026854..26a7e9c3507 100644
--- a/gcc/doc/sourcebuild.texi
+++ b/gcc/doc/sourcebuild.texi
@@ -2983,6 +2983,9 @@ Target supports statically linking @samp{libgfortran}.
 @item string_merging
 Target supports merging string constants at link time.
 
+@item strub
+Target supports attribute @code{strub} for stack scrubbing.
+
 @item ucn
 Target supports compiling and assembling UCN.
 
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 89a1735dd79..768ada0af52 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -3450,6 +3450,12 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@deftypefn {Target Hook} bool TARGET_HAVE_STRUB_SUPPORT_FOR (tree)
+Returns true if the target supports stack scrubbing for the given function
+or type, otherwise return false.  The default implementation always returns
+true.
+@end deftypefn
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index ebc1d3de5ca..4fe0805394e 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2686,6 +2686,8 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@hook TARGET_HAVE_STRUB_SUPPORT_FOR
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
index 293bec132b8..2afb7a45575 100644
--- a/gcc/ipa-strub.cc
+++ b/gcc/ipa-strub.cc
@@ -60,6 +60,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-strub.h"
 #include "symtab-thunks.h"
 #include "attr-fnspec.h"
+#include "target.h"
 
 /* This file introduces two passes that, together, implement
    machine-independent stack scrubbing, strub for short.  It arranges
@@ -631,17 +632,60 @@ strub_always_inline_p (cgraph_node *node)
   return lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl));
 }
 
+/* Return TRUE iff the target has strub support for T, a function
+   decl, or a type used in an indirect call, and optionally REPORT the
+   reasons for ineligibility.  If T is a type and error REPORTing is
+   enabled, the LOCation (of the indirect call) should be provided.  */
+static inline bool
+strub_target_support_p (tree t, bool report = false,
+			location_t loc = UNKNOWN_LOCATION)
+{
+  bool result = true;
+
+  if (!targetm.have_strub_support_for (t))
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      if (DECL_P (t))
+	sorry_at (DECL_SOURCE_LOCATION (t),
+		  "%qD is not eligible for %<strub%>"
+		  " on the target system", t);
+      else
+	sorry_at (loc,
+		  "unsupported %<strub%> call"
+		  " on the target system");
+    }
+
+  return result;
+}
+
 /* Return TRUE iff NODE is potentially eligible for any strub-enabled mode, and
    optionally REPORT the reasons for ineligibility.  */
 
 static inline bool
 can_strub_p (cgraph_node *node, bool report = false)
 {
-  bool result = true;
+  bool result = strub_target_support_p (node->decl, report);
 
-  if (!report && strub_always_inline_p (node))
+  if (!report && (!result || strub_always_inline_p (node)))
     return result;
 
+  if (flag_split_stack)
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (node->decl),
+		"%qD is not eligible for %<strub%>"
+		" because %<-fsplit-stack%> is enabled",
+		node->decl);
+    }
+
   if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
     {
       result = false;
@@ -2417,6 +2461,12 @@ pass_ipa_strub::adjust_at_calls_call (cgraph_edge *e, int named_args,
 			 && (TREE_TYPE (gimple_call_arg (ocall, named_args))
 			     == get_pwmt ())));
 
+  tree tsup;
+  if (!(tsup = gimple_call_fndecl (ocall)))
+    tsup = TREE_TYPE (TREE_TYPE (gimple_call_fn (ocall)));
+  if (!strub_target_support_p (tsup, true, gimple_location (ocall)))
+    return;
+
   /* If we're already within a strub context, pass on the incoming watermark
      pointer, and omit the enter and leave calls around the modified call, as an
      optimization, or as a means to satisfy a tail-call requirement.  */
diff --git a/gcc/target.def b/gcc/target.def
index 52b83e091b9..08218f3a42a 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4457,6 +4457,14 @@ otherwise return false.  The default implementation always returns true.",
  bool, (void),
  hook_bool_void_true)
 
+DEFHOOK
+(have_strub_support_for,
+ "Returns true if the target supports stack scrubbing for the given function\n\
+or type, otherwise return false.  The default implementation always returns\n\
+true.",
+ bool, (tree),
+ hook_bool_tree_true)
+
 DEFHOOK
 (have_speculation_safe_value,
 "This hook is used to determine the level of target support for\n\
diff --git a/gcc/testsuite/c-c++-common/strub-O0.c b/gcc/testsuite/c-c++-common/strub-O0.c
index c7a79a6ea0d..f0a3f7b4c6f 100644
--- a/gcc/testsuite/c-c++-common/strub-O0.c
+++ b/gcc/testsuite/c-c++-common/strub-O0.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -O0, none of the strub builtins are expanded inline.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O1.c b/gcc/testsuite/c-c++-common/strub-O1.c
index 96285c975d9..50403426b18 100644
--- a/gcc/testsuite/c-c++-common/strub-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -O1, without -fno-inline, we fully expand enter, but neither update nor
    leave.  */
diff --git a/gcc/testsuite/c-c++-common/strub-O2.c b/gcc/testsuite/c-c++-common/strub-O2.c
index 8edc0d8aa13..37e02998e31 100644
--- a/gcc/testsuite/c-c++-common/strub-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -O2, without -fno-inline, we fully expand enter and update, and add a test
    around the leave call.  */
diff --git a/gcc/testsuite/c-c++-common/strub-O2fni.c b/gcc/testsuite/c-c++-common/strub-O2fni.c
index c6d900cf3c4..905e2c6b2ff 100644
--- a/gcc/testsuite/c-c++-common/strub-O2fni.c
+++ b/gcc/testsuite/c-c++-common/strub-O2fni.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
+/* { dg-require-effective-target strub } */
 
 /* With -fno-inline, none of the strub builtins are inlined.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O3.c b/gcc/testsuite/c-c++-common/strub-O3.c
index 33ee465e51c..3bbf132bdf1 100644
--- a/gcc/testsuite/c-c++-common/strub-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-O3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 int __attribute__ ((__strub__)) var;
 
diff --git a/gcc/testsuite/c-c++-common/strub-O3fni.c b/gcc/testsuite/c-c++-common/strub-O3fni.c
index 2936f82079e..c46fce38e5c 100644
--- a/gcc/testsuite/c-c++-common/strub-O3fni.c
+++ b/gcc/testsuite/c-c++-common/strub-O3fni.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
+/* { dg-require-effective-target strub } */
 
 /* With -fno-inline, none of the strub builtins are inlined.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-Og.c b/gcc/testsuite/c-c++-common/strub-Og.c
index 479746e57d8..3b8eb19765c 100644
--- a/gcc/testsuite/c-c++-common/strub-Og.c
+++ b/gcc/testsuite/c-c++-common/strub-Og.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-Og -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -Og, without -fno-inline, we fully expand enter, but neither update nor
    leave.  */
diff --git a/gcc/testsuite/c-c++-common/strub-Os.c b/gcc/testsuite/c-c++-common/strub-Os.c
index 2241d4ea07f..8cfb253d676 100644
--- a/gcc/testsuite/c-c++-common/strub-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-Os.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-Os -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -Os, without -fno-inline, we fully expand enter, and also update.  The
    expanded update might be larger than a call proper, but argument saving and
diff --git a/gcc/testsuite/c-c++-common/strub-all1.c b/gcc/testsuite/c-c++-common/strub-all1.c
index a322bcc5da6..2037f681f29 100644
--- a/gcc/testsuite/c-c++-common/strub-all1.c
+++ b/gcc/testsuite/c-c++-common/strub-all1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
    strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub.  */
diff --git a/gcc/testsuite/c-c++-common/strub-all2.c b/gcc/testsuite/c-c++-common/strub-all2.c
index db60026d0e0..c026e7d9d28 100644
--- a/gcc/testsuite/c-c++-common/strub-all2.c
+++ b/gcc/testsuite/c-c++-common/strub-all2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* g becomes STRUB_INTERNAL, because of the flag.  Without inline, force_output
    is set for static non-inline functions when not optimizing, and that keeps
diff --git a/gcc/testsuite/c-c++-common/strub-apply1.c b/gcc/testsuite/c-c++-common/strub-apply1.c
index 2f462adc1ef..3edc89c54ee 100644
--- a/gcc/testsuite/c-c++-common/strub-apply1.c
+++ b/gcc/testsuite/c-c++-common/strub-apply1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 void __attribute__ ((__strub__ ("callable")))
 apply_function (void *args)
diff --git a/gcc/testsuite/c-c++-common/strub-apply2.c b/gcc/testsuite/c-c++-common/strub-apply2.c
index a5d7551f5da..838fc752734 100644
--- a/gcc/testsuite/c-c++-common/strub-apply2.c
+++ b/gcc/testsuite/c-c++-common/strub-apply2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 extern void __attribute__ ((__strub__))
 apply_function (void *args);
diff --git a/gcc/testsuite/c-c++-common/strub-apply3.c b/gcc/testsuite/c-c++-common/strub-apply3.c
index 64422a0d1e8..0206e4d930e 100644
--- a/gcc/testsuite/c-c++-common/strub-apply3.c
+++ b/gcc/testsuite/c-c++-common/strub-apply3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 void __attribute__ ((__strub__))
 apply_function (void *args)
diff --git a/gcc/testsuite/c-c++-common/strub-apply4.c b/gcc/testsuite/c-c++-common/strub-apply4.c
index 15ffaa031b8..e82504728b2 100644
--- a/gcc/testsuite/c-c++-common/strub-apply4.c
+++ b/gcc/testsuite/c-c++-common/strub-apply4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that implicit enabling of strub mode selects internal strub when the
    function uses __builtin_apply_args, that prevents the optimization to
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls1.c b/gcc/testsuite/c-c++-common/strub-at-calls1.c
index b70843b4215..a20acc0a48a 100644
--- a/gcc/testsuite/c-c++-common/strub-at-calls1.c
+++ b/gcc/testsuite/c-c++-common/strub-at-calls1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
    strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub.  */
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls2.c b/gcc/testsuite/c-c++-common/strub-at-calls2.c
index 97a3988a6b9..7915b33a39a 100644
--- a/gcc/testsuite/c-c++-common/strub-at-calls2.c
+++ b/gcc/testsuite/c-c++-common/strub-at-calls2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* g does NOT become STRUB_AT_CALLS because it's not viable.  Without inline,
    force_output is set for static non-inline functions when not optimizing, and
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O1.c b/gcc/testsuite/c-c++-common/strub-defer-O1.c
index 3d73431b3dc..3689998b5a3 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O1" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function does NOT defer
    the strubbing to its caller at -O1.  */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O2.c b/gcc/testsuite/c-c++-common/strub-defer-O2.c
index fddf3c745e7..9e01949db6b 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O2" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function does NOT defer
    the strubbing to its caller at -O2.  */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O3.c b/gcc/testsuite/c-c++-common/strub-defer-O3.c
index 7ebc65b58dd..40ee8edd1e0 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O3.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O3" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function defers the
    strubbing to its caller at -O3.  */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-Os.c b/gcc/testsuite/c-c++-common/strub-defer-Os.c
index fbaf85fe0fa..67ea9f04639 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-Os.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -Os" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function defers the
    strubbing to its caller at -Os.  */
diff --git a/gcc/testsuite/c-c++-common/strub-internal1.c b/gcc/testsuite/c-c++-common/strub-internal1.c
index e9d7b7b9ee0..d17254904e5 100644
--- a/gcc/testsuite/c-c++-common/strub-internal1.c
+++ b/gcc/testsuite/c-c++-common/strub-internal1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
    strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub.  */
diff --git a/gcc/testsuite/c-c++-common/strub-internal2.c b/gcc/testsuite/c-c++-common/strub-internal2.c
index 8b8e15a51c7..afc9189701f 100644
--- a/gcc/testsuite/c-c++-common/strub-internal2.c
+++ b/gcc/testsuite/c-c++-common/strub-internal2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* g becomes STRUB_INTERNAL, because of the flag.  */
 static void
diff --git a/gcc/testsuite/c-c++-common/strub-parms1.c b/gcc/testsuite/c-c++-common/strub-parms1.c
index 0a4a7539d34..f410b268971 100644
--- a/gcc/testsuite/c-c++-common/strub-parms1.c
+++ b/gcc/testsuite/c-c++-common/strub-parms1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 #include <stdarg.h>
 
diff --git a/gcc/testsuite/c-c++-common/strub-parms2.c b/gcc/testsuite/c-c++-common/strub-parms2.c
index 147171d96d5..6f572115a88 100644
--- a/gcc/testsuite/c-c++-common/strub-parms2.c
+++ b/gcc/testsuite/c-c++-common/strub-parms2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 #include <stdarg.h>
 
diff --git a/gcc/testsuite/c-c++-common/strub-parms3.c b/gcc/testsuite/c-c++-common/strub-parms3.c
index 4e92682895a..7383fea9ce8 100644
--- a/gcc/testsuite/c-c++-common/strub-parms3.c
+++ b/gcc/testsuite/c-c++-common/strub-parms3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that uses of a strub variable implicitly enables internal strub for
    publicly-visible functions, and causes the same transformations to their
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed1.c b/gcc/testsuite/c-c++-common/strub-relaxed1.c
index e2f9d8aebca..d2b4b52c51e 100644
--- a/gcc/testsuite/c-c++-common/strub-relaxed1.c
+++ b/gcc/testsuite/c-c++-common/strub-relaxed1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The difference between relaxed and strict in this case is that we accept the
    call from one internal-strub function to another.  Without the error,
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed2.c b/gcc/testsuite/c-c++-common/strub-relaxed2.c
index 98474435d2e..9e5a8e76b6c 100644
--- a/gcc/testsuite/c-c++-common/strub-relaxed2.c
+++ b/gcc/testsuite/c-c++-common/strub-relaxed2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The difference between relaxed and strict in this case is that we accept the
    call from one internal-strub function to another.  */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
index 1de15342595..aaeba2a2159 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fexceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0.c b/gcc/testsuite/c-c++-common/strub-short-O0.c
index f9209c81900..30cbdd819f1 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O0.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O0.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O1.c b/gcc/testsuite/c-c++-common/strub-short-O1.c
index bed1dcfb54a..911fdfb6db9 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O2.c b/gcc/testsuite/c-c++-common/strub-short-O2.c
index 6bf0071f52b..9b23ee3ac33 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O3.c b/gcc/testsuite/c-c++-common/strub-short-O3.c
index 4732f515bf7..4b3a8f843ea 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  At -O3 and -Os, we omit
    enter and leave calls within strub contexts, passing on the enclosing
diff --git a/gcc/testsuite/c-c++-common/strub-short-Os.c b/gcc/testsuite/c-c++-common/strub-short-Os.c
index 8d6424c479a..3627a240600 100644
--- a/gcc/testsuite/c-c++-common/strub-short-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-short-Os.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-Os -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  At -O3 and -Os, we omit
    enter and leave calls within strub contexts, passing on the enclosing
diff --git a/gcc/testsuite/c-c++-common/strub-split-stack.c b/gcc/testsuite/c-c++-common/strub-split-stack.c
new file mode 100644
index 00000000000..acbd750c3cd
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-split-stack.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-fsplit-stack" } */
+/* { dg-require-effective-target strub } */
+/* { dg-require-effective-target split-stack } */
+
+void __attribute__ ((__strub__))
+f {} /* { dg-message "not eligible" }
+
+void __attribute__ ((__strub__ ("internal")))
+g {} /* { dg-message "not eligible" }
diff --git a/gcc/testsuite/c-c++-common/strub-strict1.c b/gcc/testsuite/c-c++-common/strub-strict1.c
index 36852244206..503eb1734e3 100644
--- a/gcc/testsuite/c-c++-common/strub-strict1.c
+++ b/gcc/testsuite/c-c++-common/strub-strict1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
 
 static int __attribute__ ((__strub__)) var;
 
diff --git a/gcc/testsuite/c-c++-common/strub-strict2.c b/gcc/testsuite/c-c++-common/strub-strict2.c
index b4f28883218..3bf1aa30b4a 100644
--- a/gcc/testsuite/c-c++-common/strub-strict2.c
+++ b/gcc/testsuite/c-c++-common/strub-strict2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
 
 static int __attribute__ ((__strub__)) var;
 
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O1.c b/gcc/testsuite/c-c++-common/strub-tail-O1.c
index e48e0610e07..ba4b1623e28 100644
--- a/gcc/testsuite/c-c++-common/strub-tail-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-tail-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-tail-O2.c"
 
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O2.c b/gcc/testsuite/c-c++-common/strub-tail-O2.c
index 87cda7ab21b..043813b1de4 100644
--- a/gcc/testsuite/c-c++-common/strub-tail-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-tail-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.
    Tail calls are short-circuited at -O2+.  */
diff --git a/gcc/testsuite/c-c++-common/strub-unsupported-2.c b/gcc/testsuite/c-c++-common/strub-unsupported-2.c
new file mode 100644
index 00000000000..3586f4f679d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-unsupported-2.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+
+/* Check that, when strub is not supported (so no dg-required-effective-target
+   strub above), we report when pointers to strub functions are called.  This
+   cannot be part of strub-unsupported.c because errors in the strub-mode pass
+   prevent the main strub pass, where errors at calls are detected, from
+   running.  */
+
+void __attribute__ ((__strub__ ("at-calls"))) (*p) (void);
+
+void m () {
+  p (); /* { dg-message "unsupported" "" { target { ! strub } } } */
+}
diff --git a/gcc/testsuite/c-c++-common/strub-unsupported-3.c b/gcc/testsuite/c-c++-common/strub-unsupported-3.c
new file mode 100644
index 00000000000..760237769b4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-unsupported-3.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+
+/* Check that, when strub is not supported (so no dg-required-effective-target
+   strub above), we report when strub functions that are not defined are
+   called.  This cannot be part of strub-unsupported-2.c because errors in the
+   strub-mode pass prevent the main strub pass, where errors at calls are
+   detected, from running.  */
+
+extern void __attribute__ ((__strub__))
+s (void); /* { dg-message "not eligible" "" { target { ! strub } } } */
+
+extern void __attribute__ ((__strub__ ("internal")))
+t (void); /* { dg-message "not eligible" "" { target { ! strub } } } */
+
+void m () {
+  s ();
+  t ();
+}
diff --git a/gcc/testsuite/c-c++-common/strub-unsupported.c b/gcc/testsuite/c-c++-common/strub-unsupported.c
new file mode 100644
index 00000000000..9dfa67df08b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-unsupported.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+
+/* Check that, when strub is not supported (so no dg-required-effective-target
+   strub above), we report when strub functions are defined, and when they're
+   called in ways that would require changes.  */
+
+void __attribute__ ((__strub__))
+f (void) {} /* { dg-message "not eligible" "" { target { ! strub } } } */
+
+void __attribute__ ((__strub__ ("internal")))
+g (void) {} /* { dg-message "not eligible" "" { target { ! strub } } } */
+
+/* This only gets an error when called, see strub-unsupported-2.c.  */
+void __attribute__ ((__strub__ ("at-calls"))) (*p) (void);
+
+/* These too, see strub-unsupported-3.c.  */
+extern void __attribute__ ((__strub__))
+s (void);
+
+extern void __attribute__ ((__strub__ ("internal")))
+t (void);
diff --git a/gcc/testsuite/c-c++-common/strub-var1.c b/gcc/testsuite/c-c++-common/strub-var1.c
index eb6250fd39c..67014aa5de8 100644
--- a/gcc/testsuite/c-c++-common/strub-var1.c
+++ b/gcc/testsuite/c-c++-common/strub-var1.c
@@ -1,4 +1,5 @@
 /* { dg-do compile } */
+/* { dg-require-effective-target strub } */
 
 int __attribute__ ((strub)) x;
 float __attribute__ ((strub)) f;
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable1.c b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
index b5e45ab0525..86dbee6746d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-callable1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that strub and non-strub functions can be called from non-strub
    contexts, and that strub and callable functions can be called from strub
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable2.c b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
index 96aa7fe4b07..9da120f6156 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-callable2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that impermissible (cross-strub-context) calls are reported.  */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const1.c b/gcc/testsuite/c-c++-common/torture/strub-const1.c
index 5e956cb1a9b..22056713cce 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub const function call, we issue an asm
    statement to make sure the watermark passed to it is held in memory before
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const2.c b/gcc/testsuite/c-c++-common/torture/strub-const2.c
index 73d650292df..a105c66d7a9 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-const function call, we issue an
    asm statement to make sure the watermark passed to it is held in memory
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const3.c b/gcc/testsuite/c-c++-common/torture/strub-const3.c
index 2584f1f974a..386200c2784 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub const wrapping call, we issue an asm statement
    to make sure the watermark passed to it is held in memory before the call,
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const4.c b/gcc/testsuite/c-c++-common/torture/strub-const4.c
index d819f54ec02..817e9fa2118 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-const wrapping call, we issue an
    asm statement to make sure the watermark passed to it is held in memory
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data1.c b/gcc/testsuite/c-c++-common/torture/strub-data1.c
index 7c27a2a1a6d..132ab63ef73 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointed-to data enables strubbing if accessed.  */
 int __attribute__ ((__strub__)) var;
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data2.c b/gcc/testsuite/c-c++-common/torture/strub-data2.c
index e66d903780a..b660702d26e 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointer itself is a strub variable, enabling internal strubbing when
    its value is used.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data3.c b/gcc/testsuite/c-c++-common/torture/strub-data3.c
index 5e08e0e58c6..fc44eef6f8f 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointer itself is a strub variable, that would enable internal strubbing
    if its value was used.  Here, it's only overwritten, so no strub.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data4.c b/gcc/testsuite/c-c++-common/torture/strub-data4.c
index a818e7a38bb..85e2f59055b 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointer itself is a strub variable, that would enable internal strubbing
    if its value was used.  Here, it's only overwritten, so no strub.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data5.c b/gcc/testsuite/c-c++-common/torture/strub-data5.c
index ddb0b5c0543..0a5edac414d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data5.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data5.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* It would be desirable to issue at least warnings for these.  */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
index c165f312f16..988954e7ed6 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 typedef void __attribute__ ((__strub__)) fntype ();
 fntype (*ptr);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
index 69fcff8d376..d3ca91389a7 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 typedef void __attribute__ ((__strub__)) fntype (int, int);
 fntype (*ptr);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
index ff006224909..89b5979cf7b 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 typedef void __attribute__ ((__strub__)) fntype (int, int, ...);
 fntype (*ptr);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
index 614b02228ba..4917dda8826 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed" } */
+/* { dg-require-effective-target strub } */
 
 inline void __attribute__ ((strub ("internal"), always_inline))
 inl_int_ali (void)
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
index f9a6b4a16fa..c45903856d4 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all" } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-inlinable1.c"
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
index b4a7f3992bb..b0d6139f0a8 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 typedef void ft (void);
 typedef void ft2 (int, int);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
index ef634d35126..1148c246f20 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -Wpedantic" } */
+/* { dg-require-effective-target strub } */
 
 /* C++ does not warn about the partial incompatibilities.
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
index e1f179e160e..06a72d86d2c 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
@@ -1,6 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -Wpedantic -fpermissive" } */
 /* { dg-prune-output "command-line option .-fpermissive." } */
+/* { dg-require-effective-target strub } */
 
 /* See strub-ptrfn2.c.  */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
index 70b558afad0..83ea1af7056 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed" } */
+/* { dg-require-effective-target strub } */
 
 /* This is strub-ptrfn2.c without -Wpedantic.
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure1.c b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
index a262a086837..2643136f178 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub pure function call, we issue an asm statement
    to make sure the watermark passed to it is not assumed to be unchanged.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure2.c b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
index 4c4bd50c209..8bda129b77d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-pure function call, we issue an asm
    statement to make sure the watermark passed to it is not assumed to be
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure3.c b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
index ce195c6b1f1..00bcbdd097a 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub pure wrapping call, we issue an asm statement
    to make sure the watermark passed to it is not assumed to be unchanged.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure4.c b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
index 75cd54ccb5b..ea7c40e7912 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-pure wrapping call, we issue an asm
    statement to make sure the watermark passed to it is not assumed to be
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run1.c b/gcc/testsuite/c-c++-common/torture/strub-run1.c
index 7458b3fb54d..fdf10042863 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run1.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a non-strub function leaves a string behind in the stack, and that
    equivalent strub functions don't.  Avoid the use of red zones by avoiding
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run2.c b/gcc/testsuite/c-c++-common/torture/strub-run2.c
index 5d60a7775f4..1228a665997 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run2.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a non-strub function leaves a string behind in the stack, and that
    equivalent strub functions don't.  Allow red zones to be used.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run3.c b/gcc/testsuite/c-c++-common/torture/strub-run3.c
index c2ad710858e..e5047a988f5 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run3.c
@@ -1,6 +1,7 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a non-strub function leaves a string behind in the stack, and that
    equivalent strub functions don't.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4.c b/gcc/testsuite/c-c++-common/torture/strub-run4.c
index 3b36b8e5d68..0e84a4bab80 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4.c
@@ -1,6 +1,7 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=all" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 /* Check that multi-level, multi-inlined functions still get cleaned up as
    expected, without overwriting temporary stack allocations while they should
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4c.c b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
index 57f9baf758d..edc98486dc9 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4c.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=at-calls" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-run4.c"
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4d.c b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
index 08de3f1c3b1..487ed08bb66 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4d.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
@@ -1,6 +1,7 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 #define ATTR_STRUB_AT_CALLS __attribute__ ((__strub__ ("at-calls")))
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4i.c b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
index 459f6886c54..a85447ffabf 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4i.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=internal" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-run4.c"
diff --git a/gcc/testsuite/g++.dg/strub-run1.C b/gcc/testsuite/g++.dg/strub-run1.C
index 0d367fb83d0..beb8b811f8f 100644
--- a/gcc/testsuite/g++.dg/strub-run1.C
+++ b/gcc/testsuite/g++.dg/strub-run1.C
@@ -1,5 +1,6 @@
 // { dg-do run }
 // { dg-options "-fstrub=internal" }
+// { dg-require-effective-target strub }
 
 // Check that we don't get extra copies.
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init1.C b/gcc/testsuite/g++.dg/torture/strub-init1.C
index c226ab10ff6..6ae45fadd70 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init1.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init1.C
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
 
 extern int __attribute__((__strub__)) initializer ();
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init2.C b/gcc/testsuite/g++.dg/torture/strub-init2.C
index a7911f1fa72..8f4849c7fde 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init2.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init2.C
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
 
 extern int __attribute__((__strub__)) initializer ();
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init3.C b/gcc/testsuite/g++.dg/torture/strub-init3.C
index 6ebebcd01e8..14f28e3c276 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init3.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init3.C
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
 
 extern int __attribute__((__strub__)) initializer ();
 
diff --git a/gcc/testsuite/gnat.dg/strub_access.adb b/gcc/testsuite/gnat.dg/strub_access.adb
index 29e6996ecf6..488a2d64afe 100644
--- a/gcc/testsuite/gnat.dg/strub_access.adb
+++ b/gcc/testsuite/gnat.dg/strub_access.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed -fdump-ipa-strubm" }
+--  { dg-require-effective-target strub }
 
 --  The main subprogram doesn't read from the automatic variable, but
 --  being an automatic variable, its presence should be enough for the
diff --git a/gcc/testsuite/gnat.dg/strub_access1.adb b/gcc/testsuite/gnat.dg/strub_access1.adb
index dae47060164..4a8653c4d84 100644
--- a/gcc/testsuite/gnat.dg/strub_access1.adb
+++ b/gcc/testsuite/gnat.dg/strub_access1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed" }
+--  { dg-require-effective-target strub }
 
 --  Check that we reject 'Access of a strub variable whose type does
 --  not carry a strub modifier.
diff --git a/gcc/testsuite/gnat.dg/strub_attr.adb b/gcc/testsuite/gnat.dg/strub_attr.adb
index 10445d7cf84..eb7826dc990 100644
--- a/gcc/testsuite/gnat.dg/strub_attr.adb
+++ b/gcc/testsuite/gnat.dg/strub_attr.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm -fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 package body Strub_Attr is
    E : exception;
diff --git a/gcc/testsuite/gnat.dg/strub_disp.adb b/gcc/testsuite/gnat.dg/strub_disp.adb
index 3dbcc4a357c..f23d4675def 100644
--- a/gcc/testsuite/gnat.dg/strub_disp.adb
+++ b/gcc/testsuite/gnat.dg/strub_disp.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Disp is
    package Foo is
diff --git a/gcc/testsuite/gnat.dg/strub_disp1.adb b/gcc/testsuite/gnat.dg/strub_disp1.adb
index 09756a74b7d..9c4c7f69637 100644
--- a/gcc/testsuite/gnat.dg/strub_disp1.adb
+++ b/gcc/testsuite/gnat.dg/strub_disp1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 -- Check that at-calls dispatching calls are transformed.
 
diff --git a/gcc/testsuite/gnat.dg/strub_ind.adb b/gcc/testsuite/gnat.dg/strub_ind.adb
index da56acaa957..613db69305e 100644
--- a/gcc/testsuite/gnat.dg/strub_ind.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict" }
+--  { dg-require-effective-target strub }
 
 --  This is essentially the same test as strub_attr.adb, 
 --  but applying attributes to access types as well.
diff --git a/gcc/testsuite/gnat.dg/strub_ind1.adb b/gcc/testsuite/gnat.dg/strub_ind1.adb
index 825e395e681..245b0a830f6 100644
--- a/gcc/testsuite/gnat.dg/strub_ind1.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm" }
+--  { dg-require-effective-target strub }
 
 --  This is essentially the same test as strub_attr.adb, 
 --  but with an explicit conversion.
diff --git a/gcc/testsuite/gnat.dg/strub_ind2.adb b/gcc/testsuite/gnat.dg/strub_ind2.adb
index e918b392631..b9bfe50e929 100644
--- a/gcc/testsuite/gnat.dg/strub_ind2.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind2.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict" }
+--  { dg-require-effective-target strub }
 
 --  This is essentially the same test as strub_attr.adb, 
 --  but with an explicit conversion.
diff --git a/gcc/testsuite/gnat.dg/strub_intf.adb b/gcc/testsuite/gnat.dg/strub_intf.adb
index 8f0212a7586..f43854705d0 100644
--- a/gcc/testsuite/gnat.dg/strub_intf.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 --  Check that strub mode mismatches between overrider and overridden
 --  subprograms are reported.
diff --git a/gcc/testsuite/gnat.dg/strub_intf1.adb b/gcc/testsuite/gnat.dg/strub_intf1.adb
index bf77321cef7..7a38a4c49ba 100644
--- a/gcc/testsuite/gnat.dg/strub_intf1.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 -- Check that at-calls dispatching calls to interfaces are transformed.
 
diff --git a/gcc/testsuite/gnat.dg/strub_intf2.adb b/gcc/testsuite/gnat.dg/strub_intf2.adb
index e8880dbc437..7992b7344fb 100644
--- a/gcc/testsuite/gnat.dg/strub_intf2.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf2.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 --  Check that strub mode mismatches between overrider and overridden
 --  subprograms are reported even when the overriders for an
diff --git a/gcc/testsuite/gnat.dg/strub_renm.adb b/gcc/testsuite/gnat.dg/strub_renm.adb
index 217367e712d..abfb120b514 100644
--- a/gcc/testsuite/gnat.dg/strub_renm.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Renm is
    procedure P (X : Integer);
diff --git a/gcc/testsuite/gnat.dg/strub_renm1.adb b/gcc/testsuite/gnat.dg/strub_renm1.adb
index a11adbfb5a9..68d3230b535 100644
--- a/gcc/testsuite/gnat.dg/strub_renm1.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed -fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Renm1 is
    V : Integer := 0;
diff --git a/gcc/testsuite/gnat.dg/strub_renm2.adb b/gcc/testsuite/gnat.dg/strub_renm2.adb
index c488c20826f..3cb81ea03f7 100644
--- a/gcc/testsuite/gnat.dg/strub_renm2.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm2.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Renm2 is
    V : Integer := 0;
diff --git a/gcc/testsuite/gnat.dg/strub_var.adb b/gcc/testsuite/gnat.dg/strub_var.adb
index 3d158de2803..7c6affa06d4 100644
--- a/gcc/testsuite/gnat.dg/strub_var.adb
+++ b/gcc/testsuite/gnat.dg/strub_var.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm" }
+--  { dg-require-effective-target strub }
 
 -- We don't read from the automatic variable, but being an automatic
 --  variable, its presence should be enough for the procedure to get
diff --git a/gcc/testsuite/gnat.dg/strub_var1.adb b/gcc/testsuite/gnat.dg/strub_var1.adb
index 6a504e09198..64b7e65fe9b 100644
--- a/gcc/testsuite/gnat.dg/strub_var1.adb
+++ b/gcc/testsuite/gnat.dg/strub_var1.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 with Strub_Attr;
 procedure Strub_Var1 is
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 3fcce6be49d..40a60c198cf 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -1302,6 +1302,13 @@ proc check_stack_check_available { stack_kind } {
     } "$stack_opt"]
 }
 
+# Return 1 if the target supports stack scrubbing.
+proc check_effective_target_strub {} {
+    return [check_no_compiler_messages strub assembly {
+	void __attribute__ ((__strub__)) fn (void) {}
+    } ""]
+}
+
 # Return 1 if compilation with -freorder-blocks-and-partition is error-free
 # for trivial code, 0 otherwise.  As some targets (ARM for example) only
 # warn when -fprofile-use is also supplied we test that combination too.
diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in
index d8163c5af99..3f77283490e 100644
--- a/libgcc/Makefile.in
+++ b/libgcc/Makefile.in
@@ -434,7 +434,7 @@ LIB2ADD += enable-execute-stack.c
 LIB2ADD += $(srcdir)/hardcfr.c
 
 # Stack scrubbing infrastructure.
-LIB2ADD += $(srcdir)/strub.c
+@HAVE_STRUB_SUPPORT@LIB2ADD += $(srcdir)/strub.c
 
 # While emutls.c has nothing to do with EH, it is in LIB2ADDEH*
 # instead of LIB2ADD because that's the way to be sure on some targets
diff --git a/libgcc/configure b/libgcc/configure
index cf149209652..567158955a3 100755
--- a/libgcc/configure
+++ b/libgcc/configure
@@ -593,6 +593,7 @@ asm_hidden_op
 extra_parts
 cpu_type
 get_gcc_base_ver
+HAVE_STRUB_SUPPORT
 thread_header
 tm_defines
 tm_file
@@ -5702,6 +5703,31 @@ esac
 
 
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for strub support" >&5
+$as_echo_n "checking for strub support... " >&6; }
+if ${libgcc_cv_strub_support+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+void __attribute__ ((__strub__)) fn (void) {}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  libgcc_cv_strub_support=yes
+else
+  libgcc_cv_strub_support=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgcc_cv_strub_support" >&5
+$as_echo "$libgcc_cv_strub_support" >&6; }
+if test "x$libgcc_cv_strub_support" != xno; then
+  HAVE_STRUB_SUPPORT=
+else
+  HAVE_STRUB_SUPPORT='# '
+fi
+
+
 # Determine what GCC version number to use in filesystem paths.
 
   get_gcc_base_ver="cat"
diff --git a/libgcc/configure.ac b/libgcc/configure.ac
index 2fc9d5d7c93..9c0e415501a 100644
--- a/libgcc/configure.ac
+++ b/libgcc/configure.ac
@@ -694,6 +694,19 @@ AC_SUBST(tm_defines)
 # Map from thread model to thread header.
 GCC_AC_THREAD_HEADER([$target_thread_file])
 
+AC_CACHE_CHECK([for strub support],
+  [libgcc_cv_strub_support],
+  [AC_COMPILE_IFELSE(
+    [AC_LANG_SOURCE([void __attribute__ ((__strub__)) fn (void) {}])],
+    [libgcc_cv_strub_support=yes],
+    [libgcc_cv_strub_support=no])])
+if test "x$libgcc_cv_strub_support" != xno; then
+  HAVE_STRUB_SUPPORT=
+else
+  HAVE_STRUB_SUPPORT='# '
+fi
+AC_SUBST(HAVE_STRUB_SUPPORT)
+
 # Determine what GCC version number to use in filesystem paths.
 GCC_BASE_VER

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [gcc(refs/users/aoliva/heads/testme)] strub: enable conditional support
@ 2023-12-07  1:39 Alexandre Oliva
  0 siblings, 0 replies; 25+ messages in thread
From: Alexandre Oliva @ 2023-12-07  1:39 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:e968f0aa3b12ee7a11440455adff419692c02087

commit e968f0aa3b12ee7a11440455adff419692c02087
Author: Alexandre Oliva <oliva@adacore.com>
Date:   Wed Dec 6 19:36:02 2023 -0300

    strub: enable conditional support
    
    Targets that don't expose callee stacks to callers, such as nvptx, as
    well as -fsplit-stack compilations, violate fundamental assumptions of
    the current strub implementation.  This patch enables targets to
    disable strub, and disables it when -fsplit-stack is enabled.
    
    When strub support is disabled, the testsuite will now skip strub
    tests, and libgcc will not build the strub runtime components.
    
    
    for  gcc/ChangeLog
    
            * target.def (have_strub_support_for): New hook.
            * doc/tm.texi.in: Document it.
            * doc/tm.texi: Rebuild.
            * ipa-strub.cc: Include target.h.
            (strub_target_support_p): New.
            (can_strub_p): Call it.  Test for no flag_split_stack.
            (pass_ipa_strub::adjust_at_calls_call): Check for target
            support.
            * config/nvptx/nvptx.cc (TARGET_HAVE_STRUB_SUPPORT_FOR):
            Disable.
            * doc/sourcebuild.texi (strub): Document new effective
            target.
    
    for  gcc/testsuite/ChangeLog
    
            * gcc.dg/strub-split-stack.c: New.
            * gcc.dg/strub-unsupported.c: New.
            * gcc.dg/strub-unsupported-2.c: New.
            * gcc.dg/strub-unsupported-3.c: New.
            * lib/target-supports.exp (check_effective_target_strub): New.
            * c-c++-common/strub-O0.c: Require effective target strub.
            * c-c++-common/strub-O1.c: Likewise.
            * c-c++-common/strub-O2.c: Likewise.
            * c-c++-common/strub-O2fni.c: Likewise.
            * c-c++-common/strub-O3.c: Likewise.
            * c-c++-common/strub-O3fni.c: Likewise.
            * c-c++-common/strub-Og.c: Likewise.
            * c-c++-common/strub-Os.c: Likewise.
            * c-c++-common/strub-all1.c: Likewise.
            * c-c++-common/strub-all2.c: Likewise.
            * c-c++-common/strub-apply1.c: Likewise.
            * c-c++-common/strub-apply2.c: Likewise.
            * c-c++-common/strub-apply3.c: Likewise.
            * c-c++-common/strub-apply4.c: Likewise.
            * c-c++-common/strub-at-calls1.c: Likewise.
            * c-c++-common/strub-at-calls2.c: Likewise.
            * c-c++-common/strub-defer-O1.c: Likewise.
            * c-c++-common/strub-defer-O2.c: Likewise.
            * c-c++-common/strub-defer-O3.c: Likewise.
            * c-c++-common/strub-defer-Os.c: Likewise.
            * c-c++-common/strub-internal1.c: Likewise.
            * c-c++-common/strub-internal2.c: Likewise.
            * c-c++-common/strub-parms1.c: Likewise.
            * c-c++-common/strub-parms2.c: Likewise.
            * c-c++-common/strub-parms3.c: Likewise.
            * c-c++-common/strub-relaxed1.c: Likewise.
            * c-c++-common/strub-relaxed2.c: Likewise.
            * c-c++-common/strub-short-O0-exc.c: Likewise.
            * c-c++-common/strub-short-O0.c: Likewise.
            * c-c++-common/strub-short-O1.c: Likewise.
            * c-c++-common/strub-short-O2.c: Likewise.
            * c-c++-common/strub-short-O3.c: Likewise.
            * c-c++-common/strub-short-Os.c: Likewise.
            * c-c++-common/strub-strict1.c: Likewise.
            * c-c++-common/strub-strict2.c: Likewise.
            * c-c++-common/strub-tail-O1.c: Likewise.
            * c-c++-common/strub-tail-O2.c: Likewise.
            * c-c++-common/strub-var1.c: Likewise.
            * c-c++-common/torture/strub-callable1.c: Likewise.
            * c-c++-common/torture/strub-callable2.c: Likewise.
            * c-c++-common/torture/strub-const1.c: Likewise.
            * c-c++-common/torture/strub-const2.c: Likewise.
            * c-c++-common/torture/strub-const3.c: Likewise.
            * c-c++-common/torture/strub-const4.c: Likewise.
            * c-c++-common/torture/strub-data1.c: Likewise.
            * c-c++-common/torture/strub-data2.c: Likewise.
            * c-c++-common/torture/strub-data3.c: Likewise.
            * c-c++-common/torture/strub-data4.c: Likewise.
            * c-c++-common/torture/strub-data5.c: Likewise.
            * c-c++-common/torture/strub-indcall1.c: Likewise.
            * c-c++-common/torture/strub-indcall2.c: Likewise.
            * c-c++-common/torture/strub-indcall3.c: Likewise.
            * c-c++-common/torture/strub-inlinable1.c: Likewise.
            * c-c++-common/torture/strub-inlinable2.c: Likewise.
            * c-c++-common/torture/strub-ptrfn1.c: Likewise.
            * c-c++-common/torture/strub-ptrfn2.c: Likewise.
            * c-c++-common/torture/strub-ptrfn3.c: Likewise.
            * c-c++-common/torture/strub-ptrfn4.c: Likewise.
            * c-c++-common/torture/strub-pure1.c: Likewise.
            * c-c++-common/torture/strub-pure2.c: Likewise.
            * c-c++-common/torture/strub-pure3.c: Likewise.
            * c-c++-common/torture/strub-pure4.c: Likewise.
            * c-c++-common/torture/strub-run1.c: Likewise.
            * c-c++-common/torture/strub-run2.c: Likewise.
            * c-c++-common/torture/strub-run3.c: Likewise.
            * c-c++-common/torture/strub-run4.c: Likewise.
            * c-c++-common/torture/strub-run4c.c: Likewise.
            * c-c++-common/torture/strub-run4d.c: Likewise.
            * c-c++-common/torture/strub-run4i.c: Likewise.
            * g++.dg/strub-run1.C: Likewise.
            * g++.dg/torture/strub-init1.C: Likewise.
            * g++.dg/torture/strub-init2.C: Likewise.
            * g++.dg/torture/strub-init3.C: Likewise.
            * gnat.dg/strub_attr.adb: Likewise.
            * gnat.dg/strub_ind.adb: Likewise.
            * gnat.dg/strub_access.adb: Likewise.
            * gnat.dg/strub_access1.adb: Likewise.
            * gnat.dg/strub_disp.adb: Likewise.
            * gnat.dg/strub_disp1.adb: Likewise.
            * gnat.dg/strub_ind1.adb: Likewise.
            * gnat.dg/strub_ind2.adb: Likewise.
            * gnat.dg/strub_intf.adb: Likewise.
            * gnat.dg/strub_intf1.adb: Likewise.
            * gnat.dg/strub_intf2.adb: Likewise.
            * gnat.dg/strub_renm.adb: Likewise.
            * gnat.dg/strub_renm1.adb: Likewise.
            * gnat.dg/strub_renm2.adb: Likewise.
            * gnat.dg/strub_var.adb: Likewise.
            * gnat.dg/strub_var1.adb: Likewise.
    
    for  libgcc/ChangeLog
    
            * configure.ac: Check for strub support.
            * configure: Rebuilt.
            * Makefile.in: Compile strub.c conditionally.

Diff:
---
 gcc/config/i386/i386.cc                            |  4 ++
 gcc/config/nvptx/nvptx.cc                          |  3 ++
 gcc/doc/sourcebuild.texi                           |  3 ++
 gcc/doc/tm.texi                                    |  6 +++
 gcc/doc/tm.texi.in                                 |  2 +
 gcc/ipa-strub.cc                                   | 54 +++++++++++++++++++++-
 gcc/target.def                                     |  8 ++++
 gcc/testsuite/c-c++-common/strub-O0.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O1.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O2.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O2fni.c           |  1 +
 gcc/testsuite/c-c++-common/strub-O3.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O3fni.c           |  1 +
 gcc/testsuite/c-c++-common/strub-Og.c              |  1 +
 gcc/testsuite/c-c++-common/strub-Os.c              |  1 +
 gcc/testsuite/c-c++-common/strub-all1.c            |  1 +
 gcc/testsuite/c-c++-common/strub-all2.c            |  1 +
 gcc/testsuite/c-c++-common/strub-apply1.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply2.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply3.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply4.c          |  1 +
 gcc/testsuite/c-c++-common/strub-at-calls1.c       |  1 +
 gcc/testsuite/c-c++-common/strub-at-calls2.c       |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O3.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-Os.c        |  1 +
 gcc/testsuite/c-c++-common/strub-internal1.c       |  1 +
 gcc/testsuite/c-c++-common/strub-internal2.c       |  1 +
 gcc/testsuite/c-c++-common/strub-parms1.c          |  1 +
 gcc/testsuite/c-c++-common/strub-parms2.c          |  1 +
 gcc/testsuite/c-c++-common/strub-parms3.c          |  1 +
 gcc/testsuite/c-c++-common/strub-relaxed1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-relaxed2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O0-exc.c    |  1 +
 gcc/testsuite/c-c++-common/strub-short-O0.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O3.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-Os.c        |  1 +
 gcc/testsuite/c-c++-common/strub-split-stack.c     | 10 ++++
 gcc/testsuite/c-c++-common/strub-strict1.c         |  1 +
 gcc/testsuite/c-c++-common/strub-strict2.c         |  1 +
 gcc/testsuite/c-c++-common/strub-tail-O1.c         |  1 +
 gcc/testsuite/c-c++-common/strub-tail-O2.c         |  1 +
 gcc/testsuite/c-c++-common/strub-unsupported-2.c   | 13 ++++++
 gcc/testsuite/c-c++-common/strub-unsupported-3.c   | 18 ++++++++
 gcc/testsuite/c-c++-common/strub-unsupported.c     | 21 +++++++++
 gcc/testsuite/c-c++-common/strub-var1.c            |  1 +
 .../c-c++-common/torture/strub-callable1.c         |  1 +
 .../c-c++-common/torture/strub-callable2.c         |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const1.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const2.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const3.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const4.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data1.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data2.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data3.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data4.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data5.c   |  1 +
 .../c-c++-common/torture/strub-indcall1.c          |  1 +
 .../c-c++-common/torture/strub-indcall2.c          |  1 +
 .../c-c++-common/torture/strub-indcall3.c          |  1 +
 .../c-c++-common/torture/strub-inlinable1.c        |  1 +
 .../c-c++-common/torture/strub-inlinable2.c        |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure1.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure2.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure3.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure4.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run1.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run2.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run3.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4c.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4d.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4i.c   |  1 +
 gcc/testsuite/g++.dg/strub-run1.C                  |  1 +
 gcc/testsuite/g++.dg/torture/strub-init1.C         |  1 +
 gcc/testsuite/g++.dg/torture/strub-init2.C         |  1 +
 gcc/testsuite/g++.dg/torture/strub-init3.C         |  1 +
 gcc/testsuite/gnat.dg/strub_access.adb             |  1 +
 gcc/testsuite/gnat.dg/strub_access1.adb            |  1 +
 gcc/testsuite/gnat.dg/strub_attr.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_disp.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_disp1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_ind.adb                |  1 +
 gcc/testsuite/gnat.dg/strub_ind1.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_ind2.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_intf.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_intf1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_intf2.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_renm.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_renm1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_renm2.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_var.adb                |  1 +
 gcc/testsuite/gnat.dg/strub_var1.adb               |  1 +
 gcc/testsuite/lib/target-supports.exp              |  7 +++
 libgcc/Makefile.in                                 |  2 +-
 libgcc/configure                                   | 26 +++++++++++
 libgcc/configure.ac                                | 13 ++++++
 104 files changed, 276 insertions(+), 3 deletions(-)

diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 7c5cab4e2c6..f933c9c23c7 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -26658,6 +26658,10 @@ ix86_libm_function_max_error (unsigned cfn, machine_mode mode,
 #define TARGET_RUN_TARGET_SELFTESTS selftest::ix86_run_selftests
 #endif /* #if CHECKING_P */
 
+// ??? for testing only
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 #include "gt-i386.h"
diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc
index ae20802c879..3fb1deb70fd 100644
--- a/gcc/config/nvptx/nvptx.cc
+++ b/gcc/config/nvptx/nvptx.cc
@@ -7789,6 +7789,9 @@ nvptx_asm_output_def_from_decls (FILE *stream, tree name, tree value)
 #undef TARGET_LIBC_HAS_FUNCTION
 #define TARGET_LIBC_HAS_FUNCTION nvptx_libc_has_function
 
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-nvptx.h"
diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi
index c9909026854..26a7e9c3507 100644
--- a/gcc/doc/sourcebuild.texi
+++ b/gcc/doc/sourcebuild.texi
@@ -2983,6 +2983,9 @@ Target supports statically linking @samp{libgfortran}.
 @item string_merging
 Target supports merging string constants at link time.
 
+@item strub
+Target supports attribute @code{strub} for stack scrubbing.
+
 @item ucn
 Target supports compiling and assembling UCN.
 
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 89a1735dd79..768ada0af52 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -3450,6 +3450,12 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@deftypefn {Target Hook} bool TARGET_HAVE_STRUB_SUPPORT_FOR (tree)
+Returns true if the target supports stack scrubbing for the given function
+or type, otherwise return false.  The default implementation always returns
+true.
+@end deftypefn
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index ebc1d3de5ca..4fe0805394e 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2686,6 +2686,8 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@hook TARGET_HAVE_STRUB_SUPPORT_FOR
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
index 293bec132b8..2afb7a45575 100644
--- a/gcc/ipa-strub.cc
+++ b/gcc/ipa-strub.cc
@@ -60,6 +60,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-strub.h"
 #include "symtab-thunks.h"
 #include "attr-fnspec.h"
+#include "target.h"
 
 /* This file introduces two passes that, together, implement
    machine-independent stack scrubbing, strub for short.  It arranges
@@ -631,17 +632,60 @@ strub_always_inline_p (cgraph_node *node)
   return lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl));
 }
 
+/* Return TRUE iff the target has strub support for T, a function
+   decl, or a type used in an indirect call, and optionally REPORT the
+   reasons for ineligibility.  If T is a type and error REPORTing is
+   enabled, the LOCation (of the indirect call) should be provided.  */
+static inline bool
+strub_target_support_p (tree t, bool report = false,
+			location_t loc = UNKNOWN_LOCATION)
+{
+  bool result = true;
+
+  if (!targetm.have_strub_support_for (t))
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      if (DECL_P (t))
+	sorry_at (DECL_SOURCE_LOCATION (t),
+		  "%qD is not eligible for %<strub%>"
+		  " on the target system", t);
+      else
+	sorry_at (loc,
+		  "unsupported %<strub%> call"
+		  " on the target system");
+    }
+
+  return result;
+}
+
 /* Return TRUE iff NODE is potentially eligible for any strub-enabled mode, and
    optionally REPORT the reasons for ineligibility.  */
 
 static inline bool
 can_strub_p (cgraph_node *node, bool report = false)
 {
-  bool result = true;
+  bool result = strub_target_support_p (node->decl, report);
 
-  if (!report && strub_always_inline_p (node))
+  if (!report && (!result || strub_always_inline_p (node)))
     return result;
 
+  if (flag_split_stack)
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (node->decl),
+		"%qD is not eligible for %<strub%>"
+		" because %<-fsplit-stack%> is enabled",
+		node->decl);
+    }
+
   if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
     {
       result = false;
@@ -2417,6 +2461,12 @@ pass_ipa_strub::adjust_at_calls_call (cgraph_edge *e, int named_args,
 			 && (TREE_TYPE (gimple_call_arg (ocall, named_args))
 			     == get_pwmt ())));
 
+  tree tsup;
+  if (!(tsup = gimple_call_fndecl (ocall)))
+    tsup = TREE_TYPE (TREE_TYPE (gimple_call_fn (ocall)));
+  if (!strub_target_support_p (tsup, true, gimple_location (ocall)))
+    return;
+
   /* If we're already within a strub context, pass on the incoming watermark
      pointer, and omit the enter and leave calls around the modified call, as an
      optimization, or as a means to satisfy a tail-call requirement.  */
diff --git a/gcc/target.def b/gcc/target.def
index 52b83e091b9..08218f3a42a 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4457,6 +4457,14 @@ otherwise return false.  The default implementation always returns true.",
  bool, (void),
  hook_bool_void_true)
 
+DEFHOOK
+(have_strub_support_for,
+ "Returns true if the target supports stack scrubbing for the given function\n\
+or type, otherwise return false.  The default implementation always returns\n\
+true.",
+ bool, (tree),
+ hook_bool_tree_true)
+
 DEFHOOK
 (have_speculation_safe_value,
 "This hook is used to determine the level of target support for\n\
diff --git a/gcc/testsuite/c-c++-common/strub-O0.c b/gcc/testsuite/c-c++-common/strub-O0.c
index c7a79a6ea0d..f0a3f7b4c6f 100644
--- a/gcc/testsuite/c-c++-common/strub-O0.c
+++ b/gcc/testsuite/c-c++-common/strub-O0.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -O0, none of the strub builtins are expanded inline.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O1.c b/gcc/testsuite/c-c++-common/strub-O1.c
index 96285c975d9..50403426b18 100644
--- a/gcc/testsuite/c-c++-common/strub-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -O1, without -fno-inline, we fully expand enter, but neither update nor
    leave.  */
diff --git a/gcc/testsuite/c-c++-common/strub-O2.c b/gcc/testsuite/c-c++-common/strub-O2.c
index 8edc0d8aa13..37e02998e31 100644
--- a/gcc/testsuite/c-c++-common/strub-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -O2, without -fno-inline, we fully expand enter and update, and add a test
    around the leave call.  */
diff --git a/gcc/testsuite/c-c++-common/strub-O2fni.c b/gcc/testsuite/c-c++-common/strub-O2fni.c
index c6d900cf3c4..905e2c6b2ff 100644
--- a/gcc/testsuite/c-c++-common/strub-O2fni.c
+++ b/gcc/testsuite/c-c++-common/strub-O2fni.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
+/* { dg-require-effective-target strub } */
 
 /* With -fno-inline, none of the strub builtins are inlined.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O3.c b/gcc/testsuite/c-c++-common/strub-O3.c
index 33ee465e51c..3bbf132bdf1 100644
--- a/gcc/testsuite/c-c++-common/strub-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-O3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 int __attribute__ ((__strub__)) var;
 
diff --git a/gcc/testsuite/c-c++-common/strub-O3fni.c b/gcc/testsuite/c-c++-common/strub-O3fni.c
index 2936f82079e..c46fce38e5c 100644
--- a/gcc/testsuite/c-c++-common/strub-O3fni.c
+++ b/gcc/testsuite/c-c++-common/strub-O3fni.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
+/* { dg-require-effective-target strub } */
 
 /* With -fno-inline, none of the strub builtins are inlined.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-Og.c b/gcc/testsuite/c-c++-common/strub-Og.c
index 479746e57d8..3b8eb19765c 100644
--- a/gcc/testsuite/c-c++-common/strub-Og.c
+++ b/gcc/testsuite/c-c++-common/strub-Og.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-Og -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -Og, without -fno-inline, we fully expand enter, but neither update nor
    leave.  */
diff --git a/gcc/testsuite/c-c++-common/strub-Os.c b/gcc/testsuite/c-c++-common/strub-Os.c
index 2241d4ea07f..8cfb253d676 100644
--- a/gcc/testsuite/c-c++-common/strub-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-Os.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-Os -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -Os, without -fno-inline, we fully expand enter, and also update.  The
    expanded update might be larger than a call proper, but argument saving and
diff --git a/gcc/testsuite/c-c++-common/strub-all1.c b/gcc/testsuite/c-c++-common/strub-all1.c
index a322bcc5da6..2037f681f29 100644
--- a/gcc/testsuite/c-c++-common/strub-all1.c
+++ b/gcc/testsuite/c-c++-common/strub-all1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
    strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub.  */
diff --git a/gcc/testsuite/c-c++-common/strub-all2.c b/gcc/testsuite/c-c++-common/strub-all2.c
index db60026d0e0..c026e7d9d28 100644
--- a/gcc/testsuite/c-c++-common/strub-all2.c
+++ b/gcc/testsuite/c-c++-common/strub-all2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* g becomes STRUB_INTERNAL, because of the flag.  Without inline, force_output
    is set for static non-inline functions when not optimizing, and that keeps
diff --git a/gcc/testsuite/c-c++-common/strub-apply1.c b/gcc/testsuite/c-c++-common/strub-apply1.c
index 2f462adc1ef..3edc89c54ee 100644
--- a/gcc/testsuite/c-c++-common/strub-apply1.c
+++ b/gcc/testsuite/c-c++-common/strub-apply1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 void __attribute__ ((__strub__ ("callable")))
 apply_function (void *args)
diff --git a/gcc/testsuite/c-c++-common/strub-apply2.c b/gcc/testsuite/c-c++-common/strub-apply2.c
index a5d7551f5da..838fc752734 100644
--- a/gcc/testsuite/c-c++-common/strub-apply2.c
+++ b/gcc/testsuite/c-c++-common/strub-apply2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 extern void __attribute__ ((__strub__))
 apply_function (void *args);
diff --git a/gcc/testsuite/c-c++-common/strub-apply3.c b/gcc/testsuite/c-c++-common/strub-apply3.c
index 64422a0d1e8..0206e4d930e 100644
--- a/gcc/testsuite/c-c++-common/strub-apply3.c
+++ b/gcc/testsuite/c-c++-common/strub-apply3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 void __attribute__ ((__strub__))
 apply_function (void *args)
diff --git a/gcc/testsuite/c-c++-common/strub-apply4.c b/gcc/testsuite/c-c++-common/strub-apply4.c
index 15ffaa031b8..e82504728b2 100644
--- a/gcc/testsuite/c-c++-common/strub-apply4.c
+++ b/gcc/testsuite/c-c++-common/strub-apply4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that implicit enabling of strub mode selects internal strub when the
    function uses __builtin_apply_args, that prevents the optimization to
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls1.c b/gcc/testsuite/c-c++-common/strub-at-calls1.c
index b70843b4215..a20acc0a48a 100644
--- a/gcc/testsuite/c-c++-common/strub-at-calls1.c
+++ b/gcc/testsuite/c-c++-common/strub-at-calls1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
    strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub.  */
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls2.c b/gcc/testsuite/c-c++-common/strub-at-calls2.c
index 97a3988a6b9..7915b33a39a 100644
--- a/gcc/testsuite/c-c++-common/strub-at-calls2.c
+++ b/gcc/testsuite/c-c++-common/strub-at-calls2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* g does NOT become STRUB_AT_CALLS because it's not viable.  Without inline,
    force_output is set for static non-inline functions when not optimizing, and
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O1.c b/gcc/testsuite/c-c++-common/strub-defer-O1.c
index 3d73431b3dc..3689998b5a3 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O1" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function does NOT defer
    the strubbing to its caller at -O1.  */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O2.c b/gcc/testsuite/c-c++-common/strub-defer-O2.c
index fddf3c745e7..9e01949db6b 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O2" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function does NOT defer
    the strubbing to its caller at -O2.  */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O3.c b/gcc/testsuite/c-c++-common/strub-defer-O3.c
index 7ebc65b58dd..40ee8edd1e0 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O3.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O3" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function defers the
    strubbing to its caller at -O3.  */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-Os.c b/gcc/testsuite/c-c++-common/strub-defer-Os.c
index fbaf85fe0fa..67ea9f04639 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-Os.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -Os" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function defers the
    strubbing to its caller at -Os.  */
diff --git a/gcc/testsuite/c-c++-common/strub-internal1.c b/gcc/testsuite/c-c++-common/strub-internal1.c
index e9d7b7b9ee0..d17254904e5 100644
--- a/gcc/testsuite/c-c++-common/strub-internal1.c
+++ b/gcc/testsuite/c-c++-common/strub-internal1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
    strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub.  */
diff --git a/gcc/testsuite/c-c++-common/strub-internal2.c b/gcc/testsuite/c-c++-common/strub-internal2.c
index 8b8e15a51c7..afc9189701f 100644
--- a/gcc/testsuite/c-c++-common/strub-internal2.c
+++ b/gcc/testsuite/c-c++-common/strub-internal2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* g becomes STRUB_INTERNAL, because of the flag.  */
 static void
diff --git a/gcc/testsuite/c-c++-common/strub-parms1.c b/gcc/testsuite/c-c++-common/strub-parms1.c
index 0a4a7539d34..f410b268971 100644
--- a/gcc/testsuite/c-c++-common/strub-parms1.c
+++ b/gcc/testsuite/c-c++-common/strub-parms1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 #include <stdarg.h>
 
diff --git a/gcc/testsuite/c-c++-common/strub-parms2.c b/gcc/testsuite/c-c++-common/strub-parms2.c
index 147171d96d5..6f572115a88 100644
--- a/gcc/testsuite/c-c++-common/strub-parms2.c
+++ b/gcc/testsuite/c-c++-common/strub-parms2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 #include <stdarg.h>
 
diff --git a/gcc/testsuite/c-c++-common/strub-parms3.c b/gcc/testsuite/c-c++-common/strub-parms3.c
index 4e92682895a..7383fea9ce8 100644
--- a/gcc/testsuite/c-c++-common/strub-parms3.c
+++ b/gcc/testsuite/c-c++-common/strub-parms3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that uses of a strub variable implicitly enables internal strub for
    publicly-visible functions, and causes the same transformations to their
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed1.c b/gcc/testsuite/c-c++-common/strub-relaxed1.c
index e2f9d8aebca..d2b4b52c51e 100644
--- a/gcc/testsuite/c-c++-common/strub-relaxed1.c
+++ b/gcc/testsuite/c-c++-common/strub-relaxed1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The difference between relaxed and strict in this case is that we accept the
    call from one internal-strub function to another.  Without the error,
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed2.c b/gcc/testsuite/c-c++-common/strub-relaxed2.c
index 98474435d2e..9e5a8e76b6c 100644
--- a/gcc/testsuite/c-c++-common/strub-relaxed2.c
+++ b/gcc/testsuite/c-c++-common/strub-relaxed2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The difference between relaxed and strict in this case is that we accept the
    call from one internal-strub function to another.  */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
index 1de15342595..aaeba2a2159 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fexceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0.c b/gcc/testsuite/c-c++-common/strub-short-O0.c
index f9209c81900..30cbdd819f1 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O0.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O0.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O1.c b/gcc/testsuite/c-c++-common/strub-short-O1.c
index bed1dcfb54a..911fdfb6db9 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O2.c b/gcc/testsuite/c-c++-common/strub-short-O2.c
index 6bf0071f52b..9b23ee3ac33 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O3.c b/gcc/testsuite/c-c++-common/strub-short-O3.c
index 4732f515bf7..4b3a8f843ea 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  At -O3 and -Os, we omit
    enter and leave calls within strub contexts, passing on the enclosing
diff --git a/gcc/testsuite/c-c++-common/strub-short-Os.c b/gcc/testsuite/c-c++-common/strub-short-Os.c
index 8d6424c479a..3627a240600 100644
--- a/gcc/testsuite/c-c++-common/strub-short-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-short-Os.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-Os -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  At -O3 and -Os, we omit
    enter and leave calls within strub contexts, passing on the enclosing
diff --git a/gcc/testsuite/c-c++-common/strub-split-stack.c b/gcc/testsuite/c-c++-common/strub-split-stack.c
new file mode 100644
index 00000000000..acbd750c3cd
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-split-stack.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-fsplit-stack" } */
+/* { dg-require-effective-target strub } */
+/* { dg-require-effective-target split-stack } */
+
+void __attribute__ ((__strub__))
+f {} /* { dg-message "not eligible" }
+
+void __attribute__ ((__strub__ ("internal")))
+g {} /* { dg-message "not eligible" }
diff --git a/gcc/testsuite/c-c++-common/strub-strict1.c b/gcc/testsuite/c-c++-common/strub-strict1.c
index 36852244206..503eb1734e3 100644
--- a/gcc/testsuite/c-c++-common/strub-strict1.c
+++ b/gcc/testsuite/c-c++-common/strub-strict1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
 
 static int __attribute__ ((__strub__)) var;
 
diff --git a/gcc/testsuite/c-c++-common/strub-strict2.c b/gcc/testsuite/c-c++-common/strub-strict2.c
index b4f28883218..3bf1aa30b4a 100644
--- a/gcc/testsuite/c-c++-common/strub-strict2.c
+++ b/gcc/testsuite/c-c++-common/strub-strict2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
 
 static int __attribute__ ((__strub__)) var;
 
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O1.c b/gcc/testsuite/c-c++-common/strub-tail-O1.c
index e48e0610e07..ba4b1623e28 100644
--- a/gcc/testsuite/c-c++-common/strub-tail-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-tail-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-tail-O2.c"
 
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O2.c b/gcc/testsuite/c-c++-common/strub-tail-O2.c
index 87cda7ab21b..043813b1de4 100644
--- a/gcc/testsuite/c-c++-common/strub-tail-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-tail-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.
    Tail calls are short-circuited at -O2+.  */
diff --git a/gcc/testsuite/c-c++-common/strub-unsupported-2.c b/gcc/testsuite/c-c++-common/strub-unsupported-2.c
new file mode 100644
index 00000000000..3586f4f679d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-unsupported-2.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+
+/* Check that, when strub is not supported (so no dg-required-effective-target
+   strub above), we report when pointers to strub functions are called.  This
+   cannot be part of strub-unsupported.c because errors in the strub-mode pass
+   prevent the main strub pass, where errors at calls are detected, from
+   running.  */
+
+void __attribute__ ((__strub__ ("at-calls"))) (*p) (void);
+
+void m () {
+  p (); /* { dg-message "unsupported" "" { target { ! strub } } } */
+}
diff --git a/gcc/testsuite/c-c++-common/strub-unsupported-3.c b/gcc/testsuite/c-c++-common/strub-unsupported-3.c
new file mode 100644
index 00000000000..760237769b4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-unsupported-3.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+
+/* Check that, when strub is not supported (so no dg-required-effective-target
+   strub above), we report when strub functions that are not defined are
+   called.  This cannot be part of strub-unsupported-2.c because errors in the
+   strub-mode pass prevent the main strub pass, where errors at calls are
+   detected, from running.  */
+
+extern void __attribute__ ((__strub__))
+s (void); /* { dg-message "not eligible" "" { target { ! strub } } } */
+
+extern void __attribute__ ((__strub__ ("internal")))
+t (void); /* { dg-message "not eligible" "" { target { ! strub } } } */
+
+void m () {
+  s ();
+  t ();
+}
diff --git a/gcc/testsuite/c-c++-common/strub-unsupported.c b/gcc/testsuite/c-c++-common/strub-unsupported.c
new file mode 100644
index 00000000000..e2c0620a22e
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-unsupported.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+
+/* Check that, when strub is not supported (so no dg-required-effective-target
+   strub above), we report when strub functions are defined, and when they're
+   called in ways that would require changes.  */
+
+void __attribute__ ((__strub__))
+f (void) {} /* { dg-message "not eligible" "" { target { ! strub } } } */
+
+void __attribute__ ((__strub__ ("internal")))
+g (void) {} /* { dg-message "not eligible" "" { target { ! strub } } } */
+
+/* This only gets an error when called, see strub-unsupported-2.c.  */
+void __attribute__ ((__strub__ ("at-calls"))) (*p) (void);
+
+/* These too, see strub-unsupported-3.c.  */
+extern void __attribute__ ((__strub__))
+s (void); /* { dg-message "not eligible" "" { target { ! strub } } } */
+
+extern void __attribute__ ((__strub__ ("internal")))
+t (void); /* { dg-message "not eligible" "" { target { ! strub } } } */
diff --git a/gcc/testsuite/c-c++-common/strub-var1.c b/gcc/testsuite/c-c++-common/strub-var1.c
index eb6250fd39c..67014aa5de8 100644
--- a/gcc/testsuite/c-c++-common/strub-var1.c
+++ b/gcc/testsuite/c-c++-common/strub-var1.c
@@ -1,4 +1,5 @@
 /* { dg-do compile } */
+/* { dg-require-effective-target strub } */
 
 int __attribute__ ((strub)) x;
 float __attribute__ ((strub)) f;
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable1.c b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
index b5e45ab0525..86dbee6746d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-callable1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that strub and non-strub functions can be called from non-strub
    contexts, and that strub and callable functions can be called from strub
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable2.c b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
index 96aa7fe4b07..9da120f6156 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-callable2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that impermissible (cross-strub-context) calls are reported.  */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const1.c b/gcc/testsuite/c-c++-common/torture/strub-const1.c
index 5e956cb1a9b..22056713cce 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub const function call, we issue an asm
    statement to make sure the watermark passed to it is held in memory before
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const2.c b/gcc/testsuite/c-c++-common/torture/strub-const2.c
index 73d650292df..a105c66d7a9 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-const function call, we issue an
    asm statement to make sure the watermark passed to it is held in memory
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const3.c b/gcc/testsuite/c-c++-common/torture/strub-const3.c
index 2584f1f974a..386200c2784 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub const wrapping call, we issue an asm statement
    to make sure the watermark passed to it is held in memory before the call,
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const4.c b/gcc/testsuite/c-c++-common/torture/strub-const4.c
index d819f54ec02..817e9fa2118 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-const wrapping call, we issue an
    asm statement to make sure the watermark passed to it is held in memory
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data1.c b/gcc/testsuite/c-c++-common/torture/strub-data1.c
index 7c27a2a1a6d..132ab63ef73 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointed-to data enables strubbing if accessed.  */
 int __attribute__ ((__strub__)) var;
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data2.c b/gcc/testsuite/c-c++-common/torture/strub-data2.c
index e66d903780a..b660702d26e 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointer itself is a strub variable, enabling internal strubbing when
    its value is used.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data3.c b/gcc/testsuite/c-c++-common/torture/strub-data3.c
index 5e08e0e58c6..fc44eef6f8f 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointer itself is a strub variable, that would enable internal strubbing
    if its value was used.  Here, it's only overwritten, so no strub.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data4.c b/gcc/testsuite/c-c++-common/torture/strub-data4.c
index a818e7a38bb..85e2f59055b 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointer itself is a strub variable, that would enable internal strubbing
    if its value was used.  Here, it's only overwritten, so no strub.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data5.c b/gcc/testsuite/c-c++-common/torture/strub-data5.c
index ddb0b5c0543..0a5edac414d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data5.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data5.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* It would be desirable to issue at least warnings for these.  */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
index c165f312f16..988954e7ed6 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 typedef void __attribute__ ((__strub__)) fntype ();
 fntype (*ptr);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
index 69fcff8d376..d3ca91389a7 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 typedef void __attribute__ ((__strub__)) fntype (int, int);
 fntype (*ptr);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
index ff006224909..89b5979cf7b 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 typedef void __attribute__ ((__strub__)) fntype (int, int, ...);
 fntype (*ptr);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
index 614b02228ba..4917dda8826 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed" } */
+/* { dg-require-effective-target strub } */
 
 inline void __attribute__ ((strub ("internal"), always_inline))
 inl_int_ali (void)
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
index f9a6b4a16fa..c45903856d4 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all" } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-inlinable1.c"
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
index b4a7f3992bb..b0d6139f0a8 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 typedef void ft (void);
 typedef void ft2 (int, int);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
index ef634d35126..1148c246f20 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -Wpedantic" } */
+/* { dg-require-effective-target strub } */
 
 /* C++ does not warn about the partial incompatibilities.
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
index e1f179e160e..06a72d86d2c 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
@@ -1,6 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -Wpedantic -fpermissive" } */
 /* { dg-prune-output "command-line option .-fpermissive." } */
+/* { dg-require-effective-target strub } */
 
 /* See strub-ptrfn2.c.  */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
index 70b558afad0..83ea1af7056 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed" } */
+/* { dg-require-effective-target strub } */
 
 /* This is strub-ptrfn2.c without -Wpedantic.
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure1.c b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
index a262a086837..2643136f178 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub pure function call, we issue an asm statement
    to make sure the watermark passed to it is not assumed to be unchanged.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure2.c b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
index 4c4bd50c209..8bda129b77d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-pure function call, we issue an asm
    statement to make sure the watermark passed to it is not assumed to be
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure3.c b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
index ce195c6b1f1..00bcbdd097a 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub pure wrapping call, we issue an asm statement
    to make sure the watermark passed to it is not assumed to be unchanged.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure4.c b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
index 75cd54ccb5b..ea7c40e7912 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-pure wrapping call, we issue an asm
    statement to make sure the watermark passed to it is not assumed to be
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run1.c b/gcc/testsuite/c-c++-common/torture/strub-run1.c
index 7458b3fb54d..fdf10042863 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run1.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a non-strub function leaves a string behind in the stack, and that
    equivalent strub functions don't.  Avoid the use of red zones by avoiding
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run2.c b/gcc/testsuite/c-c++-common/torture/strub-run2.c
index 5d60a7775f4..1228a665997 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run2.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a non-strub function leaves a string behind in the stack, and that
    equivalent strub functions don't.  Allow red zones to be used.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run3.c b/gcc/testsuite/c-c++-common/torture/strub-run3.c
index c2ad710858e..e5047a988f5 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run3.c
@@ -1,6 +1,7 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a non-strub function leaves a string behind in the stack, and that
    equivalent strub functions don't.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4.c b/gcc/testsuite/c-c++-common/torture/strub-run4.c
index 3b36b8e5d68..0e84a4bab80 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4.c
@@ -1,6 +1,7 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=all" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 /* Check that multi-level, multi-inlined functions still get cleaned up as
    expected, without overwriting temporary stack allocations while they should
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4c.c b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
index 57f9baf758d..edc98486dc9 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4c.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=at-calls" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-run4.c"
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4d.c b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
index 08de3f1c3b1..487ed08bb66 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4d.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
@@ -1,6 +1,7 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 #define ATTR_STRUB_AT_CALLS __attribute__ ((__strub__ ("at-calls")))
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4i.c b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
index 459f6886c54..a85447ffabf 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4i.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=internal" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-run4.c"
diff --git a/gcc/testsuite/g++.dg/strub-run1.C b/gcc/testsuite/g++.dg/strub-run1.C
index 0d367fb83d0..beb8b811f8f 100644
--- a/gcc/testsuite/g++.dg/strub-run1.C
+++ b/gcc/testsuite/g++.dg/strub-run1.C
@@ -1,5 +1,6 @@
 // { dg-do run }
 // { dg-options "-fstrub=internal" }
+// { dg-require-effective-target strub }
 
 // Check that we don't get extra copies.
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init1.C b/gcc/testsuite/g++.dg/torture/strub-init1.C
index c226ab10ff6..6ae45fadd70 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init1.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init1.C
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
 
 extern int __attribute__((__strub__)) initializer ();
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init2.C b/gcc/testsuite/g++.dg/torture/strub-init2.C
index a7911f1fa72..8f4849c7fde 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init2.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init2.C
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
 
 extern int __attribute__((__strub__)) initializer ();
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init3.C b/gcc/testsuite/g++.dg/torture/strub-init3.C
index 6ebebcd01e8..14f28e3c276 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init3.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init3.C
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
 
 extern int __attribute__((__strub__)) initializer ();
 
diff --git a/gcc/testsuite/gnat.dg/strub_access.adb b/gcc/testsuite/gnat.dg/strub_access.adb
index 29e6996ecf6..488a2d64afe 100644
--- a/gcc/testsuite/gnat.dg/strub_access.adb
+++ b/gcc/testsuite/gnat.dg/strub_access.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed -fdump-ipa-strubm" }
+--  { dg-require-effective-target strub }
 
 --  The main subprogram doesn't read from the automatic variable, but
 --  being an automatic variable, its presence should be enough for the
diff --git a/gcc/testsuite/gnat.dg/strub_access1.adb b/gcc/testsuite/gnat.dg/strub_access1.adb
index dae47060164..4a8653c4d84 100644
--- a/gcc/testsuite/gnat.dg/strub_access1.adb
+++ b/gcc/testsuite/gnat.dg/strub_access1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed" }
+--  { dg-require-effective-target strub }
 
 --  Check that we reject 'Access of a strub variable whose type does
 --  not carry a strub modifier.
diff --git a/gcc/testsuite/gnat.dg/strub_attr.adb b/gcc/testsuite/gnat.dg/strub_attr.adb
index 10445d7cf84..eb7826dc990 100644
--- a/gcc/testsuite/gnat.dg/strub_attr.adb
+++ b/gcc/testsuite/gnat.dg/strub_attr.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm -fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 package body Strub_Attr is
    E : exception;
diff --git a/gcc/testsuite/gnat.dg/strub_disp.adb b/gcc/testsuite/gnat.dg/strub_disp.adb
index 3dbcc4a357c..f23d4675def 100644
--- a/gcc/testsuite/gnat.dg/strub_disp.adb
+++ b/gcc/testsuite/gnat.dg/strub_disp.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Disp is
    package Foo is
diff --git a/gcc/testsuite/gnat.dg/strub_disp1.adb b/gcc/testsuite/gnat.dg/strub_disp1.adb
index 09756a74b7d..9c4c7f69637 100644
--- a/gcc/testsuite/gnat.dg/strub_disp1.adb
+++ b/gcc/testsuite/gnat.dg/strub_disp1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 -- Check that at-calls dispatching calls are transformed.
 
diff --git a/gcc/testsuite/gnat.dg/strub_ind.adb b/gcc/testsuite/gnat.dg/strub_ind.adb
index da56acaa957..613db69305e 100644
--- a/gcc/testsuite/gnat.dg/strub_ind.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict" }
+--  { dg-require-effective-target strub }
 
 --  This is essentially the same test as strub_attr.adb, 
 --  but applying attributes to access types as well.
diff --git a/gcc/testsuite/gnat.dg/strub_ind1.adb b/gcc/testsuite/gnat.dg/strub_ind1.adb
index 825e395e681..245b0a830f6 100644
--- a/gcc/testsuite/gnat.dg/strub_ind1.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm" }
+--  { dg-require-effective-target strub }
 
 --  This is essentially the same test as strub_attr.adb, 
 --  but with an explicit conversion.
diff --git a/gcc/testsuite/gnat.dg/strub_ind2.adb b/gcc/testsuite/gnat.dg/strub_ind2.adb
index e918b392631..b9bfe50e929 100644
--- a/gcc/testsuite/gnat.dg/strub_ind2.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind2.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict" }
+--  { dg-require-effective-target strub }
 
 --  This is essentially the same test as strub_attr.adb, 
 --  but with an explicit conversion.
diff --git a/gcc/testsuite/gnat.dg/strub_intf.adb b/gcc/testsuite/gnat.dg/strub_intf.adb
index 8f0212a7586..f43854705d0 100644
--- a/gcc/testsuite/gnat.dg/strub_intf.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 --  Check that strub mode mismatches between overrider and overridden
 --  subprograms are reported.
diff --git a/gcc/testsuite/gnat.dg/strub_intf1.adb b/gcc/testsuite/gnat.dg/strub_intf1.adb
index bf77321cef7..7a38a4c49ba 100644
--- a/gcc/testsuite/gnat.dg/strub_intf1.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 -- Check that at-calls dispatching calls to interfaces are transformed.
 
diff --git a/gcc/testsuite/gnat.dg/strub_intf2.adb b/gcc/testsuite/gnat.dg/strub_intf2.adb
index e8880dbc437..7992b7344fb 100644
--- a/gcc/testsuite/gnat.dg/strub_intf2.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf2.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 --  Check that strub mode mismatches between overrider and overridden
 --  subprograms are reported even when the overriders for an
diff --git a/gcc/testsuite/gnat.dg/strub_renm.adb b/gcc/testsuite/gnat.dg/strub_renm.adb
index 217367e712d..abfb120b514 100644
--- a/gcc/testsuite/gnat.dg/strub_renm.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Renm is
    procedure P (X : Integer);
diff --git a/gcc/testsuite/gnat.dg/strub_renm1.adb b/gcc/testsuite/gnat.dg/strub_renm1.adb
index a11adbfb5a9..68d3230b535 100644
--- a/gcc/testsuite/gnat.dg/strub_renm1.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed -fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Renm1 is
    V : Integer := 0;
diff --git a/gcc/testsuite/gnat.dg/strub_renm2.adb b/gcc/testsuite/gnat.dg/strub_renm2.adb
index c488c20826f..3cb81ea03f7 100644
--- a/gcc/testsuite/gnat.dg/strub_renm2.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm2.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Renm2 is
    V : Integer := 0;
diff --git a/gcc/testsuite/gnat.dg/strub_var.adb b/gcc/testsuite/gnat.dg/strub_var.adb
index 3d158de2803..7c6affa06d4 100644
--- a/gcc/testsuite/gnat.dg/strub_var.adb
+++ b/gcc/testsuite/gnat.dg/strub_var.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm" }
+--  { dg-require-effective-target strub }
 
 -- We don't read from the automatic variable, but being an automatic
 --  variable, its presence should be enough for the procedure to get
diff --git a/gcc/testsuite/gnat.dg/strub_var1.adb b/gcc/testsuite/gnat.dg/strub_var1.adb
index 6a504e09198..64b7e65fe9b 100644
--- a/gcc/testsuite/gnat.dg/strub_var1.adb
+++ b/gcc/testsuite/gnat.dg/strub_var1.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 with Strub_Attr;
 procedure Strub_Var1 is
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 3fcce6be49d..40a60c198cf 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -1302,6 +1302,13 @@ proc check_stack_check_available { stack_kind } {
     } "$stack_opt"]
 }
 
+# Return 1 if the target supports stack scrubbing.
+proc check_effective_target_strub {} {
+    return [check_no_compiler_messages strub assembly {
+	void __attribute__ ((__strub__)) fn (void) {}
+    } ""]
+}
+
 # Return 1 if compilation with -freorder-blocks-and-partition is error-free
 # for trivial code, 0 otherwise.  As some targets (ARM for example) only
 # warn when -fprofile-use is also supplied we test that combination too.
diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in
index d8163c5af99..3f77283490e 100644
--- a/libgcc/Makefile.in
+++ b/libgcc/Makefile.in
@@ -434,7 +434,7 @@ LIB2ADD += enable-execute-stack.c
 LIB2ADD += $(srcdir)/hardcfr.c
 
 # Stack scrubbing infrastructure.
-LIB2ADD += $(srcdir)/strub.c
+@HAVE_STRUB_SUPPORT@LIB2ADD += $(srcdir)/strub.c
 
 # While emutls.c has nothing to do with EH, it is in LIB2ADDEH*
 # instead of LIB2ADD because that's the way to be sure on some targets
diff --git a/libgcc/configure b/libgcc/configure
index cf149209652..567158955a3 100755
--- a/libgcc/configure
+++ b/libgcc/configure
@@ -593,6 +593,7 @@ asm_hidden_op
 extra_parts
 cpu_type
 get_gcc_base_ver
+HAVE_STRUB_SUPPORT
 thread_header
 tm_defines
 tm_file
@@ -5702,6 +5703,31 @@ esac
 
 
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for strub support" >&5
+$as_echo_n "checking for strub support... " >&6; }
+if ${libgcc_cv_strub_support+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+void __attribute__ ((__strub__)) fn (void) {}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  libgcc_cv_strub_support=yes
+else
+  libgcc_cv_strub_support=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgcc_cv_strub_support" >&5
+$as_echo "$libgcc_cv_strub_support" >&6; }
+if test "x$libgcc_cv_strub_support" != xno; then
+  HAVE_STRUB_SUPPORT=
+else
+  HAVE_STRUB_SUPPORT='# '
+fi
+
+
 # Determine what GCC version number to use in filesystem paths.
 
   get_gcc_base_ver="cat"
diff --git a/libgcc/configure.ac b/libgcc/configure.ac
index 2fc9d5d7c93..9c0e415501a 100644
--- a/libgcc/configure.ac
+++ b/libgcc/configure.ac
@@ -694,6 +694,19 @@ AC_SUBST(tm_defines)
 # Map from thread model to thread header.
 GCC_AC_THREAD_HEADER([$target_thread_file])
 
+AC_CACHE_CHECK([for strub support],
+  [libgcc_cv_strub_support],
+  [AC_COMPILE_IFELSE(
+    [AC_LANG_SOURCE([void __attribute__ ((__strub__)) fn (void) {}])],
+    [libgcc_cv_strub_support=yes],
+    [libgcc_cv_strub_support=no])])
+if test "x$libgcc_cv_strub_support" != xno; then
+  HAVE_STRUB_SUPPORT=
+else
+  HAVE_STRUB_SUPPORT='# '
+fi
+AC_SUBST(HAVE_STRUB_SUPPORT)
+
 # Determine what GCC version number to use in filesystem paths.
 GCC_BASE_VER

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [gcc(refs/users/aoliva/heads/testme)] strub: enable conditional support
@ 2023-12-07  1:34 Alexandre Oliva
  0 siblings, 0 replies; 25+ messages in thread
From: Alexandre Oliva @ 2023-12-07  1:34 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:33d4312cf29a259b54113a968b9658110621b3ac

commit 33d4312cf29a259b54113a968b9658110621b3ac
Author: Alexandre Oliva <oliva@adacore.com>
Date:   Wed Dec 6 19:36:02 2023 -0300

    strub: enable conditional support
    
    Targets that don't expose callee stacks to callers, such as nvptx, as
    well as -fsplit-stack compilations, violate fundamental assumptions of
    the current strub implementation.  This patch enables targets to
    disable strub, and disables it when -fsplit-stack is enabled.
    
    When strub support is disabled, the testsuite will now skip strub
    tests, and libgcc will not build the strub runtime components.
    
    
    for  gcc/ChangeLog
    
            * target.def (have_strub_support_for): New hook.
            * doc/tm.texi.in: Document it.
            * doc/tm.texi: Rebuild.
            * ipa-strub.cc: Include target.h.
            (strub_target_support_p): New.
            (can_strub_p): Call it.  Test for no flag_split_stack.
            (pass_ipa_strub::adjust_at_calls_call): Check for target
            support.
            * config/nvptx/nvptx.cc (TARGET_HAVE_STRUB_SUPPORT_FOR):
            Disable.
            * doc/sourcebuild.texi (strub): Document new effective
            target.
    
    for  gcc/testsuite/ChangeLog
    
            * gcc.dg/strub-split-stack.c: New.
            * gcc.dg/strub-unsupported.c: New.
            * gcc.dg/strub-unsupported-2.c: New.
            * lib/target-supports.exp (check_effective_target_strub): New.
            * c-c++-common/strub-O0.c: Require effective target strub.
            * c-c++-common/strub-O1.c: Likewise.
            * c-c++-common/strub-O2.c: Likewise.
            * c-c++-common/strub-O2fni.c: Likewise.
            * c-c++-common/strub-O3.c: Likewise.
            * c-c++-common/strub-O3fni.c: Likewise.
            * c-c++-common/strub-Og.c: Likewise.
            * c-c++-common/strub-Os.c: Likewise.
            * c-c++-common/strub-all1.c: Likewise.
            * c-c++-common/strub-all2.c: Likewise.
            * c-c++-common/strub-apply1.c: Likewise.
            * c-c++-common/strub-apply2.c: Likewise.
            * c-c++-common/strub-apply3.c: Likewise.
            * c-c++-common/strub-apply4.c: Likewise.
            * c-c++-common/strub-at-calls1.c: Likewise.
            * c-c++-common/strub-at-calls2.c: Likewise.
            * c-c++-common/strub-defer-O1.c: Likewise.
            * c-c++-common/strub-defer-O2.c: Likewise.
            * c-c++-common/strub-defer-O3.c: Likewise.
            * c-c++-common/strub-defer-Os.c: Likewise.
            * c-c++-common/strub-internal1.c: Likewise.
            * c-c++-common/strub-internal2.c: Likewise.
            * c-c++-common/strub-parms1.c: Likewise.
            * c-c++-common/strub-parms2.c: Likewise.
            * c-c++-common/strub-parms3.c: Likewise.
            * c-c++-common/strub-relaxed1.c: Likewise.
            * c-c++-common/strub-relaxed2.c: Likewise.
            * c-c++-common/strub-short-O0-exc.c: Likewise.
            * c-c++-common/strub-short-O0.c: Likewise.
            * c-c++-common/strub-short-O1.c: Likewise.
            * c-c++-common/strub-short-O2.c: Likewise.
            * c-c++-common/strub-short-O3.c: Likewise.
            * c-c++-common/strub-short-Os.c: Likewise.
            * c-c++-common/strub-strict1.c: Likewise.
            * c-c++-common/strub-strict2.c: Likewise.
            * c-c++-common/strub-tail-O1.c: Likewise.
            * c-c++-common/strub-tail-O2.c: Likewise.
            * c-c++-common/strub-var1.c: Likewise.
            * c-c++-common/torture/strub-callable1.c: Likewise.
            * c-c++-common/torture/strub-callable2.c: Likewise.
            * c-c++-common/torture/strub-const1.c: Likewise.
            * c-c++-common/torture/strub-const2.c: Likewise.
            * c-c++-common/torture/strub-const3.c: Likewise.
            * c-c++-common/torture/strub-const4.c: Likewise.
            * c-c++-common/torture/strub-data1.c: Likewise.
            * c-c++-common/torture/strub-data2.c: Likewise.
            * c-c++-common/torture/strub-data3.c: Likewise.
            * c-c++-common/torture/strub-data4.c: Likewise.
            * c-c++-common/torture/strub-data5.c: Likewise.
            * c-c++-common/torture/strub-indcall1.c: Likewise.
            * c-c++-common/torture/strub-indcall2.c: Likewise.
            * c-c++-common/torture/strub-indcall3.c: Likewise.
            * c-c++-common/torture/strub-inlinable1.c: Likewise.
            * c-c++-common/torture/strub-inlinable2.c: Likewise.
            * c-c++-common/torture/strub-ptrfn1.c: Likewise.
            * c-c++-common/torture/strub-ptrfn2.c: Likewise.
            * c-c++-common/torture/strub-ptrfn3.c: Likewise.
            * c-c++-common/torture/strub-ptrfn4.c: Likewise.
            * c-c++-common/torture/strub-pure1.c: Likewise.
            * c-c++-common/torture/strub-pure2.c: Likewise.
            * c-c++-common/torture/strub-pure3.c: Likewise.
            * c-c++-common/torture/strub-pure4.c: Likewise.
            * c-c++-common/torture/strub-run1.c: Likewise.
            * c-c++-common/torture/strub-run2.c: Likewise.
            * c-c++-common/torture/strub-run3.c: Likewise.
            * c-c++-common/torture/strub-run4.c: Likewise.
            * c-c++-common/torture/strub-run4c.c: Likewise.
            * c-c++-common/torture/strub-run4d.c: Likewise.
            * c-c++-common/torture/strub-run4i.c: Likewise.
            * g++.dg/strub-run1.C: Likewise.
            * g++.dg/torture/strub-init1.C: Likewise.
            * g++.dg/torture/strub-init2.C: Likewise.
            * g++.dg/torture/strub-init3.C: Likewise.
            * gnat.dg/strub_attr.adb: Likewise.
            * gnat.dg/strub_ind.adb: Likewise.
            * gnat.dg/strub_access.adb: Likewise.
            * gnat.dg/strub_access1.adb: Likewise.
            * gnat.dg/strub_disp.adb: Likewise.
            * gnat.dg/strub_disp1.adb: Likewise.
            * gnat.dg/strub_ind1.adb: Likewise.
            * gnat.dg/strub_ind2.adb: Likewise.
            * gnat.dg/strub_intf.adb: Likewise.
            * gnat.dg/strub_intf1.adb: Likewise.
            * gnat.dg/strub_intf2.adb: Likewise.
            * gnat.dg/strub_renm.adb: Likewise.
            * gnat.dg/strub_renm1.adb: Likewise.
            * gnat.dg/strub_renm2.adb: Likewise.
            * gnat.dg/strub_var.adb: Likewise.
            * gnat.dg/strub_var1.adb: Likewise.
    
    for  libgcc/ChangeLog
    
            * configure.ac: Check for strub support.
            * configure: Rebuilt.
            * Makefile.in: Compile strub.c conditionally.

Diff:
---
 gcc/config/i386/i386.cc                            |  4 ++
 gcc/config/nvptx/nvptx.cc                          |  3 ++
 gcc/doc/sourcebuild.texi                           |  3 ++
 gcc/doc/tm.texi                                    |  6 +++
 gcc/doc/tm.texi.in                                 |  2 +
 gcc/ipa-strub.cc                                   | 54 +++++++++++++++++++++-
 gcc/target.def                                     |  8 ++++
 gcc/testsuite/c-c++-common/strub-O0.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O1.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O2.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O2fni.c           |  1 +
 gcc/testsuite/c-c++-common/strub-O3.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O3fni.c           |  1 +
 gcc/testsuite/c-c++-common/strub-Og.c              |  1 +
 gcc/testsuite/c-c++-common/strub-Os.c              |  1 +
 gcc/testsuite/c-c++-common/strub-all1.c            |  1 +
 gcc/testsuite/c-c++-common/strub-all2.c            |  1 +
 gcc/testsuite/c-c++-common/strub-apply1.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply2.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply3.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply4.c          |  1 +
 gcc/testsuite/c-c++-common/strub-at-calls1.c       |  1 +
 gcc/testsuite/c-c++-common/strub-at-calls2.c       |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O3.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-Os.c        |  1 +
 gcc/testsuite/c-c++-common/strub-internal1.c       |  1 +
 gcc/testsuite/c-c++-common/strub-internal2.c       |  1 +
 gcc/testsuite/c-c++-common/strub-parms1.c          |  1 +
 gcc/testsuite/c-c++-common/strub-parms2.c          |  1 +
 gcc/testsuite/c-c++-common/strub-parms3.c          |  1 +
 gcc/testsuite/c-c++-common/strub-relaxed1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-relaxed2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O0-exc.c    |  1 +
 gcc/testsuite/c-c++-common/strub-short-O0.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O3.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-Os.c        |  1 +
 gcc/testsuite/c-c++-common/strub-split-stack.c     | 10 ++++
 gcc/testsuite/c-c++-common/strub-strict1.c         |  1 +
 gcc/testsuite/c-c++-common/strub-strict2.c         |  1 +
 gcc/testsuite/c-c++-common/strub-tail-O1.c         |  1 +
 gcc/testsuite/c-c++-common/strub-tail-O2.c         |  1 +
 gcc/testsuite/c-c++-common/strub-unsupported-2.c   | 13 ++++++
 gcc/testsuite/c-c++-common/strub-unsupported.c     | 20 ++++++++
 gcc/testsuite/c-c++-common/strub-var1.c            |  1 +
 .../c-c++-common/torture/strub-callable1.c         |  1 +
 .../c-c++-common/torture/strub-callable2.c         |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const1.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const2.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const3.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const4.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data1.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data2.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data3.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data4.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data5.c   |  1 +
 .../c-c++-common/torture/strub-indcall1.c          |  1 +
 .../c-c++-common/torture/strub-indcall2.c          |  1 +
 .../c-c++-common/torture/strub-indcall3.c          |  1 +
 .../c-c++-common/torture/strub-inlinable1.c        |  1 +
 .../c-c++-common/torture/strub-inlinable2.c        |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure1.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure2.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure3.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure4.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run1.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run2.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run3.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4c.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4d.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4i.c   |  1 +
 gcc/testsuite/g++.dg/strub-run1.C                  |  1 +
 gcc/testsuite/g++.dg/torture/strub-init1.C         |  1 +
 gcc/testsuite/g++.dg/torture/strub-init2.C         |  1 +
 gcc/testsuite/g++.dg/torture/strub-init3.C         |  1 +
 gcc/testsuite/gnat.dg/strub_access.adb             |  1 +
 gcc/testsuite/gnat.dg/strub_access1.adb            |  1 +
 gcc/testsuite/gnat.dg/strub_attr.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_disp.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_disp1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_ind.adb                |  1 +
 gcc/testsuite/gnat.dg/strub_ind1.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_ind2.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_intf.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_intf1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_intf2.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_renm.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_renm1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_renm2.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_var.adb                |  1 +
 gcc/testsuite/gnat.dg/strub_var1.adb               |  1 +
 gcc/testsuite/lib/target-supports.exp              |  7 +++
 libgcc/Makefile.in                                 |  2 +-
 libgcc/configure                                   | 26 +++++++++++
 libgcc/configure.ac                                | 13 ++++++
 103 files changed, 257 insertions(+), 3 deletions(-)

diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 7c5cab4e2c6..f933c9c23c7 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -26658,6 +26658,10 @@ ix86_libm_function_max_error (unsigned cfn, machine_mode mode,
 #define TARGET_RUN_TARGET_SELFTESTS selftest::ix86_run_selftests
 #endif /* #if CHECKING_P */
 
+// ??? for testing only
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 #include "gt-i386.h"
diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc
index ae20802c879..3fb1deb70fd 100644
--- a/gcc/config/nvptx/nvptx.cc
+++ b/gcc/config/nvptx/nvptx.cc
@@ -7789,6 +7789,9 @@ nvptx_asm_output_def_from_decls (FILE *stream, tree name, tree value)
 #undef TARGET_LIBC_HAS_FUNCTION
 #define TARGET_LIBC_HAS_FUNCTION nvptx_libc_has_function
 
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-nvptx.h"
diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi
index c9909026854..26a7e9c3507 100644
--- a/gcc/doc/sourcebuild.texi
+++ b/gcc/doc/sourcebuild.texi
@@ -2983,6 +2983,9 @@ Target supports statically linking @samp{libgfortran}.
 @item string_merging
 Target supports merging string constants at link time.
 
+@item strub
+Target supports attribute @code{strub} for stack scrubbing.
+
 @item ucn
 Target supports compiling and assembling UCN.
 
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 89a1735dd79..768ada0af52 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -3450,6 +3450,12 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@deftypefn {Target Hook} bool TARGET_HAVE_STRUB_SUPPORT_FOR (tree)
+Returns true if the target supports stack scrubbing for the given function
+or type, otherwise return false.  The default implementation always returns
+true.
+@end deftypefn
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index ebc1d3de5ca..4fe0805394e 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2686,6 +2686,8 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@hook TARGET_HAVE_STRUB_SUPPORT_FOR
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
index 293bec132b8..2afb7a45575 100644
--- a/gcc/ipa-strub.cc
+++ b/gcc/ipa-strub.cc
@@ -60,6 +60,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-strub.h"
 #include "symtab-thunks.h"
 #include "attr-fnspec.h"
+#include "target.h"
 
 /* This file introduces two passes that, together, implement
    machine-independent stack scrubbing, strub for short.  It arranges
@@ -631,17 +632,60 @@ strub_always_inline_p (cgraph_node *node)
   return lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl));
 }
 
+/* Return TRUE iff the target has strub support for T, a function
+   decl, or a type used in an indirect call, and optionally REPORT the
+   reasons for ineligibility.  If T is a type and error REPORTing is
+   enabled, the LOCation (of the indirect call) should be provided.  */
+static inline bool
+strub_target_support_p (tree t, bool report = false,
+			location_t loc = UNKNOWN_LOCATION)
+{
+  bool result = true;
+
+  if (!targetm.have_strub_support_for (t))
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      if (DECL_P (t))
+	sorry_at (DECL_SOURCE_LOCATION (t),
+		  "%qD is not eligible for %<strub%>"
+		  " on the target system", t);
+      else
+	sorry_at (loc,
+		  "unsupported %<strub%> call"
+		  " on the target system");
+    }
+
+  return result;
+}
+
 /* Return TRUE iff NODE is potentially eligible for any strub-enabled mode, and
    optionally REPORT the reasons for ineligibility.  */
 
 static inline bool
 can_strub_p (cgraph_node *node, bool report = false)
 {
-  bool result = true;
+  bool result = strub_target_support_p (node->decl, report);
 
-  if (!report && strub_always_inline_p (node))
+  if (!report && (!result || strub_always_inline_p (node)))
     return result;
 
+  if (flag_split_stack)
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (node->decl),
+		"%qD is not eligible for %<strub%>"
+		" because %<-fsplit-stack%> is enabled",
+		node->decl);
+    }
+
   if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
     {
       result = false;
@@ -2417,6 +2461,12 @@ pass_ipa_strub::adjust_at_calls_call (cgraph_edge *e, int named_args,
 			 && (TREE_TYPE (gimple_call_arg (ocall, named_args))
 			     == get_pwmt ())));
 
+  tree tsup;
+  if (!(tsup = gimple_call_fndecl (ocall)))
+    tsup = TREE_TYPE (TREE_TYPE (gimple_call_fn (ocall)));
+  if (!strub_target_support_p (tsup, true, gimple_location (ocall)))
+    return;
+
   /* If we're already within a strub context, pass on the incoming watermark
      pointer, and omit the enter and leave calls around the modified call, as an
      optimization, or as a means to satisfy a tail-call requirement.  */
diff --git a/gcc/target.def b/gcc/target.def
index 52b83e091b9..08218f3a42a 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4457,6 +4457,14 @@ otherwise return false.  The default implementation always returns true.",
  bool, (void),
  hook_bool_void_true)
 
+DEFHOOK
+(have_strub_support_for,
+ "Returns true if the target supports stack scrubbing for the given function\n\
+or type, otherwise return false.  The default implementation always returns\n\
+true.",
+ bool, (tree),
+ hook_bool_tree_true)
+
 DEFHOOK
 (have_speculation_safe_value,
 "This hook is used to determine the level of target support for\n\
diff --git a/gcc/testsuite/c-c++-common/strub-O0.c b/gcc/testsuite/c-c++-common/strub-O0.c
index c7a79a6ea0d..f0a3f7b4c6f 100644
--- a/gcc/testsuite/c-c++-common/strub-O0.c
+++ b/gcc/testsuite/c-c++-common/strub-O0.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -O0, none of the strub builtins are expanded inline.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O1.c b/gcc/testsuite/c-c++-common/strub-O1.c
index 96285c975d9..50403426b18 100644
--- a/gcc/testsuite/c-c++-common/strub-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -O1, without -fno-inline, we fully expand enter, but neither update nor
    leave.  */
diff --git a/gcc/testsuite/c-c++-common/strub-O2.c b/gcc/testsuite/c-c++-common/strub-O2.c
index 8edc0d8aa13..37e02998e31 100644
--- a/gcc/testsuite/c-c++-common/strub-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -O2, without -fno-inline, we fully expand enter and update, and add a test
    around the leave call.  */
diff --git a/gcc/testsuite/c-c++-common/strub-O2fni.c b/gcc/testsuite/c-c++-common/strub-O2fni.c
index c6d900cf3c4..905e2c6b2ff 100644
--- a/gcc/testsuite/c-c++-common/strub-O2fni.c
+++ b/gcc/testsuite/c-c++-common/strub-O2fni.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
+/* { dg-require-effective-target strub } */
 
 /* With -fno-inline, none of the strub builtins are inlined.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O3.c b/gcc/testsuite/c-c++-common/strub-O3.c
index 33ee465e51c..3bbf132bdf1 100644
--- a/gcc/testsuite/c-c++-common/strub-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-O3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 int __attribute__ ((__strub__)) var;
 
diff --git a/gcc/testsuite/c-c++-common/strub-O3fni.c b/gcc/testsuite/c-c++-common/strub-O3fni.c
index 2936f82079e..c46fce38e5c 100644
--- a/gcc/testsuite/c-c++-common/strub-O3fni.c
+++ b/gcc/testsuite/c-c++-common/strub-O3fni.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
+/* { dg-require-effective-target strub } */
 
 /* With -fno-inline, none of the strub builtins are inlined.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-Og.c b/gcc/testsuite/c-c++-common/strub-Og.c
index 479746e57d8..3b8eb19765c 100644
--- a/gcc/testsuite/c-c++-common/strub-Og.c
+++ b/gcc/testsuite/c-c++-common/strub-Og.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-Og -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -Og, without -fno-inline, we fully expand enter, but neither update nor
    leave.  */
diff --git a/gcc/testsuite/c-c++-common/strub-Os.c b/gcc/testsuite/c-c++-common/strub-Os.c
index 2241d4ea07f..8cfb253d676 100644
--- a/gcc/testsuite/c-c++-common/strub-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-Os.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-Os -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -Os, without -fno-inline, we fully expand enter, and also update.  The
    expanded update might be larger than a call proper, but argument saving and
diff --git a/gcc/testsuite/c-c++-common/strub-all1.c b/gcc/testsuite/c-c++-common/strub-all1.c
index a322bcc5da6..2037f681f29 100644
--- a/gcc/testsuite/c-c++-common/strub-all1.c
+++ b/gcc/testsuite/c-c++-common/strub-all1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
    strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub.  */
diff --git a/gcc/testsuite/c-c++-common/strub-all2.c b/gcc/testsuite/c-c++-common/strub-all2.c
index db60026d0e0..c026e7d9d28 100644
--- a/gcc/testsuite/c-c++-common/strub-all2.c
+++ b/gcc/testsuite/c-c++-common/strub-all2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* g becomes STRUB_INTERNAL, because of the flag.  Without inline, force_output
    is set for static non-inline functions when not optimizing, and that keeps
diff --git a/gcc/testsuite/c-c++-common/strub-apply1.c b/gcc/testsuite/c-c++-common/strub-apply1.c
index 2f462adc1ef..3edc89c54ee 100644
--- a/gcc/testsuite/c-c++-common/strub-apply1.c
+++ b/gcc/testsuite/c-c++-common/strub-apply1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 void __attribute__ ((__strub__ ("callable")))
 apply_function (void *args)
diff --git a/gcc/testsuite/c-c++-common/strub-apply2.c b/gcc/testsuite/c-c++-common/strub-apply2.c
index a5d7551f5da..838fc752734 100644
--- a/gcc/testsuite/c-c++-common/strub-apply2.c
+++ b/gcc/testsuite/c-c++-common/strub-apply2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 extern void __attribute__ ((__strub__))
 apply_function (void *args);
diff --git a/gcc/testsuite/c-c++-common/strub-apply3.c b/gcc/testsuite/c-c++-common/strub-apply3.c
index 64422a0d1e8..0206e4d930e 100644
--- a/gcc/testsuite/c-c++-common/strub-apply3.c
+++ b/gcc/testsuite/c-c++-common/strub-apply3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 void __attribute__ ((__strub__))
 apply_function (void *args)
diff --git a/gcc/testsuite/c-c++-common/strub-apply4.c b/gcc/testsuite/c-c++-common/strub-apply4.c
index 15ffaa031b8..e82504728b2 100644
--- a/gcc/testsuite/c-c++-common/strub-apply4.c
+++ b/gcc/testsuite/c-c++-common/strub-apply4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that implicit enabling of strub mode selects internal strub when the
    function uses __builtin_apply_args, that prevents the optimization to
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls1.c b/gcc/testsuite/c-c++-common/strub-at-calls1.c
index b70843b4215..a20acc0a48a 100644
--- a/gcc/testsuite/c-c++-common/strub-at-calls1.c
+++ b/gcc/testsuite/c-c++-common/strub-at-calls1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
    strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub.  */
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls2.c b/gcc/testsuite/c-c++-common/strub-at-calls2.c
index 97a3988a6b9..7915b33a39a 100644
--- a/gcc/testsuite/c-c++-common/strub-at-calls2.c
+++ b/gcc/testsuite/c-c++-common/strub-at-calls2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* g does NOT become STRUB_AT_CALLS because it's not viable.  Without inline,
    force_output is set for static non-inline functions when not optimizing, and
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O1.c b/gcc/testsuite/c-c++-common/strub-defer-O1.c
index 3d73431b3dc..3689998b5a3 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O1" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function does NOT defer
    the strubbing to its caller at -O1.  */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O2.c b/gcc/testsuite/c-c++-common/strub-defer-O2.c
index fddf3c745e7..9e01949db6b 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O2" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function does NOT defer
    the strubbing to its caller at -O2.  */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O3.c b/gcc/testsuite/c-c++-common/strub-defer-O3.c
index 7ebc65b58dd..40ee8edd1e0 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O3.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O3" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function defers the
    strubbing to its caller at -O3.  */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-Os.c b/gcc/testsuite/c-c++-common/strub-defer-Os.c
index fbaf85fe0fa..67ea9f04639 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-Os.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -Os" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function defers the
    strubbing to its caller at -Os.  */
diff --git a/gcc/testsuite/c-c++-common/strub-internal1.c b/gcc/testsuite/c-c++-common/strub-internal1.c
index e9d7b7b9ee0..d17254904e5 100644
--- a/gcc/testsuite/c-c++-common/strub-internal1.c
+++ b/gcc/testsuite/c-c++-common/strub-internal1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
    strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub.  */
diff --git a/gcc/testsuite/c-c++-common/strub-internal2.c b/gcc/testsuite/c-c++-common/strub-internal2.c
index 8b8e15a51c7..afc9189701f 100644
--- a/gcc/testsuite/c-c++-common/strub-internal2.c
+++ b/gcc/testsuite/c-c++-common/strub-internal2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* g becomes STRUB_INTERNAL, because of the flag.  */
 static void
diff --git a/gcc/testsuite/c-c++-common/strub-parms1.c b/gcc/testsuite/c-c++-common/strub-parms1.c
index 0a4a7539d34..f410b268971 100644
--- a/gcc/testsuite/c-c++-common/strub-parms1.c
+++ b/gcc/testsuite/c-c++-common/strub-parms1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 #include <stdarg.h>
 
diff --git a/gcc/testsuite/c-c++-common/strub-parms2.c b/gcc/testsuite/c-c++-common/strub-parms2.c
index 147171d96d5..6f572115a88 100644
--- a/gcc/testsuite/c-c++-common/strub-parms2.c
+++ b/gcc/testsuite/c-c++-common/strub-parms2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 #include <stdarg.h>
 
diff --git a/gcc/testsuite/c-c++-common/strub-parms3.c b/gcc/testsuite/c-c++-common/strub-parms3.c
index 4e92682895a..7383fea9ce8 100644
--- a/gcc/testsuite/c-c++-common/strub-parms3.c
+++ b/gcc/testsuite/c-c++-common/strub-parms3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that uses of a strub variable implicitly enables internal strub for
    publicly-visible functions, and causes the same transformations to their
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed1.c b/gcc/testsuite/c-c++-common/strub-relaxed1.c
index e2f9d8aebca..d2b4b52c51e 100644
--- a/gcc/testsuite/c-c++-common/strub-relaxed1.c
+++ b/gcc/testsuite/c-c++-common/strub-relaxed1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The difference between relaxed and strict in this case is that we accept the
    call from one internal-strub function to another.  Without the error,
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed2.c b/gcc/testsuite/c-c++-common/strub-relaxed2.c
index 98474435d2e..9e5a8e76b6c 100644
--- a/gcc/testsuite/c-c++-common/strub-relaxed2.c
+++ b/gcc/testsuite/c-c++-common/strub-relaxed2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The difference between relaxed and strict in this case is that we accept the
    call from one internal-strub function to another.  */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
index 1de15342595..aaeba2a2159 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fexceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0.c b/gcc/testsuite/c-c++-common/strub-short-O0.c
index f9209c81900..30cbdd819f1 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O0.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O0.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O1.c b/gcc/testsuite/c-c++-common/strub-short-O1.c
index bed1dcfb54a..911fdfb6db9 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O2.c b/gcc/testsuite/c-c++-common/strub-short-O2.c
index 6bf0071f52b..9b23ee3ac33 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O3.c b/gcc/testsuite/c-c++-common/strub-short-O3.c
index 4732f515bf7..4b3a8f843ea 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  At -O3 and -Os, we omit
    enter and leave calls within strub contexts, passing on the enclosing
diff --git a/gcc/testsuite/c-c++-common/strub-short-Os.c b/gcc/testsuite/c-c++-common/strub-short-Os.c
index 8d6424c479a..3627a240600 100644
--- a/gcc/testsuite/c-c++-common/strub-short-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-short-Os.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-Os -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  At -O3 and -Os, we omit
    enter and leave calls within strub contexts, passing on the enclosing
diff --git a/gcc/testsuite/c-c++-common/strub-split-stack.c b/gcc/testsuite/c-c++-common/strub-split-stack.c
new file mode 100644
index 00000000000..acbd750c3cd
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-split-stack.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-fsplit-stack" } */
+/* { dg-require-effective-target strub } */
+/* { dg-require-effective-target split-stack } */
+
+void __attribute__ ((__strub__))
+f {} /* { dg-message "not eligible" }
+
+void __attribute__ ((__strub__ ("internal")))
+g {} /* { dg-message "not eligible" }
diff --git a/gcc/testsuite/c-c++-common/strub-strict1.c b/gcc/testsuite/c-c++-common/strub-strict1.c
index 36852244206..503eb1734e3 100644
--- a/gcc/testsuite/c-c++-common/strub-strict1.c
+++ b/gcc/testsuite/c-c++-common/strub-strict1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
 
 static int __attribute__ ((__strub__)) var;
 
diff --git a/gcc/testsuite/c-c++-common/strub-strict2.c b/gcc/testsuite/c-c++-common/strub-strict2.c
index b4f28883218..3bf1aa30b4a 100644
--- a/gcc/testsuite/c-c++-common/strub-strict2.c
+++ b/gcc/testsuite/c-c++-common/strub-strict2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
 
 static int __attribute__ ((__strub__)) var;
 
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O1.c b/gcc/testsuite/c-c++-common/strub-tail-O1.c
index e48e0610e07..ba4b1623e28 100644
--- a/gcc/testsuite/c-c++-common/strub-tail-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-tail-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-tail-O2.c"
 
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O2.c b/gcc/testsuite/c-c++-common/strub-tail-O2.c
index 87cda7ab21b..043813b1de4 100644
--- a/gcc/testsuite/c-c++-common/strub-tail-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-tail-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.
    Tail calls are short-circuited at -O2+.  */
diff --git a/gcc/testsuite/c-c++-common/strub-unsupported-2.c b/gcc/testsuite/c-c++-common/strub-unsupported-2.c
new file mode 100644
index 00000000000..3586f4f679d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-unsupported-2.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+
+/* Check that, when strub is not supported (so no dg-required-effective-target
+   strub above), we report when pointers to strub functions are called.  This
+   cannot be part of strub-unsupported.c because errors in the strub-mode pass
+   prevent the main strub pass, where errors at calls are detected, from
+   running.  */
+
+void __attribute__ ((__strub__ ("at-calls"))) (*p) (void);
+
+void m () {
+  p (); /* { dg-message "unsupported" "" { target { ! strub } } } */
+}
diff --git a/gcc/testsuite/c-c++-common/strub-unsupported.c b/gcc/testsuite/c-c++-common/strub-unsupported.c
new file mode 100644
index 00000000000..ecfee3bc36a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-unsupported.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+
+/* Check that, when strub is not supported (so no dg-required-effective-target
+   strub above), we report when strub functions are defined, and when they're
+   called in ways that would require changes.  */
+
+void __attribute__ ((__strub__))
+f (void) {} /* { dg-message "not eligible" "" { target { ! strub } } } */
+
+void __attribute__ ((__strub__ ("internal")))
+g (void) {} /* { dg-message "not eligible" "" { target { ! strub } } } */
+
+extern void __attribute__ ((__strub__))
+h (void); /* { dg-message "not eligible" "" { target { ! strub } } } */
+
+extern void __attribute__ ((__strub__ ("internal")))
+i (void); /* { dg-message "not eligible" "" { target { ! strub } } } */
+
+/* This only gets an error when called, see strub-unsupported-2.c.  */
+void __attribute__ ((__strub__ ("at-calls"))) (*p) (void);
diff --git a/gcc/testsuite/c-c++-common/strub-var1.c b/gcc/testsuite/c-c++-common/strub-var1.c
index eb6250fd39c..67014aa5de8 100644
--- a/gcc/testsuite/c-c++-common/strub-var1.c
+++ b/gcc/testsuite/c-c++-common/strub-var1.c
@@ -1,4 +1,5 @@
 /* { dg-do compile } */
+/* { dg-require-effective-target strub } */
 
 int __attribute__ ((strub)) x;
 float __attribute__ ((strub)) f;
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable1.c b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
index b5e45ab0525..86dbee6746d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-callable1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that strub and non-strub functions can be called from non-strub
    contexts, and that strub and callable functions can be called from strub
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable2.c b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
index 96aa7fe4b07..9da120f6156 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-callable2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that impermissible (cross-strub-context) calls are reported.  */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const1.c b/gcc/testsuite/c-c++-common/torture/strub-const1.c
index 5e956cb1a9b..22056713cce 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub const function call, we issue an asm
    statement to make sure the watermark passed to it is held in memory before
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const2.c b/gcc/testsuite/c-c++-common/torture/strub-const2.c
index 73d650292df..a105c66d7a9 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-const function call, we issue an
    asm statement to make sure the watermark passed to it is held in memory
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const3.c b/gcc/testsuite/c-c++-common/torture/strub-const3.c
index 2584f1f974a..386200c2784 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub const wrapping call, we issue an asm statement
    to make sure the watermark passed to it is held in memory before the call,
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const4.c b/gcc/testsuite/c-c++-common/torture/strub-const4.c
index d819f54ec02..817e9fa2118 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-const wrapping call, we issue an
    asm statement to make sure the watermark passed to it is held in memory
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data1.c b/gcc/testsuite/c-c++-common/torture/strub-data1.c
index 7c27a2a1a6d..132ab63ef73 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointed-to data enables strubbing if accessed.  */
 int __attribute__ ((__strub__)) var;
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data2.c b/gcc/testsuite/c-c++-common/torture/strub-data2.c
index e66d903780a..b660702d26e 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointer itself is a strub variable, enabling internal strubbing when
    its value is used.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data3.c b/gcc/testsuite/c-c++-common/torture/strub-data3.c
index 5e08e0e58c6..fc44eef6f8f 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointer itself is a strub variable, that would enable internal strubbing
    if its value was used.  Here, it's only overwritten, so no strub.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data4.c b/gcc/testsuite/c-c++-common/torture/strub-data4.c
index a818e7a38bb..85e2f59055b 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointer itself is a strub variable, that would enable internal strubbing
    if its value was used.  Here, it's only overwritten, so no strub.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data5.c b/gcc/testsuite/c-c++-common/torture/strub-data5.c
index ddb0b5c0543..0a5edac414d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data5.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data5.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* It would be desirable to issue at least warnings for these.  */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
index c165f312f16..988954e7ed6 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 typedef void __attribute__ ((__strub__)) fntype ();
 fntype (*ptr);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
index 69fcff8d376..d3ca91389a7 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 typedef void __attribute__ ((__strub__)) fntype (int, int);
 fntype (*ptr);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
index ff006224909..89b5979cf7b 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 typedef void __attribute__ ((__strub__)) fntype (int, int, ...);
 fntype (*ptr);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
index 614b02228ba..4917dda8826 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed" } */
+/* { dg-require-effective-target strub } */
 
 inline void __attribute__ ((strub ("internal"), always_inline))
 inl_int_ali (void)
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
index f9a6b4a16fa..c45903856d4 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all" } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-inlinable1.c"
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
index b4a7f3992bb..b0d6139f0a8 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 typedef void ft (void);
 typedef void ft2 (int, int);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
index ef634d35126..1148c246f20 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -Wpedantic" } */
+/* { dg-require-effective-target strub } */
 
 /* C++ does not warn about the partial incompatibilities.
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
index e1f179e160e..06a72d86d2c 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
@@ -1,6 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -Wpedantic -fpermissive" } */
 /* { dg-prune-output "command-line option .-fpermissive." } */
+/* { dg-require-effective-target strub } */
 
 /* See strub-ptrfn2.c.  */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
index 70b558afad0..83ea1af7056 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed" } */
+/* { dg-require-effective-target strub } */
 
 /* This is strub-ptrfn2.c without -Wpedantic.
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure1.c b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
index a262a086837..2643136f178 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub pure function call, we issue an asm statement
    to make sure the watermark passed to it is not assumed to be unchanged.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure2.c b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
index 4c4bd50c209..8bda129b77d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-pure function call, we issue an asm
    statement to make sure the watermark passed to it is not assumed to be
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure3.c b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
index ce195c6b1f1..00bcbdd097a 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub pure wrapping call, we issue an asm statement
    to make sure the watermark passed to it is not assumed to be unchanged.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure4.c b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
index 75cd54ccb5b..ea7c40e7912 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-pure wrapping call, we issue an asm
    statement to make sure the watermark passed to it is not assumed to be
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run1.c b/gcc/testsuite/c-c++-common/torture/strub-run1.c
index 7458b3fb54d..fdf10042863 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run1.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a non-strub function leaves a string behind in the stack, and that
    equivalent strub functions don't.  Avoid the use of red zones by avoiding
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run2.c b/gcc/testsuite/c-c++-common/torture/strub-run2.c
index 5d60a7775f4..1228a665997 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run2.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a non-strub function leaves a string behind in the stack, and that
    equivalent strub functions don't.  Allow red zones to be used.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run3.c b/gcc/testsuite/c-c++-common/torture/strub-run3.c
index c2ad710858e..e5047a988f5 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run3.c
@@ -1,6 +1,7 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a non-strub function leaves a string behind in the stack, and that
    equivalent strub functions don't.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4.c b/gcc/testsuite/c-c++-common/torture/strub-run4.c
index 3b36b8e5d68..0e84a4bab80 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4.c
@@ -1,6 +1,7 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=all" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 /* Check that multi-level, multi-inlined functions still get cleaned up as
    expected, without overwriting temporary stack allocations while they should
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4c.c b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
index 57f9baf758d..edc98486dc9 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4c.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=at-calls" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-run4.c"
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4d.c b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
index 08de3f1c3b1..487ed08bb66 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4d.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
@@ -1,6 +1,7 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 #define ATTR_STRUB_AT_CALLS __attribute__ ((__strub__ ("at-calls")))
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4i.c b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
index 459f6886c54..a85447ffabf 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4i.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=internal" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-run4.c"
diff --git a/gcc/testsuite/g++.dg/strub-run1.C b/gcc/testsuite/g++.dg/strub-run1.C
index 0d367fb83d0..beb8b811f8f 100644
--- a/gcc/testsuite/g++.dg/strub-run1.C
+++ b/gcc/testsuite/g++.dg/strub-run1.C
@@ -1,5 +1,6 @@
 // { dg-do run }
 // { dg-options "-fstrub=internal" }
+// { dg-require-effective-target strub }
 
 // Check that we don't get extra copies.
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init1.C b/gcc/testsuite/g++.dg/torture/strub-init1.C
index c226ab10ff6..6ae45fadd70 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init1.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init1.C
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
 
 extern int __attribute__((__strub__)) initializer ();
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init2.C b/gcc/testsuite/g++.dg/torture/strub-init2.C
index a7911f1fa72..8f4849c7fde 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init2.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init2.C
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
 
 extern int __attribute__((__strub__)) initializer ();
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init3.C b/gcc/testsuite/g++.dg/torture/strub-init3.C
index 6ebebcd01e8..14f28e3c276 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init3.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init3.C
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
 
 extern int __attribute__((__strub__)) initializer ();
 
diff --git a/gcc/testsuite/gnat.dg/strub_access.adb b/gcc/testsuite/gnat.dg/strub_access.adb
index 29e6996ecf6..488a2d64afe 100644
--- a/gcc/testsuite/gnat.dg/strub_access.adb
+++ b/gcc/testsuite/gnat.dg/strub_access.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed -fdump-ipa-strubm" }
+--  { dg-require-effective-target strub }
 
 --  The main subprogram doesn't read from the automatic variable, but
 --  being an automatic variable, its presence should be enough for the
diff --git a/gcc/testsuite/gnat.dg/strub_access1.adb b/gcc/testsuite/gnat.dg/strub_access1.adb
index dae47060164..4a8653c4d84 100644
--- a/gcc/testsuite/gnat.dg/strub_access1.adb
+++ b/gcc/testsuite/gnat.dg/strub_access1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed" }
+--  { dg-require-effective-target strub }
 
 --  Check that we reject 'Access of a strub variable whose type does
 --  not carry a strub modifier.
diff --git a/gcc/testsuite/gnat.dg/strub_attr.adb b/gcc/testsuite/gnat.dg/strub_attr.adb
index 10445d7cf84..eb7826dc990 100644
--- a/gcc/testsuite/gnat.dg/strub_attr.adb
+++ b/gcc/testsuite/gnat.dg/strub_attr.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm -fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 package body Strub_Attr is
    E : exception;
diff --git a/gcc/testsuite/gnat.dg/strub_disp.adb b/gcc/testsuite/gnat.dg/strub_disp.adb
index 3dbcc4a357c..f23d4675def 100644
--- a/gcc/testsuite/gnat.dg/strub_disp.adb
+++ b/gcc/testsuite/gnat.dg/strub_disp.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Disp is
    package Foo is
diff --git a/gcc/testsuite/gnat.dg/strub_disp1.adb b/gcc/testsuite/gnat.dg/strub_disp1.adb
index 09756a74b7d..9c4c7f69637 100644
--- a/gcc/testsuite/gnat.dg/strub_disp1.adb
+++ b/gcc/testsuite/gnat.dg/strub_disp1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 -- Check that at-calls dispatching calls are transformed.
 
diff --git a/gcc/testsuite/gnat.dg/strub_ind.adb b/gcc/testsuite/gnat.dg/strub_ind.adb
index da56acaa957..613db69305e 100644
--- a/gcc/testsuite/gnat.dg/strub_ind.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict" }
+--  { dg-require-effective-target strub }
 
 --  This is essentially the same test as strub_attr.adb, 
 --  but applying attributes to access types as well.
diff --git a/gcc/testsuite/gnat.dg/strub_ind1.adb b/gcc/testsuite/gnat.dg/strub_ind1.adb
index 825e395e681..245b0a830f6 100644
--- a/gcc/testsuite/gnat.dg/strub_ind1.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm" }
+--  { dg-require-effective-target strub }
 
 --  This is essentially the same test as strub_attr.adb, 
 --  but with an explicit conversion.
diff --git a/gcc/testsuite/gnat.dg/strub_ind2.adb b/gcc/testsuite/gnat.dg/strub_ind2.adb
index e918b392631..b9bfe50e929 100644
--- a/gcc/testsuite/gnat.dg/strub_ind2.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind2.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict" }
+--  { dg-require-effective-target strub }
 
 --  This is essentially the same test as strub_attr.adb, 
 --  but with an explicit conversion.
diff --git a/gcc/testsuite/gnat.dg/strub_intf.adb b/gcc/testsuite/gnat.dg/strub_intf.adb
index 8f0212a7586..f43854705d0 100644
--- a/gcc/testsuite/gnat.dg/strub_intf.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 --  Check that strub mode mismatches between overrider and overridden
 --  subprograms are reported.
diff --git a/gcc/testsuite/gnat.dg/strub_intf1.adb b/gcc/testsuite/gnat.dg/strub_intf1.adb
index bf77321cef7..7a38a4c49ba 100644
--- a/gcc/testsuite/gnat.dg/strub_intf1.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 -- Check that at-calls dispatching calls to interfaces are transformed.
 
diff --git a/gcc/testsuite/gnat.dg/strub_intf2.adb b/gcc/testsuite/gnat.dg/strub_intf2.adb
index e8880dbc437..7992b7344fb 100644
--- a/gcc/testsuite/gnat.dg/strub_intf2.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf2.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 --  Check that strub mode mismatches between overrider and overridden
 --  subprograms are reported even when the overriders for an
diff --git a/gcc/testsuite/gnat.dg/strub_renm.adb b/gcc/testsuite/gnat.dg/strub_renm.adb
index 217367e712d..abfb120b514 100644
--- a/gcc/testsuite/gnat.dg/strub_renm.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Renm is
    procedure P (X : Integer);
diff --git a/gcc/testsuite/gnat.dg/strub_renm1.adb b/gcc/testsuite/gnat.dg/strub_renm1.adb
index a11adbfb5a9..68d3230b535 100644
--- a/gcc/testsuite/gnat.dg/strub_renm1.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed -fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Renm1 is
    V : Integer := 0;
diff --git a/gcc/testsuite/gnat.dg/strub_renm2.adb b/gcc/testsuite/gnat.dg/strub_renm2.adb
index c488c20826f..3cb81ea03f7 100644
--- a/gcc/testsuite/gnat.dg/strub_renm2.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm2.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Renm2 is
    V : Integer := 0;
diff --git a/gcc/testsuite/gnat.dg/strub_var.adb b/gcc/testsuite/gnat.dg/strub_var.adb
index 3d158de2803..7c6affa06d4 100644
--- a/gcc/testsuite/gnat.dg/strub_var.adb
+++ b/gcc/testsuite/gnat.dg/strub_var.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm" }
+--  { dg-require-effective-target strub }
 
 -- We don't read from the automatic variable, but being an automatic
 --  variable, its presence should be enough for the procedure to get
diff --git a/gcc/testsuite/gnat.dg/strub_var1.adb b/gcc/testsuite/gnat.dg/strub_var1.adb
index 6a504e09198..64b7e65fe9b 100644
--- a/gcc/testsuite/gnat.dg/strub_var1.adb
+++ b/gcc/testsuite/gnat.dg/strub_var1.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 with Strub_Attr;
 procedure Strub_Var1 is
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 3fcce6be49d..40a60c198cf 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -1302,6 +1302,13 @@ proc check_stack_check_available { stack_kind } {
     } "$stack_opt"]
 }
 
+# Return 1 if the target supports stack scrubbing.
+proc check_effective_target_strub {} {
+    return [check_no_compiler_messages strub assembly {
+	void __attribute__ ((__strub__)) fn (void) {}
+    } ""]
+}
+
 # Return 1 if compilation with -freorder-blocks-and-partition is error-free
 # for trivial code, 0 otherwise.  As some targets (ARM for example) only
 # warn when -fprofile-use is also supplied we test that combination too.
diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in
index d8163c5af99..3f77283490e 100644
--- a/libgcc/Makefile.in
+++ b/libgcc/Makefile.in
@@ -434,7 +434,7 @@ LIB2ADD += enable-execute-stack.c
 LIB2ADD += $(srcdir)/hardcfr.c
 
 # Stack scrubbing infrastructure.
-LIB2ADD += $(srcdir)/strub.c
+@HAVE_STRUB_SUPPORT@LIB2ADD += $(srcdir)/strub.c
 
 # While emutls.c has nothing to do with EH, it is in LIB2ADDEH*
 # instead of LIB2ADD because that's the way to be sure on some targets
diff --git a/libgcc/configure b/libgcc/configure
index cf149209652..567158955a3 100755
--- a/libgcc/configure
+++ b/libgcc/configure
@@ -593,6 +593,7 @@ asm_hidden_op
 extra_parts
 cpu_type
 get_gcc_base_ver
+HAVE_STRUB_SUPPORT
 thread_header
 tm_defines
 tm_file
@@ -5702,6 +5703,31 @@ esac
 
 
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for strub support" >&5
+$as_echo_n "checking for strub support... " >&6; }
+if ${libgcc_cv_strub_support+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+void __attribute__ ((__strub__)) fn (void) {}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  libgcc_cv_strub_support=yes
+else
+  libgcc_cv_strub_support=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgcc_cv_strub_support" >&5
+$as_echo "$libgcc_cv_strub_support" >&6; }
+if test "x$libgcc_cv_strub_support" != xno; then
+  HAVE_STRUB_SUPPORT=
+else
+  HAVE_STRUB_SUPPORT='# '
+fi
+
+
 # Determine what GCC version number to use in filesystem paths.
 
   get_gcc_base_ver="cat"
diff --git a/libgcc/configure.ac b/libgcc/configure.ac
index 2fc9d5d7c93..9c0e415501a 100644
--- a/libgcc/configure.ac
+++ b/libgcc/configure.ac
@@ -694,6 +694,19 @@ AC_SUBST(tm_defines)
 # Map from thread model to thread header.
 GCC_AC_THREAD_HEADER([$target_thread_file])
 
+AC_CACHE_CHECK([for strub support],
+  [libgcc_cv_strub_support],
+  [AC_COMPILE_IFELSE(
+    [AC_LANG_SOURCE([void __attribute__ ((__strub__)) fn (void) {}])],
+    [libgcc_cv_strub_support=yes],
+    [libgcc_cv_strub_support=no])])
+if test "x$libgcc_cv_strub_support" != xno; then
+  HAVE_STRUB_SUPPORT=
+else
+  HAVE_STRUB_SUPPORT='# '
+fi
+AC_SUBST(HAVE_STRUB_SUPPORT)
+
 # Determine what GCC version number to use in filesystem paths.
 GCC_BASE_VER

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [gcc(refs/users/aoliva/heads/testme)] strub: enable conditional support
@ 2023-12-07  1:26 Alexandre Oliva
  0 siblings, 0 replies; 25+ messages in thread
From: Alexandre Oliva @ 2023-12-07  1:26 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:be0d5bf65f35ceb4507b832073cb8aae5480aa9b

commit be0d5bf65f35ceb4507b832073cb8aae5480aa9b
Author: Alexandre Oliva <oliva@adacore.com>
Date:   Wed Dec 6 19:36:02 2023 -0300

    strub: enable conditional support
    
    Targets that don't expose callee stacks to callers, such as nvptx, as
    well as -fsplit-stack compilations, violate fundamental assumptions of
    the current strub implementation.  This patch enables targets to
    disable strub, and disables it when -fsplit-stack is enabled.
    
    When strub support is disabled, the testsuite will now skip strub
    tests, and libgcc will not build the strub runtime components.
    
    
    for  gcc/ChangeLog
    
            * target.def (have_strub_support_for): New hook.
            * doc/tm.texi.in: Document it.
            * doc/tm.texi: Rebuild.
            * ipa-strub.cc: Include target.h.
            (strub_target_support_p): New.
            (can_strub_p): Call it.  Test for no flag_split_stack.
            (pass_ipa_strub::adjust_at_calls_call): Check for target
            support.
            * config/nvptx/nvptx.cc (TARGET_HAVE_STRUB_SUPPORT_FOR):
            Disable.
            * doc/sourcebuild.texi (strub): Document new effective
            target.
    
    for  gcc/testsuite/ChangeLog
    
            * gcc.dg/strub-split-stack.c: New.
            * gcc.dg/strub-unsupported.c: New.
            * gcc.dg/strub-unsupported-2.c: New.
            * lib/target-supports.exp (check_effective_target_strub): New.
            * c-c++-common/strub-O0.c: Require effective target strub.
            * c-c++-common/strub-O1.c: Likewise.
            * c-c++-common/strub-O2.c: Likewise.
            * c-c++-common/strub-O2fni.c: Likewise.
            * c-c++-common/strub-O3.c: Likewise.
            * c-c++-common/strub-O3fni.c: Likewise.
            * c-c++-common/strub-Og.c: Likewise.
            * c-c++-common/strub-Os.c: Likewise.
            * c-c++-common/strub-all1.c: Likewise.
            * c-c++-common/strub-all2.c: Likewise.
            * c-c++-common/strub-apply1.c: Likewise.
            * c-c++-common/strub-apply2.c: Likewise.
            * c-c++-common/strub-apply3.c: Likewise.
            * c-c++-common/strub-apply4.c: Likewise.
            * c-c++-common/strub-at-calls1.c: Likewise.
            * c-c++-common/strub-at-calls2.c: Likewise.
            * c-c++-common/strub-defer-O1.c: Likewise.
            * c-c++-common/strub-defer-O2.c: Likewise.
            * c-c++-common/strub-defer-O3.c: Likewise.
            * c-c++-common/strub-defer-Os.c: Likewise.
            * c-c++-common/strub-internal1.c: Likewise.
            * c-c++-common/strub-internal2.c: Likewise.
            * c-c++-common/strub-parms1.c: Likewise.
            * c-c++-common/strub-parms2.c: Likewise.
            * c-c++-common/strub-parms3.c: Likewise.
            * c-c++-common/strub-relaxed1.c: Likewise.
            * c-c++-common/strub-relaxed2.c: Likewise.
            * c-c++-common/strub-short-O0-exc.c: Likewise.
            * c-c++-common/strub-short-O0.c: Likewise.
            * c-c++-common/strub-short-O1.c: Likewise.
            * c-c++-common/strub-short-O2.c: Likewise.
            * c-c++-common/strub-short-O3.c: Likewise.
            * c-c++-common/strub-short-Os.c: Likewise.
            * c-c++-common/strub-strict1.c: Likewise.
            * c-c++-common/strub-strict2.c: Likewise.
            * c-c++-common/strub-tail-O1.c: Likewise.
            * c-c++-common/strub-tail-O2.c: Likewise.
            * c-c++-common/strub-var1.c: Likewise.
            * c-c++-common/torture/strub-callable1.c: Likewise.
            * c-c++-common/torture/strub-callable2.c: Likewise.
            * c-c++-common/torture/strub-const1.c: Likewise.
            * c-c++-common/torture/strub-const2.c: Likewise.
            * c-c++-common/torture/strub-const3.c: Likewise.
            * c-c++-common/torture/strub-const4.c: Likewise.
            * c-c++-common/torture/strub-data1.c: Likewise.
            * c-c++-common/torture/strub-data2.c: Likewise.
            * c-c++-common/torture/strub-data3.c: Likewise.
            * c-c++-common/torture/strub-data4.c: Likewise.
            * c-c++-common/torture/strub-data5.c: Likewise.
            * c-c++-common/torture/strub-indcall1.c: Likewise.
            * c-c++-common/torture/strub-indcall2.c: Likewise.
            * c-c++-common/torture/strub-indcall3.c: Likewise.
            * c-c++-common/torture/strub-inlinable1.c: Likewise.
            * c-c++-common/torture/strub-inlinable2.c: Likewise.
            * c-c++-common/torture/strub-ptrfn1.c: Likewise.
            * c-c++-common/torture/strub-ptrfn2.c: Likewise.
            * c-c++-common/torture/strub-ptrfn3.c: Likewise.
            * c-c++-common/torture/strub-ptrfn4.c: Likewise.
            * c-c++-common/torture/strub-pure1.c: Likewise.
            * c-c++-common/torture/strub-pure2.c: Likewise.
            * c-c++-common/torture/strub-pure3.c: Likewise.
            * c-c++-common/torture/strub-pure4.c: Likewise.
            * c-c++-common/torture/strub-run1.c: Likewise.
            * c-c++-common/torture/strub-run2.c: Likewise.
            * c-c++-common/torture/strub-run3.c: Likewise.
            * c-c++-common/torture/strub-run4.c: Likewise.
            * c-c++-common/torture/strub-run4c.c: Likewise.
            * c-c++-common/torture/strub-run4d.c: Likewise.
            * c-c++-common/torture/strub-run4i.c: Likewise.
            * g++.dg/strub-run1.C: Likewise.
            * g++.dg/torture/strub-init1.C: Likewise.
            * g++.dg/torture/strub-init2.C: Likewise.
            * g++.dg/torture/strub-init3.C: Likewise.
            * gnat.dg/strub_attr.adb: Likewise.
            * gnat.dg/strub_ind.adb: Likewise.
            * gnat.dg/strub_access.adb: Likewise.
            * gnat.dg/strub_access1.adb: Likewise.
            * gnat.dg/strub_disp.adb: Likewise.
            * gnat.dg/strub_disp1.adb: Likewise.
            * gnat.dg/strub_ind1.adb: Likewise.
            * gnat.dg/strub_ind2.adb: Likewise.
            * gnat.dg/strub_intf.adb: Likewise.
            * gnat.dg/strub_intf1.adb: Likewise.
            * gnat.dg/strub_intf2.adb: Likewise.
            * gnat.dg/strub_renm.adb: Likewise.
            * gnat.dg/strub_renm1.adb: Likewise.
            * gnat.dg/strub_renm2.adb: Likewise.
            * gnat.dg/strub_var.adb: Likewise.
            * gnat.dg/strub_var1.adb: Likewise.
    
    for  libgcc/ChangeLog
    
            * configure.ac: Check for strub support.
            * configure: Rebuilt.
            * Makefile.in: Compile strub.c conditionally.

Diff:
---
 gcc/config/i386/i386.cc                            |  4 ++
 gcc/config/nvptx/nvptx.cc                          |  3 ++
 gcc/doc/sourcebuild.texi                           |  3 ++
 gcc/doc/tm.texi                                    |  6 +++
 gcc/doc/tm.texi.in                                 |  2 +
 gcc/ipa-strub.cc                                   | 54 +++++++++++++++++++++-
 gcc/target.def                                     |  8 ++++
 gcc/testsuite/c-c++-common/strub-O0.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O1.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O2.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O2fni.c           |  1 +
 gcc/testsuite/c-c++-common/strub-O3.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O3fni.c           |  1 +
 gcc/testsuite/c-c++-common/strub-Og.c              |  1 +
 gcc/testsuite/c-c++-common/strub-Os.c              |  1 +
 gcc/testsuite/c-c++-common/strub-all1.c            |  1 +
 gcc/testsuite/c-c++-common/strub-all2.c            |  1 +
 gcc/testsuite/c-c++-common/strub-apply1.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply2.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply3.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply4.c          |  1 +
 gcc/testsuite/c-c++-common/strub-at-calls1.c       |  1 +
 gcc/testsuite/c-c++-common/strub-at-calls2.c       |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O3.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-Os.c        |  1 +
 gcc/testsuite/c-c++-common/strub-internal1.c       |  1 +
 gcc/testsuite/c-c++-common/strub-internal2.c       |  1 +
 gcc/testsuite/c-c++-common/strub-parms1.c          |  1 +
 gcc/testsuite/c-c++-common/strub-parms2.c          |  1 +
 gcc/testsuite/c-c++-common/strub-parms3.c          |  1 +
 gcc/testsuite/c-c++-common/strub-relaxed1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-relaxed2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O0-exc.c    |  1 +
 gcc/testsuite/c-c++-common/strub-short-O0.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O3.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-Os.c        |  1 +
 gcc/testsuite/c-c++-common/strub-split-stack.c     | 10 ++++
 gcc/testsuite/c-c++-common/strub-strict1.c         |  1 +
 gcc/testsuite/c-c++-common/strub-strict2.c         |  1 +
 gcc/testsuite/c-c++-common/strub-tail-O1.c         |  1 +
 gcc/testsuite/c-c++-common/strub-tail-O2.c         |  1 +
 gcc/testsuite/c-c++-common/strub-unsupported-2.c   | 13 ++++++
 gcc/testsuite/c-c++-common/strub-unsupported.c     | 20 ++++++++
 gcc/testsuite/c-c++-common/strub-var1.c            |  1 +
 .../c-c++-common/torture/strub-callable1.c         |  1 +
 .../c-c++-common/torture/strub-callable2.c         |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const1.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const2.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const3.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const4.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data1.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data2.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data3.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data4.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data5.c   |  1 +
 .../c-c++-common/torture/strub-indcall1.c          |  1 +
 .../c-c++-common/torture/strub-indcall2.c          |  1 +
 .../c-c++-common/torture/strub-indcall3.c          |  1 +
 .../c-c++-common/torture/strub-inlinable1.c        |  1 +
 .../c-c++-common/torture/strub-inlinable2.c        |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure1.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure2.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure3.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure4.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run1.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run2.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run3.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4c.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4d.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4i.c   |  1 +
 gcc/testsuite/g++.dg/strub-run1.C                  |  1 +
 gcc/testsuite/g++.dg/torture/strub-init1.C         |  1 +
 gcc/testsuite/g++.dg/torture/strub-init2.C         |  1 +
 gcc/testsuite/g++.dg/torture/strub-init3.C         |  1 +
 gcc/testsuite/gnat.dg/strub_access.adb             |  1 +
 gcc/testsuite/gnat.dg/strub_access1.adb            |  1 +
 gcc/testsuite/gnat.dg/strub_attr.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_disp.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_disp1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_ind.adb                |  1 +
 gcc/testsuite/gnat.dg/strub_ind1.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_ind2.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_intf.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_intf1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_intf2.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_renm.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_renm1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_renm2.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_var.adb                |  1 +
 gcc/testsuite/gnat.dg/strub_var1.adb               |  1 +
 gcc/testsuite/lib/target-supports.exp              |  7 +++
 libgcc/Makefile.in                                 |  2 +-
 libgcc/configure                                   | 26 +++++++++++
 libgcc/configure.ac                                | 13 ++++++
 103 files changed, 257 insertions(+), 3 deletions(-)

diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 7c5cab4e2c6..f933c9c23c7 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -26658,6 +26658,10 @@ ix86_libm_function_max_error (unsigned cfn, machine_mode mode,
 #define TARGET_RUN_TARGET_SELFTESTS selftest::ix86_run_selftests
 #endif /* #if CHECKING_P */
 
+// ??? for testing only
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 #include "gt-i386.h"
diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc
index ae20802c879..3fb1deb70fd 100644
--- a/gcc/config/nvptx/nvptx.cc
+++ b/gcc/config/nvptx/nvptx.cc
@@ -7789,6 +7789,9 @@ nvptx_asm_output_def_from_decls (FILE *stream, tree name, tree value)
 #undef TARGET_LIBC_HAS_FUNCTION
 #define TARGET_LIBC_HAS_FUNCTION nvptx_libc_has_function
 
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-nvptx.h"
diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi
index c9909026854..26a7e9c3507 100644
--- a/gcc/doc/sourcebuild.texi
+++ b/gcc/doc/sourcebuild.texi
@@ -2983,6 +2983,9 @@ Target supports statically linking @samp{libgfortran}.
 @item string_merging
 Target supports merging string constants at link time.
 
+@item strub
+Target supports attribute @code{strub} for stack scrubbing.
+
 @item ucn
 Target supports compiling and assembling UCN.
 
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 89a1735dd79..768ada0af52 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -3450,6 +3450,12 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@deftypefn {Target Hook} bool TARGET_HAVE_STRUB_SUPPORT_FOR (tree)
+Returns true if the target supports stack scrubbing for the given function
+or type, otherwise return false.  The default implementation always returns
+true.
+@end deftypefn
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index ebc1d3de5ca..4fe0805394e 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2686,6 +2686,8 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@hook TARGET_HAVE_STRUB_SUPPORT_FOR
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
index 293bec132b8..f3100bb1d44 100644
--- a/gcc/ipa-strub.cc
+++ b/gcc/ipa-strub.cc
@@ -60,6 +60,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-strub.h"
 #include "symtab-thunks.h"
 #include "attr-fnspec.h"
+#include "target.h"
 
 /* This file introduces two passes that, together, implement
    machine-independent stack scrubbing, strub for short.  It arranges
@@ -631,17 +632,60 @@ strub_always_inline_p (cgraph_node *node)
   return lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl));
 }
 
+/* Return TRUE iff the target has strub support for T, a function decl
+   or a type, and optionally REPORT thereasons for ineligibility.  If
+   T is a type and error REPORTing is enabled, the LOCation (e.g. of
+   the indirect call) should be given in LOC.  */
+static inline bool
+strub_target_support_p (tree t, bool report = false,
+			location_t loc = UNKNOWN_LOCATION)
+{
+  bool result = true;
+
+  if (!targetm.have_strub_support_for (t))
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      if (DECL_P (t))
+	sorry_at (DECL_SOURCE_LOCATION (t),
+		  "%qD is not eligible for %<strub%>"
+		  " on the target system", t);
+      else
+	sorry_at (loc,
+		  "%qT is not an eligible type for %<strub%>"
+		  " on the target system", t);
+    }
+
+  return result;
+}
+
 /* Return TRUE iff NODE is potentially eligible for any strub-enabled mode, and
    optionally REPORT the reasons for ineligibility.  */
 
 static inline bool
 can_strub_p (cgraph_node *node, bool report = false)
 {
-  bool result = true;
+  bool result = strub_target_support_p (node->decl, report);
 
-  if (!report && strub_always_inline_p (node))
+  if (!report && (!result || strub_always_inline_p (node)))
     return result;
 
+  if (flag_split_stack)
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (node->decl),
+		"%qD is not eligible for %<strub%>"
+		" because %<-fsplit-stack%> is enabled",
+		node->decl);
+    }
+
   if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
     {
       result = false;
@@ -2417,6 +2461,12 @@ pass_ipa_strub::adjust_at_calls_call (cgraph_edge *e, int named_args,
 			 && (TREE_TYPE (gimple_call_arg (ocall, named_args))
 			     == get_pwmt ())));
 
+  tree tsup;
+  if (!(tsup = gimple_call_fndecl (ocall)))
+    tsup = TREE_TYPE (TREE_TYPE (gimple_call_fn (ocall)));
+  if (!strub_target_support_p (tsup, true, gimple_location (ocall)))
+    return;
+
   /* If we're already within a strub context, pass on the incoming watermark
      pointer, and omit the enter and leave calls around the modified call, as an
      optimization, or as a means to satisfy a tail-call requirement.  */
diff --git a/gcc/target.def b/gcc/target.def
index 52b83e091b9..08218f3a42a 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4457,6 +4457,14 @@ otherwise return false.  The default implementation always returns true.",
  bool, (void),
  hook_bool_void_true)
 
+DEFHOOK
+(have_strub_support_for,
+ "Returns true if the target supports stack scrubbing for the given function\n\
+or type, otherwise return false.  The default implementation always returns\n\
+true.",
+ bool, (tree),
+ hook_bool_tree_true)
+
 DEFHOOK
 (have_speculation_safe_value,
 "This hook is used to determine the level of target support for\n\
diff --git a/gcc/testsuite/c-c++-common/strub-O0.c b/gcc/testsuite/c-c++-common/strub-O0.c
index c7a79a6ea0d..f0a3f7b4c6f 100644
--- a/gcc/testsuite/c-c++-common/strub-O0.c
+++ b/gcc/testsuite/c-c++-common/strub-O0.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -O0, none of the strub builtins are expanded inline.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O1.c b/gcc/testsuite/c-c++-common/strub-O1.c
index 96285c975d9..50403426b18 100644
--- a/gcc/testsuite/c-c++-common/strub-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -O1, without -fno-inline, we fully expand enter, but neither update nor
    leave.  */
diff --git a/gcc/testsuite/c-c++-common/strub-O2.c b/gcc/testsuite/c-c++-common/strub-O2.c
index 8edc0d8aa13..37e02998e31 100644
--- a/gcc/testsuite/c-c++-common/strub-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -O2, without -fno-inline, we fully expand enter and update, and add a test
    around the leave call.  */
diff --git a/gcc/testsuite/c-c++-common/strub-O2fni.c b/gcc/testsuite/c-c++-common/strub-O2fni.c
index c6d900cf3c4..905e2c6b2ff 100644
--- a/gcc/testsuite/c-c++-common/strub-O2fni.c
+++ b/gcc/testsuite/c-c++-common/strub-O2fni.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
+/* { dg-require-effective-target strub } */
 
 /* With -fno-inline, none of the strub builtins are inlined.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O3.c b/gcc/testsuite/c-c++-common/strub-O3.c
index 33ee465e51c..3bbf132bdf1 100644
--- a/gcc/testsuite/c-c++-common/strub-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-O3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 int __attribute__ ((__strub__)) var;
 
diff --git a/gcc/testsuite/c-c++-common/strub-O3fni.c b/gcc/testsuite/c-c++-common/strub-O3fni.c
index 2936f82079e..c46fce38e5c 100644
--- a/gcc/testsuite/c-c++-common/strub-O3fni.c
+++ b/gcc/testsuite/c-c++-common/strub-O3fni.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
+/* { dg-require-effective-target strub } */
 
 /* With -fno-inline, none of the strub builtins are inlined.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-Og.c b/gcc/testsuite/c-c++-common/strub-Og.c
index 479746e57d8..3b8eb19765c 100644
--- a/gcc/testsuite/c-c++-common/strub-Og.c
+++ b/gcc/testsuite/c-c++-common/strub-Og.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-Og -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -Og, without -fno-inline, we fully expand enter, but neither update nor
    leave.  */
diff --git a/gcc/testsuite/c-c++-common/strub-Os.c b/gcc/testsuite/c-c++-common/strub-Os.c
index 2241d4ea07f..8cfb253d676 100644
--- a/gcc/testsuite/c-c++-common/strub-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-Os.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-Os -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -Os, without -fno-inline, we fully expand enter, and also update.  The
    expanded update might be larger than a call proper, but argument saving and
diff --git a/gcc/testsuite/c-c++-common/strub-all1.c b/gcc/testsuite/c-c++-common/strub-all1.c
index a322bcc5da6..2037f681f29 100644
--- a/gcc/testsuite/c-c++-common/strub-all1.c
+++ b/gcc/testsuite/c-c++-common/strub-all1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
    strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub.  */
diff --git a/gcc/testsuite/c-c++-common/strub-all2.c b/gcc/testsuite/c-c++-common/strub-all2.c
index db60026d0e0..c026e7d9d28 100644
--- a/gcc/testsuite/c-c++-common/strub-all2.c
+++ b/gcc/testsuite/c-c++-common/strub-all2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* g becomes STRUB_INTERNAL, because of the flag.  Without inline, force_output
    is set for static non-inline functions when not optimizing, and that keeps
diff --git a/gcc/testsuite/c-c++-common/strub-apply1.c b/gcc/testsuite/c-c++-common/strub-apply1.c
index 2f462adc1ef..3edc89c54ee 100644
--- a/gcc/testsuite/c-c++-common/strub-apply1.c
+++ b/gcc/testsuite/c-c++-common/strub-apply1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 void __attribute__ ((__strub__ ("callable")))
 apply_function (void *args)
diff --git a/gcc/testsuite/c-c++-common/strub-apply2.c b/gcc/testsuite/c-c++-common/strub-apply2.c
index a5d7551f5da..838fc752734 100644
--- a/gcc/testsuite/c-c++-common/strub-apply2.c
+++ b/gcc/testsuite/c-c++-common/strub-apply2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 extern void __attribute__ ((__strub__))
 apply_function (void *args);
diff --git a/gcc/testsuite/c-c++-common/strub-apply3.c b/gcc/testsuite/c-c++-common/strub-apply3.c
index 64422a0d1e8..0206e4d930e 100644
--- a/gcc/testsuite/c-c++-common/strub-apply3.c
+++ b/gcc/testsuite/c-c++-common/strub-apply3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 void __attribute__ ((__strub__))
 apply_function (void *args)
diff --git a/gcc/testsuite/c-c++-common/strub-apply4.c b/gcc/testsuite/c-c++-common/strub-apply4.c
index 15ffaa031b8..e82504728b2 100644
--- a/gcc/testsuite/c-c++-common/strub-apply4.c
+++ b/gcc/testsuite/c-c++-common/strub-apply4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that implicit enabling of strub mode selects internal strub when the
    function uses __builtin_apply_args, that prevents the optimization to
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls1.c b/gcc/testsuite/c-c++-common/strub-at-calls1.c
index b70843b4215..a20acc0a48a 100644
--- a/gcc/testsuite/c-c++-common/strub-at-calls1.c
+++ b/gcc/testsuite/c-c++-common/strub-at-calls1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
    strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub.  */
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls2.c b/gcc/testsuite/c-c++-common/strub-at-calls2.c
index 97a3988a6b9..7915b33a39a 100644
--- a/gcc/testsuite/c-c++-common/strub-at-calls2.c
+++ b/gcc/testsuite/c-c++-common/strub-at-calls2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* g does NOT become STRUB_AT_CALLS because it's not viable.  Without inline,
    force_output is set for static non-inline functions when not optimizing, and
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O1.c b/gcc/testsuite/c-c++-common/strub-defer-O1.c
index 3d73431b3dc..3689998b5a3 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O1" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function does NOT defer
    the strubbing to its caller at -O1.  */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O2.c b/gcc/testsuite/c-c++-common/strub-defer-O2.c
index fddf3c745e7..9e01949db6b 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O2" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function does NOT defer
    the strubbing to its caller at -O2.  */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O3.c b/gcc/testsuite/c-c++-common/strub-defer-O3.c
index 7ebc65b58dd..40ee8edd1e0 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O3.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O3" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function defers the
    strubbing to its caller at -O3.  */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-Os.c b/gcc/testsuite/c-c++-common/strub-defer-Os.c
index fbaf85fe0fa..67ea9f04639 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-Os.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -Os" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function defers the
    strubbing to its caller at -Os.  */
diff --git a/gcc/testsuite/c-c++-common/strub-internal1.c b/gcc/testsuite/c-c++-common/strub-internal1.c
index e9d7b7b9ee0..d17254904e5 100644
--- a/gcc/testsuite/c-c++-common/strub-internal1.c
+++ b/gcc/testsuite/c-c++-common/strub-internal1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
    strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub.  */
diff --git a/gcc/testsuite/c-c++-common/strub-internal2.c b/gcc/testsuite/c-c++-common/strub-internal2.c
index 8b8e15a51c7..afc9189701f 100644
--- a/gcc/testsuite/c-c++-common/strub-internal2.c
+++ b/gcc/testsuite/c-c++-common/strub-internal2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* g becomes STRUB_INTERNAL, because of the flag.  */
 static void
diff --git a/gcc/testsuite/c-c++-common/strub-parms1.c b/gcc/testsuite/c-c++-common/strub-parms1.c
index 0a4a7539d34..f410b268971 100644
--- a/gcc/testsuite/c-c++-common/strub-parms1.c
+++ b/gcc/testsuite/c-c++-common/strub-parms1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 #include <stdarg.h>
 
diff --git a/gcc/testsuite/c-c++-common/strub-parms2.c b/gcc/testsuite/c-c++-common/strub-parms2.c
index 147171d96d5..6f572115a88 100644
--- a/gcc/testsuite/c-c++-common/strub-parms2.c
+++ b/gcc/testsuite/c-c++-common/strub-parms2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 #include <stdarg.h>
 
diff --git a/gcc/testsuite/c-c++-common/strub-parms3.c b/gcc/testsuite/c-c++-common/strub-parms3.c
index 4e92682895a..7383fea9ce8 100644
--- a/gcc/testsuite/c-c++-common/strub-parms3.c
+++ b/gcc/testsuite/c-c++-common/strub-parms3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that uses of a strub variable implicitly enables internal strub for
    publicly-visible functions, and causes the same transformations to their
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed1.c b/gcc/testsuite/c-c++-common/strub-relaxed1.c
index e2f9d8aebca..d2b4b52c51e 100644
--- a/gcc/testsuite/c-c++-common/strub-relaxed1.c
+++ b/gcc/testsuite/c-c++-common/strub-relaxed1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The difference between relaxed and strict in this case is that we accept the
    call from one internal-strub function to another.  Without the error,
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed2.c b/gcc/testsuite/c-c++-common/strub-relaxed2.c
index 98474435d2e..9e5a8e76b6c 100644
--- a/gcc/testsuite/c-c++-common/strub-relaxed2.c
+++ b/gcc/testsuite/c-c++-common/strub-relaxed2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The difference between relaxed and strict in this case is that we accept the
    call from one internal-strub function to another.  */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
index 1de15342595..aaeba2a2159 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fexceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0.c b/gcc/testsuite/c-c++-common/strub-short-O0.c
index f9209c81900..30cbdd819f1 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O0.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O0.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O1.c b/gcc/testsuite/c-c++-common/strub-short-O1.c
index bed1dcfb54a..911fdfb6db9 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O2.c b/gcc/testsuite/c-c++-common/strub-short-O2.c
index 6bf0071f52b..9b23ee3ac33 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O3.c b/gcc/testsuite/c-c++-common/strub-short-O3.c
index 4732f515bf7..4b3a8f843ea 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  At -O3 and -Os, we omit
    enter and leave calls within strub contexts, passing on the enclosing
diff --git a/gcc/testsuite/c-c++-common/strub-short-Os.c b/gcc/testsuite/c-c++-common/strub-short-Os.c
index 8d6424c479a..3627a240600 100644
--- a/gcc/testsuite/c-c++-common/strub-short-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-short-Os.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-Os -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  At -O3 and -Os, we omit
    enter and leave calls within strub contexts, passing on the enclosing
diff --git a/gcc/testsuite/c-c++-common/strub-split-stack.c b/gcc/testsuite/c-c++-common/strub-split-stack.c
new file mode 100644
index 00000000000..acbd750c3cd
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-split-stack.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-fsplit-stack" } */
+/* { dg-require-effective-target strub } */
+/* { dg-require-effective-target split-stack } */
+
+void __attribute__ ((__strub__))
+f {} /* { dg-message "not eligible" }
+
+void __attribute__ ((__strub__ ("internal")))
+g {} /* { dg-message "not eligible" }
diff --git a/gcc/testsuite/c-c++-common/strub-strict1.c b/gcc/testsuite/c-c++-common/strub-strict1.c
index 36852244206..503eb1734e3 100644
--- a/gcc/testsuite/c-c++-common/strub-strict1.c
+++ b/gcc/testsuite/c-c++-common/strub-strict1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
 
 static int __attribute__ ((__strub__)) var;
 
diff --git a/gcc/testsuite/c-c++-common/strub-strict2.c b/gcc/testsuite/c-c++-common/strub-strict2.c
index b4f28883218..3bf1aa30b4a 100644
--- a/gcc/testsuite/c-c++-common/strub-strict2.c
+++ b/gcc/testsuite/c-c++-common/strub-strict2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
 
 static int __attribute__ ((__strub__)) var;
 
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O1.c b/gcc/testsuite/c-c++-common/strub-tail-O1.c
index e48e0610e07..ba4b1623e28 100644
--- a/gcc/testsuite/c-c++-common/strub-tail-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-tail-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-tail-O2.c"
 
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O2.c b/gcc/testsuite/c-c++-common/strub-tail-O2.c
index 87cda7ab21b..043813b1de4 100644
--- a/gcc/testsuite/c-c++-common/strub-tail-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-tail-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.
    Tail calls are short-circuited at -O2+.  */
diff --git a/gcc/testsuite/c-c++-common/strub-unsupported-2.c b/gcc/testsuite/c-c++-common/strub-unsupported-2.c
new file mode 100644
index 00000000000..abf4556a3f3
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-unsupported-2.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+
+/* Check that, when strub is not supported (so no dg-required-effective-target
+   strub above), we report when pointers to strub functions are called.  This
+   cannot be part of strub-unsupported.c because errors in the strub-mode pass
+   prevent the main strub pass, where errors at calls are detected, from
+   running.  */
+
+void __attribute__ ((__strub__ ("at-calls"))) (*p) (void);
+
+void m () {
+  p (); /* { dg-message "not eligible" "" { target { ! strub } } } */
+}
diff --git a/gcc/testsuite/c-c++-common/strub-unsupported.c b/gcc/testsuite/c-c++-common/strub-unsupported.c
new file mode 100644
index 00000000000..ecfee3bc36a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-unsupported.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+
+/* Check that, when strub is not supported (so no dg-required-effective-target
+   strub above), we report when strub functions are defined, and when they're
+   called in ways that would require changes.  */
+
+void __attribute__ ((__strub__))
+f (void) {} /* { dg-message "not eligible" "" { target { ! strub } } } */
+
+void __attribute__ ((__strub__ ("internal")))
+g (void) {} /* { dg-message "not eligible" "" { target { ! strub } } } */
+
+extern void __attribute__ ((__strub__))
+h (void); /* { dg-message "not eligible" "" { target { ! strub } } } */
+
+extern void __attribute__ ((__strub__ ("internal")))
+i (void); /* { dg-message "not eligible" "" { target { ! strub } } } */
+
+/* This only gets an error when called, see strub-unsupported-2.c.  */
+void __attribute__ ((__strub__ ("at-calls"))) (*p) (void);
diff --git a/gcc/testsuite/c-c++-common/strub-var1.c b/gcc/testsuite/c-c++-common/strub-var1.c
index eb6250fd39c..67014aa5de8 100644
--- a/gcc/testsuite/c-c++-common/strub-var1.c
+++ b/gcc/testsuite/c-c++-common/strub-var1.c
@@ -1,4 +1,5 @@
 /* { dg-do compile } */
+/* { dg-require-effective-target strub } */
 
 int __attribute__ ((strub)) x;
 float __attribute__ ((strub)) f;
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable1.c b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
index b5e45ab0525..86dbee6746d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-callable1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that strub and non-strub functions can be called from non-strub
    contexts, and that strub and callable functions can be called from strub
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable2.c b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
index 96aa7fe4b07..9da120f6156 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-callable2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that impermissible (cross-strub-context) calls are reported.  */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const1.c b/gcc/testsuite/c-c++-common/torture/strub-const1.c
index 5e956cb1a9b..22056713cce 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub const function call, we issue an asm
    statement to make sure the watermark passed to it is held in memory before
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const2.c b/gcc/testsuite/c-c++-common/torture/strub-const2.c
index 73d650292df..a105c66d7a9 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-const function call, we issue an
    asm statement to make sure the watermark passed to it is held in memory
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const3.c b/gcc/testsuite/c-c++-common/torture/strub-const3.c
index 2584f1f974a..386200c2784 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub const wrapping call, we issue an asm statement
    to make sure the watermark passed to it is held in memory before the call,
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const4.c b/gcc/testsuite/c-c++-common/torture/strub-const4.c
index d819f54ec02..817e9fa2118 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-const wrapping call, we issue an
    asm statement to make sure the watermark passed to it is held in memory
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data1.c b/gcc/testsuite/c-c++-common/torture/strub-data1.c
index 7c27a2a1a6d..132ab63ef73 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointed-to data enables strubbing if accessed.  */
 int __attribute__ ((__strub__)) var;
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data2.c b/gcc/testsuite/c-c++-common/torture/strub-data2.c
index e66d903780a..b660702d26e 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointer itself is a strub variable, enabling internal strubbing when
    its value is used.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data3.c b/gcc/testsuite/c-c++-common/torture/strub-data3.c
index 5e08e0e58c6..fc44eef6f8f 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointer itself is a strub variable, that would enable internal strubbing
    if its value was used.  Here, it's only overwritten, so no strub.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data4.c b/gcc/testsuite/c-c++-common/torture/strub-data4.c
index a818e7a38bb..85e2f59055b 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointer itself is a strub variable, that would enable internal strubbing
    if its value was used.  Here, it's only overwritten, so no strub.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data5.c b/gcc/testsuite/c-c++-common/torture/strub-data5.c
index ddb0b5c0543..0a5edac414d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data5.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data5.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* It would be desirable to issue at least warnings for these.  */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
index c165f312f16..988954e7ed6 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 typedef void __attribute__ ((__strub__)) fntype ();
 fntype (*ptr);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
index 69fcff8d376..d3ca91389a7 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 typedef void __attribute__ ((__strub__)) fntype (int, int);
 fntype (*ptr);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
index ff006224909..89b5979cf7b 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 typedef void __attribute__ ((__strub__)) fntype (int, int, ...);
 fntype (*ptr);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
index 614b02228ba..4917dda8826 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed" } */
+/* { dg-require-effective-target strub } */
 
 inline void __attribute__ ((strub ("internal"), always_inline))
 inl_int_ali (void)
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
index f9a6b4a16fa..c45903856d4 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all" } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-inlinable1.c"
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
index b4a7f3992bb..b0d6139f0a8 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 typedef void ft (void);
 typedef void ft2 (int, int);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
index ef634d35126..1148c246f20 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -Wpedantic" } */
+/* { dg-require-effective-target strub } */
 
 /* C++ does not warn about the partial incompatibilities.
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
index e1f179e160e..06a72d86d2c 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
@@ -1,6 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -Wpedantic -fpermissive" } */
 /* { dg-prune-output "command-line option .-fpermissive." } */
+/* { dg-require-effective-target strub } */
 
 /* See strub-ptrfn2.c.  */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
index 70b558afad0..83ea1af7056 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed" } */
+/* { dg-require-effective-target strub } */
 
 /* This is strub-ptrfn2.c without -Wpedantic.
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure1.c b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
index a262a086837..2643136f178 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub pure function call, we issue an asm statement
    to make sure the watermark passed to it is not assumed to be unchanged.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure2.c b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
index 4c4bd50c209..8bda129b77d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-pure function call, we issue an asm
    statement to make sure the watermark passed to it is not assumed to be
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure3.c b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
index ce195c6b1f1..00bcbdd097a 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub pure wrapping call, we issue an asm statement
    to make sure the watermark passed to it is not assumed to be unchanged.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure4.c b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
index 75cd54ccb5b..ea7c40e7912 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-pure wrapping call, we issue an asm
    statement to make sure the watermark passed to it is not assumed to be
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run1.c b/gcc/testsuite/c-c++-common/torture/strub-run1.c
index 7458b3fb54d..fdf10042863 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run1.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a non-strub function leaves a string behind in the stack, and that
    equivalent strub functions don't.  Avoid the use of red zones by avoiding
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run2.c b/gcc/testsuite/c-c++-common/torture/strub-run2.c
index 5d60a7775f4..1228a665997 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run2.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a non-strub function leaves a string behind in the stack, and that
    equivalent strub functions don't.  Allow red zones to be used.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run3.c b/gcc/testsuite/c-c++-common/torture/strub-run3.c
index c2ad710858e..e5047a988f5 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run3.c
@@ -1,6 +1,7 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a non-strub function leaves a string behind in the stack, and that
    equivalent strub functions don't.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4.c b/gcc/testsuite/c-c++-common/torture/strub-run4.c
index 3b36b8e5d68..0e84a4bab80 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4.c
@@ -1,6 +1,7 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=all" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 /* Check that multi-level, multi-inlined functions still get cleaned up as
    expected, without overwriting temporary stack allocations while they should
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4c.c b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
index 57f9baf758d..edc98486dc9 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4c.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=at-calls" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-run4.c"
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4d.c b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
index 08de3f1c3b1..487ed08bb66 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4d.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
@@ -1,6 +1,7 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 #define ATTR_STRUB_AT_CALLS __attribute__ ((__strub__ ("at-calls")))
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4i.c b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
index 459f6886c54..a85447ffabf 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4i.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=internal" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-run4.c"
diff --git a/gcc/testsuite/g++.dg/strub-run1.C b/gcc/testsuite/g++.dg/strub-run1.C
index 0d367fb83d0..beb8b811f8f 100644
--- a/gcc/testsuite/g++.dg/strub-run1.C
+++ b/gcc/testsuite/g++.dg/strub-run1.C
@@ -1,5 +1,6 @@
 // { dg-do run }
 // { dg-options "-fstrub=internal" }
+// { dg-require-effective-target strub }
 
 // Check that we don't get extra copies.
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init1.C b/gcc/testsuite/g++.dg/torture/strub-init1.C
index c226ab10ff6..6ae45fadd70 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init1.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init1.C
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
 
 extern int __attribute__((__strub__)) initializer ();
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init2.C b/gcc/testsuite/g++.dg/torture/strub-init2.C
index a7911f1fa72..8f4849c7fde 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init2.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init2.C
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
 
 extern int __attribute__((__strub__)) initializer ();
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init3.C b/gcc/testsuite/g++.dg/torture/strub-init3.C
index 6ebebcd01e8..14f28e3c276 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init3.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init3.C
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
 
 extern int __attribute__((__strub__)) initializer ();
 
diff --git a/gcc/testsuite/gnat.dg/strub_access.adb b/gcc/testsuite/gnat.dg/strub_access.adb
index 29e6996ecf6..488a2d64afe 100644
--- a/gcc/testsuite/gnat.dg/strub_access.adb
+++ b/gcc/testsuite/gnat.dg/strub_access.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed -fdump-ipa-strubm" }
+--  { dg-require-effective-target strub }
 
 --  The main subprogram doesn't read from the automatic variable, but
 --  being an automatic variable, its presence should be enough for the
diff --git a/gcc/testsuite/gnat.dg/strub_access1.adb b/gcc/testsuite/gnat.dg/strub_access1.adb
index dae47060164..4a8653c4d84 100644
--- a/gcc/testsuite/gnat.dg/strub_access1.adb
+++ b/gcc/testsuite/gnat.dg/strub_access1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed" }
+--  { dg-require-effective-target strub }
 
 --  Check that we reject 'Access of a strub variable whose type does
 --  not carry a strub modifier.
diff --git a/gcc/testsuite/gnat.dg/strub_attr.adb b/gcc/testsuite/gnat.dg/strub_attr.adb
index 10445d7cf84..eb7826dc990 100644
--- a/gcc/testsuite/gnat.dg/strub_attr.adb
+++ b/gcc/testsuite/gnat.dg/strub_attr.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm -fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 package body Strub_Attr is
    E : exception;
diff --git a/gcc/testsuite/gnat.dg/strub_disp.adb b/gcc/testsuite/gnat.dg/strub_disp.adb
index 3dbcc4a357c..f23d4675def 100644
--- a/gcc/testsuite/gnat.dg/strub_disp.adb
+++ b/gcc/testsuite/gnat.dg/strub_disp.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Disp is
    package Foo is
diff --git a/gcc/testsuite/gnat.dg/strub_disp1.adb b/gcc/testsuite/gnat.dg/strub_disp1.adb
index 09756a74b7d..9c4c7f69637 100644
--- a/gcc/testsuite/gnat.dg/strub_disp1.adb
+++ b/gcc/testsuite/gnat.dg/strub_disp1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 -- Check that at-calls dispatching calls are transformed.
 
diff --git a/gcc/testsuite/gnat.dg/strub_ind.adb b/gcc/testsuite/gnat.dg/strub_ind.adb
index da56acaa957..613db69305e 100644
--- a/gcc/testsuite/gnat.dg/strub_ind.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict" }
+--  { dg-require-effective-target strub }
 
 --  This is essentially the same test as strub_attr.adb, 
 --  but applying attributes to access types as well.
diff --git a/gcc/testsuite/gnat.dg/strub_ind1.adb b/gcc/testsuite/gnat.dg/strub_ind1.adb
index 825e395e681..245b0a830f6 100644
--- a/gcc/testsuite/gnat.dg/strub_ind1.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm" }
+--  { dg-require-effective-target strub }
 
 --  This is essentially the same test as strub_attr.adb, 
 --  but with an explicit conversion.
diff --git a/gcc/testsuite/gnat.dg/strub_ind2.adb b/gcc/testsuite/gnat.dg/strub_ind2.adb
index e918b392631..b9bfe50e929 100644
--- a/gcc/testsuite/gnat.dg/strub_ind2.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind2.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict" }
+--  { dg-require-effective-target strub }
 
 --  This is essentially the same test as strub_attr.adb, 
 --  but with an explicit conversion.
diff --git a/gcc/testsuite/gnat.dg/strub_intf.adb b/gcc/testsuite/gnat.dg/strub_intf.adb
index 8f0212a7586..f43854705d0 100644
--- a/gcc/testsuite/gnat.dg/strub_intf.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 --  Check that strub mode mismatches between overrider and overridden
 --  subprograms are reported.
diff --git a/gcc/testsuite/gnat.dg/strub_intf1.adb b/gcc/testsuite/gnat.dg/strub_intf1.adb
index bf77321cef7..7a38a4c49ba 100644
--- a/gcc/testsuite/gnat.dg/strub_intf1.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 -- Check that at-calls dispatching calls to interfaces are transformed.
 
diff --git a/gcc/testsuite/gnat.dg/strub_intf2.adb b/gcc/testsuite/gnat.dg/strub_intf2.adb
index e8880dbc437..7992b7344fb 100644
--- a/gcc/testsuite/gnat.dg/strub_intf2.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf2.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 --  Check that strub mode mismatches between overrider and overridden
 --  subprograms are reported even when the overriders for an
diff --git a/gcc/testsuite/gnat.dg/strub_renm.adb b/gcc/testsuite/gnat.dg/strub_renm.adb
index 217367e712d..abfb120b514 100644
--- a/gcc/testsuite/gnat.dg/strub_renm.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Renm is
    procedure P (X : Integer);
diff --git a/gcc/testsuite/gnat.dg/strub_renm1.adb b/gcc/testsuite/gnat.dg/strub_renm1.adb
index a11adbfb5a9..68d3230b535 100644
--- a/gcc/testsuite/gnat.dg/strub_renm1.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed -fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Renm1 is
    V : Integer := 0;
diff --git a/gcc/testsuite/gnat.dg/strub_renm2.adb b/gcc/testsuite/gnat.dg/strub_renm2.adb
index c488c20826f..3cb81ea03f7 100644
--- a/gcc/testsuite/gnat.dg/strub_renm2.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm2.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Renm2 is
    V : Integer := 0;
diff --git a/gcc/testsuite/gnat.dg/strub_var.adb b/gcc/testsuite/gnat.dg/strub_var.adb
index 3d158de2803..7c6affa06d4 100644
--- a/gcc/testsuite/gnat.dg/strub_var.adb
+++ b/gcc/testsuite/gnat.dg/strub_var.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm" }
+--  { dg-require-effective-target strub }
 
 -- We don't read from the automatic variable, but being an automatic
 --  variable, its presence should be enough for the procedure to get
diff --git a/gcc/testsuite/gnat.dg/strub_var1.adb b/gcc/testsuite/gnat.dg/strub_var1.adb
index 6a504e09198..64b7e65fe9b 100644
--- a/gcc/testsuite/gnat.dg/strub_var1.adb
+++ b/gcc/testsuite/gnat.dg/strub_var1.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 with Strub_Attr;
 procedure Strub_Var1 is
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 3fcce6be49d..40a60c198cf 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -1302,6 +1302,13 @@ proc check_stack_check_available { stack_kind } {
     } "$stack_opt"]
 }
 
+# Return 1 if the target supports stack scrubbing.
+proc check_effective_target_strub {} {
+    return [check_no_compiler_messages strub assembly {
+	void __attribute__ ((__strub__)) fn (void) {}
+    } ""]
+}
+
 # Return 1 if compilation with -freorder-blocks-and-partition is error-free
 # for trivial code, 0 otherwise.  As some targets (ARM for example) only
 # warn when -fprofile-use is also supplied we test that combination too.
diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in
index d8163c5af99..3f77283490e 100644
--- a/libgcc/Makefile.in
+++ b/libgcc/Makefile.in
@@ -434,7 +434,7 @@ LIB2ADD += enable-execute-stack.c
 LIB2ADD += $(srcdir)/hardcfr.c
 
 # Stack scrubbing infrastructure.
-LIB2ADD += $(srcdir)/strub.c
+@HAVE_STRUB_SUPPORT@LIB2ADD += $(srcdir)/strub.c
 
 # While emutls.c has nothing to do with EH, it is in LIB2ADDEH*
 # instead of LIB2ADD because that's the way to be sure on some targets
diff --git a/libgcc/configure b/libgcc/configure
index cf149209652..567158955a3 100755
--- a/libgcc/configure
+++ b/libgcc/configure
@@ -593,6 +593,7 @@ asm_hidden_op
 extra_parts
 cpu_type
 get_gcc_base_ver
+HAVE_STRUB_SUPPORT
 thread_header
 tm_defines
 tm_file
@@ -5702,6 +5703,31 @@ esac
 
 
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for strub support" >&5
+$as_echo_n "checking for strub support... " >&6; }
+if ${libgcc_cv_strub_support+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+void __attribute__ ((__strub__)) fn (void) {}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  libgcc_cv_strub_support=yes
+else
+  libgcc_cv_strub_support=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgcc_cv_strub_support" >&5
+$as_echo "$libgcc_cv_strub_support" >&6; }
+if test "x$libgcc_cv_strub_support" != xno; then
+  HAVE_STRUB_SUPPORT=
+else
+  HAVE_STRUB_SUPPORT='# '
+fi
+
+
 # Determine what GCC version number to use in filesystem paths.
 
   get_gcc_base_ver="cat"
diff --git a/libgcc/configure.ac b/libgcc/configure.ac
index 2fc9d5d7c93..9c0e415501a 100644
--- a/libgcc/configure.ac
+++ b/libgcc/configure.ac
@@ -694,6 +694,19 @@ AC_SUBST(tm_defines)
 # Map from thread model to thread header.
 GCC_AC_THREAD_HEADER([$target_thread_file])
 
+AC_CACHE_CHECK([for strub support],
+  [libgcc_cv_strub_support],
+  [AC_COMPILE_IFELSE(
+    [AC_LANG_SOURCE([void __attribute__ ((__strub__)) fn (void) {}])],
+    [libgcc_cv_strub_support=yes],
+    [libgcc_cv_strub_support=no])])
+if test "x$libgcc_cv_strub_support" != xno; then
+  HAVE_STRUB_SUPPORT=
+else
+  HAVE_STRUB_SUPPORT='# '
+fi
+AC_SUBST(HAVE_STRUB_SUPPORT)
+
 # Determine what GCC version number to use in filesystem paths.
 GCC_BASE_VER

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [gcc(refs/users/aoliva/heads/testme)] strub: enable conditional support
@ 2023-12-07  1:17 Alexandre Oliva
  0 siblings, 0 replies; 25+ messages in thread
From: Alexandre Oliva @ 2023-12-07  1:17 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:f169484ad00d69bb0d8455a95f1c3a817632cbb8

commit f169484ad00d69bb0d8455a95f1c3a817632cbb8
Author: Alexandre Oliva <oliva@adacore.com>
Date:   Wed Dec 6 19:36:02 2023 -0300

    strub: enable conditional support
    
    Targets that don't expose callee stacks to callers, such as nvptx, as
    well as -fsplit-stack compilations, violate fundamental assumptions of
    the current strub implementation.  This patch enables targets to
    disable strub, and disables it when -fsplit-stack is enabled.
    
    When strub support is disabled, the testsuite will now skip strub
    tests, and libgcc will not build the strub runtime components.
    
    
    for  gcc/ChangeLog
    
            * target.def (have_strub_support_for): New hook.
            * doc/tm.texi.in: Document it.
            * doc/tm.texi: Rebuild.
            * ipa-strub.cc: Include target.h.
            (strub_target_support_p): New.
            (can_strub_p): Call it.  Test for no flag_split_stack.
            (pass_ipa_strub::adjust_at_calls_call): Check for target
            support.
            * config/nvptx/nvptx.cc (TARGET_HAVE_STRUB_SUPPORT_FOR):
            Disable.
            * doc/sourcebuild.texi (strub): Document new effective
            target.
    
    for  gcc/testsuite/ChangeLog
    
            * gcc.dg/strub-split-stack.c: New.
            * gcc.dg/strub-unsupported.c: New.
            * lib/target-supports.exp (check_effective_target_strub): New.
            * c-c++-common/strub-O0.c: Require effective target strub.
            * c-c++-common/strub-O1.c: Likewise.
            * c-c++-common/strub-O2.c: Likewise.
            * c-c++-common/strub-O2fni.c: Likewise.
            * c-c++-common/strub-O3.c: Likewise.
            * c-c++-common/strub-O3fni.c: Likewise.
            * c-c++-common/strub-Og.c: Likewise.
            * c-c++-common/strub-Os.c: Likewise.
            * c-c++-common/strub-all1.c: Likewise.
            * c-c++-common/strub-all2.c: Likewise.
            * c-c++-common/strub-apply1.c: Likewise.
            * c-c++-common/strub-apply2.c: Likewise.
            * c-c++-common/strub-apply3.c: Likewise.
            * c-c++-common/strub-apply4.c: Likewise.
            * c-c++-common/strub-at-calls1.c: Likewise.
            * c-c++-common/strub-at-calls2.c: Likewise.
            * c-c++-common/strub-defer-O1.c: Likewise.
            * c-c++-common/strub-defer-O2.c: Likewise.
            * c-c++-common/strub-defer-O3.c: Likewise.
            * c-c++-common/strub-defer-Os.c: Likewise.
            * c-c++-common/strub-internal1.c: Likewise.
            * c-c++-common/strub-internal2.c: Likewise.
            * c-c++-common/strub-parms1.c: Likewise.
            * c-c++-common/strub-parms2.c: Likewise.
            * c-c++-common/strub-parms3.c: Likewise.
            * c-c++-common/strub-relaxed1.c: Likewise.
            * c-c++-common/strub-relaxed2.c: Likewise.
            * c-c++-common/strub-short-O0-exc.c: Likewise.
            * c-c++-common/strub-short-O0.c: Likewise.
            * c-c++-common/strub-short-O1.c: Likewise.
            * c-c++-common/strub-short-O2.c: Likewise.
            * c-c++-common/strub-short-O3.c: Likewise.
            * c-c++-common/strub-short-Os.c: Likewise.
            * c-c++-common/strub-strict1.c: Likewise.
            * c-c++-common/strub-strict2.c: Likewise.
            * c-c++-common/strub-tail-O1.c: Likewise.
            * c-c++-common/strub-tail-O2.c: Likewise.
            * c-c++-common/strub-var1.c: Likewise.
            * c-c++-common/torture/strub-callable1.c: Likewise.
            * c-c++-common/torture/strub-callable2.c: Likewise.
            * c-c++-common/torture/strub-const1.c: Likewise.
            * c-c++-common/torture/strub-const2.c: Likewise.
            * c-c++-common/torture/strub-const3.c: Likewise.
            * c-c++-common/torture/strub-const4.c: Likewise.
            * c-c++-common/torture/strub-data1.c: Likewise.
            * c-c++-common/torture/strub-data2.c: Likewise.
            * c-c++-common/torture/strub-data3.c: Likewise.
            * c-c++-common/torture/strub-data4.c: Likewise.
            * c-c++-common/torture/strub-data5.c: Likewise.
            * c-c++-common/torture/strub-indcall1.c: Likewise.
            * c-c++-common/torture/strub-indcall2.c: Likewise.
            * c-c++-common/torture/strub-indcall3.c: Likewise.
            * c-c++-common/torture/strub-inlinable1.c: Likewise.
            * c-c++-common/torture/strub-inlinable2.c: Likewise.
            * c-c++-common/torture/strub-ptrfn1.c: Likewise.
            * c-c++-common/torture/strub-ptrfn2.c: Likewise.
            * c-c++-common/torture/strub-ptrfn3.c: Likewise.
            * c-c++-common/torture/strub-ptrfn4.c: Likewise.
            * c-c++-common/torture/strub-pure1.c: Likewise.
            * c-c++-common/torture/strub-pure2.c: Likewise.
            * c-c++-common/torture/strub-pure3.c: Likewise.
            * c-c++-common/torture/strub-pure4.c: Likewise.
            * c-c++-common/torture/strub-run1.c: Likewise.
            * c-c++-common/torture/strub-run2.c: Likewise.
            * c-c++-common/torture/strub-run3.c: Likewise.
            * c-c++-common/torture/strub-run4.c: Likewise.
            * c-c++-common/torture/strub-run4c.c: Likewise.
            * c-c++-common/torture/strub-run4d.c: Likewise.
            * c-c++-common/torture/strub-run4i.c: Likewise.
            * g++.dg/strub-run1.C: Likewise.
            * g++.dg/torture/strub-init1.C: Likewise.
            * g++.dg/torture/strub-init2.C: Likewise.
            * g++.dg/torture/strub-init3.C: Likewise.
            * gnat.dg/strub_attr.adb: Likewise.
            * gnat.dg/strub_ind.adb: Likewise.
            * gnat.dg/strub_access.adb: Likewise.
            * gnat.dg/strub_access1.adb: Likewise.
            * gnat.dg/strub_disp.adb: Likewise.
            * gnat.dg/strub_disp1.adb: Likewise.
            * gnat.dg/strub_ind1.adb: Likewise.
            * gnat.dg/strub_ind2.adb: Likewise.
            * gnat.dg/strub_intf.adb: Likewise.
            * gnat.dg/strub_intf1.adb: Likewise.
            * gnat.dg/strub_intf2.adb: Likewise.
            * gnat.dg/strub_renm.adb: Likewise.
            * gnat.dg/strub_renm1.adb: Likewise.
            * gnat.dg/strub_renm2.adb: Likewise.
            * gnat.dg/strub_var.adb: Likewise.
            * gnat.dg/strub_var1.adb: Likewise.
    
    for  libgcc/ChangeLog
    
            * configure.ac: Check for strub support.
            * configure: Rebuilt.
            * Makefile.in: Compile strub.c conditionally.

Diff:
---
 gcc/config/i386/i386.cc                            |  4 ++
 gcc/config/nvptx/nvptx.cc                          |  3 ++
 gcc/doc/sourcebuild.texi                           |  3 ++
 gcc/doc/tm.texi                                    |  6 +++
 gcc/doc/tm.texi.in                                 |  2 +
 gcc/ipa-strub.cc                                   | 54 +++++++++++++++++++++-
 gcc/target.def                                     |  8 ++++
 gcc/testsuite/c-c++-common/strub-O0.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O1.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O2.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O2fni.c           |  1 +
 gcc/testsuite/c-c++-common/strub-O3.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O3fni.c           |  1 +
 gcc/testsuite/c-c++-common/strub-Og.c              |  1 +
 gcc/testsuite/c-c++-common/strub-Os.c              |  1 +
 gcc/testsuite/c-c++-common/strub-all1.c            |  1 +
 gcc/testsuite/c-c++-common/strub-all2.c            |  1 +
 gcc/testsuite/c-c++-common/strub-apply1.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply2.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply3.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply4.c          |  1 +
 gcc/testsuite/c-c++-common/strub-at-calls1.c       |  1 +
 gcc/testsuite/c-c++-common/strub-at-calls2.c       |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O3.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-Os.c        |  1 +
 gcc/testsuite/c-c++-common/strub-internal1.c       |  1 +
 gcc/testsuite/c-c++-common/strub-internal2.c       |  1 +
 gcc/testsuite/c-c++-common/strub-parms1.c          |  1 +
 gcc/testsuite/c-c++-common/strub-parms2.c          |  1 +
 gcc/testsuite/c-c++-common/strub-parms3.c          |  1 +
 gcc/testsuite/c-c++-common/strub-relaxed1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-relaxed2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O0-exc.c    |  1 +
 gcc/testsuite/c-c++-common/strub-short-O0.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O3.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-Os.c        |  1 +
 gcc/testsuite/c-c++-common/strub-split-stack.c     | 10 ++++
 gcc/testsuite/c-c++-common/strub-strict1.c         |  1 +
 gcc/testsuite/c-c++-common/strub-strict2.c         |  1 +
 gcc/testsuite/c-c++-common/strub-tail-O1.c         |  1 +
 gcc/testsuite/c-c++-common/strub-tail-O2.c         |  1 +
 gcc/testsuite/c-c++-common/strub-unsupported.c     | 25 ++++++++++
 gcc/testsuite/c-c++-common/strub-var1.c            |  1 +
 .../c-c++-common/torture/strub-callable1.c         |  1 +
 .../c-c++-common/torture/strub-callable2.c         |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const1.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const2.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const3.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const4.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data1.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data2.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data3.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data4.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data5.c   |  1 +
 .../c-c++-common/torture/strub-indcall1.c          |  1 +
 .../c-c++-common/torture/strub-indcall2.c          |  1 +
 .../c-c++-common/torture/strub-indcall3.c          |  1 +
 .../c-c++-common/torture/strub-inlinable1.c        |  1 +
 .../c-c++-common/torture/strub-inlinable2.c        |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure1.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure2.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure3.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure4.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run1.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run2.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run3.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4c.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4d.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4i.c   |  1 +
 gcc/testsuite/g++.dg/strub-run1.C                  |  1 +
 gcc/testsuite/g++.dg/torture/strub-init1.C         |  1 +
 gcc/testsuite/g++.dg/torture/strub-init2.C         |  1 +
 gcc/testsuite/g++.dg/torture/strub-init3.C         |  1 +
 gcc/testsuite/gnat.dg/strub_access.adb             |  1 +
 gcc/testsuite/gnat.dg/strub_access1.adb            |  1 +
 gcc/testsuite/gnat.dg/strub_attr.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_disp.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_disp1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_ind.adb                |  1 +
 gcc/testsuite/gnat.dg/strub_ind1.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_ind2.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_intf.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_intf1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_intf2.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_renm.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_renm1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_renm2.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_var.adb                |  1 +
 gcc/testsuite/gnat.dg/strub_var1.adb               |  1 +
 gcc/testsuite/lib/target-supports.exp              |  7 +++
 libgcc/Makefile.in                                 |  2 +-
 libgcc/configure                                   | 26 +++++++++++
 libgcc/configure.ac                                | 13 ++++++
 102 files changed, 249 insertions(+), 3 deletions(-)

diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 7c5cab4e2c6..f933c9c23c7 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -26658,6 +26658,10 @@ ix86_libm_function_max_error (unsigned cfn, machine_mode mode,
 #define TARGET_RUN_TARGET_SELFTESTS selftest::ix86_run_selftests
 #endif /* #if CHECKING_P */
 
+// ??? for testing only
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 #include "gt-i386.h"
diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc
index ae20802c879..3fb1deb70fd 100644
--- a/gcc/config/nvptx/nvptx.cc
+++ b/gcc/config/nvptx/nvptx.cc
@@ -7789,6 +7789,9 @@ nvptx_asm_output_def_from_decls (FILE *stream, tree name, tree value)
 #undef TARGET_LIBC_HAS_FUNCTION
 #define TARGET_LIBC_HAS_FUNCTION nvptx_libc_has_function
 
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-nvptx.h"
diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi
index c9909026854..26a7e9c3507 100644
--- a/gcc/doc/sourcebuild.texi
+++ b/gcc/doc/sourcebuild.texi
@@ -2983,6 +2983,9 @@ Target supports statically linking @samp{libgfortran}.
 @item string_merging
 Target supports merging string constants at link time.
 
+@item strub
+Target supports attribute @code{strub} for stack scrubbing.
+
 @item ucn
 Target supports compiling and assembling UCN.
 
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 89a1735dd79..768ada0af52 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -3450,6 +3450,12 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@deftypefn {Target Hook} bool TARGET_HAVE_STRUB_SUPPORT_FOR (tree)
+Returns true if the target supports stack scrubbing for the given function
+or type, otherwise return false.  The default implementation always returns
+true.
+@end deftypefn
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index ebc1d3de5ca..4fe0805394e 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2686,6 +2686,8 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@hook TARGET_HAVE_STRUB_SUPPORT_FOR
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
index 293bec132b8..f3100bb1d44 100644
--- a/gcc/ipa-strub.cc
+++ b/gcc/ipa-strub.cc
@@ -60,6 +60,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-strub.h"
 #include "symtab-thunks.h"
 #include "attr-fnspec.h"
+#include "target.h"
 
 /* This file introduces two passes that, together, implement
    machine-independent stack scrubbing, strub for short.  It arranges
@@ -631,17 +632,60 @@ strub_always_inline_p (cgraph_node *node)
   return lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl));
 }
 
+/* Return TRUE iff the target has strub support for T, a function decl
+   or a type, and optionally REPORT thereasons for ineligibility.  If
+   T is a type and error REPORTing is enabled, the LOCation (e.g. of
+   the indirect call) should be given in LOC.  */
+static inline bool
+strub_target_support_p (tree t, bool report = false,
+			location_t loc = UNKNOWN_LOCATION)
+{
+  bool result = true;
+
+  if (!targetm.have_strub_support_for (t))
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      if (DECL_P (t))
+	sorry_at (DECL_SOURCE_LOCATION (t),
+		  "%qD is not eligible for %<strub%>"
+		  " on the target system", t);
+      else
+	sorry_at (loc,
+		  "%qT is not an eligible type for %<strub%>"
+		  " on the target system", t);
+    }
+
+  return result;
+}
+
 /* Return TRUE iff NODE is potentially eligible for any strub-enabled mode, and
    optionally REPORT the reasons for ineligibility.  */
 
 static inline bool
 can_strub_p (cgraph_node *node, bool report = false)
 {
-  bool result = true;
+  bool result = strub_target_support_p (node->decl, report);
 
-  if (!report && strub_always_inline_p (node))
+  if (!report && (!result || strub_always_inline_p (node)))
     return result;
 
+  if (flag_split_stack)
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (node->decl),
+		"%qD is not eligible for %<strub%>"
+		" because %<-fsplit-stack%> is enabled",
+		node->decl);
+    }
+
   if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
     {
       result = false;
@@ -2417,6 +2461,12 @@ pass_ipa_strub::adjust_at_calls_call (cgraph_edge *e, int named_args,
 			 && (TREE_TYPE (gimple_call_arg (ocall, named_args))
 			     == get_pwmt ())));
 
+  tree tsup;
+  if (!(tsup = gimple_call_fndecl (ocall)))
+    tsup = TREE_TYPE (TREE_TYPE (gimple_call_fn (ocall)));
+  if (!strub_target_support_p (tsup, true, gimple_location (ocall)))
+    return;
+
   /* If we're already within a strub context, pass on the incoming watermark
      pointer, and omit the enter and leave calls around the modified call, as an
      optimization, or as a means to satisfy a tail-call requirement.  */
diff --git a/gcc/target.def b/gcc/target.def
index 52b83e091b9..08218f3a42a 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4457,6 +4457,14 @@ otherwise return false.  The default implementation always returns true.",
  bool, (void),
  hook_bool_void_true)
 
+DEFHOOK
+(have_strub_support_for,
+ "Returns true if the target supports stack scrubbing for the given function\n\
+or type, otherwise return false.  The default implementation always returns\n\
+true.",
+ bool, (tree),
+ hook_bool_tree_true)
+
 DEFHOOK
 (have_speculation_safe_value,
 "This hook is used to determine the level of target support for\n\
diff --git a/gcc/testsuite/c-c++-common/strub-O0.c b/gcc/testsuite/c-c++-common/strub-O0.c
index c7a79a6ea0d..f0a3f7b4c6f 100644
--- a/gcc/testsuite/c-c++-common/strub-O0.c
+++ b/gcc/testsuite/c-c++-common/strub-O0.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -O0, none of the strub builtins are expanded inline.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O1.c b/gcc/testsuite/c-c++-common/strub-O1.c
index 96285c975d9..50403426b18 100644
--- a/gcc/testsuite/c-c++-common/strub-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -O1, without -fno-inline, we fully expand enter, but neither update nor
    leave.  */
diff --git a/gcc/testsuite/c-c++-common/strub-O2.c b/gcc/testsuite/c-c++-common/strub-O2.c
index 8edc0d8aa13..37e02998e31 100644
--- a/gcc/testsuite/c-c++-common/strub-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -O2, without -fno-inline, we fully expand enter and update, and add a test
    around the leave call.  */
diff --git a/gcc/testsuite/c-c++-common/strub-O2fni.c b/gcc/testsuite/c-c++-common/strub-O2fni.c
index c6d900cf3c4..905e2c6b2ff 100644
--- a/gcc/testsuite/c-c++-common/strub-O2fni.c
+++ b/gcc/testsuite/c-c++-common/strub-O2fni.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
+/* { dg-require-effective-target strub } */
 
 /* With -fno-inline, none of the strub builtins are inlined.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O3.c b/gcc/testsuite/c-c++-common/strub-O3.c
index 33ee465e51c..3bbf132bdf1 100644
--- a/gcc/testsuite/c-c++-common/strub-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-O3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 int __attribute__ ((__strub__)) var;
 
diff --git a/gcc/testsuite/c-c++-common/strub-O3fni.c b/gcc/testsuite/c-c++-common/strub-O3fni.c
index 2936f82079e..c46fce38e5c 100644
--- a/gcc/testsuite/c-c++-common/strub-O3fni.c
+++ b/gcc/testsuite/c-c++-common/strub-O3fni.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
+/* { dg-require-effective-target strub } */
 
 /* With -fno-inline, none of the strub builtins are inlined.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-Og.c b/gcc/testsuite/c-c++-common/strub-Og.c
index 479746e57d8..3b8eb19765c 100644
--- a/gcc/testsuite/c-c++-common/strub-Og.c
+++ b/gcc/testsuite/c-c++-common/strub-Og.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-Og -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -Og, without -fno-inline, we fully expand enter, but neither update nor
    leave.  */
diff --git a/gcc/testsuite/c-c++-common/strub-Os.c b/gcc/testsuite/c-c++-common/strub-Os.c
index 2241d4ea07f..8cfb253d676 100644
--- a/gcc/testsuite/c-c++-common/strub-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-Os.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-Os -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -Os, without -fno-inline, we fully expand enter, and also update.  The
    expanded update might be larger than a call proper, but argument saving and
diff --git a/gcc/testsuite/c-c++-common/strub-all1.c b/gcc/testsuite/c-c++-common/strub-all1.c
index a322bcc5da6..2037f681f29 100644
--- a/gcc/testsuite/c-c++-common/strub-all1.c
+++ b/gcc/testsuite/c-c++-common/strub-all1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
    strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub.  */
diff --git a/gcc/testsuite/c-c++-common/strub-all2.c b/gcc/testsuite/c-c++-common/strub-all2.c
index db60026d0e0..c026e7d9d28 100644
--- a/gcc/testsuite/c-c++-common/strub-all2.c
+++ b/gcc/testsuite/c-c++-common/strub-all2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* g becomes STRUB_INTERNAL, because of the flag.  Without inline, force_output
    is set for static non-inline functions when not optimizing, and that keeps
diff --git a/gcc/testsuite/c-c++-common/strub-apply1.c b/gcc/testsuite/c-c++-common/strub-apply1.c
index 2f462adc1ef..3edc89c54ee 100644
--- a/gcc/testsuite/c-c++-common/strub-apply1.c
+++ b/gcc/testsuite/c-c++-common/strub-apply1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 void __attribute__ ((__strub__ ("callable")))
 apply_function (void *args)
diff --git a/gcc/testsuite/c-c++-common/strub-apply2.c b/gcc/testsuite/c-c++-common/strub-apply2.c
index a5d7551f5da..838fc752734 100644
--- a/gcc/testsuite/c-c++-common/strub-apply2.c
+++ b/gcc/testsuite/c-c++-common/strub-apply2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 extern void __attribute__ ((__strub__))
 apply_function (void *args);
diff --git a/gcc/testsuite/c-c++-common/strub-apply3.c b/gcc/testsuite/c-c++-common/strub-apply3.c
index 64422a0d1e8..0206e4d930e 100644
--- a/gcc/testsuite/c-c++-common/strub-apply3.c
+++ b/gcc/testsuite/c-c++-common/strub-apply3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 void __attribute__ ((__strub__))
 apply_function (void *args)
diff --git a/gcc/testsuite/c-c++-common/strub-apply4.c b/gcc/testsuite/c-c++-common/strub-apply4.c
index 15ffaa031b8..e82504728b2 100644
--- a/gcc/testsuite/c-c++-common/strub-apply4.c
+++ b/gcc/testsuite/c-c++-common/strub-apply4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that implicit enabling of strub mode selects internal strub when the
    function uses __builtin_apply_args, that prevents the optimization to
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls1.c b/gcc/testsuite/c-c++-common/strub-at-calls1.c
index b70843b4215..a20acc0a48a 100644
--- a/gcc/testsuite/c-c++-common/strub-at-calls1.c
+++ b/gcc/testsuite/c-c++-common/strub-at-calls1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
    strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub.  */
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls2.c b/gcc/testsuite/c-c++-common/strub-at-calls2.c
index 97a3988a6b9..7915b33a39a 100644
--- a/gcc/testsuite/c-c++-common/strub-at-calls2.c
+++ b/gcc/testsuite/c-c++-common/strub-at-calls2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* g does NOT become STRUB_AT_CALLS because it's not viable.  Without inline,
    force_output is set for static non-inline functions when not optimizing, and
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O1.c b/gcc/testsuite/c-c++-common/strub-defer-O1.c
index 3d73431b3dc..3689998b5a3 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O1" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function does NOT defer
    the strubbing to its caller at -O1.  */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O2.c b/gcc/testsuite/c-c++-common/strub-defer-O2.c
index fddf3c745e7..9e01949db6b 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O2" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function does NOT defer
    the strubbing to its caller at -O2.  */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O3.c b/gcc/testsuite/c-c++-common/strub-defer-O3.c
index 7ebc65b58dd..40ee8edd1e0 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O3.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O3" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function defers the
    strubbing to its caller at -O3.  */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-Os.c b/gcc/testsuite/c-c++-common/strub-defer-Os.c
index fbaf85fe0fa..67ea9f04639 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-Os.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -Os" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function defers the
    strubbing to its caller at -Os.  */
diff --git a/gcc/testsuite/c-c++-common/strub-internal1.c b/gcc/testsuite/c-c++-common/strub-internal1.c
index e9d7b7b9ee0..d17254904e5 100644
--- a/gcc/testsuite/c-c++-common/strub-internal1.c
+++ b/gcc/testsuite/c-c++-common/strub-internal1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
    strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub.  */
diff --git a/gcc/testsuite/c-c++-common/strub-internal2.c b/gcc/testsuite/c-c++-common/strub-internal2.c
index 8b8e15a51c7..afc9189701f 100644
--- a/gcc/testsuite/c-c++-common/strub-internal2.c
+++ b/gcc/testsuite/c-c++-common/strub-internal2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* g becomes STRUB_INTERNAL, because of the flag.  */
 static void
diff --git a/gcc/testsuite/c-c++-common/strub-parms1.c b/gcc/testsuite/c-c++-common/strub-parms1.c
index 0a4a7539d34..f410b268971 100644
--- a/gcc/testsuite/c-c++-common/strub-parms1.c
+++ b/gcc/testsuite/c-c++-common/strub-parms1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 #include <stdarg.h>
 
diff --git a/gcc/testsuite/c-c++-common/strub-parms2.c b/gcc/testsuite/c-c++-common/strub-parms2.c
index 147171d96d5..6f572115a88 100644
--- a/gcc/testsuite/c-c++-common/strub-parms2.c
+++ b/gcc/testsuite/c-c++-common/strub-parms2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 #include <stdarg.h>
 
diff --git a/gcc/testsuite/c-c++-common/strub-parms3.c b/gcc/testsuite/c-c++-common/strub-parms3.c
index 4e92682895a..7383fea9ce8 100644
--- a/gcc/testsuite/c-c++-common/strub-parms3.c
+++ b/gcc/testsuite/c-c++-common/strub-parms3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that uses of a strub variable implicitly enables internal strub for
    publicly-visible functions, and causes the same transformations to their
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed1.c b/gcc/testsuite/c-c++-common/strub-relaxed1.c
index e2f9d8aebca..d2b4b52c51e 100644
--- a/gcc/testsuite/c-c++-common/strub-relaxed1.c
+++ b/gcc/testsuite/c-c++-common/strub-relaxed1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The difference between relaxed and strict in this case is that we accept the
    call from one internal-strub function to another.  Without the error,
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed2.c b/gcc/testsuite/c-c++-common/strub-relaxed2.c
index 98474435d2e..9e5a8e76b6c 100644
--- a/gcc/testsuite/c-c++-common/strub-relaxed2.c
+++ b/gcc/testsuite/c-c++-common/strub-relaxed2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The difference between relaxed and strict in this case is that we accept the
    call from one internal-strub function to another.  */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
index 1de15342595..aaeba2a2159 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fexceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0.c b/gcc/testsuite/c-c++-common/strub-short-O0.c
index f9209c81900..30cbdd819f1 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O0.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O0.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O1.c b/gcc/testsuite/c-c++-common/strub-short-O1.c
index bed1dcfb54a..911fdfb6db9 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O2.c b/gcc/testsuite/c-c++-common/strub-short-O2.c
index 6bf0071f52b..9b23ee3ac33 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O3.c b/gcc/testsuite/c-c++-common/strub-short-O3.c
index 4732f515bf7..4b3a8f843ea 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  At -O3 and -Os, we omit
    enter and leave calls within strub contexts, passing on the enclosing
diff --git a/gcc/testsuite/c-c++-common/strub-short-Os.c b/gcc/testsuite/c-c++-common/strub-short-Os.c
index 8d6424c479a..3627a240600 100644
--- a/gcc/testsuite/c-c++-common/strub-short-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-short-Os.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-Os -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  At -O3 and -Os, we omit
    enter and leave calls within strub contexts, passing on the enclosing
diff --git a/gcc/testsuite/c-c++-common/strub-split-stack.c b/gcc/testsuite/c-c++-common/strub-split-stack.c
new file mode 100644
index 00000000000..acbd750c3cd
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-split-stack.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-fsplit-stack" } */
+/* { dg-require-effective-target strub } */
+/* { dg-require-effective-target split-stack } */
+
+void __attribute__ ((__strub__))
+f {} /* { dg-message "not eligible" }
+
+void __attribute__ ((__strub__ ("internal")))
+g {} /* { dg-message "not eligible" }
diff --git a/gcc/testsuite/c-c++-common/strub-strict1.c b/gcc/testsuite/c-c++-common/strub-strict1.c
index 36852244206..503eb1734e3 100644
--- a/gcc/testsuite/c-c++-common/strub-strict1.c
+++ b/gcc/testsuite/c-c++-common/strub-strict1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
 
 static int __attribute__ ((__strub__)) var;
 
diff --git a/gcc/testsuite/c-c++-common/strub-strict2.c b/gcc/testsuite/c-c++-common/strub-strict2.c
index b4f28883218..3bf1aa30b4a 100644
--- a/gcc/testsuite/c-c++-common/strub-strict2.c
+++ b/gcc/testsuite/c-c++-common/strub-strict2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
 
 static int __attribute__ ((__strub__)) var;
 
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O1.c b/gcc/testsuite/c-c++-common/strub-tail-O1.c
index e48e0610e07..ba4b1623e28 100644
--- a/gcc/testsuite/c-c++-common/strub-tail-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-tail-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-tail-O2.c"
 
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O2.c b/gcc/testsuite/c-c++-common/strub-tail-O2.c
index 87cda7ab21b..043813b1de4 100644
--- a/gcc/testsuite/c-c++-common/strub-tail-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-tail-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.
    Tail calls are short-circuited at -O2+.  */
diff --git a/gcc/testsuite/c-c++-common/strub-unsupported.c b/gcc/testsuite/c-c++-common/strub-unsupported.c
new file mode 100644
index 00000000000..cacf3b93309
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-unsupported.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+
+/* Check that, when strub is not supported (so no dg-required-effective-target
+   strub above), we report when strub functions are defined, and when they're
+   called in ways that would require changes.  */
+
+void __attribute__ ((__strub__ ("at-calls"))) (*p) (void);
+
+void __attribute__ ((__strub__))
+f (void) {} /* { dg-message "not eligible" "" { target { ! strub } } } */
+
+void __attribute__ ((__strub__ ("internal")))
+g (void) {} /* { dg-message "not eligible" "" { target { ! strub } } } */
+
+extern void __attribute__ ((__strub__))
+h (void); /* { dg-message "not eligible" "" { target { ! strub } } } */
+
+extern void __attribute__ ((__strub__ ("internal")))
+i (void); /* not defined, ok.  */
+
+void m () {
+  p (); /* { dg-message "not eligible" "" { target { ! strub } } } */
+  h (); /* { dg-message "not eligible" "" { target { ! strub } } } */
+  i ();
+}
diff --git a/gcc/testsuite/c-c++-common/strub-var1.c b/gcc/testsuite/c-c++-common/strub-var1.c
index eb6250fd39c..67014aa5de8 100644
--- a/gcc/testsuite/c-c++-common/strub-var1.c
+++ b/gcc/testsuite/c-c++-common/strub-var1.c
@@ -1,4 +1,5 @@
 /* { dg-do compile } */
+/* { dg-require-effective-target strub } */
 
 int __attribute__ ((strub)) x;
 float __attribute__ ((strub)) f;
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable1.c b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
index b5e45ab0525..86dbee6746d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-callable1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that strub and non-strub functions can be called from non-strub
    contexts, and that strub and callable functions can be called from strub
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable2.c b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
index 96aa7fe4b07..9da120f6156 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-callable2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that impermissible (cross-strub-context) calls are reported.  */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const1.c b/gcc/testsuite/c-c++-common/torture/strub-const1.c
index 5e956cb1a9b..22056713cce 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub const function call, we issue an asm
    statement to make sure the watermark passed to it is held in memory before
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const2.c b/gcc/testsuite/c-c++-common/torture/strub-const2.c
index 73d650292df..a105c66d7a9 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-const function call, we issue an
    asm statement to make sure the watermark passed to it is held in memory
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const3.c b/gcc/testsuite/c-c++-common/torture/strub-const3.c
index 2584f1f974a..386200c2784 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub const wrapping call, we issue an asm statement
    to make sure the watermark passed to it is held in memory before the call,
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const4.c b/gcc/testsuite/c-c++-common/torture/strub-const4.c
index d819f54ec02..817e9fa2118 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-const wrapping call, we issue an
    asm statement to make sure the watermark passed to it is held in memory
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data1.c b/gcc/testsuite/c-c++-common/torture/strub-data1.c
index 7c27a2a1a6d..132ab63ef73 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointed-to data enables strubbing if accessed.  */
 int __attribute__ ((__strub__)) var;
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data2.c b/gcc/testsuite/c-c++-common/torture/strub-data2.c
index e66d903780a..b660702d26e 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointer itself is a strub variable, enabling internal strubbing when
    its value is used.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data3.c b/gcc/testsuite/c-c++-common/torture/strub-data3.c
index 5e08e0e58c6..fc44eef6f8f 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointer itself is a strub variable, that would enable internal strubbing
    if its value was used.  Here, it's only overwritten, so no strub.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data4.c b/gcc/testsuite/c-c++-common/torture/strub-data4.c
index a818e7a38bb..85e2f59055b 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointer itself is a strub variable, that would enable internal strubbing
    if its value was used.  Here, it's only overwritten, so no strub.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data5.c b/gcc/testsuite/c-c++-common/torture/strub-data5.c
index ddb0b5c0543..0a5edac414d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data5.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data5.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* It would be desirable to issue at least warnings for these.  */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
index c165f312f16..988954e7ed6 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 typedef void __attribute__ ((__strub__)) fntype ();
 fntype (*ptr);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
index 69fcff8d376..d3ca91389a7 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 typedef void __attribute__ ((__strub__)) fntype (int, int);
 fntype (*ptr);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
index ff006224909..89b5979cf7b 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 typedef void __attribute__ ((__strub__)) fntype (int, int, ...);
 fntype (*ptr);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
index 614b02228ba..4917dda8826 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed" } */
+/* { dg-require-effective-target strub } */
 
 inline void __attribute__ ((strub ("internal"), always_inline))
 inl_int_ali (void)
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
index f9a6b4a16fa..c45903856d4 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all" } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-inlinable1.c"
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
index b4a7f3992bb..b0d6139f0a8 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 typedef void ft (void);
 typedef void ft2 (int, int);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
index ef634d35126..1148c246f20 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -Wpedantic" } */
+/* { dg-require-effective-target strub } */
 
 /* C++ does not warn about the partial incompatibilities.
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
index e1f179e160e..06a72d86d2c 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
@@ -1,6 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -Wpedantic -fpermissive" } */
 /* { dg-prune-output "command-line option .-fpermissive." } */
+/* { dg-require-effective-target strub } */
 
 /* See strub-ptrfn2.c.  */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
index 70b558afad0..83ea1af7056 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed" } */
+/* { dg-require-effective-target strub } */
 
 /* This is strub-ptrfn2.c without -Wpedantic.
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure1.c b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
index a262a086837..2643136f178 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub pure function call, we issue an asm statement
    to make sure the watermark passed to it is not assumed to be unchanged.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure2.c b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
index 4c4bd50c209..8bda129b77d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-pure function call, we issue an asm
    statement to make sure the watermark passed to it is not assumed to be
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure3.c b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
index ce195c6b1f1..00bcbdd097a 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub pure wrapping call, we issue an asm statement
    to make sure the watermark passed to it is not assumed to be unchanged.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure4.c b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
index 75cd54ccb5b..ea7c40e7912 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-pure wrapping call, we issue an asm
    statement to make sure the watermark passed to it is not assumed to be
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run1.c b/gcc/testsuite/c-c++-common/torture/strub-run1.c
index 7458b3fb54d..fdf10042863 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run1.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a non-strub function leaves a string behind in the stack, and that
    equivalent strub functions don't.  Avoid the use of red zones by avoiding
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run2.c b/gcc/testsuite/c-c++-common/torture/strub-run2.c
index 5d60a7775f4..1228a665997 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run2.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a non-strub function leaves a string behind in the stack, and that
    equivalent strub functions don't.  Allow red zones to be used.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run3.c b/gcc/testsuite/c-c++-common/torture/strub-run3.c
index c2ad710858e..e5047a988f5 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run3.c
@@ -1,6 +1,7 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a non-strub function leaves a string behind in the stack, and that
    equivalent strub functions don't.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4.c b/gcc/testsuite/c-c++-common/torture/strub-run4.c
index 3b36b8e5d68..0e84a4bab80 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4.c
@@ -1,6 +1,7 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=all" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 /* Check that multi-level, multi-inlined functions still get cleaned up as
    expected, without overwriting temporary stack allocations while they should
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4c.c b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
index 57f9baf758d..edc98486dc9 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4c.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=at-calls" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-run4.c"
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4d.c b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
index 08de3f1c3b1..487ed08bb66 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4d.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
@@ -1,6 +1,7 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 #define ATTR_STRUB_AT_CALLS __attribute__ ((__strub__ ("at-calls")))
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4i.c b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
index 459f6886c54..a85447ffabf 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4i.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=internal" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-run4.c"
diff --git a/gcc/testsuite/g++.dg/strub-run1.C b/gcc/testsuite/g++.dg/strub-run1.C
index 0d367fb83d0..beb8b811f8f 100644
--- a/gcc/testsuite/g++.dg/strub-run1.C
+++ b/gcc/testsuite/g++.dg/strub-run1.C
@@ -1,5 +1,6 @@
 // { dg-do run }
 // { dg-options "-fstrub=internal" }
+// { dg-require-effective-target strub }
 
 // Check that we don't get extra copies.
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init1.C b/gcc/testsuite/g++.dg/torture/strub-init1.C
index c226ab10ff6..6ae45fadd70 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init1.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init1.C
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
 
 extern int __attribute__((__strub__)) initializer ();
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init2.C b/gcc/testsuite/g++.dg/torture/strub-init2.C
index a7911f1fa72..8f4849c7fde 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init2.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init2.C
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
 
 extern int __attribute__((__strub__)) initializer ();
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init3.C b/gcc/testsuite/g++.dg/torture/strub-init3.C
index 6ebebcd01e8..14f28e3c276 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init3.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init3.C
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
 
 extern int __attribute__((__strub__)) initializer ();
 
diff --git a/gcc/testsuite/gnat.dg/strub_access.adb b/gcc/testsuite/gnat.dg/strub_access.adb
index 29e6996ecf6..488a2d64afe 100644
--- a/gcc/testsuite/gnat.dg/strub_access.adb
+++ b/gcc/testsuite/gnat.dg/strub_access.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed -fdump-ipa-strubm" }
+--  { dg-require-effective-target strub }
 
 --  The main subprogram doesn't read from the automatic variable, but
 --  being an automatic variable, its presence should be enough for the
diff --git a/gcc/testsuite/gnat.dg/strub_access1.adb b/gcc/testsuite/gnat.dg/strub_access1.adb
index dae47060164..4a8653c4d84 100644
--- a/gcc/testsuite/gnat.dg/strub_access1.adb
+++ b/gcc/testsuite/gnat.dg/strub_access1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed" }
+--  { dg-require-effective-target strub }
 
 --  Check that we reject 'Access of a strub variable whose type does
 --  not carry a strub modifier.
diff --git a/gcc/testsuite/gnat.dg/strub_attr.adb b/gcc/testsuite/gnat.dg/strub_attr.adb
index 10445d7cf84..eb7826dc990 100644
--- a/gcc/testsuite/gnat.dg/strub_attr.adb
+++ b/gcc/testsuite/gnat.dg/strub_attr.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm -fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 package body Strub_Attr is
    E : exception;
diff --git a/gcc/testsuite/gnat.dg/strub_disp.adb b/gcc/testsuite/gnat.dg/strub_disp.adb
index 3dbcc4a357c..f23d4675def 100644
--- a/gcc/testsuite/gnat.dg/strub_disp.adb
+++ b/gcc/testsuite/gnat.dg/strub_disp.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Disp is
    package Foo is
diff --git a/gcc/testsuite/gnat.dg/strub_disp1.adb b/gcc/testsuite/gnat.dg/strub_disp1.adb
index 09756a74b7d..9c4c7f69637 100644
--- a/gcc/testsuite/gnat.dg/strub_disp1.adb
+++ b/gcc/testsuite/gnat.dg/strub_disp1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 -- Check that at-calls dispatching calls are transformed.
 
diff --git a/gcc/testsuite/gnat.dg/strub_ind.adb b/gcc/testsuite/gnat.dg/strub_ind.adb
index da56acaa957..613db69305e 100644
--- a/gcc/testsuite/gnat.dg/strub_ind.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict" }
+--  { dg-require-effective-target strub }
 
 --  This is essentially the same test as strub_attr.adb, 
 --  but applying attributes to access types as well.
diff --git a/gcc/testsuite/gnat.dg/strub_ind1.adb b/gcc/testsuite/gnat.dg/strub_ind1.adb
index 825e395e681..245b0a830f6 100644
--- a/gcc/testsuite/gnat.dg/strub_ind1.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm" }
+--  { dg-require-effective-target strub }
 
 --  This is essentially the same test as strub_attr.adb, 
 --  but with an explicit conversion.
diff --git a/gcc/testsuite/gnat.dg/strub_ind2.adb b/gcc/testsuite/gnat.dg/strub_ind2.adb
index e918b392631..b9bfe50e929 100644
--- a/gcc/testsuite/gnat.dg/strub_ind2.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind2.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict" }
+--  { dg-require-effective-target strub }
 
 --  This is essentially the same test as strub_attr.adb, 
 --  but with an explicit conversion.
diff --git a/gcc/testsuite/gnat.dg/strub_intf.adb b/gcc/testsuite/gnat.dg/strub_intf.adb
index 8f0212a7586..f43854705d0 100644
--- a/gcc/testsuite/gnat.dg/strub_intf.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 --  Check that strub mode mismatches between overrider and overridden
 --  subprograms are reported.
diff --git a/gcc/testsuite/gnat.dg/strub_intf1.adb b/gcc/testsuite/gnat.dg/strub_intf1.adb
index bf77321cef7..7a38a4c49ba 100644
--- a/gcc/testsuite/gnat.dg/strub_intf1.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 -- Check that at-calls dispatching calls to interfaces are transformed.
 
diff --git a/gcc/testsuite/gnat.dg/strub_intf2.adb b/gcc/testsuite/gnat.dg/strub_intf2.adb
index e8880dbc437..7992b7344fb 100644
--- a/gcc/testsuite/gnat.dg/strub_intf2.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf2.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 --  Check that strub mode mismatches between overrider and overridden
 --  subprograms are reported even when the overriders for an
diff --git a/gcc/testsuite/gnat.dg/strub_renm.adb b/gcc/testsuite/gnat.dg/strub_renm.adb
index 217367e712d..abfb120b514 100644
--- a/gcc/testsuite/gnat.dg/strub_renm.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Renm is
    procedure P (X : Integer);
diff --git a/gcc/testsuite/gnat.dg/strub_renm1.adb b/gcc/testsuite/gnat.dg/strub_renm1.adb
index a11adbfb5a9..68d3230b535 100644
--- a/gcc/testsuite/gnat.dg/strub_renm1.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed -fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Renm1 is
    V : Integer := 0;
diff --git a/gcc/testsuite/gnat.dg/strub_renm2.adb b/gcc/testsuite/gnat.dg/strub_renm2.adb
index c488c20826f..3cb81ea03f7 100644
--- a/gcc/testsuite/gnat.dg/strub_renm2.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm2.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Renm2 is
    V : Integer := 0;
diff --git a/gcc/testsuite/gnat.dg/strub_var.adb b/gcc/testsuite/gnat.dg/strub_var.adb
index 3d158de2803..7c6affa06d4 100644
--- a/gcc/testsuite/gnat.dg/strub_var.adb
+++ b/gcc/testsuite/gnat.dg/strub_var.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm" }
+--  { dg-require-effective-target strub }
 
 -- We don't read from the automatic variable, but being an automatic
 --  variable, its presence should be enough for the procedure to get
diff --git a/gcc/testsuite/gnat.dg/strub_var1.adb b/gcc/testsuite/gnat.dg/strub_var1.adb
index 6a504e09198..64b7e65fe9b 100644
--- a/gcc/testsuite/gnat.dg/strub_var1.adb
+++ b/gcc/testsuite/gnat.dg/strub_var1.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 with Strub_Attr;
 procedure Strub_Var1 is
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 3fcce6be49d..40a60c198cf 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -1302,6 +1302,13 @@ proc check_stack_check_available { stack_kind } {
     } "$stack_opt"]
 }
 
+# Return 1 if the target supports stack scrubbing.
+proc check_effective_target_strub {} {
+    return [check_no_compiler_messages strub assembly {
+	void __attribute__ ((__strub__)) fn (void) {}
+    } ""]
+}
+
 # Return 1 if compilation with -freorder-blocks-and-partition is error-free
 # for trivial code, 0 otherwise.  As some targets (ARM for example) only
 # warn when -fprofile-use is also supplied we test that combination too.
diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in
index d8163c5af99..3f77283490e 100644
--- a/libgcc/Makefile.in
+++ b/libgcc/Makefile.in
@@ -434,7 +434,7 @@ LIB2ADD += enable-execute-stack.c
 LIB2ADD += $(srcdir)/hardcfr.c
 
 # Stack scrubbing infrastructure.
-LIB2ADD += $(srcdir)/strub.c
+@HAVE_STRUB_SUPPORT@LIB2ADD += $(srcdir)/strub.c
 
 # While emutls.c has nothing to do with EH, it is in LIB2ADDEH*
 # instead of LIB2ADD because that's the way to be sure on some targets
diff --git a/libgcc/configure b/libgcc/configure
index cf149209652..567158955a3 100755
--- a/libgcc/configure
+++ b/libgcc/configure
@@ -593,6 +593,7 @@ asm_hidden_op
 extra_parts
 cpu_type
 get_gcc_base_ver
+HAVE_STRUB_SUPPORT
 thread_header
 tm_defines
 tm_file
@@ -5702,6 +5703,31 @@ esac
 
 
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for strub support" >&5
+$as_echo_n "checking for strub support... " >&6; }
+if ${libgcc_cv_strub_support+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+void __attribute__ ((__strub__)) fn (void) {}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  libgcc_cv_strub_support=yes
+else
+  libgcc_cv_strub_support=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgcc_cv_strub_support" >&5
+$as_echo "$libgcc_cv_strub_support" >&6; }
+if test "x$libgcc_cv_strub_support" != xno; then
+  HAVE_STRUB_SUPPORT=
+else
+  HAVE_STRUB_SUPPORT='# '
+fi
+
+
 # Determine what GCC version number to use in filesystem paths.
 
   get_gcc_base_ver="cat"
diff --git a/libgcc/configure.ac b/libgcc/configure.ac
index 2fc9d5d7c93..9c0e415501a 100644
--- a/libgcc/configure.ac
+++ b/libgcc/configure.ac
@@ -694,6 +694,19 @@ AC_SUBST(tm_defines)
 # Map from thread model to thread header.
 GCC_AC_THREAD_HEADER([$target_thread_file])
 
+AC_CACHE_CHECK([for strub support],
+  [libgcc_cv_strub_support],
+  [AC_COMPILE_IFELSE(
+    [AC_LANG_SOURCE([void __attribute__ ((__strub__)) fn (void) {}])],
+    [libgcc_cv_strub_support=yes],
+    [libgcc_cv_strub_support=no])])
+if test "x$libgcc_cv_strub_support" != xno; then
+  HAVE_STRUB_SUPPORT=
+else
+  HAVE_STRUB_SUPPORT='# '
+fi
+AC_SUBST(HAVE_STRUB_SUPPORT)
+
 # Determine what GCC version number to use in filesystem paths.
 GCC_BASE_VER

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [gcc(refs/users/aoliva/heads/testme)] strub: enable conditional support
@ 2023-12-07  0:19 Alexandre Oliva
  0 siblings, 0 replies; 25+ messages in thread
From: Alexandre Oliva @ 2023-12-07  0:19 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:5d2fc11965d18d4a18ed639b641a4e317d2865dd

commit 5d2fc11965d18d4a18ed639b641a4e317d2865dd
Author: Alexandre Oliva <oliva@gnu.org>
Date:   Wed Dec 6 19:36:02 2023 -0300

    strub: enable conditional support

Diff:
---
 gcc/config/nvptx/nvptx.cc                          |  3 ++
 gcc/doc/tm.texi                                    |  6 +++
 gcc/doc/tm.texi.in                                 |  2 +
 gcc/ipa-strub.cc                                   | 54 +++++++++++++++++++++-
 gcc/target.def                                     |  8 ++++
 gcc/testsuite/c-c++-common/strub-O0.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O1.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O2.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O2fni.c           |  1 +
 gcc/testsuite/c-c++-common/strub-O3.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O3fni.c           |  1 +
 gcc/testsuite/c-c++-common/strub-Og.c              |  1 +
 gcc/testsuite/c-c++-common/strub-Os.c              |  1 +
 gcc/testsuite/c-c++-common/strub-all1.c            |  1 +
 gcc/testsuite/c-c++-common/strub-all2.c            |  1 +
 gcc/testsuite/c-c++-common/strub-apply1.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply2.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply3.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply4.c          |  1 +
 gcc/testsuite/c-c++-common/strub-at-calls1.c       |  1 +
 gcc/testsuite/c-c++-common/strub-at-calls2.c       |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O3.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-Os.c        |  1 +
 gcc/testsuite/c-c++-common/strub-internal1.c       |  1 +
 gcc/testsuite/c-c++-common/strub-internal2.c       |  1 +
 gcc/testsuite/c-c++-common/strub-parms1.c          |  1 +
 gcc/testsuite/c-c++-common/strub-parms2.c          |  1 +
 gcc/testsuite/c-c++-common/strub-parms3.c          |  1 +
 gcc/testsuite/c-c++-common/strub-relaxed1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-relaxed2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O0-exc.c    |  1 +
 gcc/testsuite/c-c++-common/strub-short-O0.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O3.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-Os.c        |  1 +
 gcc/testsuite/c-c++-common/strub-strict1.c         |  1 +
 gcc/testsuite/c-c++-common/strub-strict2.c         |  1 +
 gcc/testsuite/c-c++-common/strub-tail-O1.c         |  1 +
 gcc/testsuite/c-c++-common/strub-tail-O2.c         |  1 +
 gcc/testsuite/c-c++-common/strub-var1.c            |  1 +
 .../c-c++-common/torture/strub-callable1.c         |  1 +
 .../c-c++-common/torture/strub-callable2.c         |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const1.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const2.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const3.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const4.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data1.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data2.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data3.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data4.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data5.c   |  1 +
 .../c-c++-common/torture/strub-indcall1.c          |  1 +
 .../c-c++-common/torture/strub-indcall2.c          |  1 +
 .../c-c++-common/torture/strub-indcall3.c          |  1 +
 .../c-c++-common/torture/strub-inlinable1.c        |  1 +
 .../c-c++-common/torture/strub-inlinable2.c        |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure1.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure2.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure3.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure4.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run1.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run2.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run3.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4c.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4d.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4i.c   |  1 +
 gcc/testsuite/g++.dg/strub-run1.C                  |  1 +
 gcc/testsuite/g++.dg/torture/strub-init1.C         |  1 +
 gcc/testsuite/g++.dg/torture/strub-init2.C         |  1 +
 gcc/testsuite/g++.dg/torture/strub-init3.C         |  1 +
 gcc/testsuite/gnat.dg/strub_access.adb             |  1 +
 gcc/testsuite/gnat.dg/strub_access1.adb            |  1 +
 gcc/testsuite/gnat.dg/strub_attr.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_disp.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_disp1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_ind.adb                |  1 +
 gcc/testsuite/gnat.dg/strub_ind1.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_ind2.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_intf.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_intf1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_intf2.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_renm.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_renm1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_renm2.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_var.adb                |  1 +
 gcc/testsuite/gnat.dg/strub_var1.adb               |  1 +
 gcc/testsuite/lib/target-supports.exp              |  7 +++
 libgcc/Makefile.in                                 |  2 +-
 libgcc/configure                                   | 26 +++++++++++
 libgcc/configure.ac                                | 13 ++++++
 98 files changed, 207 insertions(+), 3 deletions(-)

diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc
index ae20802c879..3fb1deb70fd 100644
--- a/gcc/config/nvptx/nvptx.cc
+++ b/gcc/config/nvptx/nvptx.cc
@@ -7789,6 +7789,9 @@ nvptx_asm_output_def_from_decls (FILE *stream, tree name, tree value)
 #undef TARGET_LIBC_HAS_FUNCTION
 #define TARGET_LIBC_HAS_FUNCTION nvptx_libc_has_function
 
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-nvptx.h"
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 89a1735dd79..768ada0af52 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -3450,6 +3450,12 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@deftypefn {Target Hook} bool TARGET_HAVE_STRUB_SUPPORT_FOR (tree)
+Returns true if the target supports stack scrubbing for the given function
+or type, otherwise return false.  The default implementation always returns
+true.
+@end deftypefn
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index ebc1d3de5ca..4fe0805394e 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2686,6 +2686,8 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@hook TARGET_HAVE_STRUB_SUPPORT_FOR
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
index 293bec132b8..f3100bb1d44 100644
--- a/gcc/ipa-strub.cc
+++ b/gcc/ipa-strub.cc
@@ -60,6 +60,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-strub.h"
 #include "symtab-thunks.h"
 #include "attr-fnspec.h"
+#include "target.h"
 
 /* This file introduces two passes that, together, implement
    machine-independent stack scrubbing, strub for short.  It arranges
@@ -631,17 +632,60 @@ strub_always_inline_p (cgraph_node *node)
   return lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl));
 }
 
+/* Return TRUE iff the target has strub support for T, a function decl
+   or a type, and optionally REPORT thereasons for ineligibility.  If
+   T is a type and error REPORTing is enabled, the LOCation (e.g. of
+   the indirect call) should be given in LOC.  */
+static inline bool
+strub_target_support_p (tree t, bool report = false,
+			location_t loc = UNKNOWN_LOCATION)
+{
+  bool result = true;
+
+  if (!targetm.have_strub_support_for (t))
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      if (DECL_P (t))
+	sorry_at (DECL_SOURCE_LOCATION (t),
+		  "%qD is not eligible for %<strub%>"
+		  " on the target system", t);
+      else
+	sorry_at (loc,
+		  "%qT is not an eligible type for %<strub%>"
+		  " on the target system", t);
+    }
+
+  return result;
+}
+
 /* Return TRUE iff NODE is potentially eligible for any strub-enabled mode, and
    optionally REPORT the reasons for ineligibility.  */
 
 static inline bool
 can_strub_p (cgraph_node *node, bool report = false)
 {
-  bool result = true;
+  bool result = strub_target_support_p (node->decl, report);
 
-  if (!report && strub_always_inline_p (node))
+  if (!report && (!result || strub_always_inline_p (node)))
     return result;
 
+  if (flag_split_stack)
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (node->decl),
+		"%qD is not eligible for %<strub%>"
+		" because %<-fsplit-stack%> is enabled",
+		node->decl);
+    }
+
   if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
     {
       result = false;
@@ -2417,6 +2461,12 @@ pass_ipa_strub::adjust_at_calls_call (cgraph_edge *e, int named_args,
 			 && (TREE_TYPE (gimple_call_arg (ocall, named_args))
 			     == get_pwmt ())));
 
+  tree tsup;
+  if (!(tsup = gimple_call_fndecl (ocall)))
+    tsup = TREE_TYPE (TREE_TYPE (gimple_call_fn (ocall)));
+  if (!strub_target_support_p (tsup, true, gimple_location (ocall)))
+    return;
+
   /* If we're already within a strub context, pass on the incoming watermark
      pointer, and omit the enter and leave calls around the modified call, as an
      optimization, or as a means to satisfy a tail-call requirement.  */
diff --git a/gcc/target.def b/gcc/target.def
index 52b83e091b9..08218f3a42a 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4457,6 +4457,14 @@ otherwise return false.  The default implementation always returns true.",
  bool, (void),
  hook_bool_void_true)
 
+DEFHOOK
+(have_strub_support_for,
+ "Returns true if the target supports stack scrubbing for the given function\n\
+or type, otherwise return false.  The default implementation always returns\n\
+true.",
+ bool, (tree),
+ hook_bool_tree_true)
+
 DEFHOOK
 (have_speculation_safe_value,
 "This hook is used to determine the level of target support for\n\
diff --git a/gcc/testsuite/c-c++-common/strub-O0.c b/gcc/testsuite/c-c++-common/strub-O0.c
index c7a79a6ea0d..f0a3f7b4c6f 100644
--- a/gcc/testsuite/c-c++-common/strub-O0.c
+++ b/gcc/testsuite/c-c++-common/strub-O0.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -O0, none of the strub builtins are expanded inline.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O1.c b/gcc/testsuite/c-c++-common/strub-O1.c
index 96285c975d9..50403426b18 100644
--- a/gcc/testsuite/c-c++-common/strub-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -O1, without -fno-inline, we fully expand enter, but neither update nor
    leave.  */
diff --git a/gcc/testsuite/c-c++-common/strub-O2.c b/gcc/testsuite/c-c++-common/strub-O2.c
index 8edc0d8aa13..37e02998e31 100644
--- a/gcc/testsuite/c-c++-common/strub-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -O2, without -fno-inline, we fully expand enter and update, and add a test
    around the leave call.  */
diff --git a/gcc/testsuite/c-c++-common/strub-O2fni.c b/gcc/testsuite/c-c++-common/strub-O2fni.c
index c6d900cf3c4..905e2c6b2ff 100644
--- a/gcc/testsuite/c-c++-common/strub-O2fni.c
+++ b/gcc/testsuite/c-c++-common/strub-O2fni.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
+/* { dg-require-effective-target strub } */
 
 /* With -fno-inline, none of the strub builtins are inlined.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O3.c b/gcc/testsuite/c-c++-common/strub-O3.c
index 33ee465e51c..3bbf132bdf1 100644
--- a/gcc/testsuite/c-c++-common/strub-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-O3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 int __attribute__ ((__strub__)) var;
 
diff --git a/gcc/testsuite/c-c++-common/strub-O3fni.c b/gcc/testsuite/c-c++-common/strub-O3fni.c
index 2936f82079e..c46fce38e5c 100644
--- a/gcc/testsuite/c-c++-common/strub-O3fni.c
+++ b/gcc/testsuite/c-c++-common/strub-O3fni.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
+/* { dg-require-effective-target strub } */
 
 /* With -fno-inline, none of the strub builtins are inlined.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-Og.c b/gcc/testsuite/c-c++-common/strub-Og.c
index 479746e57d8..3b8eb19765c 100644
--- a/gcc/testsuite/c-c++-common/strub-Og.c
+++ b/gcc/testsuite/c-c++-common/strub-Og.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-Og -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -Og, without -fno-inline, we fully expand enter, but neither update nor
    leave.  */
diff --git a/gcc/testsuite/c-c++-common/strub-Os.c b/gcc/testsuite/c-c++-common/strub-Os.c
index 2241d4ea07f..8cfb253d676 100644
--- a/gcc/testsuite/c-c++-common/strub-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-Os.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-Os -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
 
 /* At -Os, without -fno-inline, we fully expand enter, and also update.  The
    expanded update might be larger than a call proper, but argument saving and
diff --git a/gcc/testsuite/c-c++-common/strub-all1.c b/gcc/testsuite/c-c++-common/strub-all1.c
index a322bcc5da6..2037f681f29 100644
--- a/gcc/testsuite/c-c++-common/strub-all1.c
+++ b/gcc/testsuite/c-c++-common/strub-all1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
    strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub.  */
diff --git a/gcc/testsuite/c-c++-common/strub-all2.c b/gcc/testsuite/c-c++-common/strub-all2.c
index db60026d0e0..c026e7d9d28 100644
--- a/gcc/testsuite/c-c++-common/strub-all2.c
+++ b/gcc/testsuite/c-c++-common/strub-all2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* g becomes STRUB_INTERNAL, because of the flag.  Without inline, force_output
    is set for static non-inline functions when not optimizing, and that keeps
diff --git a/gcc/testsuite/c-c++-common/strub-apply1.c b/gcc/testsuite/c-c++-common/strub-apply1.c
index 2f462adc1ef..3edc89c54ee 100644
--- a/gcc/testsuite/c-c++-common/strub-apply1.c
+++ b/gcc/testsuite/c-c++-common/strub-apply1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 void __attribute__ ((__strub__ ("callable")))
 apply_function (void *args)
diff --git a/gcc/testsuite/c-c++-common/strub-apply2.c b/gcc/testsuite/c-c++-common/strub-apply2.c
index a5d7551f5da..838fc752734 100644
--- a/gcc/testsuite/c-c++-common/strub-apply2.c
+++ b/gcc/testsuite/c-c++-common/strub-apply2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 extern void __attribute__ ((__strub__))
 apply_function (void *args);
diff --git a/gcc/testsuite/c-c++-common/strub-apply3.c b/gcc/testsuite/c-c++-common/strub-apply3.c
index 64422a0d1e8..0206e4d930e 100644
--- a/gcc/testsuite/c-c++-common/strub-apply3.c
+++ b/gcc/testsuite/c-c++-common/strub-apply3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 void __attribute__ ((__strub__))
 apply_function (void *args)
diff --git a/gcc/testsuite/c-c++-common/strub-apply4.c b/gcc/testsuite/c-c++-common/strub-apply4.c
index 15ffaa031b8..e82504728b2 100644
--- a/gcc/testsuite/c-c++-common/strub-apply4.c
+++ b/gcc/testsuite/c-c++-common/strub-apply4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that implicit enabling of strub mode selects internal strub when the
    function uses __builtin_apply_args, that prevents the optimization to
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls1.c b/gcc/testsuite/c-c++-common/strub-at-calls1.c
index b70843b4215..a20acc0a48a 100644
--- a/gcc/testsuite/c-c++-common/strub-at-calls1.c
+++ b/gcc/testsuite/c-c++-common/strub-at-calls1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
    strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub.  */
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls2.c b/gcc/testsuite/c-c++-common/strub-at-calls2.c
index 97a3988a6b9..7915b33a39a 100644
--- a/gcc/testsuite/c-c++-common/strub-at-calls2.c
+++ b/gcc/testsuite/c-c++-common/strub-at-calls2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* g does NOT become STRUB_AT_CALLS because it's not viable.  Without inline,
    force_output is set for static non-inline functions when not optimizing, and
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O1.c b/gcc/testsuite/c-c++-common/strub-defer-O1.c
index 3d73431b3dc..3689998b5a3 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O1" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function does NOT defer
    the strubbing to its caller at -O1.  */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O2.c b/gcc/testsuite/c-c++-common/strub-defer-O2.c
index fddf3c745e7..9e01949db6b 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O2" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function does NOT defer
    the strubbing to its caller at -O2.  */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O3.c b/gcc/testsuite/c-c++-common/strub-defer-O3.c
index 7ebc65b58dd..40ee8edd1e0 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O3.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O3" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function defers the
    strubbing to its caller at -O3.  */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-Os.c b/gcc/testsuite/c-c++-common/strub-defer-Os.c
index fbaf85fe0fa..67ea9f04639 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-Os.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -Os" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a strub function called by another strub function defers the
    strubbing to its caller at -Os.  */
diff --git a/gcc/testsuite/c-c++-common/strub-internal1.c b/gcc/testsuite/c-c++-common/strub-internal1.c
index e9d7b7b9ee0..d17254904e5 100644
--- a/gcc/testsuite/c-c++-common/strub-internal1.c
+++ b/gcc/testsuite/c-c++-common/strub-internal1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
    strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub.  */
diff --git a/gcc/testsuite/c-c++-common/strub-internal2.c b/gcc/testsuite/c-c++-common/strub-internal2.c
index 8b8e15a51c7..afc9189701f 100644
--- a/gcc/testsuite/c-c++-common/strub-internal2.c
+++ b/gcc/testsuite/c-c++-common/strub-internal2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* g becomes STRUB_INTERNAL, because of the flag.  */
 static void
diff --git a/gcc/testsuite/c-c++-common/strub-parms1.c b/gcc/testsuite/c-c++-common/strub-parms1.c
index 0a4a7539d34..f410b268971 100644
--- a/gcc/testsuite/c-c++-common/strub-parms1.c
+++ b/gcc/testsuite/c-c++-common/strub-parms1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 #include <stdarg.h>
 
diff --git a/gcc/testsuite/c-c++-common/strub-parms2.c b/gcc/testsuite/c-c++-common/strub-parms2.c
index 147171d96d5..6f572115a88 100644
--- a/gcc/testsuite/c-c++-common/strub-parms2.c
+++ b/gcc/testsuite/c-c++-common/strub-parms2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 #include <stdarg.h>
 
diff --git a/gcc/testsuite/c-c++-common/strub-parms3.c b/gcc/testsuite/c-c++-common/strub-parms3.c
index 4e92682895a..7383fea9ce8 100644
--- a/gcc/testsuite/c-c++-common/strub-parms3.c
+++ b/gcc/testsuite/c-c++-common/strub-parms3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that uses of a strub variable implicitly enables internal strub for
    publicly-visible functions, and causes the same transformations to their
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed1.c b/gcc/testsuite/c-c++-common/strub-relaxed1.c
index e2f9d8aebca..d2b4b52c51e 100644
--- a/gcc/testsuite/c-c++-common/strub-relaxed1.c
+++ b/gcc/testsuite/c-c++-common/strub-relaxed1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The difference between relaxed and strict in this case is that we accept the
    call from one internal-strub function to another.  Without the error,
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed2.c b/gcc/testsuite/c-c++-common/strub-relaxed2.c
index 98474435d2e..9e5a8e76b6c 100644
--- a/gcc/testsuite/c-c++-common/strub-relaxed2.c
+++ b/gcc/testsuite/c-c++-common/strub-relaxed2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The difference between relaxed and strict in this case is that we accept the
    call from one internal-strub function to another.  */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
index 1de15342595..aaeba2a2159 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fexceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0.c b/gcc/testsuite/c-c++-common/strub-short-O0.c
index f9209c81900..30cbdd819f1 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O0.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O0.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O1.c b/gcc/testsuite/c-c++-common/strub-short-O1.c
index bed1dcfb54a..911fdfb6db9 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O2.c b/gcc/testsuite/c-c++-common/strub-short-O2.c
index 6bf0071f52b..9b23ee3ac33 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O3.c b/gcc/testsuite/c-c++-common/strub-short-O3.c
index 4732f515bf7..4b3a8f843ea 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  At -O3 and -Os, we omit
    enter and leave calls within strub contexts, passing on the enclosing
diff --git a/gcc/testsuite/c-c++-common/strub-short-Os.c b/gcc/testsuite/c-c++-common/strub-short-Os.c
index 8d6424c479a..3627a240600 100644
--- a/gcc/testsuite/c-c++-common/strub-short-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-short-Os.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-Os -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.  At -O3 and -Os, we omit
    enter and leave calls within strub contexts, passing on the enclosing
diff --git a/gcc/testsuite/c-c++-common/strub-strict1.c b/gcc/testsuite/c-c++-common/strub-strict1.c
index 36852244206..503eb1734e3 100644
--- a/gcc/testsuite/c-c++-common/strub-strict1.c
+++ b/gcc/testsuite/c-c++-common/strub-strict1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
 
 static int __attribute__ ((__strub__)) var;
 
diff --git a/gcc/testsuite/c-c++-common/strub-strict2.c b/gcc/testsuite/c-c++-common/strub-strict2.c
index b4f28883218..3bf1aa30b4a 100644
--- a/gcc/testsuite/c-c++-common/strub-strict2.c
+++ b/gcc/testsuite/c-c++-common/strub-strict2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
 
 static int __attribute__ ((__strub__)) var;
 
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O1.c b/gcc/testsuite/c-c++-common/strub-tail-O1.c
index e48e0610e07..ba4b1623e28 100644
--- a/gcc/testsuite/c-c++-common/strub-tail-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-tail-O1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-tail-O2.c"
 
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O2.c b/gcc/testsuite/c-c++-common/strub-tail-O2.c
index 87cda7ab21b..043813b1de4 100644
--- a/gcc/testsuite/c-c++-common/strub-tail-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-tail-O2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that the expected strub calls are issued.
    Tail calls are short-circuited at -O2+.  */
diff --git a/gcc/testsuite/c-c++-common/strub-var1.c b/gcc/testsuite/c-c++-common/strub-var1.c
index eb6250fd39c..67014aa5de8 100644
--- a/gcc/testsuite/c-c++-common/strub-var1.c
+++ b/gcc/testsuite/c-c++-common/strub-var1.c
@@ -1,4 +1,5 @@
 /* { dg-do compile } */
+/* { dg-require-effective-target strub } */
 
 int __attribute__ ((strub)) x;
 float __attribute__ ((strub)) f;
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable1.c b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
index b5e45ab0525..86dbee6746d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-callable1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that strub and non-strub functions can be called from non-strub
    contexts, and that strub and callable functions can be called from strub
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable2.c b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
index 96aa7fe4b07..9da120f6156 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-callable2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that impermissible (cross-strub-context) calls are reported.  */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const1.c b/gcc/testsuite/c-c++-common/torture/strub-const1.c
index 5e956cb1a9b..22056713cce 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub const function call, we issue an asm
    statement to make sure the watermark passed to it is held in memory before
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const2.c b/gcc/testsuite/c-c++-common/torture/strub-const2.c
index 73d650292df..a105c66d7a9 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-const function call, we issue an
    asm statement to make sure the watermark passed to it is held in memory
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const3.c b/gcc/testsuite/c-c++-common/torture/strub-const3.c
index 2584f1f974a..386200c2784 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub const wrapping call, we issue an asm statement
    to make sure the watermark passed to it is held in memory before the call,
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const4.c b/gcc/testsuite/c-c++-common/torture/strub-const4.c
index d819f54ec02..817e9fa2118 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-const wrapping call, we issue an
    asm statement to make sure the watermark passed to it is held in memory
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data1.c b/gcc/testsuite/c-c++-common/torture/strub-data1.c
index 7c27a2a1a6d..132ab63ef73 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointed-to data enables strubbing if accessed.  */
 int __attribute__ ((__strub__)) var;
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data2.c b/gcc/testsuite/c-c++-common/torture/strub-data2.c
index e66d903780a..b660702d26e 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointer itself is a strub variable, enabling internal strubbing when
    its value is used.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data3.c b/gcc/testsuite/c-c++-common/torture/strub-data3.c
index 5e08e0e58c6..fc44eef6f8f 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointer itself is a strub variable, that would enable internal strubbing
    if its value was used.  Here, it's only overwritten, so no strub.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data4.c b/gcc/testsuite/c-c++-common/torture/strub-data4.c
index a818e7a38bb..85e2f59055b 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* The pointer itself is a strub variable, that would enable internal strubbing
    if its value was used.  Here, it's only overwritten, so no strub.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data5.c b/gcc/testsuite/c-c++-common/torture/strub-data5.c
index ddb0b5c0543..0a5edac414d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data5.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data5.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* It would be desirable to issue at least warnings for these.  */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
index c165f312f16..988954e7ed6 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 typedef void __attribute__ ((__strub__)) fntype ();
 fntype (*ptr);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
index 69fcff8d376..d3ca91389a7 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 typedef void __attribute__ ((__strub__)) fntype (int, int);
 fntype (*ptr);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
index ff006224909..89b5979cf7b 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 typedef void __attribute__ ((__strub__)) fntype (int, int, ...);
 fntype (*ptr);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
index 614b02228ba..4917dda8826 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed" } */
+/* { dg-require-effective-target strub } */
 
 inline void __attribute__ ((strub ("internal"), always_inline))
 inl_int_ali (void)
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
index f9a6b4a16fa..c45903856d4 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all" } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-inlinable1.c"
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
index b4a7f3992bb..b0d6139f0a8 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 typedef void ft (void);
 typedef void ft2 (int, int);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
index ef634d35126..1148c246f20 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -Wpedantic" } */
+/* { dg-require-effective-target strub } */
 
 /* C++ does not warn about the partial incompatibilities.
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
index e1f179e160e..06a72d86d2c 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
@@ -1,6 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -Wpedantic -fpermissive" } */
 /* { dg-prune-output "command-line option .-fpermissive." } */
+/* { dg-require-effective-target strub } */
 
 /* See strub-ptrfn2.c.  */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
index 70b558afad0..83ea1af7056 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed" } */
+/* { dg-require-effective-target strub } */
 
 /* This is strub-ptrfn2.c without -Wpedantic.
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure1.c b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
index a262a086837..2643136f178 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub pure function call, we issue an asm statement
    to make sure the watermark passed to it is not assumed to be unchanged.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure2.c b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
index 4c4bd50c209..8bda129b77d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-pure function call, we issue an asm
    statement to make sure the watermark passed to it is not assumed to be
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure3.c b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
index ce195c6b1f1..00bcbdd097a 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub pure wrapping call, we issue an asm statement
    to make sure the watermark passed to it is not assumed to be unchanged.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure4.c b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
index 75cd54ccb5b..ea7c40e7912 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that, along with a strub implicitly-pure wrapping call, we issue an asm
    statement to make sure the watermark passed to it is not assumed to be
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run1.c b/gcc/testsuite/c-c++-common/torture/strub-run1.c
index 7458b3fb54d..fdf10042863 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run1.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a non-strub function leaves a string behind in the stack, and that
    equivalent strub functions don't.  Avoid the use of red zones by avoiding
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run2.c b/gcc/testsuite/c-c++-common/torture/strub-run2.c
index 5d60a7775f4..1228a665997 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run2.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a non-strub function leaves a string behind in the stack, and that
    equivalent strub functions don't.  Allow red zones to be used.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run3.c b/gcc/testsuite/c-c++-common/torture/strub-run3.c
index c2ad710858e..e5047a988f5 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run3.c
@@ -1,6 +1,7 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 /* Check that a non-strub function leaves a string behind in the stack, and that
    equivalent strub functions don't.  */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4.c b/gcc/testsuite/c-c++-common/torture/strub-run4.c
index 3b36b8e5d68..0e84a4bab80 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4.c
@@ -1,6 +1,7 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=all" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 /* Check that multi-level, multi-inlined functions still get cleaned up as
    expected, without overwriting temporary stack allocations while they should
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4c.c b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
index 57f9baf758d..edc98486dc9 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4c.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=at-calls" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-run4.c"
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4d.c b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
index 08de3f1c3b1..487ed08bb66 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4d.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
@@ -1,6 +1,7 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 #define ATTR_STRUB_AT_CALLS __attribute__ ((__strub__ ("at-calls")))
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4i.c b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
index 459f6886c54..a85447ffabf 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4i.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fstrub=internal" } */
 /* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
 
 #include "strub-run4.c"
diff --git a/gcc/testsuite/g++.dg/strub-run1.C b/gcc/testsuite/g++.dg/strub-run1.C
index 0d367fb83d0..beb8b811f8f 100644
--- a/gcc/testsuite/g++.dg/strub-run1.C
+++ b/gcc/testsuite/g++.dg/strub-run1.C
@@ -1,5 +1,6 @@
 // { dg-do run }
 // { dg-options "-fstrub=internal" }
+// { dg-require-effective-target strub }
 
 // Check that we don't get extra copies.
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init1.C b/gcc/testsuite/g++.dg/torture/strub-init1.C
index c226ab10ff6..6ae45fadd70 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init1.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init1.C
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
 
 extern int __attribute__((__strub__)) initializer ();
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init2.C b/gcc/testsuite/g++.dg/torture/strub-init2.C
index a7911f1fa72..8f4849c7fde 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init2.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init2.C
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
 
 extern int __attribute__((__strub__)) initializer ();
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init3.C b/gcc/testsuite/g++.dg/torture/strub-init3.C
index 6ebebcd01e8..14f28e3c276 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init3.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init3.C
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
 
 extern int __attribute__((__strub__)) initializer ();
 
diff --git a/gcc/testsuite/gnat.dg/strub_access.adb b/gcc/testsuite/gnat.dg/strub_access.adb
index 29e6996ecf6..488a2d64afe 100644
--- a/gcc/testsuite/gnat.dg/strub_access.adb
+++ b/gcc/testsuite/gnat.dg/strub_access.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed -fdump-ipa-strubm" }
+--  { dg-require-effective-target strub }
 
 --  The main subprogram doesn't read from the automatic variable, but
 --  being an automatic variable, its presence should be enough for the
diff --git a/gcc/testsuite/gnat.dg/strub_access1.adb b/gcc/testsuite/gnat.dg/strub_access1.adb
index dae47060164..4a8653c4d84 100644
--- a/gcc/testsuite/gnat.dg/strub_access1.adb
+++ b/gcc/testsuite/gnat.dg/strub_access1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed" }
+--  { dg-require-effective-target strub }
 
 --  Check that we reject 'Access of a strub variable whose type does
 --  not carry a strub modifier.
diff --git a/gcc/testsuite/gnat.dg/strub_attr.adb b/gcc/testsuite/gnat.dg/strub_attr.adb
index 10445d7cf84..eb7826dc990 100644
--- a/gcc/testsuite/gnat.dg/strub_attr.adb
+++ b/gcc/testsuite/gnat.dg/strub_attr.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm -fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 package body Strub_Attr is
    E : exception;
diff --git a/gcc/testsuite/gnat.dg/strub_disp.adb b/gcc/testsuite/gnat.dg/strub_disp.adb
index 3dbcc4a357c..f23d4675def 100644
--- a/gcc/testsuite/gnat.dg/strub_disp.adb
+++ b/gcc/testsuite/gnat.dg/strub_disp.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Disp is
    package Foo is
diff --git a/gcc/testsuite/gnat.dg/strub_disp1.adb b/gcc/testsuite/gnat.dg/strub_disp1.adb
index 09756a74b7d..9c4c7f69637 100644
--- a/gcc/testsuite/gnat.dg/strub_disp1.adb
+++ b/gcc/testsuite/gnat.dg/strub_disp1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 -- Check that at-calls dispatching calls are transformed.
 
diff --git a/gcc/testsuite/gnat.dg/strub_ind.adb b/gcc/testsuite/gnat.dg/strub_ind.adb
index da56acaa957..613db69305e 100644
--- a/gcc/testsuite/gnat.dg/strub_ind.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict" }
+--  { dg-require-effective-target strub }
 
 --  This is essentially the same test as strub_attr.adb, 
 --  but applying attributes to access types as well.
diff --git a/gcc/testsuite/gnat.dg/strub_ind1.adb b/gcc/testsuite/gnat.dg/strub_ind1.adb
index 825e395e681..245b0a830f6 100644
--- a/gcc/testsuite/gnat.dg/strub_ind1.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm" }
+--  { dg-require-effective-target strub }
 
 --  This is essentially the same test as strub_attr.adb, 
 --  but with an explicit conversion.
diff --git a/gcc/testsuite/gnat.dg/strub_ind2.adb b/gcc/testsuite/gnat.dg/strub_ind2.adb
index e918b392631..b9bfe50e929 100644
--- a/gcc/testsuite/gnat.dg/strub_ind2.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind2.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict" }
+--  { dg-require-effective-target strub }
 
 --  This is essentially the same test as strub_attr.adb, 
 --  but with an explicit conversion.
diff --git a/gcc/testsuite/gnat.dg/strub_intf.adb b/gcc/testsuite/gnat.dg/strub_intf.adb
index 8f0212a7586..f43854705d0 100644
--- a/gcc/testsuite/gnat.dg/strub_intf.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 --  Check that strub mode mismatches between overrider and overridden
 --  subprograms are reported.
diff --git a/gcc/testsuite/gnat.dg/strub_intf1.adb b/gcc/testsuite/gnat.dg/strub_intf1.adb
index bf77321cef7..7a38a4c49ba 100644
--- a/gcc/testsuite/gnat.dg/strub_intf1.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 -- Check that at-calls dispatching calls to interfaces are transformed.
 
diff --git a/gcc/testsuite/gnat.dg/strub_intf2.adb b/gcc/testsuite/gnat.dg/strub_intf2.adb
index e8880dbc437..7992b7344fb 100644
--- a/gcc/testsuite/gnat.dg/strub_intf2.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf2.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 --  Check that strub mode mismatches between overrider and overridden
 --  subprograms are reported even when the overriders for an
diff --git a/gcc/testsuite/gnat.dg/strub_renm.adb b/gcc/testsuite/gnat.dg/strub_renm.adb
index 217367e712d..abfb120b514 100644
--- a/gcc/testsuite/gnat.dg/strub_renm.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Renm is
    procedure P (X : Integer);
diff --git a/gcc/testsuite/gnat.dg/strub_renm1.adb b/gcc/testsuite/gnat.dg/strub_renm1.adb
index a11adbfb5a9..68d3230b535 100644
--- a/gcc/testsuite/gnat.dg/strub_renm1.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm1.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed -fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Renm1 is
    V : Integer := 0;
diff --git a/gcc/testsuite/gnat.dg/strub_renm2.adb b/gcc/testsuite/gnat.dg/strub_renm2.adb
index c488c20826f..3cb81ea03f7 100644
--- a/gcc/testsuite/gnat.dg/strub_renm2.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm2.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strub" }
+--  { dg-require-effective-target strub }
 
 procedure Strub_Renm2 is
    V : Integer := 0;
diff --git a/gcc/testsuite/gnat.dg/strub_var.adb b/gcc/testsuite/gnat.dg/strub_var.adb
index 3d158de2803..7c6affa06d4 100644
--- a/gcc/testsuite/gnat.dg/strub_var.adb
+++ b/gcc/testsuite/gnat.dg/strub_var.adb
@@ -1,5 +1,6 @@
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm" }
+--  { dg-require-effective-target strub }
 
 -- We don't read from the automatic variable, but being an automatic
 --  variable, its presence should be enough for the procedure to get
diff --git a/gcc/testsuite/gnat.dg/strub_var1.adb b/gcc/testsuite/gnat.dg/strub_var1.adb
index 6a504e09198..64b7e65fe9b 100644
--- a/gcc/testsuite/gnat.dg/strub_var1.adb
+++ b/gcc/testsuite/gnat.dg/strub_var1.adb
@@ -1,4 +1,5 @@
 --  { dg-do compile }
+--  { dg-require-effective-target strub }
 
 with Strub_Attr;
 procedure Strub_Var1 is
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 3fcce6be49d..daf1d259aae 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -1302,6 +1302,13 @@ proc check_stack_check_available { stack_kind } {
     } "$stack_opt"]
 }
 
+# Return 1 if the target supports stack scrubbing.
+proc check_effective_target_strub {} {
+    return [check_no_compiler_messages strub assembly {
+	int __attribute__ ((__strub__)) fn () {}
+    } ""]
+}
+
 # Return 1 if compilation with -freorder-blocks-and-partition is error-free
 # for trivial code, 0 otherwise.  As some targets (ARM for example) only
 # warn when -fprofile-use is also supplied we test that combination too.
diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in
index d8163c5af99..3f77283490e 100644
--- a/libgcc/Makefile.in
+++ b/libgcc/Makefile.in
@@ -434,7 +434,7 @@ LIB2ADD += enable-execute-stack.c
 LIB2ADD += $(srcdir)/hardcfr.c
 
 # Stack scrubbing infrastructure.
-LIB2ADD += $(srcdir)/strub.c
+@HAVE_STRUB_SUPPORT@LIB2ADD += $(srcdir)/strub.c
 
 # While emutls.c has nothing to do with EH, it is in LIB2ADDEH*
 # instead of LIB2ADD because that's the way to be sure on some targets
diff --git a/libgcc/configure b/libgcc/configure
index cf149209652..f77d39df625 100755
--- a/libgcc/configure
+++ b/libgcc/configure
@@ -593,6 +593,7 @@ asm_hidden_op
 extra_parts
 cpu_type
 get_gcc_base_ver
+HAVE_STRUB_SUPPORT
 thread_header
 tm_defines
 tm_file
@@ -5702,6 +5703,31 @@ esac
 
 
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for strub support" >&5
+$as_echo_n "checking for strub support... " >&6; }
+if ${libgcc_cv_strub_support+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int __attribute__ ((__strub__)) fn () {}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  libgcc_cv_strub_support=yes
+else
+  libgcc_cv_strub_support=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgcc_cv_strub_support" >&5
+$as_echo "$libgcc_cv_strub_support" >&6; }
+if test "x$libgcc_cv_strub_support" != xno; then
+  HAVE_STRUB_SUPPORT=
+else
+  HAVE_STRUB_SUPPORT='# '
+fi
+
+
 # Determine what GCC version number to use in filesystem paths.
 
   get_gcc_base_ver="cat"
diff --git a/libgcc/configure.ac b/libgcc/configure.ac
index 2fc9d5d7c93..a8def244998 100644
--- a/libgcc/configure.ac
+++ b/libgcc/configure.ac
@@ -694,6 +694,19 @@ AC_SUBST(tm_defines)
 # Map from thread model to thread header.
 GCC_AC_THREAD_HEADER([$target_thread_file])
 
+AC_CACHE_CHECK([for strub support],
+  [libgcc_cv_strub_support],
+  [AC_COMPILE_IFELSE(
+    [AC_LANG_SOURCE([int __attribute__ ((__strub__)) fn () {}])],
+    [libgcc_cv_strub_support=yes],
+    [libgcc_cv_strub_support=no])])
+if test "x$libgcc_cv_strub_support" != xno; then
+  HAVE_STRUB_SUPPORT=
+else
+  HAVE_STRUB_SUPPORT='# '
+fi
+AC_SUBST(HAVE_STRUB_SUPPORT)
+
 # Determine what GCC version number to use in filesystem paths.
 GCC_BASE_VER

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [gcc(refs/users/aoliva/heads/testme)] strub: enable conditional support
@ 2023-12-07  0:04 Alexandre Oliva
  0 siblings, 0 replies; 25+ messages in thread
From: Alexandre Oliva @ 2023-12-07  0:04 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:fd0be5938310462adf6e9e117c97ecc87c4a6e2e

commit fd0be5938310462adf6e9e117c97ecc87c4a6e2e
Author: Alexandre Oliva <oliva@gnu.org>
Date:   Wed Dec 6 19:36:02 2023 -0300

    strub: enable conditional support

Diff:
---
 gcc/config/nvptx/nvptx.cc                          |  3 ++
 gcc/doc/tm.texi                                    |  6 +++
 gcc/doc/tm.texi.in                                 |  2 +
 gcc/ipa-strub.cc                                   | 54 +++++++++++++++++++++-
 gcc/target.def                                     |  8 ++++
 gcc/testsuite/c-c++-common/strub-O0.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O1.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O2.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O2fni.c           |  1 +
 gcc/testsuite/c-c++-common/strub-O3.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O3fni.c           |  1 +
 gcc/testsuite/c-c++-common/strub-Og.c              |  1 +
 gcc/testsuite/c-c++-common/strub-Os.c              |  1 +
 gcc/testsuite/c-c++-common/strub-all1.c            |  1 +
 gcc/testsuite/c-c++-common/strub-all2.c            |  1 +
 gcc/testsuite/c-c++-common/strub-apply1.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply2.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply3.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply4.c          |  1 +
 gcc/testsuite/c-c++-common/strub-at-calls1.c       |  1 +
 gcc/testsuite/c-c++-common/strub-at-calls2.c       |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O3.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-Os.c        |  1 +
 gcc/testsuite/c-c++-common/strub-internal1.c       |  1 +
 gcc/testsuite/c-c++-common/strub-internal2.c       |  1 +
 gcc/testsuite/c-c++-common/strub-parms1.c          |  1 +
 gcc/testsuite/c-c++-common/strub-parms2.c          |  1 +
 gcc/testsuite/c-c++-common/strub-parms3.c          |  1 +
 gcc/testsuite/c-c++-common/strub-relaxed1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-relaxed2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O0-exc.c    |  1 +
 gcc/testsuite/c-c++-common/strub-short-O0.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O3.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-Os.c        |  1 +
 gcc/testsuite/c-c++-common/strub-strict1.c         |  1 +
 gcc/testsuite/c-c++-common/strub-strict2.c         |  1 +
 gcc/testsuite/c-c++-common/strub-tail-O1.c         |  1 +
 gcc/testsuite/c-c++-common/strub-tail-O2.c         |  1 +
 gcc/testsuite/c-c++-common/strub-var1.c            |  1 +
 .../c-c++-common/torture/strub-callable1.c         |  1 +
 .../c-c++-common/torture/strub-callable2.c         |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const1.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const2.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const3.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const4.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data1.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data2.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data3.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data4.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data5.c   |  1 +
 .../c-c++-common/torture/strub-indcall1.c          |  1 +
 .../c-c++-common/torture/strub-indcall2.c          |  1 +
 .../c-c++-common/torture/strub-indcall3.c          |  1 +
 .../c-c++-common/torture/strub-inlinable1.c        |  1 +
 .../c-c++-common/torture/strub-inlinable2.c        |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure1.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure2.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure3.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure4.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run1.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run2.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run3.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4c.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4d.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4i.c   |  1 +
 gcc/testsuite/g++.dg/strub-run1.C                  |  1 +
 gcc/testsuite/g++.dg/torture/strub-init1.C         |  1 +
 gcc/testsuite/g++.dg/torture/strub-init2.C         |  1 +
 gcc/testsuite/g++.dg/torture/strub-init3.C         |  1 +
 gcc/testsuite/gnat.dg/strub_access.adb             |  1 +
 gcc/testsuite/gnat.dg/strub_access1.adb            |  1 +
 gcc/testsuite/gnat.dg/strub_attr.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_disp.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_disp1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_ind.adb                |  1 +
 gcc/testsuite/gnat.dg/strub_ind1.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_ind2.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_intf.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_intf1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_intf2.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_renm.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_renm1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_renm2.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_var.adb                |  1 +
 gcc/testsuite/gnat.dg/strub_var1.adb               |  1 +
 gcc/testsuite/lib/target-supports.exp              |  7 +++
 libgcc/Makefile.in                                 |  2 +-
 libgcc/configure                                   | 26 +++++++++++
 libgcc/configure.ac                                | 13 ++++++
 98 files changed, 207 insertions(+), 3 deletions(-)

diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc
index ae20802c879..3fb1deb70fd 100644
--- a/gcc/config/nvptx/nvptx.cc
+++ b/gcc/config/nvptx/nvptx.cc
@@ -7789,6 +7789,9 @@ nvptx_asm_output_def_from_decls (FILE *stream, tree name, tree value)
 #undef TARGET_LIBC_HAS_FUNCTION
 #define TARGET_LIBC_HAS_FUNCTION nvptx_libc_has_function
 
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-nvptx.h"
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 89a1735dd79..768ada0af52 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -3450,6 +3450,12 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@deftypefn {Target Hook} bool TARGET_HAVE_STRUB_SUPPORT_FOR (tree)
+Returns true if the target supports stack scrubbing for the given function
+or type, otherwise return false.  The default implementation always returns
+true.
+@end deftypefn
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index ebc1d3de5ca..4fe0805394e 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2686,6 +2686,8 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@hook TARGET_HAVE_STRUB_SUPPORT_FOR
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
index 293bec132b8..f3100bb1d44 100644
--- a/gcc/ipa-strub.cc
+++ b/gcc/ipa-strub.cc
@@ -60,6 +60,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-strub.h"
 #include "symtab-thunks.h"
 #include "attr-fnspec.h"
+#include "target.h"
 
 /* This file introduces two passes that, together, implement
    machine-independent stack scrubbing, strub for short.  It arranges
@@ -631,17 +632,60 @@ strub_always_inline_p (cgraph_node *node)
   return lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl));
 }
 
+/* Return TRUE iff the target has strub support for T, a function decl
+   or a type, and optionally REPORT thereasons for ineligibility.  If
+   T is a type and error REPORTing is enabled, the LOCation (e.g. of
+   the indirect call) should be given in LOC.  */
+static inline bool
+strub_target_support_p (tree t, bool report = false,
+			location_t loc = UNKNOWN_LOCATION)
+{
+  bool result = true;
+
+  if (!targetm.have_strub_support_for (t))
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      if (DECL_P (t))
+	sorry_at (DECL_SOURCE_LOCATION (t),
+		  "%qD is not eligible for %<strub%>"
+		  " on the target system", t);
+      else
+	sorry_at (loc,
+		  "%qT is not an eligible type for %<strub%>"
+		  " on the target system", t);
+    }
+
+  return result;
+}
+
 /* Return TRUE iff NODE is potentially eligible for any strub-enabled mode, and
    optionally REPORT the reasons for ineligibility.  */
 
 static inline bool
 can_strub_p (cgraph_node *node, bool report = false)
 {
-  bool result = true;
+  bool result = strub_target_support_p (node->decl, report);
 
-  if (!report && strub_always_inline_p (node))
+  if (!report && (!result || strub_always_inline_p (node)))
     return result;
 
+  if (flag_split_stack)
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (node->decl),
+		"%qD is not eligible for %<strub%>"
+		" because %<-fsplit-stack%> is enabled",
+		node->decl);
+    }
+
   if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
     {
       result = false;
@@ -2417,6 +2461,12 @@ pass_ipa_strub::adjust_at_calls_call (cgraph_edge *e, int named_args,
 			 && (TREE_TYPE (gimple_call_arg (ocall, named_args))
 			     == get_pwmt ())));
 
+  tree tsup;
+  if (!(tsup = gimple_call_fndecl (ocall)))
+    tsup = TREE_TYPE (TREE_TYPE (gimple_call_fn (ocall)));
+  if (!strub_target_support_p (tsup, true, gimple_location (ocall)))
+    return;
+
   /* If we're already within a strub context, pass on the incoming watermark
      pointer, and omit the enter and leave calls around the modified call, as an
      optimization, or as a means to satisfy a tail-call requirement.  */
diff --git a/gcc/target.def b/gcc/target.def
index 52b83e091b9..08218f3a42a 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4457,6 +4457,14 @@ otherwise return false.  The default implementation always returns true.",
  bool, (void),
  hook_bool_void_true)
 
+DEFHOOK
+(have_strub_support_for,
+ "Returns true if the target supports stack scrubbing for the given function\n\
+or type, otherwise return false.  The default implementation always returns\n\
+true.",
+ bool, (tree),
+ hook_bool_tree_true)
+
 DEFHOOK
 (have_speculation_safe_value,
 "This hook is used to determine the level of target support for\n\
diff --git a/gcc/testsuite/c-c++-common/strub-O0.c b/gcc/testsuite/c-c++-common/strub-O0.c
index c7a79a6ea0d..f30f46df396 100644
--- a/gcc/testsuite/c-c++-common/strub-O0.c
+++ b/gcc/testsuite/c-c++-common/strub-O0.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fdump-rtl-expand" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O1.c b/gcc/testsuite/c-c++-common/strub-O1.c
index 96285c975d9..111c08a8eb2 100644
--- a/gcc/testsuite/c-c++-common/strub-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-O1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fdump-rtl-expand" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O2.c b/gcc/testsuite/c-c++-common/strub-O2.c
index 8edc0d8aa13..220fdeb03a4 100644
--- a/gcc/testsuite/c-c++-common/strub-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-O2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O2fni.c b/gcc/testsuite/c-c++-common/strub-O2fni.c
index c6d900cf3c4..8a8cc2db75c 100644
--- a/gcc/testsuite/c-c++-common/strub-O2fni.c
+++ b/gcc/testsuite/c-c++-common/strub-O2fni.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O3.c b/gcc/testsuite/c-c++-common/strub-O3.c
index 33ee465e51c..85e8aea5d97 100644
--- a/gcc/testsuite/c-c++-common/strub-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-O3.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O3fni.c b/gcc/testsuite/c-c++-common/strub-O3fni.c
index 2936f82079e..07e846b5552 100644
--- a/gcc/testsuite/c-c++-common/strub-O3fni.c
+++ b/gcc/testsuite/c-c++-common/strub-O3fni.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-Og.c b/gcc/testsuite/c-c++-common/strub-Og.c
index 479746e57d8..25f2b2f8db9 100644
--- a/gcc/testsuite/c-c++-common/strub-Og.c
+++ b/gcc/testsuite/c-c++-common/strub-Og.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-Og -fstrub=strict -fdump-rtl-expand" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-Os.c b/gcc/testsuite/c-c++-common/strub-Os.c
index 2241d4ea07f..84c7600cb06 100644
--- a/gcc/testsuite/c-c++-common/strub-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-Os.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-Os -fstrub=strict -fdump-rtl-expand" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-all1.c b/gcc/testsuite/c-c++-common/strub-all1.c
index a322bcc5da6..d83aab446a1 100644
--- a/gcc/testsuite/c-c++-common/strub-all1.c
+++ b/gcc/testsuite/c-c++-common/strub-all1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-all2.c b/gcc/testsuite/c-c++-common/strub-all2.c
index db60026d0e0..abc8d4946c8 100644
--- a/gcc/testsuite/c-c++-common/strub-all2.c
+++ b/gcc/testsuite/c-c++-common/strub-all2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-apply1.c b/gcc/testsuite/c-c++-common/strub-apply1.c
index 2f462adc1ef..0f467a8e8b2 100644
--- a/gcc/testsuite/c-c++-common/strub-apply1.c
+++ b/gcc/testsuite/c-c++-common/strub-apply1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-apply2.c b/gcc/testsuite/c-c++-common/strub-apply2.c
index a5d7551f5da..ef14d59a598 100644
--- a/gcc/testsuite/c-c++-common/strub-apply2.c
+++ b/gcc/testsuite/c-c++-common/strub-apply2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-apply3.c b/gcc/testsuite/c-c++-common/strub-apply3.c
index 64422a0d1e8..26338f8a1ab 100644
--- a/gcc/testsuite/c-c++-common/strub-apply3.c
+++ b/gcc/testsuite/c-c++-common/strub-apply3.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-apply4.c b/gcc/testsuite/c-c++-common/strub-apply4.c
index 15ffaa031b8..cdff9f060a2 100644
--- a/gcc/testsuite/c-c++-common/strub-apply4.c
+++ b/gcc/testsuite/c-c++-common/strub-apply4.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-ipa-strubm" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls1.c b/gcc/testsuite/c-c++-common/strub-at-calls1.c
index b70843b4215..74936b67e66 100644
--- a/gcc/testsuite/c-c++-common/strub-at-calls1.c
+++ b/gcc/testsuite/c-c++-common/strub-at-calls1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls2.c b/gcc/testsuite/c-c++-common/strub-at-calls2.c
index 97a3988a6b9..01c80866fba 100644
--- a/gcc/testsuite/c-c++-common/strub-at-calls2.c
+++ b/gcc/testsuite/c-c++-common/strub-at-calls2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O1.c b/gcc/testsuite/c-c++-common/strub-defer-O1.c
index 3d73431b3dc..84ea941e9ea 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O1" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O2.c b/gcc/testsuite/c-c++-common/strub-defer-O2.c
index fddf3c745e7..8dc8e47872b 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O2" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O3.c b/gcc/testsuite/c-c++-common/strub-defer-O3.c
index 7ebc65b58dd..79c9076cada 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O3.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O3" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-defer-Os.c b/gcc/testsuite/c-c++-common/strub-defer-Os.c
index fbaf85fe0fa..867a825e48d 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-Os.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -Os" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-internal1.c b/gcc/testsuite/c-c++-common/strub-internal1.c
index e9d7b7b9ee0..89a64b3b248 100644
--- a/gcc/testsuite/c-c++-common/strub-internal1.c
+++ b/gcc/testsuite/c-c++-common/strub-internal1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-internal2.c b/gcc/testsuite/c-c++-common/strub-internal2.c
index 8b8e15a51c7..4396dec3cc5 100644
--- a/gcc/testsuite/c-c++-common/strub-internal2.c
+++ b/gcc/testsuite/c-c++-common/strub-internal2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-parms1.c b/gcc/testsuite/c-c++-common/strub-parms1.c
index 0a4a7539d34..f5b648d3a70 100644
--- a/gcc/testsuite/c-c++-common/strub-parms1.c
+++ b/gcc/testsuite/c-c++-common/strub-parms1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-parms2.c b/gcc/testsuite/c-c++-common/strub-parms2.c
index 147171d96d5..25aa7e2cc22 100644
--- a/gcc/testsuite/c-c++-common/strub-parms2.c
+++ b/gcc/testsuite/c-c++-common/strub-parms2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-parms3.c b/gcc/testsuite/c-c++-common/strub-parms3.c
index 4e92682895a..c5fc2514089 100644
--- a/gcc/testsuite/c-c++-common/strub-parms3.c
+++ b/gcc/testsuite/c-c++-common/strub-parms3.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed1.c b/gcc/testsuite/c-c++-common/strub-relaxed1.c
index e2f9d8aebca..0d7321eec95 100644
--- a/gcc/testsuite/c-c++-common/strub-relaxed1.c
+++ b/gcc/testsuite/c-c++-common/strub-relaxed1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed2.c b/gcc/testsuite/c-c++-common/strub-relaxed2.c
index 98474435d2e..b81277b9b64 100644
--- a/gcc/testsuite/c-c++-common/strub-relaxed2.c
+++ b/gcc/testsuite/c-c++-common/strub-relaxed2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
index 1de15342595..9e14dc1e01c 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fexceptions -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0.c b/gcc/testsuite/c-c++-common/strub-short-O0.c
index f9209c81900..e99d233c914 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O0.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O0.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O1.c b/gcc/testsuite/c-c++-common/strub-short-O1.c
index bed1dcfb54a..ea5e4a9846d 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O2.c b/gcc/testsuite/c-c++-common/strub-short-O2.c
index 6bf0071f52b..91357cb9928 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O3.c b/gcc/testsuite/c-c++-common/strub-short-O3.c
index 4732f515bf7..d613944f802 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O3.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-Os.c b/gcc/testsuite/c-c++-common/strub-short-Os.c
index 8d6424c479a..7234c0a7584 100644
--- a/gcc/testsuite/c-c++-common/strub-short-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-short-Os.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-Os -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-strict1.c b/gcc/testsuite/c-c++-common/strub-strict1.c
index 36852244206..5211fb39ad8 100644
--- a/gcc/testsuite/c-c++-common/strub-strict1.c
+++ b/gcc/testsuite/c-c++-common/strub-strict1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-strict2.c b/gcc/testsuite/c-c++-common/strub-strict2.c
index b4f28883218..2c0c6d1496d 100644
--- a/gcc/testsuite/c-c++-common/strub-strict2.c
+++ b/gcc/testsuite/c-c++-common/strub-strict2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O1.c b/gcc/testsuite/c-c++-common/strub-tail-O1.c
index e48e0610e07..3056c7dc3bf 100644
--- a/gcc/testsuite/c-c++-common/strub-tail-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-tail-O1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O2.c b/gcc/testsuite/c-c++-common/strub-tail-O2.c
index 87cda7ab21b..1188b5330a2 100644
--- a/gcc/testsuite/c-c++-common/strub-tail-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-tail-O2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-var1.c b/gcc/testsuite/c-c++-common/strub-var1.c
index eb6250fd39c..34983ed0b5a 100644
--- a/gcc/testsuite/c-c++-common/strub-var1.c
+++ b/gcc/testsuite/c-c++-common/strub-var1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 
 int __attribute__ ((strub)) x;
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable1.c b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
index b5e45ab0525..4c2cb9740fd 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-callable1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable2.c b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
index 96aa7fe4b07..2957e680a90 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-callable2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const1.c b/gcc/testsuite/c-c++-common/torture/strub-const1.c
index 5e956cb1a9b..299bc43491d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const2.c b/gcc/testsuite/c-c++-common/torture/strub-const2.c
index 73d650292df..fd82716442a 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const3.c b/gcc/testsuite/c-c++-common/torture/strub-const3.c
index 2584f1f974a..f9ef35b64fa 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const3.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const4.c b/gcc/testsuite/c-c++-common/torture/strub-const4.c
index d819f54ec02..cf3b70e10ba 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const4.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data1.c b/gcc/testsuite/c-c++-common/torture/strub-data1.c
index 7c27a2a1a6d..f163fcd70f4 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data2.c b/gcc/testsuite/c-c++-common/torture/strub-data2.c
index e66d903780a..03ddc16d46f 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data3.c b/gcc/testsuite/c-c++-common/torture/strub-data3.c
index 5e08e0e58c6..0194de88c31 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data3.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data4.c b/gcc/testsuite/c-c++-common/torture/strub-data4.c
index a818e7a38bb..3802153965c 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data4.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data5.c b/gcc/testsuite/c-c++-common/torture/strub-data5.c
index ddb0b5c0543..bfcbbe0a202 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data5.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data5.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
index c165f312f16..dd4f3eb4f2f 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
index 69fcff8d376..f2bfb8283ec 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
index ff006224909..12c13acb4e0 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
index 614b02228ba..4344a37f046 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
index f9a6b4a16fa..fb6eb6ac712 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
index b4a7f3992bb..66041524a85 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
index ef634d35126..bec39d07cba 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -Wpedantic" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
index e1f179e160e..10dcff9dbfc 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -Wpedantic -fpermissive" } */
 /* { dg-prune-output "command-line option .-fpermissive." } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
index 70b558afad0..d7f10c432a8 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure1.c b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
index a262a086837..fdce58942cd 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure2.c b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
index 4c4bd50c209..f5e2cf0de48 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure3.c b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
index ce195c6b1f1..9ef92c9443e 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure4.c b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
index 75cd54ccb5b..6c62d15996f 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run1.c b/gcc/testsuite/c-c++-common/torture/strub-run1.c
index 7458b3fb54d..ec3b5cee434 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run2.c b/gcc/testsuite/c-c++-common/torture/strub-run2.c
index 5d60a7775f4..986ec5de959 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run2.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run3.c b/gcc/testsuite/c-c++-common/torture/strub-run3.c
index c2ad710858e..86c8e3e6180 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run3.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 /* { dg-require-effective-target alloca } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4.c b/gcc/testsuite/c-c++-common/torture/strub-run4.c
index 3b36b8e5d68..5003e26c764 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=all" } */
 /* { dg-require-effective-target alloca } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4c.c b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
index 57f9baf758d..bd0d2c907df 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4c.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=at-calls" } */
 /* { dg-require-effective-target alloca } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4d.c b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
index 08de3f1c3b1..802ef621631 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4d.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 /* { dg-require-effective-target alloca } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4i.c b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
index 459f6886c54..f5c59d6aec8 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4i.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=internal" } */
 /* { dg-require-effective-target alloca } */
diff --git a/gcc/testsuite/g++.dg/strub-run1.C b/gcc/testsuite/g++.dg/strub-run1.C
index 0d367fb83d0..4217ea1a13a 100644
--- a/gcc/testsuite/g++.dg/strub-run1.C
+++ b/gcc/testsuite/g++.dg/strub-run1.C
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 // { dg-do run }
 // { dg-options "-fstrub=internal" }
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init1.C b/gcc/testsuite/g++.dg/torture/strub-init1.C
index c226ab10ff6..0e127773783 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init1.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init1.C
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init2.C b/gcc/testsuite/g++.dg/torture/strub-init2.C
index a7911f1fa72..8ba1ecd9fe8 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init2.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init2.C
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init3.C b/gcc/testsuite/g++.dg/torture/strub-init3.C
index 6ebebcd01e8..a47869b12c4 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init3.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init3.C
@@ -1,3 +1,4 @@
+/* { dg-skip-if "strub unsupported" { ! strub } } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/gnat.dg/strub_access.adb b/gcc/testsuite/gnat.dg/strub_access.adb
index 29e6996ecf6..38bc138e654 100644
--- a/gcc/testsuite/gnat.dg/strub_access.adb
+++ b/gcc/testsuite/gnat.dg/strub_access.adb
@@ -1,3 +1,4 @@
+--  { dg-skip-if "strub unsupported" { ! strub } }
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed -fdump-ipa-strubm" }
 
diff --git a/gcc/testsuite/gnat.dg/strub_access1.adb b/gcc/testsuite/gnat.dg/strub_access1.adb
index dae47060164..2e88b3b46a9 100644
--- a/gcc/testsuite/gnat.dg/strub_access1.adb
+++ b/gcc/testsuite/gnat.dg/strub_access1.adb
@@ -1,3 +1,4 @@
+--  { dg-skip-if "strub unsupported" { ! strub } }
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed" }
 
diff --git a/gcc/testsuite/gnat.dg/strub_attr.adb b/gcc/testsuite/gnat.dg/strub_attr.adb
index 10445d7cf84..3c73a39cb02 100644
--- a/gcc/testsuite/gnat.dg/strub_attr.adb
+++ b/gcc/testsuite/gnat.dg/strub_attr.adb
@@ -1,3 +1,4 @@
+--  { dg-skip-if "strub unsupported" { ! strub } }
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm -fdump-ipa-strub" }
 
diff --git a/gcc/testsuite/gnat.dg/strub_disp.adb b/gcc/testsuite/gnat.dg/strub_disp.adb
index 3dbcc4a357c..c4b86a66302 100644
--- a/gcc/testsuite/gnat.dg/strub_disp.adb
+++ b/gcc/testsuite/gnat.dg/strub_disp.adb
@@ -1,3 +1,4 @@
+--  { dg-skip-if "strub unsupported" { ! strub } }
 --  { dg-do compile }
 
 procedure Strub_Disp is
diff --git a/gcc/testsuite/gnat.dg/strub_disp1.adb b/gcc/testsuite/gnat.dg/strub_disp1.adb
index 09756a74b7d..9fc3f9c5661 100644
--- a/gcc/testsuite/gnat.dg/strub_disp1.adb
+++ b/gcc/testsuite/gnat.dg/strub_disp1.adb
@@ -1,3 +1,4 @@
+--  { dg-skip-if "strub unsupported" { ! strub } }
 --  { dg-do compile }
 --  { dg-options "-fdump-ipa-strub" }
 
diff --git a/gcc/testsuite/gnat.dg/strub_ind.adb b/gcc/testsuite/gnat.dg/strub_ind.adb
index da56acaa957..d72c44a945a 100644
--- a/gcc/testsuite/gnat.dg/strub_ind.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind.adb
@@ -1,3 +1,4 @@
+--  { dg-skip-if "strub unsupported" { ! strub } }
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict" }
 
diff --git a/gcc/testsuite/gnat.dg/strub_ind1.adb b/gcc/testsuite/gnat.dg/strub_ind1.adb
index 825e395e681..09540d79942 100644
--- a/gcc/testsuite/gnat.dg/strub_ind1.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind1.adb
@@ -1,3 +1,4 @@
+--  { dg-skip-if "strub unsupported" { ! strub } }
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm" }
 
diff --git a/gcc/testsuite/gnat.dg/strub_ind2.adb b/gcc/testsuite/gnat.dg/strub_ind2.adb
index e918b392631..e1952b69652 100644
--- a/gcc/testsuite/gnat.dg/strub_ind2.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind2.adb
@@ -1,3 +1,4 @@
+--  { dg-skip-if "strub unsupported" { ! strub } }
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict" }
 
diff --git a/gcc/testsuite/gnat.dg/strub_intf.adb b/gcc/testsuite/gnat.dg/strub_intf.adb
index 8f0212a7586..6b1bc11bcf7 100644
--- a/gcc/testsuite/gnat.dg/strub_intf.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf.adb
@@ -1,3 +1,4 @@
+--  { dg-skip-if "strub unsupported" { ! strub } }
 --  { dg-do compile }
 
 --  Check that strub mode mismatches between overrider and overridden
diff --git a/gcc/testsuite/gnat.dg/strub_intf1.adb b/gcc/testsuite/gnat.dg/strub_intf1.adb
index bf77321cef7..014f7960421 100644
--- a/gcc/testsuite/gnat.dg/strub_intf1.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf1.adb
@@ -1,3 +1,4 @@
+--  { dg-skip-if "strub unsupported" { ! strub } }
 --  { dg-do compile }
 --  { dg-options "-fdump-ipa-strub" }
 
diff --git a/gcc/testsuite/gnat.dg/strub_intf2.adb b/gcc/testsuite/gnat.dg/strub_intf2.adb
index e8880dbc437..d90fd715073 100644
--- a/gcc/testsuite/gnat.dg/strub_intf2.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf2.adb
@@ -1,3 +1,4 @@
+--  { dg-skip-if "strub unsupported" { ! strub } }
 --  { dg-do compile }
 
 --  Check that strub mode mismatches between overrider and overridden
diff --git a/gcc/testsuite/gnat.dg/strub_renm.adb b/gcc/testsuite/gnat.dg/strub_renm.adb
index 217367e712d..7f9295c5652 100644
--- a/gcc/testsuite/gnat.dg/strub_renm.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm.adb
@@ -1,3 +1,4 @@
+--  { dg-skip-if "strub unsupported" { ! strub } }
 --  { dg-do compile }
 
 procedure Strub_Renm is
diff --git a/gcc/testsuite/gnat.dg/strub_renm1.adb b/gcc/testsuite/gnat.dg/strub_renm1.adb
index a11adbfb5a9..f6e7dc76185 100644
--- a/gcc/testsuite/gnat.dg/strub_renm1.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm1.adb
@@ -1,3 +1,4 @@
+--  { dg-skip-if "strub unsupported" { ! strub } }
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed -fdump-ipa-strub" }
 
diff --git a/gcc/testsuite/gnat.dg/strub_renm2.adb b/gcc/testsuite/gnat.dg/strub_renm2.adb
index c488c20826f..c74c1644615 100644
--- a/gcc/testsuite/gnat.dg/strub_renm2.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm2.adb
@@ -1,3 +1,4 @@
+--  { dg-skip-if "strub unsupported" { ! strub } }
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strub" }
 
diff --git a/gcc/testsuite/gnat.dg/strub_var.adb b/gcc/testsuite/gnat.dg/strub_var.adb
index 3d158de2803..d4255064eb9 100644
--- a/gcc/testsuite/gnat.dg/strub_var.adb
+++ b/gcc/testsuite/gnat.dg/strub_var.adb
@@ -1,3 +1,4 @@
+--  { dg-skip-if "strub unsupported" { ! strub } }
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm" }
 
diff --git a/gcc/testsuite/gnat.dg/strub_var1.adb b/gcc/testsuite/gnat.dg/strub_var1.adb
index 6a504e09198..fd5b6ed802b 100644
--- a/gcc/testsuite/gnat.dg/strub_var1.adb
+++ b/gcc/testsuite/gnat.dg/strub_var1.adb
@@ -1,3 +1,4 @@
+--  { dg-skip-if "strub unsupported" { ! strub } }
 --  { dg-do compile }
 
 with Strub_Attr;
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 3fcce6be49d..daf1d259aae 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -1302,6 +1302,13 @@ proc check_stack_check_available { stack_kind } {
     } "$stack_opt"]
 }
 
+# Return 1 if the target supports stack scrubbing.
+proc check_effective_target_strub {} {
+    return [check_no_compiler_messages strub assembly {
+	int __attribute__ ((__strub__)) fn () {}
+    } ""]
+}
+
 # Return 1 if compilation with -freorder-blocks-and-partition is error-free
 # for trivial code, 0 otherwise.  As some targets (ARM for example) only
 # warn when -fprofile-use is also supplied we test that combination too.
diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in
index d8163c5af99..3f77283490e 100644
--- a/libgcc/Makefile.in
+++ b/libgcc/Makefile.in
@@ -434,7 +434,7 @@ LIB2ADD += enable-execute-stack.c
 LIB2ADD += $(srcdir)/hardcfr.c
 
 # Stack scrubbing infrastructure.
-LIB2ADD += $(srcdir)/strub.c
+@HAVE_STRUB_SUPPORT@LIB2ADD += $(srcdir)/strub.c
 
 # While emutls.c has nothing to do with EH, it is in LIB2ADDEH*
 # instead of LIB2ADD because that's the way to be sure on some targets
diff --git a/libgcc/configure b/libgcc/configure
index cf149209652..f77d39df625 100755
--- a/libgcc/configure
+++ b/libgcc/configure
@@ -593,6 +593,7 @@ asm_hidden_op
 extra_parts
 cpu_type
 get_gcc_base_ver
+HAVE_STRUB_SUPPORT
 thread_header
 tm_defines
 tm_file
@@ -5702,6 +5703,31 @@ esac
 
 
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for strub support" >&5
+$as_echo_n "checking for strub support... " >&6; }
+if ${libgcc_cv_strub_support+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int __attribute__ ((__strub__)) fn () {}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  libgcc_cv_strub_support=yes
+else
+  libgcc_cv_strub_support=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgcc_cv_strub_support" >&5
+$as_echo "$libgcc_cv_strub_support" >&6; }
+if test "x$libgcc_cv_strub_support" != xno; then
+  HAVE_STRUB_SUPPORT=
+else
+  HAVE_STRUB_SUPPORT='# '
+fi
+
+
 # Determine what GCC version number to use in filesystem paths.
 
   get_gcc_base_ver="cat"
diff --git a/libgcc/configure.ac b/libgcc/configure.ac
index 2fc9d5d7c93..a8def244998 100644
--- a/libgcc/configure.ac
+++ b/libgcc/configure.ac
@@ -694,6 +694,19 @@ AC_SUBST(tm_defines)
 # Map from thread model to thread header.
 GCC_AC_THREAD_HEADER([$target_thread_file])
 
+AC_CACHE_CHECK([for strub support],
+  [libgcc_cv_strub_support],
+  [AC_COMPILE_IFELSE(
+    [AC_LANG_SOURCE([int __attribute__ ((__strub__)) fn () {}])],
+    [libgcc_cv_strub_support=yes],
+    [libgcc_cv_strub_support=no])])
+if test "x$libgcc_cv_strub_support" != xno; then
+  HAVE_STRUB_SUPPORT=
+else
+  HAVE_STRUB_SUPPORT='# '
+fi
+AC_SUBST(HAVE_STRUB_SUPPORT)
+
 # Determine what GCC version number to use in filesystem paths.
 GCC_BASE_VER

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [gcc(refs/users/aoliva/heads/testme)] strub: enable conditional support
@ 2023-12-06 23:58 Alexandre Oliva
  0 siblings, 0 replies; 25+ messages in thread
From: Alexandre Oliva @ 2023-12-06 23:58 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:ec132a765ab9cc51209e92233684990913da8d18

commit ec132a765ab9cc51209e92233684990913da8d18
Author: Alexandre Oliva <oliva@gnu.org>
Date:   Wed Dec 6 19:36:02 2023 -0300

    strub: enable conditional support

Diff:
---
 gcc/config/nvptx/nvptx.cc                          |  3 ++
 gcc/doc/tm.texi                                    |  6 +++
 gcc/doc/tm.texi.in                                 |  2 +
 gcc/ipa-strub.cc                                   | 54 +++++++++++++++++++++-
 gcc/target.def                                     |  8 ++++
 gcc/testsuite/c-c++-common/strub-O0.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O1.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O2.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O2fni.c           |  1 +
 gcc/testsuite/c-c++-common/strub-O3.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O3fni.c           |  1 +
 gcc/testsuite/c-c++-common/strub-Og.c              |  1 +
 gcc/testsuite/c-c++-common/strub-Os.c              |  1 +
 gcc/testsuite/c-c++-common/strub-all1.c            |  1 +
 gcc/testsuite/c-c++-common/strub-all2.c            |  1 +
 gcc/testsuite/c-c++-common/strub-apply1.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply2.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply3.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply4.c          |  1 +
 gcc/testsuite/c-c++-common/strub-at-calls1.c       |  1 +
 gcc/testsuite/c-c++-common/strub-at-calls2.c       |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O3.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-Os.c        |  1 +
 gcc/testsuite/c-c++-common/strub-internal1.c       |  1 +
 gcc/testsuite/c-c++-common/strub-internal2.c       |  1 +
 gcc/testsuite/c-c++-common/strub-parms1.c          |  1 +
 gcc/testsuite/c-c++-common/strub-parms2.c          |  1 +
 gcc/testsuite/c-c++-common/strub-parms3.c          |  1 +
 gcc/testsuite/c-c++-common/strub-relaxed1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-relaxed2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O0-exc.c    |  1 +
 gcc/testsuite/c-c++-common/strub-short-O0.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O3.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-Os.c        |  1 +
 gcc/testsuite/c-c++-common/strub-strict1.c         |  1 +
 gcc/testsuite/c-c++-common/strub-strict2.c         |  1 +
 gcc/testsuite/c-c++-common/strub-tail-O1.c         |  1 +
 gcc/testsuite/c-c++-common/strub-tail-O2.c         |  1 +
 gcc/testsuite/c-c++-common/strub-var1.c            |  1 +
 .../c-c++-common/torture/strub-callable1.c         |  1 +
 .../c-c++-common/torture/strub-callable2.c         |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const1.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const2.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const3.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const4.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data1.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data2.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data3.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data4.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data5.c   |  1 +
 .../c-c++-common/torture/strub-indcall1.c          |  1 +
 .../c-c++-common/torture/strub-indcall2.c          |  1 +
 .../c-c++-common/torture/strub-indcall3.c          |  1 +
 .../c-c++-common/torture/strub-inlinable1.c        |  1 +
 .../c-c++-common/torture/strub-inlinable2.c        |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure1.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure2.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure3.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure4.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run1.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run2.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run3.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4c.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4d.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4i.c   |  1 +
 gcc/testsuite/g++.dg/strub-run1.C                  |  1 +
 gcc/testsuite/g++.dg/torture/strub-init1.C         |  1 +
 gcc/testsuite/g++.dg/torture/strub-init2.C         |  1 +
 gcc/testsuite/g++.dg/torture/strub-init3.C         |  1 +
 gcc/testsuite/gnat.dg/strub_access.adb             |  1 +
 gcc/testsuite/gnat.dg/strub_access1.adb            |  1 +
 gcc/testsuite/gnat.dg/strub_attr.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_disp.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_disp1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_ind.adb                |  1 +
 gcc/testsuite/gnat.dg/strub_ind1.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_ind2.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_intf.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_intf1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_intf2.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_renm.adb               |  1 +
 gcc/testsuite/gnat.dg/strub_renm1.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_renm2.adb              |  1 +
 gcc/testsuite/gnat.dg/strub_var.adb                |  1 +
 gcc/testsuite/gnat.dg/strub_var1.adb               |  1 +
 gcc/testsuite/lib/target-supports.exp              |  7 +++
 libgcc/Makefile.in                                 |  2 +-
 libgcc/configure                                   | 26 +++++++++++
 libgcc/configure.ac                                | 13 ++++++
 98 files changed, 207 insertions(+), 3 deletions(-)

diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc
index ae20802c879..3fb1deb70fd 100644
--- a/gcc/config/nvptx/nvptx.cc
+++ b/gcc/config/nvptx/nvptx.cc
@@ -7789,6 +7789,9 @@ nvptx_asm_output_def_from_decls (FILE *stream, tree name, tree value)
 #undef TARGET_LIBC_HAS_FUNCTION
 #define TARGET_LIBC_HAS_FUNCTION nvptx_libc_has_function
 
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-nvptx.h"
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 89a1735dd79..768ada0af52 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -3450,6 +3450,12 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@deftypefn {Target Hook} bool TARGET_HAVE_STRUB_SUPPORT_FOR (tree)
+Returns true if the target supports stack scrubbing for the given function
+or type, otherwise return false.  The default implementation always returns
+true.
+@end deftypefn
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index ebc1d3de5ca..4fe0805394e 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2686,6 +2686,8 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@hook TARGET_HAVE_STRUB_SUPPORT_FOR
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
index 293bec132b8..f3100bb1d44 100644
--- a/gcc/ipa-strub.cc
+++ b/gcc/ipa-strub.cc
@@ -60,6 +60,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-strub.h"
 #include "symtab-thunks.h"
 #include "attr-fnspec.h"
+#include "target.h"
 
 /* This file introduces two passes that, together, implement
    machine-independent stack scrubbing, strub for short.  It arranges
@@ -631,17 +632,60 @@ strub_always_inline_p (cgraph_node *node)
   return lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl));
 }
 
+/* Return TRUE iff the target has strub support for T, a function decl
+   or a type, and optionally REPORT thereasons for ineligibility.  If
+   T is a type and error REPORTing is enabled, the LOCation (e.g. of
+   the indirect call) should be given in LOC.  */
+static inline bool
+strub_target_support_p (tree t, bool report = false,
+			location_t loc = UNKNOWN_LOCATION)
+{
+  bool result = true;
+
+  if (!targetm.have_strub_support_for (t))
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      if (DECL_P (t))
+	sorry_at (DECL_SOURCE_LOCATION (t),
+		  "%qD is not eligible for %<strub%>"
+		  " on the target system", t);
+      else
+	sorry_at (loc,
+		  "%qT is not an eligible type for %<strub%>"
+		  " on the target system", t);
+    }
+
+  return result;
+}
+
 /* Return TRUE iff NODE is potentially eligible for any strub-enabled mode, and
    optionally REPORT the reasons for ineligibility.  */
 
 static inline bool
 can_strub_p (cgraph_node *node, bool report = false)
 {
-  bool result = true;
+  bool result = strub_target_support_p (node->decl, report);
 
-  if (!report && strub_always_inline_p (node))
+  if (!report && (!result || strub_always_inline_p (node)))
     return result;
 
+  if (flag_split_stack)
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (node->decl),
+		"%qD is not eligible for %<strub%>"
+		" because %<-fsplit-stack%> is enabled",
+		node->decl);
+    }
+
   if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
     {
       result = false;
@@ -2417,6 +2461,12 @@ pass_ipa_strub::adjust_at_calls_call (cgraph_edge *e, int named_args,
 			 && (TREE_TYPE (gimple_call_arg (ocall, named_args))
 			     == get_pwmt ())));
 
+  tree tsup;
+  if (!(tsup = gimple_call_fndecl (ocall)))
+    tsup = TREE_TYPE (TREE_TYPE (gimple_call_fn (ocall)));
+  if (!strub_target_support_p (tsup, true, gimple_location (ocall)))
+    return;
+
   /* If we're already within a strub context, pass on the incoming watermark
      pointer, and omit the enter and leave calls around the modified call, as an
      optimization, or as a means to satisfy a tail-call requirement.  */
diff --git a/gcc/target.def b/gcc/target.def
index 52b83e091b9..08218f3a42a 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4457,6 +4457,14 @@ otherwise return false.  The default implementation always returns true.",
  bool, (void),
  hook_bool_void_true)
 
+DEFHOOK
+(have_strub_support_for,
+ "Returns true if the target supports stack scrubbing for the given function\n\
+or type, otherwise return false.  The default implementation always returns\n\
+true.",
+ bool, (tree),
+ hook_bool_tree_true)
+
 DEFHOOK
 (have_speculation_safe_value,
 "This hook is used to determine the level of target support for\n\
diff --git a/gcc/testsuite/c-c++-common/strub-O0.c b/gcc/testsuite/c-c++-common/strub-O0.c
index c7a79a6ea0d..a4af42aaf98 100644
--- a/gcc/testsuite/c-c++-common/strub-O0.c
+++ b/gcc/testsuite/c-c++-common/strub-O0.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fdump-rtl-expand" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O1.c b/gcc/testsuite/c-c++-common/strub-O1.c
index 96285c975d9..e5443c2a420 100644
--- a/gcc/testsuite/c-c++-common/strub-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-O1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fdump-rtl-expand" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O2.c b/gcc/testsuite/c-c++-common/strub-O2.c
index 8edc0d8aa13..3ab3b8cad28 100644
--- a/gcc/testsuite/c-c++-common/strub-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-O2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O2fni.c b/gcc/testsuite/c-c++-common/strub-O2fni.c
index c6d900cf3c4..a00d37b44bc 100644
--- a/gcc/testsuite/c-c++-common/strub-O2fni.c
+++ b/gcc/testsuite/c-c++-common/strub-O2fni.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O3.c b/gcc/testsuite/c-c++-common/strub-O3.c
index 33ee465e51c..3ae3d36c732 100644
--- a/gcc/testsuite/c-c++-common/strub-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-O3.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O3fni.c b/gcc/testsuite/c-c++-common/strub-O3fni.c
index 2936f82079e..35353d9eea6 100644
--- a/gcc/testsuite/c-c++-common/strub-O3fni.c
+++ b/gcc/testsuite/c-c++-common/strub-O3fni.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-Og.c b/gcc/testsuite/c-c++-common/strub-Og.c
index 479746e57d8..6cf7ff09596 100644
--- a/gcc/testsuite/c-c++-common/strub-Og.c
+++ b/gcc/testsuite/c-c++-common/strub-Og.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-Og -fstrub=strict -fdump-rtl-expand" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-Os.c b/gcc/testsuite/c-c++-common/strub-Os.c
index 2241d4ea07f..e209a2c7914 100644
--- a/gcc/testsuite/c-c++-common/strub-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-Os.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-Os -fstrub=strict -fdump-rtl-expand" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-all1.c b/gcc/testsuite/c-c++-common/strub-all1.c
index a322bcc5da6..8341f80af16 100644
--- a/gcc/testsuite/c-c++-common/strub-all1.c
+++ b/gcc/testsuite/c-c++-common/strub-all1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-all2.c b/gcc/testsuite/c-c++-common/strub-all2.c
index db60026d0e0..0a1b59b1671 100644
--- a/gcc/testsuite/c-c++-common/strub-all2.c
+++ b/gcc/testsuite/c-c++-common/strub-all2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-apply1.c b/gcc/testsuite/c-c++-common/strub-apply1.c
index 2f462adc1ef..725a082955b 100644
--- a/gcc/testsuite/c-c++-common/strub-apply1.c
+++ b/gcc/testsuite/c-c++-common/strub-apply1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-apply2.c b/gcc/testsuite/c-c++-common/strub-apply2.c
index a5d7551f5da..67ed41bd63b 100644
--- a/gcc/testsuite/c-c++-common/strub-apply2.c
+++ b/gcc/testsuite/c-c++-common/strub-apply2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-apply3.c b/gcc/testsuite/c-c++-common/strub-apply3.c
index 64422a0d1e8..44893940435 100644
--- a/gcc/testsuite/c-c++-common/strub-apply3.c
+++ b/gcc/testsuite/c-c++-common/strub-apply3.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-apply4.c b/gcc/testsuite/c-c++-common/strub-apply4.c
index 15ffaa031b8..a0ddc4f0382 100644
--- a/gcc/testsuite/c-c++-common/strub-apply4.c
+++ b/gcc/testsuite/c-c++-common/strub-apply4.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-ipa-strubm" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls1.c b/gcc/testsuite/c-c++-common/strub-at-calls1.c
index b70843b4215..1ea6fa261eb 100644
--- a/gcc/testsuite/c-c++-common/strub-at-calls1.c
+++ b/gcc/testsuite/c-c++-common/strub-at-calls1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls2.c b/gcc/testsuite/c-c++-common/strub-at-calls2.c
index 97a3988a6b9..a14d6b8394f 100644
--- a/gcc/testsuite/c-c++-common/strub-at-calls2.c
+++ b/gcc/testsuite/c-c++-common/strub-at-calls2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O1.c b/gcc/testsuite/c-c++-common/strub-defer-O1.c
index 3d73431b3dc..9e51bd04104 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O1" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O2.c b/gcc/testsuite/c-c++-common/strub-defer-O2.c
index fddf3c745e7..40112180cfd 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O2" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O3.c b/gcc/testsuite/c-c++-common/strub-defer-O3.c
index 7ebc65b58dd..4f901c19fa9 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O3.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O3" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-defer-Os.c b/gcc/testsuite/c-c++-common/strub-defer-Os.c
index fbaf85fe0fa..d69a5fa8246 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-Os.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -Os" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-internal1.c b/gcc/testsuite/c-c++-common/strub-internal1.c
index e9d7b7b9ee0..e7a0af164ad 100644
--- a/gcc/testsuite/c-c++-common/strub-internal1.c
+++ b/gcc/testsuite/c-c++-common/strub-internal1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-internal2.c b/gcc/testsuite/c-c++-common/strub-internal2.c
index 8b8e15a51c7..09ff0daabd2 100644
--- a/gcc/testsuite/c-c++-common/strub-internal2.c
+++ b/gcc/testsuite/c-c++-common/strub-internal2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-parms1.c b/gcc/testsuite/c-c++-common/strub-parms1.c
index 0a4a7539d34..2cd60d5e660 100644
--- a/gcc/testsuite/c-c++-common/strub-parms1.c
+++ b/gcc/testsuite/c-c++-common/strub-parms1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-parms2.c b/gcc/testsuite/c-c++-common/strub-parms2.c
index 147171d96d5..96205e4c386 100644
--- a/gcc/testsuite/c-c++-common/strub-parms2.c
+++ b/gcc/testsuite/c-c++-common/strub-parms2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-parms3.c b/gcc/testsuite/c-c++-common/strub-parms3.c
index 4e92682895a..6f36272574b 100644
--- a/gcc/testsuite/c-c++-common/strub-parms3.c
+++ b/gcc/testsuite/c-c++-common/strub-parms3.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed1.c b/gcc/testsuite/c-c++-common/strub-relaxed1.c
index e2f9d8aebca..9131423cb35 100644
--- a/gcc/testsuite/c-c++-common/strub-relaxed1.c
+++ b/gcc/testsuite/c-c++-common/strub-relaxed1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed2.c b/gcc/testsuite/c-c++-common/strub-relaxed2.c
index 98474435d2e..17c1b162f2a 100644
--- a/gcc/testsuite/c-c++-common/strub-relaxed2.c
+++ b/gcc/testsuite/c-c++-common/strub-relaxed2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
index 1de15342595..9a1085661f7 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fexceptions -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0.c b/gcc/testsuite/c-c++-common/strub-short-O0.c
index f9209c81900..8f941554e80 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O0.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O0.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O1.c b/gcc/testsuite/c-c++-common/strub-short-O1.c
index bed1dcfb54a..bd92eb02a25 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O2.c b/gcc/testsuite/c-c++-common/strub-short-O2.c
index 6bf0071f52b..8d45b22d946 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O3.c b/gcc/testsuite/c-c++-common/strub-short-O3.c
index 4732f515bf7..8f3cd12e08d 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O3.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-Os.c b/gcc/testsuite/c-c++-common/strub-short-Os.c
index 8d6424c479a..992209ef457 100644
--- a/gcc/testsuite/c-c++-common/strub-short-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-short-Os.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-Os -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-strict1.c b/gcc/testsuite/c-c++-common/strub-strict1.c
index 36852244206..1448aa47cdb 100644
--- a/gcc/testsuite/c-c++-common/strub-strict1.c
+++ b/gcc/testsuite/c-c++-common/strub-strict1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-strict2.c b/gcc/testsuite/c-c++-common/strub-strict2.c
index b4f28883218..2391a8f5c3e 100644
--- a/gcc/testsuite/c-c++-common/strub-strict2.c
+++ b/gcc/testsuite/c-c++-common/strub-strict2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O1.c b/gcc/testsuite/c-c++-common/strub-tail-O1.c
index e48e0610e07..43efb167794 100644
--- a/gcc/testsuite/c-c++-common/strub-tail-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-tail-O1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O2.c b/gcc/testsuite/c-c++-common/strub-tail-O2.c
index 87cda7ab21b..e5c3d8858e1 100644
--- a/gcc/testsuite/c-c++-common/strub-tail-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-tail-O2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-var1.c b/gcc/testsuite/c-c++-common/strub-var1.c
index eb6250fd39c..68906296022 100644
--- a/gcc/testsuite/c-c++-common/strub-var1.c
+++ b/gcc/testsuite/c-c++-common/strub-var1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 
 int __attribute__ ((strub)) x;
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable1.c b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
index b5e45ab0525..43d165e44c5 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-callable1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable2.c b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
index 96aa7fe4b07..c5e5ec321ce 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-callable2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const1.c b/gcc/testsuite/c-c++-common/torture/strub-const1.c
index 5e956cb1a9b..690915b3782 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const2.c b/gcc/testsuite/c-c++-common/torture/strub-const2.c
index 73d650292df..5719bfed135 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const3.c b/gcc/testsuite/c-c++-common/torture/strub-const3.c
index 2584f1f974a..2f4e32b47f7 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const3.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const4.c b/gcc/testsuite/c-c++-common/torture/strub-const4.c
index d819f54ec02..9f69c790318 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const4.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data1.c b/gcc/testsuite/c-c++-common/torture/strub-data1.c
index 7c27a2a1a6d..3f87659d64d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data2.c b/gcc/testsuite/c-c++-common/torture/strub-data2.c
index e66d903780a..6366eae7345 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data3.c b/gcc/testsuite/c-c++-common/torture/strub-data3.c
index 5e08e0e58c6..42f42c2b2d7 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data3.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data4.c b/gcc/testsuite/c-c++-common/torture/strub-data4.c
index a818e7a38bb..a7395c40664 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data4.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data5.c b/gcc/testsuite/c-c++-common/torture/strub-data5.c
index ddb0b5c0543..67e65b99a0d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data5.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data5.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
index c165f312f16..8bad34d7176 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
index 69fcff8d376..96837834e84 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
index ff006224909..1871566fe15 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
index 614b02228ba..c96218656d5 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
index f9a6b4a16fa..3a1a77c1b5e 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
index b4a7f3992bb..699af8deb8e 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
index ef634d35126..7cc9612ce8a 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -Wpedantic" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
index e1f179e160e..fb070384355 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -Wpedantic -fpermissive" } */
 /* { dg-prune-output "command-line option .-fpermissive." } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
index 70b558afad0..6ff5baad179 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure1.c b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
index a262a086837..186c35e1aaa 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure2.c b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
index 4c4bd50c209..0e381df42fb 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure3.c b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
index ce195c6b1f1..f9f0f8f3beb 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure4.c b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
index 75cd54ccb5b..3eb6286ca52 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run1.c b/gcc/testsuite/c-c++-common/torture/strub-run1.c
index 7458b3fb54d..d5e0e2ece8d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run2.c b/gcc/testsuite/c-c++-common/torture/strub-run2.c
index 5d60a7775f4..268371d7bf1 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run3.c b/gcc/testsuite/c-c++-common/torture/strub-run3.c
index c2ad710858e..8a6b7b5fc97 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run3.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 /* { dg-require-effective-target alloca } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4.c b/gcc/testsuite/c-c++-common/torture/strub-run4.c
index 3b36b8e5d68..f424f8357fa 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=all" } */
 /* { dg-require-effective-target alloca } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4c.c b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
index 57f9baf758d..a780d858c22 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4c.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=at-calls" } */
 /* { dg-require-effective-target alloca } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4d.c b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
index 08de3f1c3b1..82a65ce1a48 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4d.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 /* { dg-require-effective-target alloca } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4i.c b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
index 459f6886c54..0ed243086f6 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4i.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=internal" } */
 /* { dg-require-effective-target alloca } */
diff --git a/gcc/testsuite/g++.dg/strub-run1.C b/gcc/testsuite/g++.dg/strub-run1.C
index 0d367fb83d0..0d8e9bc23e9 100644
--- a/gcc/testsuite/g++.dg/strub-run1.C
+++ b/gcc/testsuite/g++.dg/strub-run1.C
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 // { dg-do run }
 // { dg-options "-fstrub=internal" }
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init1.C b/gcc/testsuite/g++.dg/torture/strub-init1.C
index c226ab10ff6..5d347ad353d 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init1.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init1.C
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init2.C b/gcc/testsuite/g++.dg/torture/strub-init2.C
index a7911f1fa72..17bffe7b142 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init2.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init2.C
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init3.C b/gcc/testsuite/g++.dg/torture/strub-init3.C
index 6ebebcd01e8..4f9a57f2345 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init3.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init3.C
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/gnat.dg/strub_access.adb b/gcc/testsuite/gnat.dg/strub_access.adb
index 29e6996ecf6..a5cf761f651 100644
--- a/gcc/testsuite/gnat.dg/strub_access.adb
+++ b/gcc/testsuite/gnat.dg/strub_access.adb
@@ -1,3 +1,4 @@
+--  { dg-require-effective-target strub }
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed -fdump-ipa-strubm" }
 
diff --git a/gcc/testsuite/gnat.dg/strub_access1.adb b/gcc/testsuite/gnat.dg/strub_access1.adb
index dae47060164..323ab69aa55 100644
--- a/gcc/testsuite/gnat.dg/strub_access1.adb
+++ b/gcc/testsuite/gnat.dg/strub_access1.adb
@@ -1,3 +1,4 @@
+--  { dg-require-effective-target strub }
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed" }
 
diff --git a/gcc/testsuite/gnat.dg/strub_attr.adb b/gcc/testsuite/gnat.dg/strub_attr.adb
index 10445d7cf84..69b629f3e38 100644
--- a/gcc/testsuite/gnat.dg/strub_attr.adb
+++ b/gcc/testsuite/gnat.dg/strub_attr.adb
@@ -1,3 +1,4 @@
+--  { dg-require-effective-target strub }
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm -fdump-ipa-strub" }
 
diff --git a/gcc/testsuite/gnat.dg/strub_disp.adb b/gcc/testsuite/gnat.dg/strub_disp.adb
index 3dbcc4a357c..67625dfef77 100644
--- a/gcc/testsuite/gnat.dg/strub_disp.adb
+++ b/gcc/testsuite/gnat.dg/strub_disp.adb
@@ -1,3 +1,4 @@
+--  { dg-require-effective-target strub }
 --  { dg-do compile }
 
 procedure Strub_Disp is
diff --git a/gcc/testsuite/gnat.dg/strub_disp1.adb b/gcc/testsuite/gnat.dg/strub_disp1.adb
index 09756a74b7d..7de82216730 100644
--- a/gcc/testsuite/gnat.dg/strub_disp1.adb
+++ b/gcc/testsuite/gnat.dg/strub_disp1.adb
@@ -1,3 +1,4 @@
+--  { dg-require-effective-target strub }
 --  { dg-do compile }
 --  { dg-options "-fdump-ipa-strub" }
 
diff --git a/gcc/testsuite/gnat.dg/strub_ind.adb b/gcc/testsuite/gnat.dg/strub_ind.adb
index da56acaa957..b2d86b0cbce 100644
--- a/gcc/testsuite/gnat.dg/strub_ind.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind.adb
@@ -1,3 +1,4 @@
+--  { dg-require-effective-target strub }
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict" }
 
diff --git a/gcc/testsuite/gnat.dg/strub_ind1.adb b/gcc/testsuite/gnat.dg/strub_ind1.adb
index 825e395e681..4471e6efb9f 100644
--- a/gcc/testsuite/gnat.dg/strub_ind1.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind1.adb
@@ -1,3 +1,4 @@
+--  { dg-require-effective-target strub }
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm" }
 
diff --git a/gcc/testsuite/gnat.dg/strub_ind2.adb b/gcc/testsuite/gnat.dg/strub_ind2.adb
index e918b392631..d0e3add3ca1 100644
--- a/gcc/testsuite/gnat.dg/strub_ind2.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind2.adb
@@ -1,3 +1,4 @@
+--  { dg-require-effective-target strub }
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict" }
 
diff --git a/gcc/testsuite/gnat.dg/strub_intf.adb b/gcc/testsuite/gnat.dg/strub_intf.adb
index 8f0212a7586..7b553cda63b 100644
--- a/gcc/testsuite/gnat.dg/strub_intf.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf.adb
@@ -1,3 +1,4 @@
+--  { dg-require-effective-target strub }
 --  { dg-do compile }
 
 --  Check that strub mode mismatches between overrider and overridden
diff --git a/gcc/testsuite/gnat.dg/strub_intf1.adb b/gcc/testsuite/gnat.dg/strub_intf1.adb
index bf77321cef7..3b8092bdc35 100644
--- a/gcc/testsuite/gnat.dg/strub_intf1.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf1.adb
@@ -1,3 +1,4 @@
+--  { dg-require-effective-target strub }
 --  { dg-do compile }
 --  { dg-options "-fdump-ipa-strub" }
 
diff --git a/gcc/testsuite/gnat.dg/strub_intf2.adb b/gcc/testsuite/gnat.dg/strub_intf2.adb
index e8880dbc437..feafea3e0a7 100644
--- a/gcc/testsuite/gnat.dg/strub_intf2.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf2.adb
@@ -1,3 +1,4 @@
+--  { dg-require-effective-target strub }
 --  { dg-do compile }
 
 --  Check that strub mode mismatches between overrider and overridden
diff --git a/gcc/testsuite/gnat.dg/strub_renm.adb b/gcc/testsuite/gnat.dg/strub_renm.adb
index 217367e712d..6c7ec56ece8 100644
--- a/gcc/testsuite/gnat.dg/strub_renm.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm.adb
@@ -1,3 +1,4 @@
+--  { dg-require-effective-target strub }
 --  { dg-do compile }
 
 procedure Strub_Renm is
diff --git a/gcc/testsuite/gnat.dg/strub_renm1.adb b/gcc/testsuite/gnat.dg/strub_renm1.adb
index a11adbfb5a9..b22db5d5b96 100644
--- a/gcc/testsuite/gnat.dg/strub_renm1.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm1.adb
@@ -1,3 +1,4 @@
+--  { dg-require-effective-target strub }
 --  { dg-do compile }
 --  { dg-options "-fstrub=relaxed -fdump-ipa-strub" }
 
diff --git a/gcc/testsuite/gnat.dg/strub_renm2.adb b/gcc/testsuite/gnat.dg/strub_renm2.adb
index c488c20826f..a8da13ae167 100644
--- a/gcc/testsuite/gnat.dg/strub_renm2.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm2.adb
@@ -1,3 +1,4 @@
+--  { dg-require-effective-target strub }
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strub" }
 
diff --git a/gcc/testsuite/gnat.dg/strub_var.adb b/gcc/testsuite/gnat.dg/strub_var.adb
index 3d158de2803..9087198a2cd 100644
--- a/gcc/testsuite/gnat.dg/strub_var.adb
+++ b/gcc/testsuite/gnat.dg/strub_var.adb
@@ -1,3 +1,4 @@
+--  { dg-require-effective-target strub }
 --  { dg-do compile }
 --  { dg-options "-fstrub=strict -fdump-ipa-strubm" }
 
diff --git a/gcc/testsuite/gnat.dg/strub_var1.adb b/gcc/testsuite/gnat.dg/strub_var1.adb
index 6a504e09198..ac62f81a7d7 100644
--- a/gcc/testsuite/gnat.dg/strub_var1.adb
+++ b/gcc/testsuite/gnat.dg/strub_var1.adb
@@ -1,3 +1,4 @@
+--  { dg-require-effective-target strub }
 --  { dg-do compile }
 
 with Strub_Attr;
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 3fcce6be49d..daf1d259aae 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -1302,6 +1302,13 @@ proc check_stack_check_available { stack_kind } {
     } "$stack_opt"]
 }
 
+# Return 1 if the target supports stack scrubbing.
+proc check_effective_target_strub {} {
+    return [check_no_compiler_messages strub assembly {
+	int __attribute__ ((__strub__)) fn () {}
+    } ""]
+}
+
 # Return 1 if compilation with -freorder-blocks-and-partition is error-free
 # for trivial code, 0 otherwise.  As some targets (ARM for example) only
 # warn when -fprofile-use is also supplied we test that combination too.
diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in
index d8163c5af99..3f77283490e 100644
--- a/libgcc/Makefile.in
+++ b/libgcc/Makefile.in
@@ -434,7 +434,7 @@ LIB2ADD += enable-execute-stack.c
 LIB2ADD += $(srcdir)/hardcfr.c
 
 # Stack scrubbing infrastructure.
-LIB2ADD += $(srcdir)/strub.c
+@HAVE_STRUB_SUPPORT@LIB2ADD += $(srcdir)/strub.c
 
 # While emutls.c has nothing to do with EH, it is in LIB2ADDEH*
 # instead of LIB2ADD because that's the way to be sure on some targets
diff --git a/libgcc/configure b/libgcc/configure
index cf149209652..f77d39df625 100755
--- a/libgcc/configure
+++ b/libgcc/configure
@@ -593,6 +593,7 @@ asm_hidden_op
 extra_parts
 cpu_type
 get_gcc_base_ver
+HAVE_STRUB_SUPPORT
 thread_header
 tm_defines
 tm_file
@@ -5702,6 +5703,31 @@ esac
 
 
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for strub support" >&5
+$as_echo_n "checking for strub support... " >&6; }
+if ${libgcc_cv_strub_support+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int __attribute__ ((__strub__)) fn () {}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  libgcc_cv_strub_support=yes
+else
+  libgcc_cv_strub_support=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgcc_cv_strub_support" >&5
+$as_echo "$libgcc_cv_strub_support" >&6; }
+if test "x$libgcc_cv_strub_support" != xno; then
+  HAVE_STRUB_SUPPORT=
+else
+  HAVE_STRUB_SUPPORT='# '
+fi
+
+
 # Determine what GCC version number to use in filesystem paths.
 
   get_gcc_base_ver="cat"
diff --git a/libgcc/configure.ac b/libgcc/configure.ac
index 2fc9d5d7c93..a8def244998 100644
--- a/libgcc/configure.ac
+++ b/libgcc/configure.ac
@@ -694,6 +694,19 @@ AC_SUBST(tm_defines)
 # Map from thread model to thread header.
 GCC_AC_THREAD_HEADER([$target_thread_file])
 
+AC_CACHE_CHECK([for strub support],
+  [libgcc_cv_strub_support],
+  [AC_COMPILE_IFELSE(
+    [AC_LANG_SOURCE([int __attribute__ ((__strub__)) fn () {}])],
+    [libgcc_cv_strub_support=yes],
+    [libgcc_cv_strub_support=no])])
+if test "x$libgcc_cv_strub_support" != xno; then
+  HAVE_STRUB_SUPPORT=
+else
+  HAVE_STRUB_SUPPORT='# '
+fi
+AC_SUBST(HAVE_STRUB_SUPPORT)
+
 # Determine what GCC version number to use in filesystem paths.
 GCC_BASE_VER

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [gcc(refs/users/aoliva/heads/testme)] strub: enable conditional support
@ 2023-12-06 23:50 Alexandre Oliva
  0 siblings, 0 replies; 25+ messages in thread
From: Alexandre Oliva @ 2023-12-06 23:50 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:8701b60f100b7e122e1ea687812f3c923c9e2ceb

commit 8701b60f100b7e122e1ea687812f3c923c9e2ceb
Author: Alexandre Oliva <oliva@gnu.org>
Date:   Wed Dec 6 19:36:02 2023 -0300

    strub: enable conditional support

Diff:
---
 gcc/config/i386/i386.cc                            |  4 ++
 gcc/config/nvptx/nvptx.cc                          |  3 ++
 gcc/doc/tm.texi                                    |  6 +++
 gcc/doc/tm.texi.in                                 |  2 +
 gcc/ipa-strub.cc                                   | 54 +++++++++++++++++++++-
 gcc/target.def                                     |  8 ++++
 gcc/testsuite/c-c++-common/strub-O0.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O1.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O2.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O2fni.c           |  1 +
 gcc/testsuite/c-c++-common/strub-O3.c              |  1 +
 gcc/testsuite/c-c++-common/strub-O3fni.c           |  1 +
 gcc/testsuite/c-c++-common/strub-Og.c              |  1 +
 gcc/testsuite/c-c++-common/strub-Os.c              |  1 +
 gcc/testsuite/c-c++-common/strub-all1.c            |  1 +
 gcc/testsuite/c-c++-common/strub-all2.c            |  1 +
 gcc/testsuite/c-c++-common/strub-apply1.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply2.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply3.c          |  1 +
 gcc/testsuite/c-c++-common/strub-apply4.c          |  1 +
 gcc/testsuite/c-c++-common/strub-at-calls1.c       |  1 +
 gcc/testsuite/c-c++-common/strub-at-calls2.c       |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-O3.c        |  1 +
 gcc/testsuite/c-c++-common/strub-defer-Os.c        |  1 +
 gcc/testsuite/c-c++-common/strub-internal1.c       |  1 +
 gcc/testsuite/c-c++-common/strub-internal2.c       |  1 +
 gcc/testsuite/c-c++-common/strub-parms1.c          |  1 +
 gcc/testsuite/c-c++-common/strub-parms2.c          |  1 +
 gcc/testsuite/c-c++-common/strub-parms3.c          |  1 +
 gcc/testsuite/c-c++-common/strub-relaxed1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-relaxed2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O0-exc.c    |  1 +
 gcc/testsuite/c-c++-common/strub-short-O0.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O1.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O2.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-O3.c        |  1 +
 gcc/testsuite/c-c++-common/strub-short-Os.c        |  1 +
 gcc/testsuite/c-c++-common/strub-strict1.c         |  1 +
 gcc/testsuite/c-c++-common/strub-strict2.c         |  1 +
 gcc/testsuite/c-c++-common/strub-tail-O1.c         |  1 +
 gcc/testsuite/c-c++-common/strub-tail-O2.c         |  1 +
 gcc/testsuite/c-c++-common/strub-var1.c            |  1 +
 .../c-c++-common/torture/strub-callable1.c         |  1 +
 .../c-c++-common/torture/strub-callable2.c         |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const1.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const2.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const3.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-const4.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data1.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data2.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data3.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data4.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-data5.c   |  1 +
 .../c-c++-common/torture/strub-indcall1.c          |  1 +
 .../c-c++-common/torture/strub-indcall2.c          |  1 +
 .../c-c++-common/torture/strub-indcall3.c          |  1 +
 .../c-c++-common/torture/strub-inlinable1.c        |  1 +
 .../c-c++-common/torture/strub-inlinable2.c        |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c  |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure1.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure2.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure3.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-pure4.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run1.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run2.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run3.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4.c    |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4c.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4d.c   |  1 +
 gcc/testsuite/c-c++-common/torture/strub-run4i.c   |  1 +
 gcc/testsuite/g++.dg/strub-run1.C                  |  1 +
 gcc/testsuite/g++.dg/torture/strub-init1.C         |  1 +
 gcc/testsuite/g++.dg/torture/strub-init2.C         |  1 +
 gcc/testsuite/g++.dg/torture/strub-init3.C         |  1 +
 gcc/testsuite/lib/target-supports.exp              |  7 +++
 libgcc/Makefile.in                                 |  2 +-
 libgcc/configure                                   | 26 +++++++++++
 libgcc/configure.ac                                | 13 ++++++
 83 files changed, 195 insertions(+), 3 deletions(-)

diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 7c5cab4e2c6..f933c9c23c7 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -26658,6 +26658,10 @@ ix86_libm_function_max_error (unsigned cfn, machine_mode mode,
 #define TARGET_RUN_TARGET_SELFTESTS selftest::ix86_run_selftests
 #endif /* #if CHECKING_P */
 
+// ??? for testing only
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 #include "gt-i386.h"
diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc
index ae20802c879..3fb1deb70fd 100644
--- a/gcc/config/nvptx/nvptx.cc
+++ b/gcc/config/nvptx/nvptx.cc
@@ -7789,6 +7789,9 @@ nvptx_asm_output_def_from_decls (FILE *stream, tree name, tree value)
 #undef TARGET_LIBC_HAS_FUNCTION
 #define TARGET_LIBC_HAS_FUNCTION nvptx_libc_has_function
 
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-nvptx.h"
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 89a1735dd79..768ada0af52 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -3450,6 +3450,12 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@deftypefn {Target Hook} bool TARGET_HAVE_STRUB_SUPPORT_FOR (tree)
+Returns true if the target supports stack scrubbing for the given function
+or type, otherwise return false.  The default implementation always returns
+true.
+@end deftypefn
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index ebc1d3de5ca..4fe0805394e 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2686,6 +2686,8 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@hook TARGET_HAVE_STRUB_SUPPORT_FOR
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
index 293bec132b8..f3100bb1d44 100644
--- a/gcc/ipa-strub.cc
+++ b/gcc/ipa-strub.cc
@@ -60,6 +60,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-strub.h"
 #include "symtab-thunks.h"
 #include "attr-fnspec.h"
+#include "target.h"
 
 /* This file introduces two passes that, together, implement
    machine-independent stack scrubbing, strub for short.  It arranges
@@ -631,17 +632,60 @@ strub_always_inline_p (cgraph_node *node)
   return lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl));
 }
 
+/* Return TRUE iff the target has strub support for T, a function decl
+   or a type, and optionally REPORT thereasons for ineligibility.  If
+   T is a type and error REPORTing is enabled, the LOCation (e.g. of
+   the indirect call) should be given in LOC.  */
+static inline bool
+strub_target_support_p (tree t, bool report = false,
+			location_t loc = UNKNOWN_LOCATION)
+{
+  bool result = true;
+
+  if (!targetm.have_strub_support_for (t))
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      if (DECL_P (t))
+	sorry_at (DECL_SOURCE_LOCATION (t),
+		  "%qD is not eligible for %<strub%>"
+		  " on the target system", t);
+      else
+	sorry_at (loc,
+		  "%qT is not an eligible type for %<strub%>"
+		  " on the target system", t);
+    }
+
+  return result;
+}
+
 /* Return TRUE iff NODE is potentially eligible for any strub-enabled mode, and
    optionally REPORT the reasons for ineligibility.  */
 
 static inline bool
 can_strub_p (cgraph_node *node, bool report = false)
 {
-  bool result = true;
+  bool result = strub_target_support_p (node->decl, report);
 
-  if (!report && strub_always_inline_p (node))
+  if (!report && (!result || strub_always_inline_p (node)))
     return result;
 
+  if (flag_split_stack)
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (node->decl),
+		"%qD is not eligible for %<strub%>"
+		" because %<-fsplit-stack%> is enabled",
+		node->decl);
+    }
+
   if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
     {
       result = false;
@@ -2417,6 +2461,12 @@ pass_ipa_strub::adjust_at_calls_call (cgraph_edge *e, int named_args,
 			 && (TREE_TYPE (gimple_call_arg (ocall, named_args))
 			     == get_pwmt ())));
 
+  tree tsup;
+  if (!(tsup = gimple_call_fndecl (ocall)))
+    tsup = TREE_TYPE (TREE_TYPE (gimple_call_fn (ocall)));
+  if (!strub_target_support_p (tsup, true, gimple_location (ocall)))
+    return;
+
   /* If we're already within a strub context, pass on the incoming watermark
      pointer, and omit the enter and leave calls around the modified call, as an
      optimization, or as a means to satisfy a tail-call requirement.  */
diff --git a/gcc/target.def b/gcc/target.def
index 52b83e091b9..08218f3a42a 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4457,6 +4457,14 @@ otherwise return false.  The default implementation always returns true.",
  bool, (void),
  hook_bool_void_true)
 
+DEFHOOK
+(have_strub_support_for,
+ "Returns true if the target supports stack scrubbing for the given function\n\
+or type, otherwise return false.  The default implementation always returns\n\
+true.",
+ bool, (tree),
+ hook_bool_tree_true)
+
 DEFHOOK
 (have_speculation_safe_value,
 "This hook is used to determine the level of target support for\n\
diff --git a/gcc/testsuite/c-c++-common/strub-O0.c b/gcc/testsuite/c-c++-common/strub-O0.c
index c7a79a6ea0d..a4af42aaf98 100644
--- a/gcc/testsuite/c-c++-common/strub-O0.c
+++ b/gcc/testsuite/c-c++-common/strub-O0.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fdump-rtl-expand" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O1.c b/gcc/testsuite/c-c++-common/strub-O1.c
index 96285c975d9..e5443c2a420 100644
--- a/gcc/testsuite/c-c++-common/strub-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-O1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fdump-rtl-expand" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O2.c b/gcc/testsuite/c-c++-common/strub-O2.c
index 8edc0d8aa13..3ab3b8cad28 100644
--- a/gcc/testsuite/c-c++-common/strub-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-O2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O2fni.c b/gcc/testsuite/c-c++-common/strub-O2fni.c
index c6d900cf3c4..a00d37b44bc 100644
--- a/gcc/testsuite/c-c++-common/strub-O2fni.c
+++ b/gcc/testsuite/c-c++-common/strub-O2fni.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O3.c b/gcc/testsuite/c-c++-common/strub-O3.c
index 33ee465e51c..3ae3d36c732 100644
--- a/gcc/testsuite/c-c++-common/strub-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-O3.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-O3fni.c b/gcc/testsuite/c-c++-common/strub-O3fni.c
index 2936f82079e..35353d9eea6 100644
--- a/gcc/testsuite/c-c++-common/strub-O3fni.c
+++ b/gcc/testsuite/c-c++-common/strub-O3fni.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-Og.c b/gcc/testsuite/c-c++-common/strub-Og.c
index 479746e57d8..6cf7ff09596 100644
--- a/gcc/testsuite/c-c++-common/strub-Og.c
+++ b/gcc/testsuite/c-c++-common/strub-Og.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-Og -fstrub=strict -fdump-rtl-expand" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-Os.c b/gcc/testsuite/c-c++-common/strub-Os.c
index 2241d4ea07f..e209a2c7914 100644
--- a/gcc/testsuite/c-c++-common/strub-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-Os.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-Os -fstrub=strict -fdump-rtl-expand" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-all1.c b/gcc/testsuite/c-c++-common/strub-all1.c
index a322bcc5da6..8341f80af16 100644
--- a/gcc/testsuite/c-c++-common/strub-all1.c
+++ b/gcc/testsuite/c-c++-common/strub-all1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-all2.c b/gcc/testsuite/c-c++-common/strub-all2.c
index db60026d0e0..0a1b59b1671 100644
--- a/gcc/testsuite/c-c++-common/strub-all2.c
+++ b/gcc/testsuite/c-c++-common/strub-all2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-apply1.c b/gcc/testsuite/c-c++-common/strub-apply1.c
index 2f462adc1ef..725a082955b 100644
--- a/gcc/testsuite/c-c++-common/strub-apply1.c
+++ b/gcc/testsuite/c-c++-common/strub-apply1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-apply2.c b/gcc/testsuite/c-c++-common/strub-apply2.c
index a5d7551f5da..67ed41bd63b 100644
--- a/gcc/testsuite/c-c++-common/strub-apply2.c
+++ b/gcc/testsuite/c-c++-common/strub-apply2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-apply3.c b/gcc/testsuite/c-c++-common/strub-apply3.c
index 64422a0d1e8..44893940435 100644
--- a/gcc/testsuite/c-c++-common/strub-apply3.c
+++ b/gcc/testsuite/c-c++-common/strub-apply3.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-apply4.c b/gcc/testsuite/c-c++-common/strub-apply4.c
index 15ffaa031b8..a0ddc4f0382 100644
--- a/gcc/testsuite/c-c++-common/strub-apply4.c
+++ b/gcc/testsuite/c-c++-common/strub-apply4.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fdump-ipa-strubm" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls1.c b/gcc/testsuite/c-c++-common/strub-at-calls1.c
index b70843b4215..1ea6fa261eb 100644
--- a/gcc/testsuite/c-c++-common/strub-at-calls1.c
+++ b/gcc/testsuite/c-c++-common/strub-at-calls1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls2.c b/gcc/testsuite/c-c++-common/strub-at-calls2.c
index 97a3988a6b9..a14d6b8394f 100644
--- a/gcc/testsuite/c-c++-common/strub-at-calls2.c
+++ b/gcc/testsuite/c-c++-common/strub-at-calls2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O1.c b/gcc/testsuite/c-c++-common/strub-defer-O1.c
index 3d73431b3dc..9e51bd04104 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O1" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O2.c b/gcc/testsuite/c-c++-common/strub-defer-O2.c
index fddf3c745e7..40112180cfd 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O2" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O3.c b/gcc/testsuite/c-c++-common/strub-defer-O3.c
index 7ebc65b58dd..4f901c19fa9 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O3.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -O3" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-defer-Os.c b/gcc/testsuite/c-c++-common/strub-defer-Os.c
index fbaf85fe0fa..d69a5fa8246 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-Os.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict -Os" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-internal1.c b/gcc/testsuite/c-c++-common/strub-internal1.c
index e9d7b7b9ee0..e7a0af164ad 100644
--- a/gcc/testsuite/c-c++-common/strub-internal1.c
+++ b/gcc/testsuite/c-c++-common/strub-internal1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-internal2.c b/gcc/testsuite/c-c++-common/strub-internal2.c
index 8b8e15a51c7..09ff0daabd2 100644
--- a/gcc/testsuite/c-c++-common/strub-internal2.c
+++ b/gcc/testsuite/c-c++-common/strub-internal2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-parms1.c b/gcc/testsuite/c-c++-common/strub-parms1.c
index 0a4a7539d34..2cd60d5e660 100644
--- a/gcc/testsuite/c-c++-common/strub-parms1.c
+++ b/gcc/testsuite/c-c++-common/strub-parms1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-parms2.c b/gcc/testsuite/c-c++-common/strub-parms2.c
index 147171d96d5..96205e4c386 100644
--- a/gcc/testsuite/c-c++-common/strub-parms2.c
+++ b/gcc/testsuite/c-c++-common/strub-parms2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-parms3.c b/gcc/testsuite/c-c++-common/strub-parms3.c
index 4e92682895a..6f36272574b 100644
--- a/gcc/testsuite/c-c++-common/strub-parms3.c
+++ b/gcc/testsuite/c-c++-common/strub-parms3.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed1.c b/gcc/testsuite/c-c++-common/strub-relaxed1.c
index e2f9d8aebca..9131423cb35 100644
--- a/gcc/testsuite/c-c++-common/strub-relaxed1.c
+++ b/gcc/testsuite/c-c++-common/strub-relaxed1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed2.c b/gcc/testsuite/c-c++-common/strub-relaxed2.c
index 98474435d2e..17c1b162f2a 100644
--- a/gcc/testsuite/c-c++-common/strub-relaxed2.c
+++ b/gcc/testsuite/c-c++-common/strub-relaxed2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
index 1de15342595..9a1085661f7 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fexceptions -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0.c b/gcc/testsuite/c-c++-common/strub-short-O0.c
index f9209c81900..8f941554e80 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O0.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O0.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-O0 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O1.c b/gcc/testsuite/c-c++-common/strub-short-O1.c
index bed1dcfb54a..bd92eb02a25 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O2.c b/gcc/testsuite/c-c++-common/strub-short-O2.c
index 6bf0071f52b..8d45b22d946 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-O3.c b/gcc/testsuite/c-c++-common/strub-short-O3.c
index 4732f515bf7..8f3cd12e08d 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O3.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-O3 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-short-Os.c b/gcc/testsuite/c-c++-common/strub-short-Os.c
index 8d6424c479a..992209ef457 100644
--- a/gcc/testsuite/c-c++-common/strub-short-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-short-Os.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-Os -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-strict1.c b/gcc/testsuite/c-c++-common/strub-strict1.c
index 36852244206..1448aa47cdb 100644
--- a/gcc/testsuite/c-c++-common/strub-strict1.c
+++ b/gcc/testsuite/c-c++-common/strub-strict1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-strict2.c b/gcc/testsuite/c-c++-common/strub-strict2.c
index b4f28883218..2391a8f5c3e 100644
--- a/gcc/testsuite/c-c++-common/strub-strict2.c
+++ b/gcc/testsuite/c-c++-common/strub-strict2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O1.c b/gcc/testsuite/c-c++-common/strub-tail-O1.c
index e48e0610e07..43efb167794 100644
--- a/gcc/testsuite/c-c++-common/strub-tail-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-tail-O1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O2.c b/gcc/testsuite/c-c++-common/strub-tail-O2.c
index 87cda7ab21b..e5c3d8858e1 100644
--- a/gcc/testsuite/c-c++-common/strub-tail-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-tail-O2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/strub-var1.c b/gcc/testsuite/c-c++-common/strub-var1.c
index eb6250fd39c..68906296022 100644
--- a/gcc/testsuite/c-c++-common/strub-var1.c
+++ b/gcc/testsuite/c-c++-common/strub-var1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 
 int __attribute__ ((strub)) x;
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable1.c b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
index b5e45ab0525..43d165e44c5 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-callable1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable2.c b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
index 96aa7fe4b07..c5e5ec321ce 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-callable2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const1.c b/gcc/testsuite/c-c++-common/torture/strub-const1.c
index 5e956cb1a9b..690915b3782 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const2.c b/gcc/testsuite/c-c++-common/torture/strub-const2.c
index 73d650292df..5719bfed135 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const3.c b/gcc/testsuite/c-c++-common/torture/strub-const3.c
index 2584f1f974a..2f4e32b47f7 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const3.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const4.c b/gcc/testsuite/c-c++-common/torture/strub-const4.c
index d819f54ec02..9f69c790318 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const4.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data1.c b/gcc/testsuite/c-c++-common/torture/strub-data1.c
index 7c27a2a1a6d..3f87659d64d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data2.c b/gcc/testsuite/c-c++-common/torture/strub-data2.c
index e66d903780a..6366eae7345 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data3.c b/gcc/testsuite/c-c++-common/torture/strub-data3.c
index 5e08e0e58c6..42f42c2b2d7 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data3.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data4.c b/gcc/testsuite/c-c++-common/torture/strub-data4.c
index a818e7a38bb..a7395c40664 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data4.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data5.c b/gcc/testsuite/c-c++-common/torture/strub-data5.c
index ddb0b5c0543..67e65b99a0d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data5.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data5.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
index c165f312f16..8bad34d7176 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
index 69fcff8d376..96837834e84 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
index ff006224909..1871566fe15 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
index 614b02228ba..c96218656d5 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
index f9a6b4a16fa..3a1a77c1b5e 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=all" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
index b4a7f3992bb..699af8deb8e 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
index ef634d35126..7cc9612ce8a 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -Wpedantic" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
index e1f179e160e..fb070384355 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed -Wpedantic -fpermissive" } */
 /* { dg-prune-output "command-line option .-fpermissive." } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
index 70b558afad0..6ff5baad179 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=relaxed" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure1.c b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
index a262a086837..186c35e1aaa 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure2.c b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
index 4c4bd50c209..0e381df42fb 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure3.c b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
index ce195c6b1f1..f9f0f8f3beb 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure4.c b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
index 75cd54ccb5b..3eb6286ca52 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run1.c b/gcc/testsuite/c-c++-common/torture/strub-run1.c
index 7458b3fb54d..d5e0e2ece8d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run1.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run2.c b/gcc/testsuite/c-c++-common/torture/strub-run2.c
index 5d60a7775f4..268371d7bf1 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run2.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run3.c b/gcc/testsuite/c-c++-common/torture/strub-run3.c
index c2ad710858e..8a6b7b5fc97 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run3.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 /* { dg-require-effective-target alloca } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4.c b/gcc/testsuite/c-c++-common/torture/strub-run4.c
index 3b36b8e5d68..f424f8357fa 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=all" } */
 /* { dg-require-effective-target alloca } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4c.c b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
index 57f9baf758d..a780d858c22 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4c.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=at-calls" } */
 /* { dg-require-effective-target alloca } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4d.c b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
index 08de3f1c3b1..82a65ce1a48 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4d.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=strict" } */
 /* { dg-require-effective-target alloca } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4i.c b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
index 459f6886c54..0ed243086f6 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4i.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do run } */
 /* { dg-options "-fstrub=internal" } */
 /* { dg-require-effective-target alloca } */
diff --git a/gcc/testsuite/g++.dg/strub-run1.C b/gcc/testsuite/g++.dg/strub-run1.C
index 0d367fb83d0..0d8e9bc23e9 100644
--- a/gcc/testsuite/g++.dg/strub-run1.C
+++ b/gcc/testsuite/g++.dg/strub-run1.C
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 // { dg-do run }
 // { dg-options "-fstrub=internal" }
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init1.C b/gcc/testsuite/g++.dg/torture/strub-init1.C
index c226ab10ff6..5d347ad353d 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init1.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init1.C
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init2.C b/gcc/testsuite/g++.dg/torture/strub-init2.C
index a7911f1fa72..17bffe7b142 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init2.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init2.C
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/g++.dg/torture/strub-init3.C b/gcc/testsuite/g++.dg/torture/strub-init3.C
index 6ebebcd01e8..4f9a57f2345 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init3.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init3.C
@@ -1,3 +1,4 @@
+/* { dg-require-effective-target strub } */
 /* { dg-do compile } */
 /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
 
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 3fcce6be49d..45ef0c28880 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -1302,6 +1302,13 @@ proc check_stack_check_available { stack_kind } {
     } "$stack_opt"]
 }
 
+# Return 1 if the target supports stack scrubbing.
+proc check_effective_target_strub {} {
+    return [check_no_compiler_messages strub assembly {
+	int __attribute__ ((__strub__)) fn () {}
+    }]
+}
+
 # Return 1 if compilation with -freorder-blocks-and-partition is error-free
 # for trivial code, 0 otherwise.  As some targets (ARM for example) only
 # warn when -fprofile-use is also supplied we test that combination too.
diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in
index d8163c5af99..3f77283490e 100644
--- a/libgcc/Makefile.in
+++ b/libgcc/Makefile.in
@@ -434,7 +434,7 @@ LIB2ADD += enable-execute-stack.c
 LIB2ADD += $(srcdir)/hardcfr.c
 
 # Stack scrubbing infrastructure.
-LIB2ADD += $(srcdir)/strub.c
+@HAVE_STRUB_SUPPORT@LIB2ADD += $(srcdir)/strub.c
 
 # While emutls.c has nothing to do with EH, it is in LIB2ADDEH*
 # instead of LIB2ADD because that's the way to be sure on some targets
diff --git a/libgcc/configure b/libgcc/configure
index cf149209652..f77d39df625 100755
--- a/libgcc/configure
+++ b/libgcc/configure
@@ -593,6 +593,7 @@ asm_hidden_op
 extra_parts
 cpu_type
 get_gcc_base_ver
+HAVE_STRUB_SUPPORT
 thread_header
 tm_defines
 tm_file
@@ -5702,6 +5703,31 @@ esac
 
 
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for strub support" >&5
+$as_echo_n "checking for strub support... " >&6; }
+if ${libgcc_cv_strub_support+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int __attribute__ ((__strub__)) fn () {}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  libgcc_cv_strub_support=yes
+else
+  libgcc_cv_strub_support=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgcc_cv_strub_support" >&5
+$as_echo "$libgcc_cv_strub_support" >&6; }
+if test "x$libgcc_cv_strub_support" != xno; then
+  HAVE_STRUB_SUPPORT=
+else
+  HAVE_STRUB_SUPPORT='# '
+fi
+
+
 # Determine what GCC version number to use in filesystem paths.
 
   get_gcc_base_ver="cat"
diff --git a/libgcc/configure.ac b/libgcc/configure.ac
index 2fc9d5d7c93..a8def244998 100644
--- a/libgcc/configure.ac
+++ b/libgcc/configure.ac
@@ -694,6 +694,19 @@ AC_SUBST(tm_defines)
 # Map from thread model to thread header.
 GCC_AC_THREAD_HEADER([$target_thread_file])
 
+AC_CACHE_CHECK([for strub support],
+  [libgcc_cv_strub_support],
+  [AC_COMPILE_IFELSE(
+    [AC_LANG_SOURCE([int __attribute__ ((__strub__)) fn () {}])],
+    [libgcc_cv_strub_support=yes],
+    [libgcc_cv_strub_support=no])])
+if test "x$libgcc_cv_strub_support" != xno; then
+  HAVE_STRUB_SUPPORT=
+else
+  HAVE_STRUB_SUPPORT='# '
+fi
+AC_SUBST(HAVE_STRUB_SUPPORT)
+
 # Determine what GCC version number to use in filesystem paths.
 GCC_BASE_VER

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [gcc(refs/users/aoliva/heads/testme)] strub: enable conditional support
@ 2023-12-06 23:34 Alexandre Oliva
  0 siblings, 0 replies; 25+ messages in thread
From: Alexandre Oliva @ 2023-12-06 23:34 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:eb5bf6ce11a6ea0f3c4c5cdd76ca445970b39e10

commit eb5bf6ce11a6ea0f3c4c5cdd76ca445970b39e10
Author: Alexandre Oliva <oliva@gnu.org>
Date:   Wed Dec 6 19:36:02 2023 -0300

    strub: enable conditional support

Diff:
---
 gcc/config/i386/i386.cc   |  4 ++++
 gcc/config/nvptx/nvptx.cc |  3 +++
 gcc/doc/tm.texi           |  6 ++++++
 gcc/doc/tm.texi.in        |  2 ++
 gcc/ipa-strub.cc          | 54 +++++++++++++++++++++++++++++++++++++++++++++--
 gcc/target.def            |  8 +++++++
 6 files changed, 75 insertions(+), 2 deletions(-)

diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 7c5cab4e2c6..f933c9c23c7 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -26658,6 +26658,10 @@ ix86_libm_function_max_error (unsigned cfn, machine_mode mode,
 #define TARGET_RUN_TARGET_SELFTESTS selftest::ix86_run_selftests
 #endif /* #if CHECKING_P */
 
+// ??? for testing only
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 #include "gt-i386.h"
diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc
index ae20802c879..3fb1deb70fd 100644
--- a/gcc/config/nvptx/nvptx.cc
+++ b/gcc/config/nvptx/nvptx.cc
@@ -7789,6 +7789,9 @@ nvptx_asm_output_def_from_decls (FILE *stream, tree name, tree value)
 #undef TARGET_LIBC_HAS_FUNCTION
 #define TARGET_LIBC_HAS_FUNCTION nvptx_libc_has_function
 
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-nvptx.h"
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 89a1735dd79..768ada0af52 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -3450,6 +3450,12 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@deftypefn {Target Hook} bool TARGET_HAVE_STRUB_SUPPORT_FOR (tree)
+Returns true if the target supports stack scrubbing for the given function
+or type, otherwise return false.  The default implementation always returns
+true.
+@end deftypefn
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index ebc1d3de5ca..4fe0805394e 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2686,6 +2686,8 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@hook TARGET_HAVE_STRUB_SUPPORT_FOR
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
index 293bec132b8..f3100bb1d44 100644
--- a/gcc/ipa-strub.cc
+++ b/gcc/ipa-strub.cc
@@ -60,6 +60,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-strub.h"
 #include "symtab-thunks.h"
 #include "attr-fnspec.h"
+#include "target.h"
 
 /* This file introduces two passes that, together, implement
    machine-independent stack scrubbing, strub for short.  It arranges
@@ -631,17 +632,60 @@ strub_always_inline_p (cgraph_node *node)
   return lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl));
 }
 
+/* Return TRUE iff the target has strub support for T, a function decl
+   or a type, and optionally REPORT thereasons for ineligibility.  If
+   T is a type and error REPORTing is enabled, the LOCation (e.g. of
+   the indirect call) should be given in LOC.  */
+static inline bool
+strub_target_support_p (tree t, bool report = false,
+			location_t loc = UNKNOWN_LOCATION)
+{
+  bool result = true;
+
+  if (!targetm.have_strub_support_for (t))
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      if (DECL_P (t))
+	sorry_at (DECL_SOURCE_LOCATION (t),
+		  "%qD is not eligible for %<strub%>"
+		  " on the target system", t);
+      else
+	sorry_at (loc,
+		  "%qT is not an eligible type for %<strub%>"
+		  " on the target system", t);
+    }
+
+  return result;
+}
+
 /* Return TRUE iff NODE is potentially eligible for any strub-enabled mode, and
    optionally REPORT the reasons for ineligibility.  */
 
 static inline bool
 can_strub_p (cgraph_node *node, bool report = false)
 {
-  bool result = true;
+  bool result = strub_target_support_p (node->decl, report);
 
-  if (!report && strub_always_inline_p (node))
+  if (!report && (!result || strub_always_inline_p (node)))
     return result;
 
+  if (flag_split_stack)
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (node->decl),
+		"%qD is not eligible for %<strub%>"
+		" because %<-fsplit-stack%> is enabled",
+		node->decl);
+    }
+
   if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
     {
       result = false;
@@ -2417,6 +2461,12 @@ pass_ipa_strub::adjust_at_calls_call (cgraph_edge *e, int named_args,
 			 && (TREE_TYPE (gimple_call_arg (ocall, named_args))
 			     == get_pwmt ())));
 
+  tree tsup;
+  if (!(tsup = gimple_call_fndecl (ocall)))
+    tsup = TREE_TYPE (TREE_TYPE (gimple_call_fn (ocall)));
+  if (!strub_target_support_p (tsup, true, gimple_location (ocall)))
+    return;
+
   /* If we're already within a strub context, pass on the incoming watermark
      pointer, and omit the enter and leave calls around the modified call, as an
      optimization, or as a means to satisfy a tail-call requirement.  */
diff --git a/gcc/target.def b/gcc/target.def
index 52b83e091b9..08218f3a42a 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4457,6 +4457,14 @@ otherwise return false.  The default implementation always returns true.",
  bool, (void),
  hook_bool_void_true)
 
+DEFHOOK
+(have_strub_support_for,
+ "Returns true if the target supports stack scrubbing for the given function\n\
+or type, otherwise return false.  The default implementation always returns\n\
+true.",
+ bool, (tree),
+ hook_bool_tree_true)
+
 DEFHOOK
 (have_speculation_safe_value,
 "This hook is used to determine the level of target support for\n\

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [gcc(refs/users/aoliva/heads/testme)] strub: enable conditional support
@ 2023-12-06 23:32 Alexandre Oliva
  0 siblings, 0 replies; 25+ messages in thread
From: Alexandre Oliva @ 2023-12-06 23:32 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:9eaa4d780d8ad456d16c3800751ec02b728462a4

commit 9eaa4d780d8ad456d16c3800751ec02b728462a4
Author: Alexandre Oliva <oliva@gnu.org>
Date:   Wed Dec 6 19:36:02 2023 -0300

    strub: enable conditional support

Diff:
---
 gcc/config/i386/i386.cc   |  4 ++++
 gcc/config/nvptx/nvptx.cc |  3 +++
 gcc/doc/tm.texi           |  6 ++++++
 gcc/doc/tm.texi.in        |  2 ++
 gcc/ipa-strub.cc          | 54 +++++++++++++++++++++++++++++++++++++++++++++--
 gcc/target.def            |  8 +++++++
 6 files changed, 75 insertions(+), 2 deletions(-)

diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 7c5cab4e2c6..f933c9c23c7 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -26658,6 +26658,10 @@ ix86_libm_function_max_error (unsigned cfn, machine_mode mode,
 #define TARGET_RUN_TARGET_SELFTESTS selftest::ix86_run_selftests
 #endif /* #if CHECKING_P */
 
+// ??? for testing only
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 #include "gt-i386.h"
diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc
index ae20802c879..3fb1deb70fd 100644
--- a/gcc/config/nvptx/nvptx.cc
+++ b/gcc/config/nvptx/nvptx.cc
@@ -7789,6 +7789,9 @@ nvptx_asm_output_def_from_decls (FILE *stream, tree name, tree value)
 #undef TARGET_LIBC_HAS_FUNCTION
 #define TARGET_LIBC_HAS_FUNCTION nvptx_libc_has_function
 
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-nvptx.h"
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 89a1735dd79..768ada0af52 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -3450,6 +3450,12 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@deftypefn {Target Hook} bool TARGET_HAVE_STRUB_SUPPORT_FOR (tree)
+Returns true if the target supports stack scrubbing for the given function
+or type, otherwise return false.  The default implementation always returns
+true.
+@end deftypefn
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index ebc1d3de5ca..4fe0805394e 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2686,6 +2686,8 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@hook TARGET_HAVE_STRUB_SUPPORT_FOR
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
index 293bec132b8..40f2abfcad6 100644
--- a/gcc/ipa-strub.cc
+++ b/gcc/ipa-strub.cc
@@ -60,6 +60,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-strub.h"
 #include "symtab-thunks.h"
 #include "attr-fnspec.h"
+#include "target.h"
 
 /* This file introduces two passes that, together, implement
    machine-independent stack scrubbing, strub for short.  It arranges
@@ -631,17 +632,60 @@ strub_always_inline_p (cgraph_node *node)
   return lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl));
 }
 
+/* Return TRUE iff the target has strub support for T, a function decl
+   or a type, and optionally REPORT thereasons for ineligibility.  If
+   T is a type and error REPORTing is enabled, the LOCation (e.g. of
+   the indirect call) should be given in LOC.  */
+static inline bool
+strub_target_support_p (tree t, bool report = false,
+			location_t loc = UNKNOWN_LOCATION)
+{
+  bool result = true;
+
+  if (!targetm.have_strub_support_for (t))
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      if (DECL_P (t))
+	sorry_at (DECL_SOURCE_LOCATION (t),
+		  "%qD is not eligible for %<strub%>"
+		  " on the target system", t);
+      else
+	sorry_at (loc,
+		  "%qT is not an eligible type for %<strub%>"
+		  " on the target system", t);
+    }
+
+  return result;
+}
+
 /* Return TRUE iff NODE is potentially eligible for any strub-enabled mode, and
    optionally REPORT the reasons for ineligibility.  */
 
 static inline bool
 can_strub_p (cgraph_node *node, bool report = false)
 {
-  bool result = true;
+  bool result = strub_target_support_p (node->decl, report);
 
-  if (!report && strub_always_inline_p (node))
+  if (!report && (!result || strub_always_inline_p (node)))
     return result;
 
+  if (flag_split_stack)
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (node->decl),
+		"%qD is not eligible for %<strub%>"
+		" because %<-fsplit-stack%> is enabled",
+		node->decl);
+    }
+
   if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
     {
       result = false;
@@ -2417,6 +2461,12 @@ pass_ipa_strub::adjust_at_calls_call (cgraph_edge *e, int named_args,
 			 && (TREE_TYPE (gimple_call_arg (ocall, named_args))
 			     == get_pwmt ())));
 
+  tree tsup;
+  if (!(tsup = gimple_call_fndecl (ocall)))
+    tsup = TREE_TYPE (TREE_TYPE (gimple_call_fn (ocall)));
+  if (!strub_target_support_p (tsup, gimple_location (ocall), true))
+    return;
+
   /* If we're already within a strub context, pass on the incoming watermark
      pointer, and omit the enter and leave calls around the modified call, as an
      optimization, or as a means to satisfy a tail-call requirement.  */
diff --git a/gcc/target.def b/gcc/target.def
index 52b83e091b9..08218f3a42a 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4457,6 +4457,14 @@ otherwise return false.  The default implementation always returns true.",
  bool, (void),
  hook_bool_void_true)
 
+DEFHOOK
+(have_strub_support_for,
+ "Returns true if the target supports stack scrubbing for the given function\n\
+or type, otherwise return false.  The default implementation always returns\n\
+true.",
+ bool, (tree),
+ hook_bool_tree_true)
+
 DEFHOOK
 (have_speculation_safe_value,
 "This hook is used to determine the level of target support for\n\

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [gcc(refs/users/aoliva/heads/testme)] strub: enable conditional support
@ 2023-12-06 23:26 Alexandre Oliva
  0 siblings, 0 replies; 25+ messages in thread
From: Alexandre Oliva @ 2023-12-06 23:26 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:ff6f9b5e487ac25d542aa37989e80a0a3f50a489

commit ff6f9b5e487ac25d542aa37989e80a0a3f50a489
Author: Alexandre Oliva <oliva@gnu.org>
Date:   Wed Dec 6 19:36:02 2023 -0300

    strub: enable conditional support

Diff:
---
 gcc/config/i386/i386.cc   |  4 ++++
 gcc/config/nvptx/nvptx.cc |  3 +++
 gcc/doc/tm.texi           |  6 ++++++
 gcc/doc/tm.texi.in        |  2 ++
 gcc/ipa-strub.cc          | 47 +++++++++++++++++++++++++++++++++++++++++++++--
 gcc/target.def            |  8 ++++++++
 6 files changed, 68 insertions(+), 2 deletions(-)

diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 7c5cab4e2c6..f933c9c23c7 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -26658,6 +26658,10 @@ ix86_libm_function_max_error (unsigned cfn, machine_mode mode,
 #define TARGET_RUN_TARGET_SELFTESTS selftest::ix86_run_selftests
 #endif /* #if CHECKING_P */
 
+// ??? for testing only
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 #include "gt-i386.h"
diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc
index ae20802c879..3fb1deb70fd 100644
--- a/gcc/config/nvptx/nvptx.cc
+++ b/gcc/config/nvptx/nvptx.cc
@@ -7789,6 +7789,9 @@ nvptx_asm_output_def_from_decls (FILE *stream, tree name, tree value)
 #undef TARGET_LIBC_HAS_FUNCTION
 #define TARGET_LIBC_HAS_FUNCTION nvptx_libc_has_function
 
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-nvptx.h"
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 89a1735dd79..768ada0af52 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -3450,6 +3450,12 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@deftypefn {Target Hook} bool TARGET_HAVE_STRUB_SUPPORT_FOR (tree)
+Returns true if the target supports stack scrubbing for the given function
+or type, otherwise return false.  The default implementation always returns
+true.
+@end deftypefn
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index ebc1d3de5ca..4fe0805394e 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2686,6 +2686,8 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@hook TARGET_HAVE_STRUB_SUPPORT_FOR
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
index 293bec132b8..f4f103cffa8 100644
--- a/gcc/ipa-strub.cc
+++ b/gcc/ipa-strub.cc
@@ -60,6 +60,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-strub.h"
 #include "symtab-thunks.h"
 #include "attr-fnspec.h"
+#include "target.h"
 
 /* This file introduces two passes that, together, implement
    machine-independent stack scrubbing, strub for short.  It arranges
@@ -631,17 +632,53 @@ strub_always_inline_p (cgraph_node *node)
   return lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl));
 }
 
+/* Return TRUE iff the target has strub support for T, a function decl
+   or a type, and optionally REPORT thereasons for ineligibility.  */
+static inline bool
+strub_target_support_p (tree t, bool report = false)
+{
+  bool result = true;
+
+  if (!targetm.have_strub_support_for (t))
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (t),
+		"%qD is not eligible for %<strub%>"
+		" on the target system",
+		t);
+    }
+
+  return result;
+}
+
 /* Return TRUE iff NODE is potentially eligible for any strub-enabled mode, and
    optionally REPORT the reasons for ineligibility.  */
 
 static inline bool
 can_strub_p (cgraph_node *node, bool report = false)
 {
-  bool result = true;
+  bool result = strub_target_support_p (node->decl, report);
 
-  if (!report && strub_always_inline_p (node))
+  if (!report && (!result || strub_always_inline_p (node)))
     return result;
 
+  if (flag_split_stack)
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (node->decl),
+		"%qD is not eligible for %<strub%>"
+		" because %<-fsplit-stack%> is enabled",
+		node->decl);
+    }
+
   if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
     {
       result = false;
@@ -2417,6 +2454,12 @@ pass_ipa_strub::adjust_at_calls_call (cgraph_edge *e, int named_args,
 			 && (TREE_TYPE (gimple_call_arg (ocall, named_args))
 			     == get_pwmt ())));
 
+  tree tsup;
+  if (!(tsup = gimple_call_fndecl (ocall)))
+    tsup = TREE_TYPE (TREE_TYPE (gimple_call_fn (ocall)));
+  if (!strub_target_support_p (tsup, true))
+    return;
+
   /* If we're already within a strub context, pass on the incoming watermark
      pointer, and omit the enter and leave calls around the modified call, as an
      optimization, or as a means to satisfy a tail-call requirement.  */
diff --git a/gcc/target.def b/gcc/target.def
index 52b83e091b9..08218f3a42a 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4457,6 +4457,14 @@ otherwise return false.  The default implementation always returns true.",
  bool, (void),
  hook_bool_void_true)
 
+DEFHOOK
+(have_strub_support_for,
+ "Returns true if the target supports stack scrubbing for the given function\n\
+or type, otherwise return false.  The default implementation always returns\n\
+true.",
+ bool, (tree),
+ hook_bool_tree_true)
+
 DEFHOOK
 (have_speculation_safe_value,
 "This hook is used to determine the level of target support for\n\

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [gcc(refs/users/aoliva/heads/testme)] strub: enable conditional support
@ 2023-12-06 23:22 Alexandre Oliva
  0 siblings, 0 replies; 25+ messages in thread
From: Alexandre Oliva @ 2023-12-06 23:22 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:207d849ab3c0d83eedfb6592a0ccd47be5a5a87d

commit 207d849ab3c0d83eedfb6592a0ccd47be5a5a87d
Author: Alexandre Oliva <oliva@gnu.org>
Date:   Wed Dec 6 19:36:02 2023 -0300

    strub: enable conditional support

Diff:
---
 gcc/config/i386/i386.cc   |  4 ++++
 gcc/config/nvptx/nvptx.cc |  3 +++
 gcc/doc/tm.texi           |  6 ++++++
 gcc/doc/tm.texi.in        |  2 ++
 gcc/ipa-strub.cc          | 45 +++++++++++++++++++++++++++++++++++++++++++--
 gcc/target.def            |  8 ++++++++
 6 files changed, 66 insertions(+), 2 deletions(-)

diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 7c5cab4e2c6..f933c9c23c7 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -26658,6 +26658,10 @@ ix86_libm_function_max_error (unsigned cfn, machine_mode mode,
 #define TARGET_RUN_TARGET_SELFTESTS selftest::ix86_run_selftests
 #endif /* #if CHECKING_P */
 
+// ??? for testing only
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 #include "gt-i386.h"
diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc
index ae20802c879..3fb1deb70fd 100644
--- a/gcc/config/nvptx/nvptx.cc
+++ b/gcc/config/nvptx/nvptx.cc
@@ -7789,6 +7789,9 @@ nvptx_asm_output_def_from_decls (FILE *stream, tree name, tree value)
 #undef TARGET_LIBC_HAS_FUNCTION
 #define TARGET_LIBC_HAS_FUNCTION nvptx_libc_has_function
 
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-nvptx.h"
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 89a1735dd79..768ada0af52 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -3450,6 +3450,12 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@deftypefn {Target Hook} bool TARGET_HAVE_STRUB_SUPPORT_FOR (tree)
+Returns true if the target supports stack scrubbing for the given function
+or type, otherwise return false.  The default implementation always returns
+true.
+@end deftypefn
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index ebc1d3de5ca..4fe0805394e 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2686,6 +2686,8 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@hook TARGET_HAVE_STRUB_SUPPORT_FOR
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
index 293bec132b8..3df110ff3a6 100644
--- a/gcc/ipa-strub.cc
+++ b/gcc/ipa-strub.cc
@@ -60,6 +60,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-strub.h"
 #include "symtab-thunks.h"
 #include "attr-fnspec.h"
+#include "target.h"
 
 /* This file introduces two passes that, together, implement
    machine-independent stack scrubbing, strub for short.  It arranges
@@ -631,17 +632,53 @@ strub_always_inline_p (cgraph_node *node)
   return lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl));
 }
 
+/* Return TRUE iff the target has strub support for T, a function decl
+   or a type, and optionally REPORT thereasons for ineligibility.  */
+static inline bool
+strub_target_support_p (tree t, bool report = false)
+{
+  bool result = true;
+
+  if (!targetm.have_strub_support_for (t))
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (t),
+		"%qD is not eligible for %<strub%>"
+		" on the target system",
+		t);
+    }
+
+  return result;
+}
+
 /* Return TRUE iff NODE is potentially eligible for any strub-enabled mode, and
    optionally REPORT the reasons for ineligibility.  */
 
 static inline bool
 can_strub_p (cgraph_node *node, bool report = false)
 {
-  bool result = true;
+  bool result = strub_target_support_p (node->decl, report);
 
-  if (!report && strub_always_inline_p (node))
+  if (!report && (!result || strub_always_inline_p (node)))
     return result;
 
+  if (flag_split_stack)
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (node->decl),
+		"%qD is not eligible for %<strub%>"
+		" because %<-fsplit-stack%> is enabled",
+		node->decl);
+    }
+
   if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
     {
       result = false;
@@ -2417,6 +2454,10 @@ pass_ipa_strub::adjust_at_calls_call (cgraph_edge *e, int named_args,
 			 && (TREE_TYPE (gimple_call_arg (ocall, named_args))
 			     == get_pwmt ())));
 
+  if (!strub_target_support_p (TREE_TYPE (gimple_call_fn (ocall)),
+			       true))
+    return;
+
   /* If we're already within a strub context, pass on the incoming watermark
      pointer, and omit the enter and leave calls around the modified call, as an
      optimization, or as a means to satisfy a tail-call requirement.  */
diff --git a/gcc/target.def b/gcc/target.def
index 52b83e091b9..08218f3a42a 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4457,6 +4457,14 @@ otherwise return false.  The default implementation always returns true.",
  bool, (void),
  hook_bool_void_true)
 
+DEFHOOK
+(have_strub_support_for,
+ "Returns true if the target supports stack scrubbing for the given function\n\
+or type, otherwise return false.  The default implementation always returns\n\
+true.",
+ bool, (tree),
+ hook_bool_tree_true)
+
 DEFHOOK
 (have_speculation_safe_value,
 "This hook is used to determine the level of target support for\n\

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [gcc(refs/users/aoliva/heads/testme)] strub: enable conditional support
@ 2023-12-06 23:20 Alexandre Oliva
  0 siblings, 0 replies; 25+ messages in thread
From: Alexandre Oliva @ 2023-12-06 23:20 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:7d0d3a704cdf6a188463ac16e43e991398e047ef

commit 7d0d3a704cdf6a188463ac16e43e991398e047ef
Author: Alexandre Oliva <oliva@gnu.org>
Date:   Wed Dec 6 19:36:02 2023 -0300

    strub: enable conditional support

Diff:
---
 gcc/config/i386/i386.cc   |  4 ++++
 gcc/config/nvptx/nvptx.cc |  3 +++
 gcc/doc/tm.texi           |  6 ++++++
 gcc/doc/tm.texi.in        |  2 ++
 gcc/ipa-strub.cc          | 45 +++++++++++++++++++++++++++++++++++++++++++--
 gcc/target.def            |  8 ++++++++
 6 files changed, 66 insertions(+), 2 deletions(-)

diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 7c5cab4e2c6..f933c9c23c7 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -26658,6 +26658,10 @@ ix86_libm_function_max_error (unsigned cfn, machine_mode mode,
 #define TARGET_RUN_TARGET_SELFTESTS selftest::ix86_run_selftests
 #endif /* #if CHECKING_P */
 
+// ??? for testing only
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 #include "gt-i386.h"
diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc
index ae20802c879..3fb1deb70fd 100644
--- a/gcc/config/nvptx/nvptx.cc
+++ b/gcc/config/nvptx/nvptx.cc
@@ -7789,6 +7789,9 @@ nvptx_asm_output_def_from_decls (FILE *stream, tree name, tree value)
 #undef TARGET_LIBC_HAS_FUNCTION
 #define TARGET_LIBC_HAS_FUNCTION nvptx_libc_has_function
 
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-nvptx.h"
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 89a1735dd79..768ada0af52 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -3450,6 +3450,12 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@deftypefn {Target Hook} bool TARGET_HAVE_STRUB_SUPPORT_FOR (tree)
+Returns true if the target supports stack scrubbing for the given function
+or type, otherwise return false.  The default implementation always returns
+true.
+@end deftypefn
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index ebc1d3de5ca..4fe0805394e 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2686,6 +2686,8 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@hook TARGET_HAVE_STRUB_SUPPORT_FOR
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
index 293bec132b8..b7aff03804e 100644
--- a/gcc/ipa-strub.cc
+++ b/gcc/ipa-strub.cc
@@ -60,6 +60,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-strub.h"
 #include "symtab-thunks.h"
 #include "attr-fnspec.h"
+#include "target.h"
 
 /* This file introduces two passes that, together, implement
    machine-independent stack scrubbing, strub for short.  It arranges
@@ -631,17 +632,53 @@ strub_always_inline_p (cgraph_node *node)
   return lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl));
 }
 
+/* Return TRUE iff the target has strub support for T, a function decl
+   or a type, and optionally REPORT thereasons for ineligibility.  */
+static inline bool
+strub_target_support_p (tree t, bool report = false)
+{
+  bool result = true;
+
+  if (!targetm.have_strub_support_for (t))
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (t),
+		"%qD is not eligible for %<strub%>"
+		" on the target system",
+		t);
+    }
+
+  return result;
+}
+
 /* Return TRUE iff NODE is potentially eligible for any strub-enabled mode, and
    optionally REPORT the reasons for ineligibility.  */
 
 static inline bool
 can_strub_p (cgraph_node *node, bool report = false)
 {
-  bool result = true;
+  bool result = strub_target_support_p (node->decl, report);
 
-  if (!report && strub_always_inline_p (node))
+  if (!report && (!result || strub_always_inline_p (node)))
     return result;
 
+  if (flag_split_stack)
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (node->decl),
+		"%qD is not eligible for %<strub%>"
+		" because %<-fsplit-stack%> is enabled",
+		node->decl);
+    }
+
   if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
     {
       result = false;
@@ -2417,6 +2454,10 @@ pass_ipa_strub::adjust_at_calls_call (cgraph_edge *e, int named_args,
 			 && (TREE_TYPE (gimple_call_arg (ocall, named_args))
 			     == get_pwmt ())));
 
+  if (!strub_target_support_p (TREE_TYPE (gimple_call_arg (ocall, named_args)),
+			       true))
+    return;
+
   /* If we're already within a strub context, pass on the incoming watermark
      pointer, and omit the enter and leave calls around the modified call, as an
      optimization, or as a means to satisfy a tail-call requirement.  */
diff --git a/gcc/target.def b/gcc/target.def
index 52b83e091b9..08218f3a42a 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4457,6 +4457,14 @@ otherwise return false.  The default implementation always returns true.",
  bool, (void),
  hook_bool_void_true)
 
+DEFHOOK
+(have_strub_support_for,
+ "Returns true if the target supports stack scrubbing for the given function\n\
+or type, otherwise return false.  The default implementation always returns\n\
+true.",
+ bool, (tree),
+ hook_bool_tree_true)
+
 DEFHOOK
 (have_speculation_safe_value,
 "This hook is used to determine the level of target support for\n\

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [gcc(refs/users/aoliva/heads/testme)] strub: enable conditional support
@ 2023-12-06 23:19 Alexandre Oliva
  0 siblings, 0 replies; 25+ messages in thread
From: Alexandre Oliva @ 2023-12-06 23:19 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:86ca86b32f8f7c826cc3767b7b172cd32cf85ff7

commit 86ca86b32f8f7c826cc3767b7b172cd32cf85ff7
Author: Alexandre Oliva <oliva@gnu.org>
Date:   Wed Dec 6 19:36:02 2023 -0300

    strub: enable conditional support

Diff:
---
 gcc/config/i386/i386.cc   |  4 ++++
 gcc/config/nvptx/nvptx.cc |  3 +++
 gcc/doc/tm.texi           |  6 ++++++
 gcc/doc/tm.texi.in        |  2 ++
 gcc/ipa-strub.cc          | 45 +++++++++++++++++++++++++++++++++++++++++++--
 gcc/target.def            |  8 ++++++++
 6 files changed, 66 insertions(+), 2 deletions(-)

diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 7c5cab4e2c6..f933c9c23c7 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -26658,6 +26658,10 @@ ix86_libm_function_max_error (unsigned cfn, machine_mode mode,
 #define TARGET_RUN_TARGET_SELFTESTS selftest::ix86_run_selftests
 #endif /* #if CHECKING_P */
 
+// ??? for testing only
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 #include "gt-i386.h"
diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc
index ae20802c879..3fb1deb70fd 100644
--- a/gcc/config/nvptx/nvptx.cc
+++ b/gcc/config/nvptx/nvptx.cc
@@ -7789,6 +7789,9 @@ nvptx_asm_output_def_from_decls (FILE *stream, tree name, tree value)
 #undef TARGET_LIBC_HAS_FUNCTION
 #define TARGET_LIBC_HAS_FUNCTION nvptx_libc_has_function
 
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-nvptx.h"
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 89a1735dd79..768ada0af52 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -3450,6 +3450,12 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@deftypefn {Target Hook} bool TARGET_HAVE_STRUB_SUPPORT_FOR (tree)
+Returns true if the target supports stack scrubbing for the given function
+or type, otherwise return false.  The default implementation always returns
+true.
+@end deftypefn
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index ebc1d3de5ca..4fe0805394e 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2686,6 +2686,8 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@hook TARGET_HAVE_STRUB_SUPPORT_FOR
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
index 293bec132b8..53a1bb650ae 100644
--- a/gcc/ipa-strub.cc
+++ b/gcc/ipa-strub.cc
@@ -60,6 +60,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-strub.h"
 #include "symtab-thunks.h"
 #include "attr-fnspec.h"
+#include "target.h"
 
 /* This file introduces two passes that, together, implement
    machine-independent stack scrubbing, strub for short.  It arranges
@@ -631,17 +632,53 @@ strub_always_inline_p (cgraph_node *node)
   return lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl));
 }
 
+/* Return TRUE iff the target has strub support for T, a function decl
+   or a type, and optionally REPORT thereasons for ineligibility.  */
+static inline bool
+strub_target_support_p (tree t, bool report = false)
+{
+  bool result = true;
+
+  if (!targetm.have_strub_support_for (node->decl))
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (node->decl),
+		"%qD is not eligible for %<strub%>"
+		" on the target system",
+		node->decl);
+    }
+
+  return result;
+}
+
 /* Return TRUE iff NODE is potentially eligible for any strub-enabled mode, and
    optionally REPORT the reasons for ineligibility.  */
 
 static inline bool
 can_strub_p (cgraph_node *node, bool report = false)
 {
-  bool result = true;
+  bool result = strub_target_support_p (node->decl, report);
 
-  if (!report && strub_always_inline_p (node))
+  if (!report && (!result || strub_always_inline_p (node)))
     return result;
 
+  if (flag_split_stack)
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (node->decl),
+		"%qD is not eligible for %<strub%>"
+		" because %<-fsplit-stack%> is enabled",
+		node->decl);
+    }
+
   if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
     {
       result = false;
@@ -2417,6 +2454,10 @@ pass_ipa_strub::adjust_at_calls_call (cgraph_edge *e, int named_args,
 			 && (TREE_TYPE (gimple_call_arg (ocall, named_args))
 			     == get_pwmt ())));
 
+  if (!strub_target_support_p (TREE_TYPE (gimple_call_arg (ocall, named_args)),
+			       true))
+    return;
+
   /* If we're already within a strub context, pass on the incoming watermark
      pointer, and omit the enter and leave calls around the modified call, as an
      optimization, or as a means to satisfy a tail-call requirement.  */
diff --git a/gcc/target.def b/gcc/target.def
index 52b83e091b9..08218f3a42a 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4457,6 +4457,14 @@ otherwise return false.  The default implementation always returns true.",
  bool, (void),
  hook_bool_void_true)
 
+DEFHOOK
+(have_strub_support_for,
+ "Returns true if the target supports stack scrubbing for the given function\n\
+or type, otherwise return false.  The default implementation always returns\n\
+true.",
+ bool, (tree),
+ hook_bool_tree_true)
+
 DEFHOOK
 (have_speculation_safe_value,
 "This hook is used to determine the level of target support for\n\

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [gcc(refs/users/aoliva/heads/testme)] strub: enable conditional support
@ 2023-12-06 23:05 Alexandre Oliva
  0 siblings, 0 replies; 25+ messages in thread
From: Alexandre Oliva @ 2023-12-06 23:05 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:de7cef7ccddfc72860b321e272ca06089c1c8b0b

commit de7cef7ccddfc72860b321e272ca06089c1c8b0b
Author: Alexandre Oliva <oliva@gnu.org>
Date:   Wed Dec 6 19:36:02 2023 -0300

    strub: enable conditional support

Diff:
---
 gcc/config/i386/i386.cc   |  4 ++++
 gcc/config/nvptx/nvptx.cc |  3 +++
 gcc/doc/tm.texi           |  6 ++++++
 gcc/doc/tm.texi.in        |  2 ++
 gcc/ipa-strub.cc          | 27 +++++++++++++++++++++++++++
 gcc/target.def            |  8 ++++++++
 6 files changed, 50 insertions(+)

diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 7c5cab4e2c6..f933c9c23c7 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -26658,6 +26658,10 @@ ix86_libm_function_max_error (unsigned cfn, machine_mode mode,
 #define TARGET_RUN_TARGET_SELFTESTS selftest::ix86_run_selftests
 #endif /* #if CHECKING_P */
 
+// ??? for testing only
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 #include "gt-i386.h"
diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc
index ae20802c879..3fb1deb70fd 100644
--- a/gcc/config/nvptx/nvptx.cc
+++ b/gcc/config/nvptx/nvptx.cc
@@ -7789,6 +7789,9 @@ nvptx_asm_output_def_from_decls (FILE *stream, tree name, tree value)
 #undef TARGET_LIBC_HAS_FUNCTION
 #define TARGET_LIBC_HAS_FUNCTION nvptx_libc_has_function
 
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-nvptx.h"
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 89a1735dd79..768ada0af52 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -3450,6 +3450,12 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@deftypefn {Target Hook} bool TARGET_HAVE_STRUB_SUPPORT_FOR (tree)
+Returns true if the target supports stack scrubbing for the given function
+or type, otherwise return false.  The default implementation always returns
+true.
+@end deftypefn
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index ebc1d3de5ca..4fe0805394e 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2686,6 +2686,8 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@hook TARGET_HAVE_STRUB_SUPPORT_FOR
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
index 293bec132b8..a13ef09b559 100644
--- a/gcc/ipa-strub.cc
+++ b/gcc/ipa-strub.cc
@@ -60,6 +60,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-strub.h"
 #include "symtab-thunks.h"
 #include "attr-fnspec.h"
+#include "target.h"
 
 /* This file introduces two passes that, together, implement
    machine-independent stack scrubbing, strub for short.  It arranges
@@ -639,9 +640,35 @@ can_strub_p (cgraph_node *node, bool report = false)
 {
   bool result = true;
 
+  if (!targetm.have_strub_support_for (node->decl))
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (node->decl),
+		"%qD is not eligible for %<strub%>"
+		" on the target system",
+		node->decl);
+    }
+
   if (!report && strub_always_inline_p (node))
     return result;
 
+  if (flag_split_stack)
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (node->decl),
+		"%qD is not eligible for %<strub%>"
+		" because %<-fsplit-stack%> is enabled",
+		node->decl);
+    }
+
   if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
     {
       result = false;
diff --git a/gcc/target.def b/gcc/target.def
index 52b83e091b9..08218f3a42a 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4457,6 +4457,14 @@ otherwise return false.  The default implementation always returns true.",
  bool, (void),
  hook_bool_void_true)
 
+DEFHOOK
+(have_strub_support_for,
+ "Returns true if the target supports stack scrubbing for the given function\n\
+or type, otherwise return false.  The default implementation always returns\n\
+true.",
+ bool, (tree),
+ hook_bool_tree_true)
+
 DEFHOOK
 (have_speculation_safe_value,
 "This hook is used to determine the level of target support for\n\

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [gcc(refs/users/aoliva/heads/testme)] strub: enable conditional support
@ 2023-12-06 23:04 Alexandre Oliva
  0 siblings, 0 replies; 25+ messages in thread
From: Alexandre Oliva @ 2023-12-06 23:04 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:cdfd2697af205121840cfeffa0aea6afb655315e

commit cdfd2697af205121840cfeffa0aea6afb655315e
Author: Alexandre Oliva <oliva@gnu.org>
Date:   Wed Dec 6 19:36:02 2023 -0300

    strub: enable conditional support

Diff:
---
 gcc/config/i386/i386.cc   |  4 ++++
 gcc/config/nvptx/nvptx.cc |  3 +++
 gcc/doc/tm.texi.in        |  2 ++
 gcc/ipa-strub.cc          | 27 +++++++++++++++++++++++++++
 gcc/target.def            |  8 ++++++++
 5 files changed, 44 insertions(+)

diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 7c5cab4e2c6..f933c9c23c7 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -26658,6 +26658,10 @@ ix86_libm_function_max_error (unsigned cfn, machine_mode mode,
 #define TARGET_RUN_TARGET_SELFTESTS selftest::ix86_run_selftests
 #endif /* #if CHECKING_P */
 
+// ??? for testing only
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 #include "gt-i386.h"
diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc
index ae20802c879..3fb1deb70fd 100644
--- a/gcc/config/nvptx/nvptx.cc
+++ b/gcc/config/nvptx/nvptx.cc
@@ -7789,6 +7789,9 @@ nvptx_asm_output_def_from_decls (FILE *stream, tree name, tree value)
 #undef TARGET_LIBC_HAS_FUNCTION
 #define TARGET_LIBC_HAS_FUNCTION nvptx_libc_has_function
 
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-nvptx.h"
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index ebc1d3de5ca..4fe0805394e 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2686,6 +2686,8 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@hook TARGET_HAVE_STRUB_SUPPORT_FOR
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
index 293bec132b8..a13ef09b559 100644
--- a/gcc/ipa-strub.cc
+++ b/gcc/ipa-strub.cc
@@ -60,6 +60,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-strub.h"
 #include "symtab-thunks.h"
 #include "attr-fnspec.h"
+#include "target.h"
 
 /* This file introduces two passes that, together, implement
    machine-independent stack scrubbing, strub for short.  It arranges
@@ -639,9 +640,35 @@ can_strub_p (cgraph_node *node, bool report = false)
 {
   bool result = true;
 
+  if (!targetm.have_strub_support_for (node->decl))
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (node->decl),
+		"%qD is not eligible for %<strub%>"
+		" on the target system",
+		node->decl);
+    }
+
   if (!report && strub_always_inline_p (node))
     return result;
 
+  if (flag_split_stack)
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (node->decl),
+		"%qD is not eligible for %<strub%>"
+		" because %<-fsplit-stack%> is enabled",
+		node->decl);
+    }
+
   if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
     {
       result = false;
diff --git a/gcc/target.def b/gcc/target.def
index 52b83e091b9..08218f3a42a 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4457,6 +4457,14 @@ otherwise return false.  The default implementation always returns true.",
  bool, (void),
  hook_bool_void_true)
 
+DEFHOOK
+(have_strub_support_for,
+ "Returns true if the target supports stack scrubbing for the given function\n\
+or type, otherwise return false.  The default implementation always returns\n\
+true.",
+ bool, (tree),
+ hook_bool_tree_true)
+
 DEFHOOK
 (have_speculation_safe_value,
 "This hook is used to determine the level of target support for\n\

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [gcc(refs/users/aoliva/heads/testme)] strub: enable conditional support
@ 2023-12-06 23:03 Alexandre Oliva
  0 siblings, 0 replies; 25+ messages in thread
From: Alexandre Oliva @ 2023-12-06 23:03 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:f7b21b07a2af938ab2d402b1e95db64dde415532

commit f7b21b07a2af938ab2d402b1e95db64dde415532
Author: Alexandre Oliva <oliva@gnu.org>
Date:   Wed Dec 6 19:36:02 2023 -0300

    strub: enable conditional support

Diff:
---
 gcc/config/i386/i386.cc   |  4 ++++
 gcc/config/nvptx/nvptx.cc |  3 +++
 gcc/doc/tm.texi.in        |  2 ++
 gcc/ipa-strub.cc          | 27 +++++++++++++++++++++++++++
 gcc/target.def            |  8 ++++++++
 5 files changed, 44 insertions(+)

diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 7c5cab4e2c6..f933c9c23c7 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -26658,6 +26658,10 @@ ix86_libm_function_max_error (unsigned cfn, machine_mode mode,
 #define TARGET_RUN_TARGET_SELFTESTS selftest::ix86_run_selftests
 #endif /* #if CHECKING_P */
 
+// ??? for testing only
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 #include "gt-i386.h"
diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc
index ae20802c879..3fb1deb70fd 100644
--- a/gcc/config/nvptx/nvptx.cc
+++ b/gcc/config/nvptx/nvptx.cc
@@ -7789,6 +7789,9 @@ nvptx_asm_output_def_from_decls (FILE *stream, tree name, tree value)
 #undef TARGET_LIBC_HAS_FUNCTION
 #define TARGET_LIBC_HAS_FUNCTION nvptx_libc_has_function
 
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-nvptx.h"
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index ebc1d3de5ca..9a23bb01b94 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2686,6 +2686,8 @@ in DWARF 2 debug information.  The default is zero.  A different value
 may reduce the size of debug information on some ports.
 @end defmac
 
+@hook HAVE_STRUB_SUPPORT_FOR
+
 @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
 If defined to nonzero, @code{__strub_leave} will allocate a dynamic
 array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
index 293bec132b8..a13ef09b559 100644
--- a/gcc/ipa-strub.cc
+++ b/gcc/ipa-strub.cc
@@ -60,6 +60,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-strub.h"
 #include "symtab-thunks.h"
 #include "attr-fnspec.h"
+#include "target.h"
 
 /* This file introduces two passes that, together, implement
    machine-independent stack scrubbing, strub for short.  It arranges
@@ -639,9 +640,35 @@ can_strub_p (cgraph_node *node, bool report = false)
 {
   bool result = true;
 
+  if (!targetm.have_strub_support_for (node->decl))
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (node->decl),
+		"%qD is not eligible for %<strub%>"
+		" on the target system",
+		node->decl);
+    }
+
   if (!report && strub_always_inline_p (node))
     return result;
 
+  if (flag_split_stack)
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (node->decl),
+		"%qD is not eligible for %<strub%>"
+		" because %<-fsplit-stack%> is enabled",
+		node->decl);
+    }
+
   if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
     {
       result = false;
diff --git a/gcc/target.def b/gcc/target.def
index 52b83e091b9..08218f3a42a 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4457,6 +4457,14 @@ otherwise return false.  The default implementation always returns true.",
  bool, (void),
  hook_bool_void_true)
 
+DEFHOOK
+(have_strub_support_for,
+ "Returns true if the target supports stack scrubbing for the given function\n\
+or type, otherwise return false.  The default implementation always returns\n\
+true.",
+ bool, (tree),
+ hook_bool_tree_true)
+
 DEFHOOK
 (have_speculation_safe_value,
 "This hook is used to determine the level of target support for\n\

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [gcc(refs/users/aoliva/heads/testme)] strub: enable conditional support
@ 2023-12-06 22:55 Alexandre Oliva
  0 siblings, 0 replies; 25+ messages in thread
From: Alexandre Oliva @ 2023-12-06 22:55 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:f8134d5fb8918da05c1b3fdaba0740d2cdc0540e

commit f8134d5fb8918da05c1b3fdaba0740d2cdc0540e
Author: Alexandre Oliva <oliva@gnu.org>
Date:   Wed Dec 6 19:36:02 2023 -0300

    strub: enable conditional support

Diff:
---
 gcc/config/i386/i386.cc   |  4 ++++
 gcc/config/nvptx/nvptx.cc |  3 +++
 gcc/ipa-strub.cc          | 27 +++++++++++++++++++++++++++
 gcc/target.def            |  8 ++++++++
 4 files changed, 42 insertions(+)

diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 7c5cab4e2c6..f933c9c23c7 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -26658,6 +26658,10 @@ ix86_libm_function_max_error (unsigned cfn, machine_mode mode,
 #define TARGET_RUN_TARGET_SELFTESTS selftest::ix86_run_selftests
 #endif /* #if CHECKING_P */
 
+// ??? for testing only
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 #include "gt-i386.h"
diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc
index ae20802c879..3fb1deb70fd 100644
--- a/gcc/config/nvptx/nvptx.cc
+++ b/gcc/config/nvptx/nvptx.cc
@@ -7789,6 +7789,9 @@ nvptx_asm_output_def_from_decls (FILE *stream, tree name, tree value)
 #undef TARGET_LIBC_HAS_FUNCTION
 #define TARGET_LIBC_HAS_FUNCTION nvptx_libc_has_function
 
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-nvptx.h"
diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
index 293bec132b8..a13ef09b559 100644
--- a/gcc/ipa-strub.cc
+++ b/gcc/ipa-strub.cc
@@ -60,6 +60,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-strub.h"
 #include "symtab-thunks.h"
 #include "attr-fnspec.h"
+#include "target.h"
 
 /* This file introduces two passes that, together, implement
    machine-independent stack scrubbing, strub for short.  It arranges
@@ -639,9 +640,35 @@ can_strub_p (cgraph_node *node, bool report = false)
 {
   bool result = true;
 
+  if (!targetm.have_strub_support_for (node->decl))
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (node->decl),
+		"%qD is not eligible for %<strub%>"
+		" on the target system",
+		node->decl);
+    }
+
   if (!report && strub_always_inline_p (node))
     return result;
 
+  if (flag_split_stack)
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (node->decl),
+		"%qD is not eligible for %<strub%>"
+		" because %<-fsplit-stack%> is enabled",
+		node->decl);
+    }
+
   if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
     {
       result = false;
diff --git a/gcc/target.def b/gcc/target.def
index 52b83e091b9..08218f3a42a 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4457,6 +4457,14 @@ otherwise return false.  The default implementation always returns true.",
  bool, (void),
  hook_bool_void_true)
 
+DEFHOOK
+(have_strub_support_for,
+ "Returns true if the target supports stack scrubbing for the given function\n\
+or type, otherwise return false.  The default implementation always returns\n\
+true.",
+ bool, (tree),
+ hook_bool_tree_true)
+
 DEFHOOK
 (have_speculation_safe_value,
 "This hook is used to determine the level of target support for\n\

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [gcc(refs/users/aoliva/heads/testme)] strub: enable conditional support
@ 2023-12-06 22:47 Alexandre Oliva
  0 siblings, 0 replies; 25+ messages in thread
From: Alexandre Oliva @ 2023-12-06 22:47 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:b451e34e642677d1f20c161582c7998c88ccf69d

commit b451e34e642677d1f20c161582c7998c88ccf69d
Author: Alexandre Oliva <oliva@gnu.org>
Date:   Wed Dec 6 19:36:02 2023 -0300

    strub: enable conditional support

Diff:
---
 gcc/config/nvptx/nvptx.cc |  3 +++
 gcc/ipa-strub.cc          | 27 +++++++++++++++++++++++++++
 gcc/target.def            |  7 +++++++
 3 files changed, 37 insertions(+)

diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc
index ae20802c879..3fb1deb70fd 100644
--- a/gcc/config/nvptx/nvptx.cc
+++ b/gcc/config/nvptx/nvptx.cc
@@ -7789,6 +7789,9 @@ nvptx_asm_output_def_from_decls (FILE *stream, tree name, tree value)
 #undef TARGET_LIBC_HAS_FUNCTION
 #define TARGET_LIBC_HAS_FUNCTION nvptx_libc_has_function
 
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-nvptx.h"
diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
index 293bec132b8..67b4c94db7d 100644
--- a/gcc/ipa-strub.cc
+++ b/gcc/ipa-strub.cc
@@ -60,6 +60,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-strub.h"
 #include "symtab-thunks.h"
 #include "attr-fnspec.h"
+#include "target.h"
 
 /* This file introduces two passes that, together, implement
    machine-independent stack scrubbing, strub for short.  It arranges
@@ -639,9 +640,35 @@ can_strub_p (cgraph_node *node, bool report = false)
 {
   bool result = true;
 
+  if (!targetm.have_strub_support_for (node->decl))
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (node->decl),
+		"%qD is not eligible for %<strub%>"
+		" on the target system",
+		node->decl);
+    }
+
   if (!report && strub_always_inline_p (node))
     return result;
 
+  if (flag_split_stack)
+    {
+      result = false;
+
+      if (!report)
+	return result;
+
+      sorry_at (DECL_SOURCE_LOCATION (node->decl),
+		"%qD is not eligible for %<strub%>"
+		" because -fsplit-stack is enabled",
+		node->decl);
+    }
+
   if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
     {
       result = false;
diff --git a/gcc/target.def b/gcc/target.def
index 52b83e091b9..11a8a797a05 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4457,6 +4457,13 @@ otherwise return false.  The default implementation always returns true.",
  bool, (void),
  hook_bool_void_true)
 
+DEFHOOK
+(have_strub_support_for,
+ "Returns true if the target supports stack scrubbing for the given function,\n\
+otherwise return false.  The default implementation always returns true.",
+ bool, (tree),
+ hook_bool_tree_true)
+
 DEFHOOK
 (have_speculation_safe_value,
 "This hook is used to determine the level of target support for\n\

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2023-12-07  1:48 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-12-07  0:02 [gcc(refs/users/aoliva/heads/testme)] strub: enable conditional support Alexandre Oliva
  -- strict thread matches above, loose matches on Subject: below --
2023-12-07  1:48 Alexandre Oliva
2023-12-07  1:45 Alexandre Oliva
2023-12-07  1:43 Alexandre Oliva
2023-12-07  1:42 Alexandre Oliva
2023-12-07  1:40 Alexandre Oliva
2023-12-07  1:39 Alexandre Oliva
2023-12-07  1:34 Alexandre Oliva
2023-12-07  1:26 Alexandre Oliva
2023-12-07  1:17 Alexandre Oliva
2023-12-07  0:19 Alexandre Oliva
2023-12-07  0:04 Alexandre Oliva
2023-12-06 23:58 Alexandre Oliva
2023-12-06 23:50 Alexandre Oliva
2023-12-06 23:34 Alexandre Oliva
2023-12-06 23:32 Alexandre Oliva
2023-12-06 23:26 Alexandre Oliva
2023-12-06 23:22 Alexandre Oliva
2023-12-06 23:20 Alexandre Oliva
2023-12-06 23:19 Alexandre Oliva
2023-12-06 23:05 Alexandre Oliva
2023-12-06 23:04 Alexandre Oliva
2023-12-06 23:03 Alexandre Oliva
2023-12-06 22:55 Alexandre Oliva
2023-12-06 22:47 Alexandre Oliva

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).