diff mbox

S/390: -mhotpatch v2

Message ID 20150127083319.GA23108@linux.vnet.ibm.com
State New
Headers show

Commit Message

Dominik Vogt Jan. 27, 2015, 8:33 a.m. UTC
The attached patch updates the -mhotpatch option and the hopatch
function attribute with (incompatible) new semantics.  Please
refer to the commit in the patch for details.

--

2015-01-27  Dominik Vogt  <vogt@linux.vnet.ibm.com>

        * doc/extend.texi: s/390: Update documentation of hotpatch attribute.
        * doc/invoke.texi (-mhotpatch): s/390: Update documentation of
        -mhotpatch= option.
        * config/s390/s390.opt (mhotpatch): s/390: Remove -mhotpatch and
        -mno-hotpatch options.  Change syntax of -mhotpatch= option.
        * config/s390/s390.c (s390_hotpatch_trampoline_halfwords_default):
        Renamed.
        (s390_hotpatch_trampoline_halfwords_max): Renamed.
        (s390_hotpatch_hw_max): New name.
        (s390_hotpatch_trampoline_halfwords): Renamed.
        (s390_hotpatch_hw_before_label): New name.
        (get_hotpatch_attribute): Removed.
        (s390_hotpatch_hw_after_label): New name.
        (s390_handle_hotpatch_attribute): Add second parameter to hotpatch
        attribute.
        (s390_attribute_table): Ditto.
        (s390_function_num_hotpatch_trampoline_halfwords): Renamed.
        (s390_function_num_hotpatch_hw): New name.
        Remove special handling of inline functions and hotpatching.
        Return number of nops before and after the function label.
        (s390_can_inline_p): Removed.
        (s390_asm_output_function_label): Emit a configurable number of nops
        after the function label.
        (s390_option_override): Update -mhotpatch= syntax and remove -mhotpatch.
        (TARGET_CAN_INLINE_P) Removed.
        (TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P): New.

Ciao

Dominik ^_^  ^_^
diff mbox

Patch

From 9123265bb1d6e325f4edc99a2d1f33a862b3ba53 Mon Sep 17 00:00:00 2001
From: Dominik Vogt <vogt@linux.vnet.ibm.com>
Date: Mon, 1 Dec 2014 15:59:42 +0100
Subject: [PATCH] S/390: -mhotpatch v2

Update the -mhotpatch option and the hotpatch function attribute to take
exactly two arguments.  The first is the number of halfwords to be filled with
two-byte-nops before the function label.  The second is the number of halfwords
to be filled with nops after the label (the biggest available nop instructions
are used).

Further changes are:

* Artificial functions and the main function are also patched.
* Functions selected for hotpatching can still be inlined.  It's the
  responsibility of the user to take care of this when patching, or to
  explicitly disable inlining.
---
 gcc/config/s390/s390.c                             | 227 ++++++++++++---------
 gcc/config/s390/s390.opt                           |  12 +-
 gcc/doc/extend.texi                                |  17 +-
 gcc/doc/invoke.texi                                |  16 +-
 gcc/testsuite/gcc.target/s390/hotpatch-1.c         |  14 +-
 gcc/testsuite/gcc.target/s390/hotpatch-10.c        |  15 +-
 gcc/testsuite/gcc.target/s390/hotpatch-11.c        |  12 +-
 gcc/testsuite/gcc.target/s390/hotpatch-12.c        |  14 +-
 gcc/testsuite/gcc.target/s390/hotpatch-13.c        |  17 ++
 gcc/testsuite/gcc.target/s390/hotpatch-14.c        |  17 ++
 gcc/testsuite/gcc.target/s390/hotpatch-15.c        |  17 ++
 gcc/testsuite/gcc.target/s390/hotpatch-16.c        |  17 ++
 gcc/testsuite/gcc.target/s390/hotpatch-17.c        |  17 ++
 gcc/testsuite/gcc.target/s390/hotpatch-18.c        |  16 ++
 gcc/testsuite/gcc.target/s390/hotpatch-19.c        |  23 +++
 gcc/testsuite/gcc.target/s390/hotpatch-2.c         |  12 +-
 gcc/testsuite/gcc.target/s390/hotpatch-20.c        |  20 ++
 gcc/testsuite/gcc.target/s390/hotpatch-3.c         |  10 +-
 gcc/testsuite/gcc.target/s390/hotpatch-4.c         |  18 +-
 gcc/testsuite/gcc.target/s390/hotpatch-5.c         |  15 +-
 gcc/testsuite/gcc.target/s390/hotpatch-6.c         |  13 +-
 gcc/testsuite/gcc.target/s390/hotpatch-7.c         |  13 +-
 gcc/testsuite/gcc.target/s390/hotpatch-8.c         |  24 +--
 gcc/testsuite/gcc.target/s390/hotpatch-9.c         |  15 +-
 gcc/testsuite/gcc.target/s390/hotpatch-compile-1.c |  24 +--
 .../gcc.target/s390/hotpatch-compile-10.c          |  12 ++
 .../gcc.target/s390/hotpatch-compile-11.c          |  12 ++
 .../gcc.target/s390/hotpatch-compile-12.c          |  12 ++
 .../gcc.target/s390/hotpatch-compile-13.c          |  29 +++
 .../gcc.target/s390/hotpatch-compile-14.c          |  11 +
 .../gcc.target/s390/hotpatch-compile-15.c          |  43 ++++
 .../gcc.target/s390/hotpatch-compile-16.c          |  24 +++
 gcc/testsuite/gcc.target/s390/hotpatch-compile-2.c |  24 +--
 gcc/testsuite/gcc.target/s390/hotpatch-compile-3.c |  24 +--
 gcc/testsuite/gcc.target/s390/hotpatch-compile-4.c |   2 +-
 gcc/testsuite/gcc.target/s390/hotpatch-compile-5.c |  23 +--
 gcc/testsuite/gcc.target/s390/hotpatch-compile-6.c |   4 +-
 gcc/testsuite/gcc.target/s390/hotpatch-compile-7.c |  66 +-----
 gcc/testsuite/gcc.target/s390/hotpatch-compile-8.c |  23 +--
 gcc/testsuite/gcc.target/s390/hotpatch-compile-9.c |  12 ++
 40 files changed, 532 insertions(+), 404 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-13.c
 create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-14.c
 create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-15.c
 create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-16.c
 create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-17.c
 create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-18.c
 create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-19.c
 create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-20.c
 create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-compile-10.c
 create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-compile-11.c
 create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-compile-12.c
 create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-compile-13.c
 create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-compile-14.c
 create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-compile-15.c
 create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-compile-16.c
 create mode 100644 gcc/testsuite/gcc.target/s390/hotpatch-compile-9.c

diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index ae3ffd1..c86189e 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -446,24 +446,9 @@  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;
-}
+static const int s390_hotpatch_hw_max = 1000000;
+static int s390_hotpatch_hw_before_label = 0;
+static int s390_hotpatch_hw_after_label = 0;
 
 /* Check whether the hotpatch attribute is applied to a function and, if it has
    an argument, the argument is valid.  */
@@ -472,32 +457,46 @@  static tree
 s390_handle_hotpatch_attribute (tree *node, tree name, tree args,
 				int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
 {
+  tree expr;
+  tree expr2;
+  int err;
+
   if (TREE_CODE (*node) != FUNCTION_DECL)
     {
       warning (OPT_Wattributes, "%qE attribute only applies to functions",
 	       name);
       *no_add_attrs = true;
     }
-  else if (args)
+  if (args != NULL && TREE_CHAIN (args) != NULL)
+    {
+      expr = TREE_VALUE (args);
+      expr2 = TREE_VALUE (TREE_CHAIN (args));
+    }
+  if (args == NULL || TREE_CHAIN (args) == NULL)
+    err = 1;
+  else if (TREE_CODE (expr) != INTEGER_CST
+	   || !INTEGRAL_TYPE_P (TREE_TYPE (expr))
+	   || wi::gtu_p (expr, s390_hotpatch_hw_max))
+    err = 1;
+  else if (TREE_CODE (expr2) != INTEGER_CST
+	   || !INTEGRAL_TYPE_P (TREE_TYPE (expr2))
+	   || wi::gtu_p (expr2, s390_hotpatch_hw_max))
+    err = 1;
+  else
+    err = 0;
+  if (err)
     {
-      tree expr = TREE_VALUE (args);
-
-      if (TREE_CODE (expr) != INTEGER_CST
-	  || !INTEGRAL_TYPE_P (TREE_TYPE (expr))
-	  || wi::gtu_p (expr, 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;
-	}
+      error ("requested %qE attribute is not a comma separated pair of"
+	     " non-negative integer constants or too large (max. %d)", name,
+	     s390_hotpatch_hw_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
+  { "hotpatch", 2, 2, true, false, false, s390_handle_hotpatch_attribute, false
   },
   /* End element.  */
   { NULL,        0, 0, false, false, false, NULL, false }
@@ -5208,53 +5207,51 @@  print_shift_count_operand (FILE *file, rtx op)
     fprintf (file, "(%s)", reg_names[REGNO (base)]);
 }
 
-/* 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. */
+/* Returns false if the function should not be made hotpatchable.
+   Otherwise it assigns the number of NOP halfwords to be emitted
+   before and after the function label to hw_before and hw_after.
+   Both must not be NULL.  */
 
-static int s390_function_num_hotpatch_trampoline_halfwords (tree decl,
-							    bool do_warn)
+static bool
+s390_function_num_hotpatch_hw (tree decl,
+			       int *hw_before,
+			       int *hw_after)
 {
   tree attr;
 
-  if (DECL_DECLARED_INLINE_P (decl)
-      || DECL_ARTIFICIAL (decl)
-      || MAIN_NAME_P (DECL_NAME (decl)))
+  *hw_before = 0;
+  *hw_after = 0;
+
+  attr = lookup_attribute ("hotpatch", DECL_ATTRIBUTES (decl));
+
+  /* Handle the arguments of the hotpatch attribute.  The values
+     specified via attribute might override the cmdline argument
+     values.  */
+  if (attr)
     {
-      /* - Explicitly inlined functions cannot be hotpatched.
-	 - Artificial functions need not be hotpatched.
-	 - Making the main function hotpatchable is useless. */
-      return -1;
+      tree args = TREE_VALUE (attr);
+
+      *hw_before = TREE_INT_CST_LOW (TREE_VALUE (args));
+      *hw_after = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (args)));
     }
-  attr = lookup_attribute ("hotpatch", DECL_ATTRIBUTES (decl));
-  if (attr || s390_hotpatch_trampoline_halfwords >= 0)
+  else
     {
-      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;
-	}
+      /* Use the values specified by the cmdline arguments.  */
+      *hw_before = s390_hotpatch_hw_before_label;
+      *hw_after = s390_hotpatch_hw_after_label;
     }
 
-  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)
+  if (*hw_before == 0 && *hw_after == 0)
     return false;
 
-  return default_target_can_inline_p (caller, callee);
+  if (decl_function_context (decl) != NULL_TREE)
+    {
+      warning_at (DECL_SOURCE_LOCATION (decl), OPT_mhotpatch_,
+		  "hotpatching is not compatible with nested functions");
+      return false;
+    }
+
+  return true;
 }
 
 /* Write the extra assembler code needed to declare a function properly.  */
