From d0de9e136f1dbe307e1d6ebb04b23131056cfa29 Mon Sep 17 00:00:00 2001 From: Dominik Vogt Date: Thu, 19 Dec 2013 12:00:43 +0000 Subject: s390.c (s390_hotpatch_trampoline_halfwords_default): New constant 2013-12-19 Dominik Vogt Andreas Krebbel * 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 Andreas Krebbel * 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 From-SVN: r206111 --- gcc/config/s390/s390-protos.h | 1 + gcc/config/s390/s390.c | 201 ++++++++++++++++++++++++++++++++++++++++++ gcc/config/s390/s390.h | 5 +- gcc/config/s390/s390.opt | 8 ++ 4 files changed, 214 insertions(+), 1 deletion(-) (limited to 'gcc/config') 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 *v = + (vec *) 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 -- cgit v1.1