aboutsummaryrefslogtreecommitdiff
path: root/gcc/config
diff options
context:
space:
mode:
authorDominik Vogt <vogt@linux.vnet.ibm.com>2013-12-19 12:00:43 +0000
committerAndreas Krebbel <krebbel@gcc.gnu.org>2013-12-19 12:00:43 +0000
commitd0de9e136f1dbe307e1d6ebb04b23131056cfa29 (patch)
tree1db5b5b063976f159ca72b6bc57086c6c957a104 /gcc/config
parent2f62165dce49a99b72d729aae9f2d992a85c7765 (diff)
downloadgcc-d0de9e136f1dbe307e1d6ebb04b23131056cfa29.zip
gcc-d0de9e136f1dbe307e1d6ebb04b23131056cfa29.tar.gz
gcc-d0de9e136f1dbe307e1d6ebb04b23131056cfa29.tar.bz2
s390.c (s390_hotpatch_trampoline_halfwords_default): New constant
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 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 Co-Authored-By: Andreas Krebbel <Andreas.Krebbel@de.ibm.com> From-SVN: r206111
Diffstat (limited to 'gcc/config')
-rw-r--r--gcc/config/s390/s390-protos.h1
-rw-r--r--gcc/config/s390/s390.c201
-rw-r--r--gcc/config/s390/s390.h5
-rw-r--r--gcc/config/s390/s390.opt8
4 files changed, 214 insertions, 1 deletions
diff --git a/gcc/config/s390/s390-protos.h b/gcc/config/s390/s390-protos.h
index 67283df..7b43ed0 100644
--- a/gcc/config/s390/s390-protos.h
+++ b/gcc/config/s390/s390-protos.h
@@ -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 */
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index f9b7cd0..5319a69 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -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,102 @@ 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,
+ 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. */
@@ -11920,6 +12115,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"
diff --git a/gcc/config/s390/s390.h b/gcc/config/s390/s390.h
index bca18fe..75b642b 100644
--- a/gcc/config/s390/s390.h
+++ b/gcc/config/s390/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. */
diff --git a/gcc/config/s390/s390.opt b/gcc/config/s390/s390.opt
index 7dedb83..ef92f46 100644
--- a/gcc/config/s390/s390.opt
+++ b/gcc/config/s390/s390.opt
@@ -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