@@ -5263,29 +5260,20 @@  void
 s390_asm_output_function_label (FILE *asm_out_file, const char *fname,
 				tree decl)
 {
-  int hotpatch_trampoline_halfwords = -1;
+  int hw_before, hw_after;
+  bool hotpatch_p = (decl
+		     ? s390_function_num_hotpatch_hw (decl,
+						      &hw_before, &hw_after)
+		     : false);
 
-  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 (DECL_SOURCE_LOCATION (decl), OPT_mhotpatch,
-		      "hotpatching is not compatible with nested functions");
-	  hotpatch_trampoline_halfwords = -1;
-	}
-    }
-
-  if (hotpatch_trampoline_halfwords > 0)
+  if (hotpatch_p)
     {
       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++)
+      for (i = 0; i < hw_before; 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
@@ -5297,10 +5285,30 @@  s390_asm_output_function_label (FILE *asm_out_file, const char *fname,
 
   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 a series of NOPs after the function label.  */
+  if (hotpatch_p)
+    {
+      while (hw_after > 0)
+	{
+	  if (hw_after >= 3 && TARGET_CPU_ZARCH)
+	    {
+	      asm_fprintf (asm_out_file, "\tbrcl\t\t0,0\n");
+	      hw_after -= 3;
+	    }
+	  else if (hw_after >= 2)
+	    {
+	      gcc_assert (hw_after == 2 || !TARGET_CPU_ZARCH);
+	      asm_fprintf (asm_out_file, "\tnop\t0\n");
+	      hw_after -= 2;
+	    }
+	  else
+	    {
+	      gcc_assert (hw_after == 1);
+	      asm_fprintf (asm_out_file, "\tnopr\t%%r7\n");
+	      hw_after -= 1;
+	    }
+	}
+    }
 }
 
 /* Output machine-dependent UNSPECs occurring in address constant X
@@ -11817,29 +11825,44 @@  s390_option_override (void)
       {
 	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)
+	      int val1;
+	      int val2;
+	      char s[256];
+	      char *t;
+
+	      strncpy (s, opt->arg, 256);
+	      s[255] = 0;
+	      t = strchr (s, ',');
+	      if (t != NULL)
+		{
+		  *t = 0;
+		  t++;
+		  val1 = integral_argument (s);
+		  val2 = integral_argument (t);
+		}
+	      else
+		{
+		  val1 = -1;
+		  val2 = -1;
+		}
+	      if (val1 == -1 || val2 == -1)
 		{
 		  /* argument is not a plain number */
-		  error ("argument to %qs should be a non-negative integer",
-			 "-mhotpatch=");
+		  error ("arguments to %qs should be non-negative integers",
+			 "-mhotpatch=n,m");
 		  break;
 		}
-	      else if (val > s390_hotpatch_trampoline_halfwords_max)
+	      else if (val1 > s390_hotpatch_hw_max
+		       || val2 > s390_hotpatch_hw_max)
 		{
 		  error ("argument to %qs is too large (max. %d)",
-			 "-mhotpatch=", s390_hotpatch_trampoline_halfwords_max);
+			 "-mhotpatch=n,m", s390_hotpatch_hw_max);
 		  break;
 		}
-	      s390_hotpatch_trampoline_halfwords = val;
+	      s390_hotpatch_hw_before_label = val1;
+	      s390_hotpatch_hw_after_label = val2;
 	      break;
 	    }
 	  default:
@@ -12224,8 +12247,8 @@  s390_use_by_pieces_infrastructure_p (unsigned HOST_WIDE_INT size,
 #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
+#undef TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P
+#define TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P hook_bool_const_tree_true
 
 #undef TARGET_SET_UP_BY_PROLOGUE
 #define TARGET_SET_UP_BY_PROLOGUE s300_set_up_by_prologue
diff --git a/gcc/config/s390/s390.opt b/gcc/config/s390/s390.opt
index 7780f87..c4b5269 100644
--- a/gcc/config/s390/s390.opt
+++ b/gcc/config/s390/s390.opt
@@ -96,13 +96,15 @@  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.
+Takes two non-negative integer numbers separated by a comma.
+Prepend the function label with the number of two-byte Nop
+instructions indicated by the first.  Append Nop instructions
+covering the number of halfwords indicated by the second after the
+label.  Nop instructions of the largest possible size are used
+(six, four or two bytes), beginning with the largest possible
+size.  Using 0 for both values disables hotpatching.
 
 mlong-double-128
 Target Report RejectNegative Negative(mlong-double-64) Mask(LONG_DOUBLE_128)
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 7178c9a..5fb9637 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -3353,16 +3353,19 @@  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})]
+@item hotpatch (@var{halfwords-before-function-label},@var{halfwords-after-function-label})
 @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.
