#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"
@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.
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.
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.
#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
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;
&& (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. */
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\
/* { 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. */
/* { 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. */
/* { 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. */
/* { 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. */
/* { dg-do compile } */
/* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
int __attribute__ ((__strub__)) var;
/* { 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. */
/* { 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. */
/* { 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
/* { 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. */
/* { 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
/* { dg-do compile } */
/* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
void __attribute__ ((__strub__ ("callable")))
apply_function (void *args)
/* { dg-do compile } */
/* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
extern void __attribute__ ((__strub__))
apply_function (void *args);
/* { dg-do compile } */
/* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
void __attribute__ ((__strub__))
apply_function (void *args)
/* { 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
/* { 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. */
/* { 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
/* { 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. */
/* { 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. */
/* { 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. */
/* { 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. */
/* { 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. */
/* { 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
/* { dg-do compile } */
/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
#include <stdarg.h>
/* { dg-do compile } */
/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
#include <stdarg.h>
/* { 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
/* { 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,
/* { 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. */
/* { 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. */
/* { 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. */
/* { 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. */
/* { 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. */
/* { 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
/* { 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
--- /dev/null
+/* { 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" } */
/* { dg-do compile } */
/* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
static int __attribute__ ((__strub__)) var;
/* { dg-do compile } */
/* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
static int __attribute__ ((__strub__)) var;
/* { dg-do compile } */
/* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
#include "strub-tail-O2.c"
/* { 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+. */
--- /dev/null
+/* { 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 } } } */
+}
--- /dev/null
+/* { 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 ();
+}
--- /dev/null
+/* { 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);
/* { dg-do compile } */
+/* { dg-require-effective-target strub } */
int __attribute__ ((strub)) x;
float __attribute__ ((strub)) f;
/* { 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
/* { dg-do compile } */
/* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
/* Check that impermissible (cross-strub-context) calls are reported. */
/* { 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
/* { 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
/* { 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,
/* { 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
/* { 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;
/* { 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. */
/* { 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. */
/* { 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. */
/* { dg-do compile } */
/* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
/* It would be desirable to issue at least warnings for these. */
/* { dg-do compile } */
/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
typedef void __attribute__ ((__strub__)) fntype ();
fntype (*ptr);
/* { dg-do compile } */
/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
typedef void __attribute__ ((__strub__)) fntype (int, int);
fntype (*ptr);
/* { dg-do compile } */
/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
typedef void __attribute__ ((__strub__)) fntype (int, int, ...);
fntype (*ptr);
/* { dg-do compile } */
/* { dg-options "-fstrub=relaxed" } */
+/* { dg-require-effective-target strub } */
inline void __attribute__ ((strub ("internal"), always_inline))
inl_int_ali (void)
/* { dg-do compile } */
/* { dg-options "-fstrub=all" } */
+/* { dg-require-effective-target strub } */
#include "strub-inlinable1.c"
/* { dg-do compile } */
/* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
typedef void ft (void);
typedef void ft2 (int, int);
/* { dg-do compile } */
/* { dg-options "-fstrub=relaxed -Wpedantic" } */
+/* { dg-require-effective-target strub } */
/* C++ does not warn about the partial incompatibilities.
/* { 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. */
/* { dg-do compile } */
/* { dg-options "-fstrub=relaxed" } */
+/* { dg-require-effective-target strub } */
/* This is strub-ptrfn2.c without -Wpedantic.
/* { 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. */
/* { 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
/* { 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. */
/* { 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
/* { 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
/* { 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. */
/* { 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. */
/* { 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
/* { dg-do run } */
/* { dg-options "-fstrub=at-calls" } */
/* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
#include "strub-run4.c"
/* { 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")))
/* { dg-do run } */
/* { dg-options "-fstrub=internal" } */
/* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
#include "strub-run4.c"
// { dg-do run }
// { dg-options "-fstrub=internal" }
+// { dg-require-effective-target strub }
// Check that we don't get extra copies.
/* { dg-do compile } */
/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
extern int __attribute__((__strub__)) initializer ();
/* { dg-do compile } */
/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
extern int __attribute__((__strub__)) initializer ();
/* { dg-do compile } */
/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
extern int __attribute__((__strub__)) initializer ();
-- { 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
-- { 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.
-- { 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;
-- { dg-do compile }
+-- { dg-require-effective-target strub }
procedure Strub_Disp is
package Foo is
-- { dg-do compile }
-- { dg-options "-fdump-ipa-strub" }
+-- { dg-require-effective-target strub }
-- Check that at-calls dispatching calls are transformed.
-- { 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.
-- { 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.
-- { 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.
-- { dg-do compile }
+-- { dg-require-effective-target strub }
-- Check that strub mode mismatches between overrider and overridden
-- subprograms are reported.
-- { dg-do compile }
-- { dg-options "-fdump-ipa-strub" }
+-- { dg-require-effective-target strub }
-- Check that at-calls dispatching calls to interfaces are transformed.
-- { 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
-- { dg-do compile }
+-- { dg-require-effective-target strub }
procedure Strub_Renm is
procedure P (X : Integer);
-- { dg-do compile }
-- { dg-options "-fstrub=relaxed -fdump-ipa-strub" }
+-- { dg-require-effective-target strub }
procedure Strub_Renm1 is
V : Integer := 0;
-- { dg-do compile }
-- { dg-options "-fstrub=strict -fdump-ipa-strub" }
+-- { dg-require-effective-target strub }
procedure Strub_Renm2 is
V : Integer := 0;
-- { 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
-- { dg-do compile }
+-- { dg-require-effective-target strub }
with Strub_Attr;
procedure Strub_Var1 is
} "$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.
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
extra_parts
cpu_type
get_gcc_base_ver
+HAVE_STRUB_SUPPORT
thread_header
tm_defines
tm_file
+{ $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"
# 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