summaryrefslogtreecommitdiff
path: root/gcc/config/s390/s390.c
diff options
context:
space:
mode:
authorbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2015-05-27 09:08:20 +0000
committerbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2015-05-27 09:08:20 +0000
commit131f3644ef87d5406722ee42b0989cb5783156fa (patch)
tree6f9c3016cb1696987ba7b0cc8c1b8c5400c6157d /gcc/config/s390/s390.c
parent851ccf1afd9b0e045e7dda2539a3dfa30c16bb64 (diff)
downloadgcc-131f3644ef87d5406722ee42b0989cb5783156fa.tar.gz
2015-05-27 Basile Starynkevitch <basile@starynkevitch.net>
{{merged with almost GCC 5. i.e. trunk r222129 from 2015-04-15, using svn merge -r219880:222129 svn+ssh://bstarynk@gcc.gnu.org/svn/gcc/trunk }} [gcc/] 2015-05-27 Basile Starynkevitch <basile@starynkevitch.net> {{merged with GCC 5, so}} * melt-runtime.h (melt_fatal_error, melt_fatal_error_at_line): Pass UNKNOWN_LOCATION for GCC 5. Re-indented with command: astyle --style=gnu -s2 * melt-runtime.cc: Re-indented with command: astyle --style=gnu -s2 (melt_branch_process_arguments, melt_ggcstart_callback) (melt_reserved_allocation_failure): Use melt_fatal_error instead of fatal_error. * melt/generated/meltrunsup-inc.cc: Manually edited for fatal_error. * melt/generated/warmelt-first.cc: Ditto. * melt/warmelt-first.melt (melt_assert_failure_fun): Ditto. * melt/warmelt-modes.melt (generate_runtypesupport_scanning): Ditto, in the emitted code. * Makefile.in: mention s-gtype instead of gt-melt-runtime.h in dependencies. (TEXI_GCCINT_FILES): Add meltgendoc.texi. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/melt-branch@223739 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/s390/s390.c')
-rw-r--r--gcc/config/s390/s390.c476
1 files changed, 324 insertions, 152 deletions
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index 6985fb77675..7d16048db8e 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -460,24 +460,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. */
@@ -486,32 +471,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 }
@@ -2407,16 +2406,29 @@ s390_float_const_zero_p (rtx value)
/* Implement TARGET_REGISTER_MOVE_COST. */
static int
-s390_register_move_cost (machine_mode mode ATTRIBUTE_UNUSED,
+s390_register_move_cost (machine_mode mode,
reg_class_t from, reg_class_t to)
{
- /* On s390, copy between fprs and gprs is expensive as long as no
- ldgr/lgdr can be used. */
- if ((!TARGET_Z10 || GET_MODE_SIZE (mode) != 8)
- && ((reg_classes_intersect_p (from, GENERAL_REGS)
- && reg_classes_intersect_p (to, FP_REGS))
- || (reg_classes_intersect_p (from, FP_REGS)
- && reg_classes_intersect_p (to, GENERAL_REGS))))
+ /* On s390, copy between fprs and gprs is expensive. */
+
+ /* It becomes somewhat faster having ldgr/lgdr. */
+ if (TARGET_Z10 && GET_MODE_SIZE (mode) == 8)
+ {
+ /* ldgr is single cycle. */
+ if (reg_classes_intersect_p (from, GENERAL_REGS)
+ && reg_classes_intersect_p (to, FP_REGS))
+ return 1;
+ /* lgdr needs 3 cycles. */
+ if (reg_classes_intersect_p (to, GENERAL_REGS)
+ && reg_classes_intersect_p (from, FP_REGS))
+ return 3;
+ }
+
+ /* Otherwise copying is done via memory. */
+ if ((reg_classes_intersect_p (from, GENERAL_REGS)
+ && reg_classes_intersect_p (to, FP_REGS))
+ || (reg_classes_intersect_p (from, FP_REGS)
+ && reg_classes_intersect_p (to, GENERAL_REGS)))
return 10;
return 1;
@@ -2429,7 +2441,7 @@ s390_memory_move_cost (machine_mode mode ATTRIBUTE_UNUSED,
reg_class_t rclass ATTRIBUTE_UNUSED,
bool in ATTRIBUTE_UNUSED)
{
- return 1;
+ return 2;
}
/* Compute a (partial) cost for rtx X. Return true if the complete
@@ -5222,53 +5234,36 @@ 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. */
+/* Assigns the number of NOP halfwords to be emitted before and after the
+ function label to *HW_BEFORE and *HW_AFTER. Both pointers must not be NULL.
+ If hotpatching is disabled for the function, the values are set to zero.
+*/
-static int s390_function_num_hotpatch_trampoline_halfwords (tree decl,
- bool do_warn)
+static void
+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)))
+ 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)
- return false;
-
- return default_target_can_inline_p (caller, callee);
}
/* Write the extra assembler code needed to declare a function properly. */
@@ -5277,44 +5272,46 @@ 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 (DECL_SOURCE_LOCATION (decl), OPT_mhotpatch,
- "hotpatching is not compatible with nested functions");
- hotpatch_trampoline_halfwords = -1;
- }
- }
+ int hw_before, hw_after;
- if (hotpatch_trampoline_halfwords > 0)
+ s390_function_num_hotpatch_hw (decl, &hw_before, &hw_after);
+ if (hw_before > 0)
{
+ unsigned int function_alignment;
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");
+ asm_fprintf (asm_out_file, "\tnopr\t%%r7"
+ "\t# pre-label NOPs for hotpatch (%d halfwords)\n",
+ hw_before);
+ for (i = 1; i < hw_before; i++)
+ fputs ("\tnopr\t%r7\n", asm_out_file);
+
/* 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. */
+ be changed atomically.
+ This alignment is done automatically using the FOUNCTION_BOUNDARY, but
+ if there are NOPs before the function label, the alignment is placed
+ before them. So it is necessary to duplicate the alignment after the
+ NOPs. */
+ function_alignment = MAX (8, DECL_ALIGN (decl) / BITS_PER_UNIT);
+ if (! DECL_USER_ALIGN (decl))
+ function_alignment = MAX (function_alignment,
+ (unsigned int) align_functions);
+ fputs ("\t# alignment for hotpatch\n", asm_out_file);
+ ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (function_alignment));
}
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");
+ if (hw_after > 0)
+ asm_fprintf (asm_out_file,
+ "\t# post-label NOPs for hotpatch (%d halfwords)\n",
+ hw_after);
}
/* Output machine-dependent UNSPECs occurring in address constant X
@@ -7789,7 +7786,8 @@ s390_frame_info (void)
cfun_frame_layout.frame_size = get_frame_size ();
if (!TARGET_64BIT && cfun_frame_layout.frame_size > 0x7fff0000)
- fatal_error ("total size of local variables exceeds architecture limit");
+ fatal_error (input_location,
+ "total size of local variables exceeds architecture limit");
if (!TARGET_PACKED_STACK)
{
@@ -9960,10 +9958,15 @@ enum s390_builtin
S390_BUILTIN_TX_NESTING_DEPTH,
S390_BUILTIN_TX_ASSIST,
- S390_BUILTIN_max
+ S390_BUILTIN_S390_SFPC,
+ S390_BUILTIN_S390_EFPC,
+
+ S390_BUILTIN_MAX
};
-static enum insn_code const code_for_builtin[S390_BUILTIN_max] = {
+tree s390_builtin_decls[S390_BUILTIN_MAX];
+
+static enum insn_code const code_for_builtin[S390_BUILTIN_MAX] = {
CODE_FOR_tbegin,
CODE_FOR_tbegin_nofloat,
CODE_FOR_tbegin_retry,
@@ -9973,7 +9976,10 @@ static enum insn_code const code_for_builtin[S390_BUILTIN_max] = {
CODE_FOR_tabort,
CODE_FOR_ntstg,
CODE_FOR_etnd,
- CODE_FOR_tx_assist
+ CODE_FOR_tx_assist,
+
+ CODE_FOR_s390_sfpc,
+ CODE_FOR_s390_efpc
};
static void
@@ -9986,44 +9992,68 @@ s390_init_builtins (void)
/* void foo (void) */
ftype = build_function_type_list (void_type_node, NULL_TREE);
- add_builtin_function ("__builtin_tbeginc", ftype, S390_BUILTIN_TBEGINC,
- BUILT_IN_MD, NULL, NULL_TREE);
+ s390_builtin_decls[S390_BUILTIN_TBEGINC] =
+ add_builtin_function ("__builtin_tbeginc", ftype, S390_BUILTIN_TBEGINC,
+ BUILT_IN_MD, NULL, NULL_TREE);
/* void foo (int) */
ftype = build_function_type_list (void_type_node, integer_type_node,
NULL_TREE);
- add_builtin_function ("__builtin_tabort", ftype,
- S390_BUILTIN_TABORT, BUILT_IN_MD, NULL, noreturn_attr);
- add_builtin_function ("__builtin_tx_assist", ftype,
- S390_BUILTIN_TX_ASSIST, BUILT_IN_MD, NULL, NULL_TREE);
+ s390_builtin_decls[S390_BUILTIN_TABORT] =
+ add_builtin_function ("__builtin_tabort", ftype,
+ S390_BUILTIN_TABORT, BUILT_IN_MD, NULL,
+ noreturn_attr);
+ s390_builtin_decls[S390_BUILTIN_TX_ASSIST] =
+ add_builtin_function ("__builtin_tx_assist", ftype,
+ S390_BUILTIN_TX_ASSIST, BUILT_IN_MD, NULL, NULL_TREE);
+
+ /* void foo (unsigned) */
+ ftype = build_function_type_list (void_type_node, unsigned_type_node,
+ NULL_TREE);
+ s390_builtin_decls[S390_BUILTIN_S390_SFPC] =
+ add_builtin_function ("__builtin_s390_sfpc", ftype,
+ S390_BUILTIN_S390_SFPC, BUILT_IN_MD, NULL, NULL_TREE);
/* int foo (void *) */
- ftype = build_function_type_list (integer_type_node, ptr_type_node, NULL_TREE);
- add_builtin_function ("__builtin_tbegin", ftype, S390_BUILTIN_TBEGIN,
- BUILT_IN_MD, NULL, returns_twice_attr);
- add_builtin_function ("__builtin_tbegin_nofloat", ftype,
- S390_BUILTIN_TBEGIN_NOFLOAT,
- BUILT_IN_MD, NULL, returns_twice_attr);
+ ftype = build_function_type_list (integer_type_node, ptr_type_node,
+ NULL_TREE);
+ s390_builtin_decls[S390_BUILTIN_TBEGIN] =
+ add_builtin_function ("__builtin_tbegin", ftype, S390_BUILTIN_TBEGIN,
+ BUILT_IN_MD, NULL, returns_twice_attr);
+ s390_builtin_decls[S390_BUILTIN_TBEGIN_NOFLOAT] =
+ add_builtin_function ("__builtin_tbegin_nofloat", ftype,
+ S390_BUILTIN_TBEGIN_NOFLOAT,
+ BUILT_IN_MD, NULL, returns_twice_attr);
/* int foo (void *, int) */
ftype = build_function_type_list (integer_type_node, ptr_type_node,
integer_type_node, NULL_TREE);
- add_builtin_function ("__builtin_tbegin_retry", ftype,
- S390_BUILTIN_TBEGIN_RETRY,
- BUILT_IN_MD,
- NULL, returns_twice_attr);
- add_builtin_function ("__builtin_tbegin_retry_nofloat", ftype,
- S390_BUILTIN_TBEGIN_RETRY_NOFLOAT,
- BUILT_IN_MD,
- NULL, returns_twice_attr);
+ s390_builtin_decls[S390_BUILTIN_TBEGIN_RETRY] =
+ add_builtin_function ("__builtin_tbegin_retry", ftype,
+ S390_BUILTIN_TBEGIN_RETRY,
+ BUILT_IN_MD,
+ NULL, returns_twice_attr);
+ s390_builtin_decls[S390_BUILTIN_TBEGIN_RETRY_NOFLOAT] =
+ add_builtin_function ("__builtin_tbegin_retry_nofloat", ftype,
+ S390_BUILTIN_TBEGIN_RETRY_NOFLOAT,
+ BUILT_IN_MD,
+ NULL, returns_twice_attr);
/* int foo (void) */
ftype = build_function_type_list (integer_type_node, NULL_TREE);
- add_builtin_function ("__builtin_tx_nesting_depth", ftype,
- S390_BUILTIN_TX_NESTING_DEPTH,
- BUILT_IN_MD, NULL, NULL_TREE);
- add_builtin_function ("__builtin_tend", ftype,
- S390_BUILTIN_TEND, BUILT_IN_MD, NULL, NULL_TREE);
+ s390_builtin_decls[S390_BUILTIN_TX_NESTING_DEPTH] =
+ add_builtin_function ("__builtin_tx_nesting_depth", ftype,
+ S390_BUILTIN_TX_NESTING_DEPTH,
+ BUILT_IN_MD, NULL, NULL_TREE);
+ s390_builtin_decls[S390_BUILTIN_TEND] =
+ add_builtin_function ("__builtin_tend", ftype,
+ S390_BUILTIN_TEND, BUILT_IN_MD, NULL, NULL_TREE);
+
+ /* unsigned foo (void) */
+ ftype = build_function_type_list (unsigned_type_node, NULL_TREE);
+ s390_builtin_decls[S390_BUILTIN_S390_EFPC] =
+ add_builtin_function ("__builtin_s390_efpc", ftype,
+ S390_BUILTIN_S390_EFPC, BUILT_IN_MD, NULL, NULL_TREE);
/* void foo (uint64_t *, uint64_t) */
if (TARGET_64BIT)
@@ -10031,12 +10061,13 @@ s390_init_builtins (void)
else
uint64_type = long_long_unsigned_type_node;
- ftype = build_function_type_list (void_type_node,
+ ftype = build_function_type_list (void_type_node,
build_pointer_type (uint64_type),
uint64_type, NULL_TREE);
- add_builtin_function ("__builtin_non_tx_store", ftype,
- S390_BUILTIN_NON_TX_STORE,
- BUILT_IN_MD, NULL, NULL_TREE);
+ s390_builtin_decls[S390_BUILTIN_NON_TX_STORE] =
+ add_builtin_function ("__builtin_non_tx_store", ftype,
+ S390_BUILTIN_NON_TX_STORE,
+ BUILT_IN_MD, NULL, NULL_TREE);
}
/* Expand an expression EXP that calls a built-in function,
@@ -10061,13 +10092,13 @@ s390_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
tree arg;
call_expr_arg_iterator iter;
- if (fcode >= S390_BUILTIN_max)
+ if (fcode >= S390_BUILTIN_MAX)
internal_error ("bad builtin fcode");
icode = code_for_builtin[fcode];
if (icode == 0)
internal_error ("bad builtin fcode");
- if (!TARGET_HTM)
+ if (!TARGET_HTM && fcode <= S390_BUILTIN_TX_ASSIST)
error ("Transactional execution builtins not enabled (-mhtm)\n");
/* Set a flag in the machine specific cfun part in order to support
@@ -10148,6 +10179,18 @@ s390_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
return const0_rtx;
}
+/* Return the decl for the target specific builtin with the function
+ code FCODE. */
+
+static tree
+s390_builtin_decl (unsigned fcode, bool initialized_p ATTRIBUTE_UNUSED)
+{
+ if (fcode >= S390_BUILTIN_MAX)
+ return error_mark_node;
+
+ return s390_builtin_decls[fcode];
+}
+
/* We call mcount before the function prologue. So a profiled leaf
function should stay a leaf function. */
@@ -11301,6 +11344,7 @@ static void
s390_reorg (void)
{
bool pool_overflow = false;
+ int hw_before, hw_after;
/* Make sure all splits have been performed; splits after
machine_dependent_reorg might confuse insn length counts. */
@@ -11436,6 +11480,40 @@ s390_reorg (void)
if (insn_added_p)
shorten_branches (get_insns ());
}
+
+ s390_function_num_hotpatch_hw (current_function_decl, &hw_before, &hw_after);
+ if (hw_after > 0)
+ {
+ rtx_insn *insn;
+
+ /* Insert NOPs for hotpatching. */
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ {
+ if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_FUNCTION_BEG)
+ break;
+ }
+ gcc_assert (insn);
+ /* Output a series of NOPs after the NOTE_INSN_FUNCTION_BEG. */
+ while (hw_after > 0)
+ {
+ if (hw_after >= 3 && TARGET_CPU_ZARCH)
+ {
+ insn = emit_insn_after (gen_nop_6_byte (), insn);
+ hw_after -= 3;
+ }
+ else if (hw_after >= 2)
+ {
+ insn = emit_insn_after (gen_nop_4_byte (), insn);
+ hw_after -= 2;
+ }
+ else
+ {
+ insn = emit_insn_after (gen_nop_2_byte (), insn);
+ hw_after -= 1;
+ }
+ }
+ gcc_assert (hw_after == 0);
+ }
}
/* Return true if INSN is a fp load insn writing register REGNO. */
@@ -11829,29 +11907,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:
@@ -12057,6 +12150,80 @@ s390_use_by_pieces_infrastructure_p (unsigned HOST_WIDE_INT size,
|| size == 4 || (TARGET_ZARCH && size == 8));
}
+/* Implement TARGET_ATOMIC_ASSIGN_EXPAND_FENV hook. */
+
+static void
+s390_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update)
+{
+ tree sfpc = s390_builtin_decls[S390_BUILTIN_S390_SFPC];
+ tree efpc = s390_builtin_decls[S390_BUILTIN_S390_EFPC];
+ tree call_efpc = build_call_expr (efpc, 0);
+ tree fenv_var = create_tmp_var (unsigned_type_node);
+
+#define FPC_EXCEPTION_MASK HOST_WIDE_INT_UC (0xf8000000)
+#define FPC_FLAGS_MASK HOST_WIDE_INT_UC (0x00f80000)
+#define FPC_DXC_MASK HOST_WIDE_INT_UC (0x0000ff00)
+#define FPC_EXCEPTION_MASK_SHIFT HOST_WIDE_INT_UC (24)
+#define FPC_FLAGS_SHIFT HOST_WIDE_INT_UC (16)
+#define FPC_DXC_SHIFT HOST_WIDE_INT_UC (8)
+
+ /* Generates the equivalent of feholdexcept (&fenv_var)
+
+ fenv_var = __builtin_s390_efpc ();
+ __builtin_s390_sfpc (fenv_var & mask) */
+ tree old_fpc = build2 (MODIFY_EXPR, unsigned_type_node, fenv_var, call_efpc);
+ tree new_fpc =
+ build2 (BIT_AND_EXPR, unsigned_type_node, fenv_var,
+ build_int_cst (unsigned_type_node,
+ ~(FPC_DXC_MASK | FPC_FLAGS_MASK |
+ FPC_EXCEPTION_MASK)));
+ tree set_new_fpc = build_call_expr (sfpc, 1, new_fpc);
+ *hold = build2 (COMPOUND_EXPR, void_type_node, old_fpc, set_new_fpc);
+
+ /* Generates the equivalent of feclearexcept (FE_ALL_EXCEPT)
+
+ __builtin_s390_sfpc (__builtin_s390_efpc () & mask) */
+ new_fpc = build2 (BIT_AND_EXPR, unsigned_type_node, call_efpc,
+ build_int_cst (unsigned_type_node,
+ ~(FPC_DXC_MASK | FPC_FLAGS_MASK)));
+ *clear = build_call_expr (sfpc, 1, new_fpc);
+
+ /* Generates the equivalent of feupdateenv (fenv_var)
+
+ old_fpc = __builtin_s390_efpc ();
+ __builtin_s390_sfpc (fenv_var);
+ __atomic_feraiseexcept ((old_fpc & FPC_FLAGS_MASK) >> FPC_FLAGS_SHIFT); */
+
+ old_fpc = create_tmp_var (unsigned_type_node);
+ tree store_old_fpc = build2 (MODIFY_EXPR, void_type_node,
+ old_fpc, call_efpc);
+
+ set_new_fpc = build_call_expr (sfpc, 1, fenv_var);
+
+ tree raise_old_except = build2 (BIT_AND_EXPR, unsigned_type_node, old_fpc,
+ build_int_cst (unsigned_type_node,
+ FPC_FLAGS_MASK));
+ raise_old_except = build2 (RSHIFT_EXPR, unsigned_type_node, raise_old_except,
+ build_int_cst (unsigned_type_node,
+ FPC_FLAGS_SHIFT));
+ tree atomic_feraiseexcept
+ = builtin_decl_implicit (BUILT_IN_ATOMIC_FERAISEEXCEPT);
+ raise_old_except = build_call_expr (atomic_feraiseexcept,
+ 1, raise_old_except);
+
+ *update = build2 (COMPOUND_EXPR, void_type_node,
+ build2 (COMPOUND_EXPR, void_type_node,
+ store_old_fpc, set_new_fpc),
+ raise_old_except);
+
+#undef FPC_EXCEPTION_MASK
+#undef FPC_FLAGS_MASK
+#undef FPC_DXC_MASK
+#undef FPC_EXCEPTION_MASK_SHIFT
+#undef FPC_FLAGS_SHIFT
+#undef FPC_DXC_SHIFT
+}
+
/* Initialize GCC target structure. */
#undef TARGET_ASM_ALIGNED_HI_OP
@@ -12101,6 +12268,8 @@ s390_use_by_pieces_infrastructure_p (unsigned HOST_WIDE_INT size,
#define TARGET_INIT_BUILTINS s390_init_builtins
#undef TARGET_EXPAND_BUILTIN
#define TARGET_EXPAND_BUILTIN s390_expand_builtin
+#undef TARGET_BUILTIN_DECL
+#define TARGET_BUILTIN_DECL s390_builtin_decl
#undef TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA
#define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA s390_output_addr_const_extra
@@ -12236,8 +12405,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
@@ -12246,6 +12415,9 @@ s390_use_by_pieces_infrastructure_p (unsigned HOST_WIDE_INT size,
#define TARGET_USE_BY_PIECES_INFRASTRUCTURE_P \
s390_use_by_pieces_infrastructure_p
+#undef TARGET_ATOMIC_ASSIGN_EXPAND_FENV
+#define TARGET_ATOMIC_ASSIGN_EXPAND_FENV s390_atomic_assign_expand_fenv
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-s390.h"