+make GCC generate a ``hot-patching'' function prologue.  If the
+@option{-mhotpatch=} command-line option is used at the same time,
+the @code{hotpatch} attribute takes precedence.  The first of the
+two arguments specifies the number of halfwords to be added before
+the function label.  A second argument can be used to specify the
+number of halfwords to be added after the function label.  For
+both arguments the maximum allowed value is 1000000.
+
+If both ar guments are zero, hotpatching is disabled.
 
 @item naked
 @cindex function without a prologue/epilogue code
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 89edddb..df96847 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -968,7 +968,7 @@  See RS/6000 and PowerPC Options.
 -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 @gol
--mhotpatch[=@var{halfwords}] -mno-hotpatch}
+-mhotpatch=@var{halfwords},@var{halfwords}}
 
 @emph{Score Options}
 @gccoptlist{-meb -mel @gol
@@ -20917,17 +20917,17 @@  In order to be efficient the extra code makes the assumption that the stack star
 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
+@item -mhotpatch=@var{pre-halfwords},@var{post-halfwords}
 @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
-that are explicitly inline.
+Nop instructions (@var{pre-halfwords}, maximum 1000000).  After
+the label, 2 * @var{post-halfwords} bytes are appended, using the
+larges nop like instructions the architecture allows (maximum
+1000000).
+
+If both arguments are zero, hotpatching is disabled.
 
 This option can be overridden for individual functions with the
 @code{hotpatch} attribute.
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-1.c b/gcc/testsuite/gcc.target/s390/hotpatch-1.c
index b9d6139..e7e9058 100644
--- a/gcc/testsuite/gcc.target/s390/hotpatch-1.c
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-1.c
@@ -1,7 +1,7 @@ 
 /* Functional tests for the function hotpatching feature.  */
 
-/* { dg-do run } */
-/* { dg-options "-O3 -mzarch -mhotpatch --save-temps" } */
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch --save-temps" } */
 
 #include <stdio.h>
 
@@ -10,11 +10,7 @@  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 } } */
+/* { dg-final { scan-assembler-not "nopr\t%r7" } } */
+/* { dg-final { scan-assembler-not "nop\t0" } } */
+/* { dg-final { scan-assembler-not "brcl\t\t0,0" } } */
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-10.c b/gcc/testsuite/gcc.target/s390/hotpatch-10.c
index b91b347..78afb8c 100644
--- a/gcc/testsuite/gcc.target/s390/hotpatch-10.c
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-10.c
@@ -1,21 +1,16 @@ 
 /* Functional tests for the function hotpatching feature.  */
 
-/* { dg-do run } */
-/* { dg-options "-O3 -mzarch -mno-hotpatch --save-temps" } */
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch -mhotpatch=0,0 --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 } } */
+/* { dg-final { scan-assembler-not "nopr\t%r7" } } */
+/* { dg-final { scan-assembler-not "nop\t0" } } */
+/* { dg-final { scan-assembler-not "brcl\t\t0,0" } } */
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-11.c b/gcc/testsuite/gcc.target/s390/hotpatch-11.c
index 4916773..d4c577e 100644
--- a/gcc/testsuite/gcc.target/s390/hotpatch-11.c
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-11.c
@@ -1,7 +1,7 @@ 
 /* Functional tests for the function hotpatching feature.  */
 
-/* { dg-do run } */
-/* { dg-options "-O3 -mzarch -mhotpatch -mno-hotpatch --save-temps" } */
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch -mhotpatch=1,0 --save-temps" } */
 
 #include <stdio.h>
 
@@ -10,11 +10,7 @@  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 "nopr\t%r7" 1 } } */
 /* { dg-final { scan-assembler-not "nop\t0" } } */
+/* { dg-final { scan-assembler-not "brcl\t\t0,0" } } */
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-12.c b/gcc/testsuite/gcc.target/s390/hotpatch-12.c
index b3e9427..cc32e7c 100644
--- a/gcc/testsuite/gcc.target/s390/hotpatch-12.c
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-12.c
@@ -1,7 +1,7 @@ 
 /* Functional tests for the function hotpatching feature.  */
 
-/* { dg-do run } */
-/* { dg-options "-O3 -mzarch -mno-hotpatch -mhotpatch=1 --save-temps" } */
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch -mhotpatch=999,0 --save-temps" } */
 
 #include <stdio.h>
 
