+2013-12-19 Dominik Vogt <vogt@linux.vnet.ibm.com>
+ Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
+
+ * config/s390/s390.c (s390_hotpatch_trampoline_halfwords_default): New
+ constant
+ (s390_hotpatch_trampoline_halfwords_max): New constant
+ (s390_hotpatch_trampoline_halfwords): New static variable
+ (get_hotpatch_attribute): New function
+ (s390_handle_hotpatch_attribute): New function
+ (s390_attribute_table): New target specific attribute table to implement
+ the hotpatch attribute
+ (s390_option_override): Parse hotpatch options
+ (s390_function_num_hotpatch_trampoline_halfwords): New function
+ (s390_can_inline_p): Implement target hook to
+ suppress hotpatching for explicitly inlined functions
+ (s390_asm_output_function_label): Generate hotpatch prologue
+ (TARGET_ATTRIBUTE_TABLE): Define to implement target attribute table
+ (TARGET_CAN_INLINE_P): Define to implement target hook
+ * config/s390/s390.opt (mhotpatch): New options -mhotpatch, -mhotpatch=
+ * config/s390/s390-protos.h (s390_asm_output_function_label): Add
+ prototype
+ * config/s390/s390.h (ASM_OUTPUT_FUNCTION_LABEL): Target specific
+ function label generation for hotpatching
+ (FUNCTION_BOUNDARY): Align functions to eight bytes
+ * doc/extend.texi: Document hotpatch attribute
+ * doc/invoke.texi: Document -mhotpatch option
+
2013-12-19 Ganesh Gopalasubramanian <Ganesh.Gopalasubramanian@amd.com>
* config/i386/i386.c: Include cfgloop.h.
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 */
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
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;
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,
+ bool do_warn)
+{
+ tree attr;
+
+ if (DECL_DECLARED_INLINE_P (decl)
+ || DECL_ARTIFICIAL (decl)
+ || MAIN_NAME_P (DECL_NAME (decl)))
+ {
+ /* - Explicitly inlined functions cannot be hotpatched.
+ - Artificial functions need not be hotpatched.
+ - Making the main function hotpatchable is useless. */
+ return -1;
+ }
+ attr = lookup_attribute ("hotpatch", DECL_ATTRIBUTES (decl));
+ if (attr || s390_hotpatch_trampoline_halfwords >= 0)
+ {
+ if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (decl)))
+ {
+ if (do_warn)
+ warning (OPT_Wattributes, "function %qE with the %qs attribute"
+ " is not hotpatchable", DECL_NAME (decl), "always_inline");
+ 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, false) >= 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, true);
+ 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. */
#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"
#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
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. */
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
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
-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
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
+2013-12-19 Dominik Vogt <vogt@linux.vnet.ibm.com>
+ Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
+
+ * gcc/testsuite/gcc.target/s390/hotpatch-1.c: New test
+ * gcc/testsuite/gcc.target/s390/hotpatch-2.c: New test
+ * gcc/testsuite/gcc.target/s390/hotpatch-3.c: New test
+ * gcc/testsuite/gcc.target/s390/hotpatch-4.c: New test
+ * gcc/testsuite/gcc.target/s390/hotpatch-5.c: New test
+ * gcc/testsuite/gcc.target/s390/hotpatch-6.c: New test
+ * gcc/testsuite/gcc.target/s390/hotpatch-7.c: New test
+ * gcc/testsuite/gcc.target/s390/hotpatch-8.c: New test
+ * gcc/testsuite/gcc.target/s390/hotpatch-9.c: New test
+ * gcc/testsuite/gcc.target/s390/hotpatch-10.c: New test
+ * gcc/testsuite/gcc.target/s390/hotpatch-11.c: New test
+ * gcc/testsuite/gcc.target/s390/hotpatch-12.c: New test
+ * gcc/testsuite/gcc.target/s390/hotpatch-compile-1.c: New test
+ * gcc/testsuite/gcc.target/s390/hotpatch-compile-2.c: New test
+ * gcc/testsuite/gcc.target/s390/hotpatch-compile-3.c: New test
+ * gcc/testsuite/gcc.target/s390/hotpatch-compile-4.c: New test
+ * gcc/testsuite/gcc.target/s390/hotpatch-compile-5.c: New test
+ * gcc/testsuite/gcc.target/s390/hotpatch-compile-6.c: New test
+ * gcc/testsuite/gcc.target/s390/hotpatch-compile-7.c: New test
+
2013-12-19 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
* c-c++-common/cilk-plus/SE/ef_error.c: Add fopenmp effective
--- /dev/null
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mhotpatch --save-temps" } */
+
+#include <stdio.h>
+
+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 } } */
--- /dev/null
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mno-hotpatch --save-temps" } */
+
+#include <stdio.h>
+
+__attribute__ ((hotpatch(2)))
+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 } } */
--- /dev/null
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mhotpatch -mno-hotpatch --save-temps" } */
+
+#include <stdio.h>
+
+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" } } */
--- /dev/null
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mno-hotpatch -mhotpatch=1 --save-temps" } */
+
+#include <stdio.h>
+
+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 } } */
--- /dev/null
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mhotpatch=1 --save-temps" } */
+
+#include <stdio.h>
+
+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 } } */
--- /dev/null
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mhotpatch=0 --save-temps" } */
+
+#include <stdio.h>
+
+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 } } */
--- /dev/null
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mhotpatch --save-temps" } */
+
+#include <stdio.h>
+
+inline void hp1(void)
+{
+ printf("hello, world!\n");
+}
+
+__attribute__ ((always_inline))
+void hp2(void) /* { dg-warning "always_inline function might not be inlinable" } */
+{
+ printf("hello, world!\n");
+} /* { dg-warning "function 'hp2' with the 'always_inline' attribute is not hotpatchable" } */
+
+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" } } */
--- /dev/null
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mhotpatch --save-temps" } */
+
+#include <stdio.h>
+
+__attribute__ ((hotpatch))
+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 } } */
--- /dev/null
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mhotpatch --save-temps" } */
+
+#include <stdio.h>
+
+__attribute__ ((hotpatch(1)))
+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 } } */
--- /dev/null
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mhotpatch --save-temps" } */
+
+#include <stdio.h>
+
+__attribute__ ((hotpatch(0)))
+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 } } */
--- /dev/null
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mhotpatch --save-temps" } */
+
+#include <stdio.h>
+
+__attribute__ ((hotpatch))
+inline void hp1(void)
+{
+ printf("hello, world!\n");
+}
+
+__attribute__ ((hotpatch))
+__attribute__ ((always_inline))
+void hp2(void) /* { dg-warning "always_inline function might not be inlinable" } */
+{
+ printf("hello, world!\n");
+} /* { dg-warning "function 'hp2' with the 'always_inline' attribute is not hotpatchable" } */
+
+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" } } */
--- /dev/null
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mhotpatch=1 --save-temps" } */
+
+#include <stdio.h>
+
+__attribute__ ((hotpatch(2)))
+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 } } */
--- /dev/null
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mhotpatch" } */
+
+#include <stdio.h>
+
+void hp1(void)
+{
+ printf("hello, world!\n");
+}
+
+inline void hp2(void)
+{
+ printf("hello, world!\n");
+}
+
+__attribute__ ((always_inline))
+void hp3(void) /* { dg-warning "always_inline function might not be inlinable" } */
+{
+ printf("hello, world!\n");
+} /* { dg-warning "function 'hp3' with the 'always_inline' attribute is not hotpatchable" } */
+
+int main (void)
+{
+ return 0;
+}
--- /dev/null
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mhotpatch=0" } */
+
+#include <stdio.h>
+
+void hp1(void)
+{
+ printf("hello, world!\n");
+}
+
+inline void hp2(void)
+{
+ printf("hello, world!\n");
+}
+
+__attribute__ ((always_inline))
+void hp3(void) /* { dg-warning "always_inline function might not be inlinable" } */
+{
+ printf("hello, world!\n");
+} /* { dg-warning "function 'hp3' with the 'always_inline' attribute is not hotpatchable" } */
+
+int main (void)
+{
+ return 0;
+}
--- /dev/null
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mhotpatch=1" } */
+
+#include <stdio.h>
+
+void hp1(void)
+{
+ printf("hello, world!\n");
+}
+
+inline void hp2(void)
+{
+ printf("hello, world!\n");
+}
+
+__attribute__ ((always_inline))
+void hp3(void) /* { dg-warning "always_inline function might not be inlinable" } */
+{
+ printf("hello, world!\n");
+} /* { dg-warning "function 'hp3' with the 'always_inline' attribute is not hotpatchable" } */
+
+int main (void)
+{
+ return 0;
+}
--- /dev/null
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch -mhotpatch=-1" } */
+
+int main (void)
+{
+ return 0;
+}
+
+/* { dg-excess-errors "argument to '-mhotpatch=' should be a non-negative integer" } */
--- /dev/null
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch -mhotpatch=1000000" } */
+
+#include <stdio.h>
+
+void hp1(void)
+{
+ printf("hello, world!\n");
+}
+
+__attribute__ ((hotpatch(1000000)))
+void hp2(void)
+{
+ printf("hello, world!\n");
+}
+
+__attribute__ ((hotpatch(1000001)))
+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;
+}
--- /dev/null
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch -mhotpatch=1000001" } */
+
+int main (void)
+{
+ return 0;
+}
+
+/* { dg-excess-errors "argument to '-mhotpatch=' is too large .max. 1000000." } */
--- /dev/null
+/* Functional tests for the function hotpatching feature. */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch -mno-hotpatch" } */
+
+#include <stdio.h>
+
+__attribute__ ((hotpatch))
+void hp1(void)
+{
+ printf("hello, world!\n");
+}
+
+__attribute__ ((hotpatch))
+inline void hp2(void)
+{
+ printf("hello, world!\n");
+}
+
+__attribute__ ((hotpatch))
+__attribute__ ((always_inline))
+void hp3(void) /* { dg-warning "always_inline function might not be inlinable" } */
+{
+ printf("hello, world!\n");
+} /* { dg-warning "function 'hp3' with the 'always_inline' attribute is not hotpatchable" } */
+
+__attribute__ ((hotpatch(0)))
+void hp4(void)
+{
+ printf("hello, world!\n");
+}
+
+__attribute__ ((hotpatch(0)))
+inline void hp5(void)
+{
+ printf("hello, world!\n");
+}
+
+__attribute__ ((hotpatch(0)))
+__attribute__ ((always_inline))
+void hp6(void) /* { dg-warning "always_inline function might not be inlinable" } */
+{
+ printf("hello, world!\n");
+} /* { dg-warning "function 'hp6' with the 'always_inline' attribute is not hotpatchable" } */
+
+__attribute__ ((hotpatch(1)))
+void hp7(void)
+{
+ printf("hello, world!\n");
+}
+
+__attribute__ ((hotpatch(1)))
+inline void hp8(void)
+{
+ printf("hello, world!\n");
+}
+
+__attribute__ ((hotpatch(1)))
+__attribute__ ((always_inline))
+void hp9(void) /* { dg-warning "always_inline function might not be inlinable" } */
+{
+ printf("hello, world!\n");
+} /* { dg-warning "function 'hp9' with the 'always_inline' attribute is not hotpatchable" } */
+
+int main (void)
+{
+ return 0;
+}