From b7f291267fb8c8afd1be38436308e4707dbe0c17 Mon Sep 17 00:00:00 2001
From: Dominik Vogt <vogt@de.ibm.com>
Date: Mon, 18 Nov 2013 15:41:46 +0000
Subject: [PATCH] S/390: Function hotpatching option and function attribute
---
gcc/config/s390/s390-protos.h | 1 +
gcc/config/s390/s390.c | 197 +++++++++++++++++++++
gcc/config/s390/s390.h | 5 +-
gcc/config/s390/s390.opt | 8 +
gcc/doc/extend.texi | 11 ++
gcc/doc/invoke.texi | 18 +-
gcc/testsuite/gcc.target/s390/hotpatch-1.c | 20 +++
gcc/testsuite/gcc.target/s390/hotpatch-10.c | 21 +++
gcc/testsuite/gcc.target/s390/hotpatch-11.c | 20 +++
gcc/testsuite/gcc.target/s390/hotpatch-12.c | 20 +++
gcc/testsuite/gcc.target/s390/hotpatch-2.c | 20 +++
gcc/testsuite/gcc.target/s390/hotpatch-3.c | 20 +++
gcc/testsuite/gcc.target/s390/hotpatch-4.c | 26 +++
gcc/testsuite/gcc.target/s390/hotpatch-5.c | 21 +++
gcc/testsuite/gcc.target/s390/hotpatch-6.c | 21 +++
gcc/testsuite/gcc.target/s390/hotpatch-7.c | 21 +++
gcc/testsuite/gcc.target/s390/hotpatch-8.c | 28 +++
gcc/testsuite/gcc.target/s390/hotpatch-9.c | 21 +++
gcc/testsuite/gcc.target/s390/hotpatch-compile-1.c | 27 +++
gcc/testsuite/gcc.target/s390/hotpatch-compile-2.c | 27 +++
gcc/testsuite/gcc.target/s390/hotpatch-compile-3.c | 27 +++
gcc/testsuite/gcc.target/s390/hotpatch-compile-4.c | 11 ++
gcc/testsuite/gcc.target/s390/hotpatch-compile-5.c | 28 +++
gcc/testsuite/gcc.target/s390/hotpatch-compile-6.c | 11 ++
gcc/testsuite/gcc.target/s390/hotpatch-compile-7.c | 68 +++++++
25 files changed, 696 insertions(+), 2 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-1.c
create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-10.c
create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-11.c
create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-12.c
create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-2.c
create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-3.c
create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-4.c
create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-5.c
create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-6.c
create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-7.c
create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-8.c
create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-9.c
create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-compile-1.c
create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-compile-2.c
create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-compile-3.c
create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-compile-4.c
create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-compile-5.c
create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-compile-6.c
create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-compile-7.c
@@ -110,5 +110,6 @@ extern bool s390_decompose_shift_count (rtx, rtx *, HOST_WIDE_INT *);
extern int s390_branch_condition_mask (rtx);
extern int s390_compare_and_branch_condition_mask (rtx);
extern bool s390_extzv_shift_ok (int, int, unsigned HOST_WIDE_INT);
+extern void s390_asm_output_function_label (FILE *, const char *, tree);
#endif /* RTX_CODE */
@@ -434,6 +434,65 @@ struct GTY(()) machine_function
bytes on a z10 (or higher) CPU. */
#define PREDICT_DISTANCE (TARGET_Z10 ? 384 : 2048)
+static const int s390_hotpatch_trampoline_halfwords_default = 12;
+static const int s390_hotpatch_trampoline_halfwords_max = 1000000;
+static int s390_hotpatch_trampoline_halfwords = -1;
+
+/* Return the argument of the given hotpatch attribute or the default value if
+ no argument is present. */
+
+static inline int
+get_hotpatch_attribute (tree hotpatch_attr)
+{
+ const_tree args;
+
+ args = TREE_VALUE (hotpatch_attr);
+
+ return (args) ?
+ TREE_INT_CST_LOW (TREE_VALUE (args)):
+ s390_hotpatch_trampoline_halfwords_default;
+}
+
+/* Check whether the hotpatch attribute is applied to a function and, if it has
+ an argument, the argument is valid. */
+
+static tree
+s390_handle_hotpatch_attribute (tree *node, tree name, tree args,
+ int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute only applies to functions",
+ name);
+ *no_add_attrs = true;
+ }
+ else if (args)
+ {
+ tree expr = TREE_VALUE (args);
+
+ if (TREE_CODE (expr) != INTEGER_CST
+ || !INTEGRAL_TYPE_P (TREE_TYPE (expr))
+ || TREE_INT_CST_HIGH (expr) != 0
+ || TREE_INT_CST_LOW (expr) > (unsigned int)
+ s390_hotpatch_trampoline_halfwords_max)
+ {
+ error ("requested %qE attribute is not a non-negative integer"
+ " constant or too large (max. %d)", name,
+ s390_hotpatch_trampoline_halfwords_max);
+ *no_add_attrs = true;
+ }
+ }
+
+ return NULL_TREE;
+}
+
+static const struct attribute_spec s390_attribute_table[] = {
+ { "hotpatch", 0, 1, true, false, false, s390_handle_hotpatch_attribute, false
+ },
+ /* End element. */
+ { NULL, 0, 0, false, false, false, NULL, false }
+};
+
/* Return the alignment for LABEL. We default to the -falign-labels
value except for the literal pool base label. */
int
@@ -1622,6 +1681,46 @@ s390_init_machine_status (void)
static void
s390_option_override (void)
{
+ unsigned int i;
+ cl_deferred_option *opt;
+ vec<cl_deferred_option> *v =
+ (vec<cl_deferred_option> *) s390_deferred_options;
+
+ if (v)
+ FOR_EACH_VEC_ELT (*v, i, opt)
+ {
+ switch (opt->opt_index)
+ {
+ case OPT_mhotpatch:
+ s390_hotpatch_trampoline_halfwords = (opt->value) ?
+ s390_hotpatch_trampoline_halfwords_default : -1;
+ break;
+ case OPT_mhotpatch_:
+ {
+ int val;
+
+ val = integral_argument (opt->arg);
+ if (val == -1)
+ {
+ /* argument is not a plain number */
+ error ("argument to %qs should be a non-negative integer",
+ "-mhotpatch=");
+ break;
+ }
+ else if (val > s390_hotpatch_trampoline_halfwords_max)
+ {
+ error ("argument to %qs is too large (max. %d)",
+ "-mhotpatch=", s390_hotpatch_trampoline_halfwords_max);
+ break;
+ }
+ s390_hotpatch_trampoline_halfwords = val;
+ break;
+ }
+ default:
+ gcc_unreachable ();
+ }
+ }
+
/* Set up function hooks. */
init_machine_status = s390_init_machine_status;
@@ -5347,6 +5446,98 @@ get_some_local_dynamic_name (void)
gcc_unreachable ();
}
+/* Returns -1 if the function should not be made hotpatchable. Otherwise it
+ returns a number >= 0 that is the desired size of the hotpatch trampoline
+ in halfwords. */
+
+static int s390_function_num_hotpatch_trampoline_halfwords (tree decl)
+{
+ tree attr;
+
+ gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
+ attr = lookup_attribute ("hotpatch", DECL_ATTRIBUTES (decl));
+ if (attr || s390_hotpatch_trampoline_halfwords >= 0)
+ {
+ if (MAIN_NAME_P (DECL_NAME (decl))
+ || DECL_DECLARED_INLINE_P (decl)
+ || lookup_attribute ("always_inline", DECL_ATTRIBUTES (decl))
+ || DECL_ARTIFICIAL (decl))
+ {
+ /* - Making the main function hotpatchable is useless.
+ - Explicitly inlined functions cannot be hotpatched.
+ - Artificial functions need not be hotpatched, so they may be
+ inlined.
+ */
+ return -1;
+ }
+ else
+ {
+ return (attr) ?
+ get_hotpatch_attribute (attr) : s390_hotpatch_trampoline_halfwords;
+ }
+ }
+
+ return -1;
+}
+
+/* Hook to determine if one function can safely inline another. */
+
+static bool
+s390_can_inline_p (tree caller, tree callee)
+{
+ if (s390_function_num_hotpatch_trampoline_halfwords (callee) >= 0)
+ return false;
+
+ return default_target_can_inline_p (caller, callee);
+}
+
+/* Write the extra assembler code needed to declare a function properly. */
+
+void
+s390_asm_output_function_label (FILE *asm_out_file, const char *fname,
+ tree decl)
+{
+ int hotpatch_trampoline_halfwords = -1;
+
+ if (decl)
+ {
+ hotpatch_trampoline_halfwords =
+ s390_function_num_hotpatch_trampoline_halfwords (decl);
+ if (hotpatch_trampoline_halfwords >= 0
+ && decl_function_context (decl) != NULL_TREE)
+ {
+ warning_at (0, DECL_SOURCE_LOCATION (decl),
+ "hotpatch_prologue is not compatible with nested"
+ " function");
+ hotpatch_trampoline_halfwords = -1;
+ }
+ }
+
+ if (hotpatch_trampoline_halfwords > 0)
+ {
+ int i;
+
+ /* Add a trampoline code area before the function label and initialize it
+ with two-byte nop instructions. This area can be overwritten with code
+ that jumps to a patched version of the function. */
+ for (i = 0; i < hotpatch_trampoline_halfwords; i++)
+ asm_fprintf (asm_out_file, "\tnopr\t%%r7\n");
+ /* Note: The function label must be aligned so that (a) the bytes of the
+ following nop do not cross a cacheline boundary, and (b) a jump address
+ (eight bytes for 64 bit targets, 4 bytes for 32 bit targets) can be
+ stored directly before the label without crossing a cacheline
+ boundary. All this is necessary to make sure the trampoline code can
+ be changed atomically. */
+ }
+
+ ASM_OUTPUT_LABEL (asm_out_file, fname);
+
+ /* Output a four-byte nop if hotpatching is enabled. This can be overwritten
+ atomically with a relative backwards jump to the trampoline area. */
+ if (hotpatch_trampoline_halfwords >= 0)
+ asm_fprintf (asm_out_file, "\tnop\t0\n");
+}
+
/* Output machine-dependent UNSPECs occurring in address constant X
in assembler syntax to stdio stream FILE. Returns true if the
constant X could be recognized, false otherwise. */
@@ -11920,6 +12111,12 @@ s390_loop_unroll_adjust (unsigned nunroll, struct loop *loop)
#undef TARGET_HARD_REGNO_SCRATCH_OK
#define TARGET_HARD_REGNO_SCRATCH_OK s390_hard_regno_scratch_ok
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE s390_attribute_table
+
+#undef TARGET_CAN_INLINE_P
+#define TARGET_CAN_INLINE_P s390_can_inline_p
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-s390.h"
@@ -217,7 +217,7 @@ enum processor_flags
#define STACK_BOUNDARY 64
/* Allocation boundary (in *bits*) for the code of a function. */
-#define FUNCTION_BOUNDARY 32
+#define FUNCTION_BOUNDARY 64
/* There is no point aligning anything to a rounder boundary than this. */
#define BIGGEST_ALIGNMENT 64
@@ -878,6 +878,9 @@ do { \
fputc ('\n', (FILE)); \
} while (0)
+#undef ASM_OUTPUT_FUNCTION_LABEL
+#define ASM_OUTPUT_FUNCTION_LABEL(FILE, NAME, DECL) \
+ s390_asm_output_function_label (FILE, NAME, DECL)
/* Miscellaneous parameters. */
@@ -96,6 +96,14 @@ mhard-float
Target Report RejectNegative Negative(msoft-float) InverseMask(SOFT_FLOAT, HARD_FLOAT)
Enable hardware floating point
+mhotpatch
+Target Report Var(s390_deferred_options) Defer
+Prepend the function label with 12 two-byte Nop instructions, and add a four byte Nop instruction after the label for hotpatching.
+
+mhotpatch=
+Target RejectNegative Report Joined Var(s390_deferred_options) Defer
+Prepend the function label with the given number of two-byte Nop instructions, and add a four byte Nop instruction after the label for hotpatching.
+
mlong-double-128
Target Report RejectNegative Negative(mlong-double-64) Mask(LONG_DOUBLE_128)
Use 128-bit long double
@@ -3259,6 +3259,17 @@ this function attribute to make GCC generate the ``hot-patching'' function
prologue used in Win32 API functions in Microsoft Windows XP Service Pack 2
and newer.
+@item hotpatch [(@var{prologue-halfwords})]
+@cindex @code{hotpatch} attribute
+
+On S/390 System z targets, you can use this function attribute to
+make GCC generate a ``hot-patching'' function prologue. The
+@code{hotpatch} has no effect on funtions that are explicitly
+inline. If the @option{-mhotpatch} or @option{-mno-hotpatch}
+command-line option is used at the same time, the @code{hotpatch}
+attribute takes precedence. If an argument is given, the maximum
+allowed value is 1000000.
+
@item naked
@cindex function without a prologue/epilogue code
Use this attribute on the ARM, AVR, MCORE, MSP430, NDS32, RL78, RX and SPU
@@ -933,7 +933,8 @@ See RS/6000 and PowerPC Options.
-msmall-exec -mno-small-exec -mmvcle -mno-mvcle @gol
-m64 -m31 -mdebug -mno-debug -mesa -mzarch @gol
-mtpf-trace -mno-tpf-trace -mfused-madd -mno-fused-madd @gol
--mwarn-framesize -mwarn-dynamicstack -mstack-size -mstack-guard}
+-mwarn-framesize -mwarn-dynamicstack -mstack-size -mstack-guard @gol
+-mhotpatch[=@var{halfwords}] -mno-hotpatch}
@emph{Score Options}
@gccoptlist{-meb -mel @gol
@@ -19721,6 +19722,21 @@ values have to be exact powers of 2 and @var{stack-size} has to be greater than
In order to be efficient the extra code makes the assumption that the stack starts
at an address aligned to the value given by @var{stack-size}.
The @var{stack-guard} option can only be used in conjunction with @var{stack-size}.
+
+@item -mhotpatch[=@var{halfwords}]
+@itemx -mno-hotpatch
+@opindex mhotpatch
+If the hotpatch option is enabled, a ``hot-patching'' function
+prologue is generated for all functions in the compilation unit.
+The funtion label is prepended with the given number of two-byte
+Nop instructions (@var{halfwords}, maximum 1000000) or 12 Nop
+instructions if no argument is present. Functions with a
+hot-patching prologue are never inlined automatically, and a
+hot-patching prologue is never generated for functions functions
+that are explicitly inline.
+
+This option can be overridden for individual functions with the
+@code{hotpatch} attribute.
@end table
@node Score Options
new file mode 100644
@@ -0,0 +1,20 @@
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mhotpatch" } */
+
+#include <stdio.h>
+
+static void hp1(void)
+{
+ printf("hello, world!\n");
+}
+
+int main (void)
+{
+ return 0;
+}
+
+/* Check number of occurences of certain instructions. */
+/* { dg-final { scan-assembler-times "nopr\t%r7" 12 } } */
+/* { dg-final { scan-assembler-times "nop\t0" 1 } } */
new file mode 100644
@@ -0,0 +1,21 @@
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mno-hotpatch" } */
+
+#include <stdio.h>
+
+__attribute__ ((hotpatch(2)))
+static void hp1(void)
+{
+ printf("hello, world!\n");
+}
+
+int main (void)
+{
+ return 0;
+}
+
+/* Check number of occurences of certain instructions. */
+/* { dg-final { scan-assembler-times "nopr\t%r7" 2 } } */
+/* { dg-final { scan-assembler-times "nop\t0" 1 } } */
new file mode 100644
@@ -0,0 +1,20 @@
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mhotpatch -mno-hotpatch" } */
+
+#include <stdio.h>
+
+static void hp1(void)
+{
+ printf("hello, world!\n");
+}
+
+int main (void)
+{
+ return 0;
+}
+
+/* Check number of occurences of certain instructions. */
+/* { dg-final { scan-assembler-not "nopr\t%r7" } } */
+/* { dg-final { scan-assembler-not "nop\t0" } } */
new file mode 100644
@@ -0,0 +1,20 @@
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mno-hotpatch -mhotpatch=1" } */
+
+#include <stdio.h>
+
+static void hp1(void)
+{
+ printf("hello, world!\n");
+}
+
+int main (void)
+{
+ return 0;
+}
+
+/* Check number of occurences of certain instructions. */
+/* { dg-final { scan-assembler-times "nopr\t%r7" 1 } } */
+/* { dg-final { scan-assembler-times "nop\t0" 1 } } */
new file mode 100644
@@ -0,0 +1,20 @@
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mhotpatch=1" } */
+
+#include <stdio.h>
+
+static void hp1(void)
+{
+ printf("hello, world!\n");
+}
+
+int main (void)
+{
+ return 0;
+}
+
+/* Check number of occurences of certain instructions. */
+/* { dg-final { scan-assembler-times "nopr\t%r7" 1 } } */
+/* { dg-final { scan-assembler-times "nop\t0" 1 } } */
new file mode 100644
@@ -0,0 +1,20 @@
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mhotpatch=0" } */
+
+#include <stdio.h>
+
+static void hp1(void)
+{
+ printf("hello, world!\n");
+}
+
+int main (void)
+{
+ return 0;
+}
+
+/* Check number of occurences of certain instructions. */
+/* { dg-final { scan-assembler-not "nopr\t%r7" } } */
+/* { dg-final { scan-assembler-times "nop\t0" 1 } } */
new file mode 100644
@@ -0,0 +1,26 @@
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mhotpatch" } */
+
+#include <stdio.h>
+
+static inline void hp1(void)
+{
+ printf("hello, world!\n");
+}
+
+__attribute__ ((always_inline))
+static void hp2(void) /* { dg-warning "always_inline function might not be inlinable" } */
+{
+ printf("hello, world!\n");
+}
+
+int main (void)
+{
+ return 0;
+}
+
+/* Check number of occurences of certain instructions. */
+/* { dg-final { scan-assembler-not "nopr\t%r7" } } */
+/* { dg-final { scan-assembler-not "nop\t0" } } */
new file mode 100644
@@ -0,0 +1,21 @@
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mhotpatch" } */
+
+#include <stdio.h>
+
+__attribute__ ((hotpatch))
+static void hp1(void)
+{
+ printf("hello, world!\n");
+}
+
+int main (void)
+{
+ return 0;
+}
+
+/* Check number of occurences of certain instructions. */
+/* { dg-final { scan-assembler-times "nopr\t%r7" 12 } } */
+/* { dg-final { scan-assembler-times "nop\t0" 1 } } */
new file mode 100644
@@ -0,0 +1,21 @@
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mhotpatch" } */
+
+#include <stdio.h>
+
+__attribute__ ((hotpatch(1)))
+static void hp1(void)
+{
+ printf("hello, world!\n");
+}
+
+int main (void)
+{
+ return 0;
+}
+
+/* Check number of occurences of certain instructions. */
+/* { dg-final { scan-assembler-times "nopr\t%r7" 1 } } */
+/* { dg-final { scan-assembler-times "nop\t0" 1 } } */
new file mode 100644
@@ -0,0 +1,21 @@
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mhotpatch" } */
+
+#include <stdio.h>
+
+__attribute__ ((hotpatch(0)))
+static void hp1(void)
+{
+ printf("hello, world!\n");
+}
+
+int main (void)
+{
+ return 0;
+}
+
+/* Check number of occurences of certain instructions. */
+/* { dg-final { scan-assembler-not "nopr\t%r7" } } */
+/* { dg-final { scan-assembler-times "nop\t0" 1 } } */
new file mode 100644
@@ -0,0 +1,28 @@
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mhotpatch" } */
+
+#include <stdio.h>
+
+__attribute__ ((hotpatch))
+static inline void hp1(void)
+{
+ printf("hello, world!\n");
+}
+
+__attribute__ ((hotpatch))
+__attribute__ ((always_inline))
+static void hp2(void) /* { dg-warning "always_inline function might not be inlinable" } */
+{
+ printf("hello, world!\n");
+}
+
+int main (void)
+{
+ return 0;
+}
+
+/* Check number of occurences of certain instructions. */
+/* { dg-final { scan-assembler-not "nopr\t%r7" } } */
+/* { dg-final { scan-assembler-not "nop\t0" } } */
new file mode 100644
@@ -0,0 +1,21 @@
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mhotpatch=1" } */
+
+#include <stdio.h>
+
+__attribute__ ((hotpatch(2)))
+static void hp1(void)
+{
+ printf("hello, world!\n");
+}
+
+int main (void)
+{
+ return 0;
+}
+
+/* Check number of occurences of certain instructions. */
+/* { dg-final { scan-assembler-times "nopr\t%r7" 2 } } */
+/* { dg-final { scan-assembler-times "nop\t0" 1 } } */
new file mode 100644
@@ -0,0 +1,27 @@
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mhotpatch" } */
+
+#include <stdio.h>
+
+static void hp1(void)
+{
+ printf("hello, world!\n");
+}
+
+static inline void hp2(void)
+{
+ printf("hello, world!\n");
+}
+
+__attribute__ ((always_inline))
+static void hp3(void) /* { dg-warning "always_inline function might not be inlinable" } */
+{
+ printf("hello, world!\n");
+}
+
+int main (void)
+{
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,27 @@
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mhotpatch=0" } */
+
+#include <stdio.h>
+
+static void hp1(void)
+{
+ printf("hello, world!\n");
+}
+
+static inline void hp2(void)
+{
+ printf("hello, world!\n");
+}
+
+__attribute__ ((always_inline))
+static void hp3(void) /* { dg-warning "always_inline function might not be inlinable" } */
+{
+ printf("hello, world!\n");
+}
+
+int main (void)
+{
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,27 @@
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mhotpatch=1" } */
+
+#include <stdio.h>
+
+static void hp1(void)
+{
+ printf("hello, world!\n");
+}
+
+static inline void hp2(void)
+{
+ printf("hello, world!\n");
+}
+
+__attribute__ ((always_inline))
+static void hp3(void) /* { dg-warning "always_inline function might not be inlinable" } */
+{
+ printf("hello, world!\n");
+}
+
+int main (void)
+{
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,11 @@
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mhotpatch=-1" } */
+
+int main (void)
+{
+ return 0;
+}
+
+/* { dg-excess-errors "argument to '-mhotpatch=' should be a non-negative integer" } */
new file mode 100644
@@ -0,0 +1,28 @@
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mhotpatch=1000000" } */
+
+#include <stdio.h>
+
+static void hp1(void)
+{
+ printf("hello, world!\n");
+}
+
+__attribute__ ((hotpatch(1000000)))
+static void hp2(void)
+{
+ printf("hello, world!\n");
+}
+
+__attribute__ ((hotpatch(1000001)))
+static void hp3(void)
+{ /* { dg-error "requested 'hotpatch' attribute is not a non-negative integer constant or too large .max. 1000000." } */
+ printf("hello, world!\n");
+}
+
+int main (void)
+{
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,11 @@
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mhotpatch=1000001" } */
+
+int main (void)
+{
+ return 0;
+}
+
+/* { dg-excess-errors "argument to '-mhotpatch=' is too large .max. 1000000." } */
new file mode 100644
@@ -0,0 +1,68 @@
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mno-hotpatch" } */
+
+#include <stdio.h>
+
+__attribute__ ((hotpatch))
+static void hp1(void)
+{
+ printf("hello, world!\n");
+}
+
+__attribute__ ((hotpatch))
+static inline void hp2(void)
+{
+ printf("hello, world!\n");
+}
+
+__attribute__ ((hotpatch))
+__attribute__ ((always_inline))
+static void hp3(void) /* { dg-warning "always_inline function might not be inlinable" } */
+{
+ printf("hello, world!\n");
+}
+
+__attribute__ ((hotpatch(0)))
+static void hp4(void)
+{
+ printf("hello, world!\n");
+}
+
+__attribute__ ((hotpatch(0)))
+static inline void hp5(void)
+{
+ printf("hello, world!\n");
+}
+
+__attribute__ ((hotpatch(0)))
+__attribute__ ((always_inline))
+static void hp6(void) /* { dg-warning "always_inline function might not be inlinable" } */
+{
+ printf("hello, world!\n");
+}
+
+__attribute__ ((hotpatch(1)))
+static void hp7(void)
+{
+ printf("hello, world!\n");
+}
+
+__attribute__ ((hotpatch(1)))
+static inline void hp8(void)
+{
+ printf("hello, world!\n");
+}
+
+__attribute__ ((hotpatch(1)))
+__attribute__ ((always_inline))
+static void hp9(void) /* { dg-warning "always_inline function might not be inlinable" } */
+{
+ printf("hello, world!\n");
+}
+
+int main (void)
+{
+ return 0;
+}
--
1.8.3.1