@@ -10,11 +10,7 @@  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 } } */
+/* { dg-final { scan-assembler-times "nopr\t%r7" 999 } } */
+/* { dg-final { scan-assembler-not "nop\t0" } } */
+/* { dg-final { scan-assembler-not "brcl\t\t0,0" } } */
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-13.c b/gcc/testsuite/gcc.target/s390/hotpatch-13.c
new file mode 100644
index 0000000..8d4adca
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-13.c
@@ -0,0 +1,17 @@ 
+/* Functional tests for the function hotpatching feature.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch --save-temps" } */
+
+#include <stdio.h>
+
+__attribute__ ((hotpatch(1,0)))
+void hp1(void)
+{
+  printf("hello, world!\n");
+}
+
+/* Check number of occurences of certain instructions.  */
+/* { dg-final { scan-assembler-times "nopr\t%r7" 1 } } */
+/* { dg-final { scan-assembler-not "nop\t0" } } */
+/* { dg-final { scan-assembler-not "brcl\t\t0,0" } } */
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-14.c b/gcc/testsuite/gcc.target/s390/hotpatch-14.c
new file mode 100644
index 0000000..f1b2325
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-14.c
@@ -0,0 +1,17 @@ 
+/* Functional tests for the function hotpatching feature.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch --save-temps" } */
+
+#include <stdio.h>
+
+__attribute__ ((hotpatch(0,2)))
+void hp1(void)
+{
+  printf("hello, world!\n");
+}
+
+/* Check number of occurences of certain instructions.  */
+/* { dg-final { scan-assembler-not "nopr\t%r7" } } */
+/* { dg-final { scan-assembler-times "nop\t0" 1 } } */
+/* { dg-final { scan-assembler-not "brcl\t\t0,0" } } */
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-15.c b/gcc/testsuite/gcc.target/s390/hotpatch-15.c
new file mode 100644
index 0000000..dd158d3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-15.c
@@ -0,0 +1,17 @@ 
+/* Functional tests for the function hotpatching feature.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch --save-temps" } */
+
+#include <stdio.h>
+
+__attribute__ ((hotpatch(1,2)))
+void hp1(void)
+{
+  printf("hello, world!\n");
+}
+
+/* Check number of occurences of certain instructions.  */
+/* { dg-final { scan-assembler-times "nopr\t%r7" 1 } } */
+/* { dg-final { scan-assembler-times "nop\t0" 1 } } */
+/* { dg-final { scan-assembler-not "brcl\t\t0,0" } } */
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-16.c b/gcc/testsuite/gcc.target/s390/hotpatch-16.c
new file mode 100644
index 0000000..592de2c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-16.c
@@ -0,0 +1,17 @@ 
+/* Functional tests for the function hotpatching feature.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch -mhotpatch=0,0 --save-temps" } */
+
+#include <stdio.h>
+
+__attribute__ ((hotpatch(1,2)))
+void hp1(void)
+{
+  printf("hello, world!\n");
+}
+
+/* Check number of occurences of certain instructions.  */
+/* { dg-final { scan-assembler-times "nopr\t%r7" 1 } } */
+/* { dg-final { scan-assembler-times "nop\t0" 1 } } */
+/* { dg-final { scan-assembler-not "brcl\t\t0,0" } } */
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-17.c b/gcc/testsuite/gcc.target/s390/hotpatch-17.c
new file mode 100644
index 0000000..a1c94db
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-17.c
@@ -0,0 +1,17 @@ 
+/* Functional tests for the function hotpatching feature.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch -mhotpatch=1,2 --save-temps" } */
+
+#include <stdio.h>
+
+__attribute__ ((hotpatch(0,0)))
+void hp1(void)
+{
+  printf("hello, world!\n");
+}
+
+/* Check number of occurences of certain instructions.  */
+/* { dg-final { scan-assembler-not "nopr\t%r7" } } */
+/* { dg-final { scan-assembler-not "nop\t0" } } */
+/* { dg-final { scan-assembler-not "brcl\t\t0,0" } } */
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-18.c b/gcc/testsuite/gcc.target/s390/hotpatch-18.c
new file mode 100644
index 0000000..19c5ce3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-18.c
@@ -0,0 +1,16 @@ 
+/* Functional tests for the function hotpatching feature.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch -mhotpatch=1,2 -mhotpatch=0,0 --save-temps" } */
+
+#include <stdio.h>
+
+void hp1(void)
+{
+  printf("hello, world!\n");
+}
+
+/* Check number of occurences of certain instructions.  */
+/* { dg-final { scan-assembler-not "nopr\t%r7" } } */
+/* { dg-final { scan-assembler-not "nop\t0" } } */
+/* { dg-final { scan-assembler-not "brcl\t\t0,0" } } */
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-19.c b/gcc/testsuite/gcc.target/s390/hotpatch-19.c
new file mode 100644
index 0000000..993d04d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-19.c
@@ -0,0 +1,23 @@ 
+/* Functional tests for the function hotpatching feature.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch -mhotpatch=1,2 --save-temps" } */
+
+#include <stdio.h>
+
+/* { dg-prune-output "always_inline function might not be inlinable" } */
+__attribute__ ((always_inline))
+static void hp2(void)
+{
+  printf("hello, world!\n");
+}
+
+void hp1(void)
+{
+  hp2();
+}
+
+/* Check number of occurences of certain instructions.  */
+/* { dg-final { scan-assembler-times "nopr\t%r7" 1 } } */
+/* { dg-final { scan-assembler-times "nop\t0" 1 } } */
+/* { dg-final { scan-assembler-not "brcl\t\t0,0" } } */
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-2.c b/gcc/testsuite/gcc.target/s390/hotpatch-2.c
index 6cc2944..af8f592 100644
--- a/gcc/testsuite/gcc.target/s390/hotpatch-2.c
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-2.c
@@ -1,7 +1,7 @@ 
 /* Functional tests for the function hotpatching feature.  */
 
-/* { dg-do run } */
-/* { dg-options "-O3 -mzarch -mhotpatch=1 --save-temps" } */
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch -mhotpatch=0,1 --save-temps" } */
 
 #include <stdio.h>
 
@@ -10,11 +10,7 @@  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 } } */
+/* { dg-final { scan-assembler-not "nop\t0" } } */
+/* { dg-final { scan-assembler-not "brcl\t\t0,0" } } */
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-20.c b/gcc/testsuite/gcc.target/s390/hotpatch-20.c
new file mode 100644
index 0000000..8872139
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-20.c
@@ -0,0 +1,20 @@ 
+/* Functional tests for the function hotpatching feature.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch --save-temps" } */
+
+#include <stdio.h>
+
+/* { dg-prune-output "always_inline function might not be inlinable" } */
+__attribute__ ((hotpatch(1,2)))
+__attribute__ ((always_inline))
+static void hp2(void)
+{
+  printf("hello, world!\n");
+}
+
+/* { dg-prune-output "called from here" } */
+void hp1(void)
+{
+  hp2();
+}
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-3.c b/gcc/testsuite/gcc.target/s390/hotpatch-3.c
index 9f0b2b7..4138d63 100644
--- a/gcc/testsuite/gcc.target/s390/hotpatch-3.c
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-3.c
@@ -1,7 +1,7 @@ 
 /* Functional tests for the function hotpatching feature.  */
 
-/* { dg-do run } */
-/* { dg-options "-O3 -mzarch -mhotpatch=0 --save-temps" } */
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch -mhotpatch=0,2 --save-temps" } */
 
 #include <stdio.h>
 
@@ -10,11 +10,7 @@  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 } } */
+/* { dg-final { scan-assembler-not "brcl\t\t0,0" } } */
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-4.c b/gcc/testsuite/gcc.target/s390/hotpatch-4.c
index c1dba20..afe1ad6 100644
--- a/gcc/testsuite/gcc.target/s390/hotpatch-4.c
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-4.c
@@ -1,26 +1,16 @@ 
 /* Functional tests for the function hotpatching feature.  */
 
-/* { dg-do run } */
-/* { dg-options "-O3 -mzarch -mhotpatch --save-temps" } */
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch -mhotpatch=0,3 --save-temps" } */
 
 #include <stdio.h>
 
-inline void hp1(void)
+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" } } */
+/* { dg-final { scan-assembler-times "brcl\t\t0,0" 1 } } */
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-5.c b/gcc/testsuite/gcc.target/s390/hotpatch-5.c
index ec267d6..ea3e29e 100644
--- a/gcc/testsuite/gcc.target/s390/hotpatch-5.c
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-5.c
@@ -1,21 +1,16 @@ 
 /* Functional tests for the function hotpatching feature.  */
 
-/* { dg-do run } */
-/* { dg-options "-O3 -mzarch -mhotpatch --save-temps" } */
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch -mhotpatch=0,4 --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 } } */
+/* { dg-final { scan-assembler-times "nopr\t%r7" 1 } } */
+/* { dg-final { scan-assembler-not "nop\t0" } } */
+/* { dg-final { scan-assembler-times "brcl\t\t0,0" 1 } } */
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-6.c b/gcc/testsuite/gcc.target/s390/hotpatch-6.c
index 5af090d..e91a2a6 100644
--- a/gcc/testsuite/gcc.target/s390/hotpatch-6.c
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-6.c
@@ -1,21 +1,16 @@ 
 /* Functional tests for the function hotpatching feature.  */
 
-/* { dg-do run } */
-/* { dg-options "-O3 -mzarch -mhotpatch --save-temps" } */
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch -mhotpatch=0,5 --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-not "nopr\t%r7" } } */
 /* { dg-final { scan-assembler-times "nop\t0" 1 } } */
+/* { dg-final { scan-assembler-times "brcl\t\t0,0" 1 } } */
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-7.c b/gcc/testsuite/gcc.target/s390/hotpatch-7.c
index e73a510..fe4b069 100644
--- a/gcc/testsuite/gcc.target/s390/hotpatch-7.c
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-7.c
@@ -1,21 +1,16 @@ 
 /* Functional tests for the function hotpatching feature.  */
 
-/* { dg-do run } */
-/* { dg-options "-O3 -mzarch -mhotpatch --save-temps" } */
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch -mhotpatch=0,6 --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 } } */
+/* { dg-final { scan-assembler-not "nop\t0" } } */
+/* { dg-final { scan-assembler-times "brcl\t\t0,0" 2 } } */
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-8.c b/gcc/testsuite/gcc.target/s390/hotpatch-8.c
index 399aa72..8edcfcc 100644
--- a/gcc/testsuite/gcc.target/s390/hotpatch-8.c
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-8.c
@@ -1,28 +1,16 @@ 
 /* Functional tests for the function hotpatching feature.  */
 
-/* { dg-do run } */
-/* { dg-options "-O3 -mzarch -mhotpatch --save-temps" } */
+/* { dg-do compile } */
+/* { dg-options "-O3 -mesa -m31 -mhotpatch=0,3 --save-temps" } */
 
 #include <stdio.h>
 
-__attribute__ ((hotpatch))
-inline void hp1(void)
+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" } } */
+/* { dg-final { scan-assembler-times "nopr\t%r7" 1 } } */
+/* { dg-final { scan-assembler-times "nop\t0" 1 } } */
+/* { dg-final { scan-assembler-not "brcl\t\t0,0" } } */
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-9.c b/gcc/testsuite/gcc.target/s390/hotpatch-9.c
index 5da6758..25b3771 100644
--- a/gcc/testsuite/gcc.target/s390/hotpatch-9.c
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-9.c
@@ -1,21 +1,16 @@ 
 /* Functional tests for the function hotpatching feature.  */
 
-/* { dg-do run } */
-/* { dg-options "-O3 -mzarch -mhotpatch=1 --save-temps" } */
+/* { dg-do compile } */
+/* { dg-options "-O3 -mesa -m31 -mhotpatch=0,4 --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 } } */
+/* { dg-final { scan-assembler-not "nopr\t%r7" } } */
+/* { dg-final { scan-assembler-times "nop\t0" 2 } } */
+/* { dg-final { scan-assembler-not "brcl\t\t0,0" } } */
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-compile-1.c b/gcc/testsuite/gcc.target/s390/hotpatch-compile-1.c
index 45a2cc5..d88e07e 100644
--- a/gcc/testsuite/gcc.target/s390/hotpatch-compile-1.c
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-compile-1.c
@@ -1,27 +1,11 @@ 
 /* 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" } */
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch -mhotpatch=-1,0" } */
 
 int main (void)
 {
   return 0;
 }
+
+/* { dg-excess-errors "argument to '-mhotpatch=' should be a non-negative integer" } */
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-compile-10.c b/gcc/testsuite/gcc.target/s390/hotpatch-compile-10.c
new file mode 100644
index 0000000..7bbdc37
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-compile-10.c
@@ -0,0 +1,12 @@ 
+/* Functional tests for the function hotpatching feature.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch" } */
+
+__attribute__((hotpatch(0,0,0)))
+int main (void)
+{
+  return 0;
+}
+
+/* { dg-excess-errors "argument to '-mhotpatch=' should be a non-negative integer" } */
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-compile-11.c b/gcc/testsuite/gcc.target/s390/hotpatch-compile-11.c
new file mode 100644
index 0000000..df01230
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-compile-11.c
@@ -0,0 +1,12 @@ 
+/* Functional tests for the function hotpatching feature.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch" } */
+
+__attribute__((hotpatch(a,0)))
+int main (void)
+{
+  return 0;
+}
+
+/* { dg-excess-errors "argument to '-mhotpatch=' should be a non-negative integer" } */
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-compile-12.c b/gcc/testsuite/gcc.target/s390/hotpatch-compile-12.c
new file mode 100644
index 0000000..d91e8fe
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-compile-12.c
@@ -0,0 +1,12 @@ 
+/* Functional tests for the function hotpatching feature.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch" } */
+
+__attribute__((hotpatch(0,a)))
+int main (void)
+{
+  return 0;
+}
+
+/* { dg-excess-errors "argument to '-mhotpatch=' should be a non-negative integer" } */
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-compile-13.c b/gcc/testsuite/gcc.target/s390/hotpatch-compile-13.c
new file mode 100644
index 0000000..72f13a0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-compile-13.c
@@ -0,0 +1,29 @@ 
+/* Functional tests for the function hotpatching feature.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch -mhotpatch=1000000,1000000" } */
+
+#include <stdio.h>
+
+void hp1(void)
+{
+  printf("hello, world!\n");
+}
+
+__attribute__ ((hotpatch(1000000,1000000)))
+void hp2(void)
+{
+  printf("hello, world!\n");
+}
+
+__attribute__ ((hotpatch(1000001,1000000)))
+void hp3(void)
+{ /* { dg-error " requested 'hotpatch' attribute is not a comma separated pair" } */
+  printf("hello, world!\n");
+}
+
+__attribute__ ((hotpatch(1000000,1000001)))
+void hp4(void)
+{ /* { dg-error " requested 'hotpatch' attribute is not a comma separated pair" } */
+  printf("hello, world!\n");
+}
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-compile-14.c b/gcc/testsuite/gcc.target/s390/hotpatch-compile-14.c
new file mode 100644
index 0000000..f3343d3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-compile-14.c
@@ -0,0 +1,11 @@ 
+/* Functional tests for the function hotpatching feature.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch -mhotpatch=1000001,1000000" } */
+
+viod main(void)
+{
+  return 0;
+}
+
+/* { dg-excess-errors "argument to '-mhotpatch=n,m' is too large" } */
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-compile-15.c b/gcc/testsuite/gcc.target/s390/hotpatch-compile-15.c
new file mode 100644
index 0000000..4ce7375
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-compile-15.c
@@ -0,0 +1,43 @@ 
+/* Functional tests for the function hotpatching feature.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch" } */
+
+/* { dg-prune-output "always_inline function might not be inlinable" } */
+/* { dg-prune-output "called from here" } */
+
+#include <stdio.h>
+
+__attribute__ ((hotpatch(1,2)))
+static void hp1(void)
+{
+  printf("hello, world!\n");
+}
+
+__attribute__ ((hotpatch(1,2)))
+static inline void hp2(void)
+{
+  printf("hello, world!\n");
+}
+
+__attribute__ ((hotpatch(0,0)))
+__attribute__ ((always_inline))
+static void hp3(void)
+{
+  printf("hello, world!\n");
+}
+
+__attribute__ ((hotpatch(1,2)))
+__attribute__ ((always_inline))
+static void hp4(void)
+{
+  printf("hello, world!\n");
+}
+
+void main(void)
+{
+  hp1();
+  hp2();
+  hp3();
+  hp4();
+}
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-compile-16.c b/gcc/testsuite/gcc.target/s390/hotpatch-compile-16.c
new file mode 100644
index 0000000..3c5c782
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-compile-16.c
@@ -0,0 +1,24 @@ 
+/* A warning will be issued when requesting hotpatching on a nested function.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch" } */
+
+typedef int (*fn_t)(void);
+
+fn_t hp1(void)
+{
+  __attribute__((hotpatch(0,0)))
+  int nested1(void)
+  { return 1; }
+
+  return nested1;
+}
+
+fn_t hp2(void)
+{
+  __attribute__ ((hotpatch(1,2)))
+  int nested2(void) /* { dg-warning "hotpatching is not compatible with nested functions" } */
+  { return 2; }
+
+  return nested2;
+}
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-compile-2.c b/gcc/testsuite/gcc.target/s390/hotpatch-compile-2.c
index 5947f56..95820e4 100644
--- a/gcc/testsuite/gcc.target/s390/hotpatch-compile-2.c
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-compile-2.c
@@ -1,27 +1,11 @@ 
 /* 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" } */
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch -mhotpatch=0,-1" } */
 
 int main (void)
 {
   return 0;
 }
+
+/* { dg-excess-errors "argument to '-mhotpatch=' should be a non-negative integer" } */
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-compile-3.c b/gcc/testsuite/gcc.target/s390/hotpatch-compile-3.c
index e0c7f6f..bbed975 100644
--- a/gcc/testsuite/gcc.target/s390/hotpatch-compile-3.c
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-compile-3.c
@@ -1,27 +1,11 @@ 
 /* 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" } */
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch -mhotpatch=0" } */
 
 int main (void)
 {
   return 0;
 }
+
+/* { dg-excess-errors "argument to '-mhotpatch=' should be a non-negative integer" } */
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-compile-4.c b/gcc/testsuite/gcc.target/s390/hotpatch-compile-4.c
index d9f1342..4d92659 100644
--- a/gcc/testsuite/gcc.target/s390/hotpatch-compile-4.c
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-compile-4.c
@@ -1,7 +1,7 @@ 
 /* Functional tests for the function hotpatching feature.  */
 
 /* { dg-do compile } */
-/* { dg-options "-O3 -mzarch -mhotpatch=-1" } */
+/* { dg-options "-O3 -mzarch -mhotpatch=0,0,0" } */
 
 int main (void)
 {
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-compile-5.c b/gcc/testsuite/gcc.target/s390/hotpatch-compile-5.c
index 53f7eac..46c9004 100644
--- a/gcc/testsuite/gcc.target/s390/hotpatch-compile-5.c
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-compile-5.c
@@ -1,28 +1,11 @@ 
 /* 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");
-}
+/* { dg-options "-O3 -mzarch -mhotpatch=a,0" } */
 
 int main (void)
 {
   return 0;
 }
+
+/* { dg-excess-errors "argument to '-mhotpatch=' should be a non-negative integer" } */
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-compile-6.c b/gcc/testsuite/gcc.target/s390/hotpatch-compile-6.c
index cb10b66..b28e205 100644
--- a/gcc/testsuite/gcc.target/s390/hotpatch-compile-6.c
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-compile-6.c
@@ -1,11 +1,11 @@ 
 /* Functional tests for the function hotpatching feature.  */
 
 /* { dg-do compile } */
-/* { dg-options "-O3 -mzarch -mhotpatch=1000001" } */
+/* { dg-options "-O3 -mzarch -mhotpatch=0,a" } */
 
 int main (void)
 {
   return 0;
 }
 
-/* { dg-excess-errors "argument to '-mhotpatch=' is too large .max. 1000000." } */
+/* { dg-excess-errors "argument to '-mhotpatch=' should be a non-negative integer" } */
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-compile-7.c b/gcc/testsuite/gcc.target/s390/hotpatch-compile-7.c
index 98ccb42..2080eb1 100644
--- a/gcc/testsuite/gcc.target/s390/hotpatch-compile-7.c
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-compile-7.c
@@ -1,68 +1,12 @@ 
 /* 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" } */
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch" } */
 
+__attribute__((hotpatch(-1,0)))
 int main (void)
 {
   return 0;
 }
+
+/* { dg-excess-errors "argument to '-mhotpatch=' should be a non-negative integer" } */
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-compile-8.c b/gcc/testsuite/gcc.target/s390/hotpatch-compile-8.c
index 489fc5d..46a38c8 100644
--- a/gcc/testsuite/gcc.target/s390/hotpatch-compile-8.c
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-compile-8.c
@@ -1,23 +1,12 @@ 
 /* Functional tests for the function hotpatching feature.  */
 
-/* { dg-do run } */
-/* { dg-options "-O3 -mzarch -mhotpatch" } */
-
-#include <stdio.h>
-
-int hp1(void)
-{
-  int nested1(void) /* { dg-warning "hotpatching is not compatible with nested functions" } */
-  { return 1; }
-
-  __attribute__ ((hotpatch))
-  int nested2(void) /* { dg-warning "hotpatching is not compatible with nested functions" } */
-  { return 1; }
-
-  return nested1() - nested2();
-}
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch" } */
 
+__attribute__((hotpatch(0,-1)))
 int main (void)
 {
-  return hp1();
+  return 0;
 }
+
+/* { dg-excess-errors "argument to '-mhotpatch=' should be a non-negative integer" } */
diff --git a/gcc/testsuite/gcc.target/s390/hotpatch-compile-9.c b/gcc/testsuite/gcc.target/s390/hotpatch-compile-9.c
new file mode 100644
index 0000000..24226eb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/hotpatch-compile-9.c
@@ -0,0 +1,12 @@ 
+/* Functional tests for the function hotpatching feature.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O3 -mzarch" } */
+
+__attribute__((hotpatch(0)))
+int main (void)
+{
+  return 0;
+}
+
+/* { dg-excess-errors "argument to '-mhotpatch=' should be a non-negative integer" } */
-- 
1.8.4.2