summaryrefslogtreecommitdiff
path: root/gcc/config/s390/s390.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/s390/s390.cc')
-rw-r--r--gcc/config/s390/s390.cc245
1 files changed, 131 insertions, 114 deletions
diff --git a/gcc/config/s390/s390.cc b/gcc/config/s390/s390.cc
index d2af6d8813d..7c3bd6cbe7f 100644
--- a/gcc/config/s390/s390.cc
+++ b/gcc/config/s390/s390.cc
@@ -337,7 +337,7 @@ const struct s390_processor processor_table[] =
{ "z13", "z13", PROCESSOR_2964_Z13, &zEC12_cost, 11 },
{ "z14", "arch12", PROCESSOR_3906_Z14, &zEC12_cost, 12 },
{ "z15", "arch13", PROCESSOR_8561_Z15, &zEC12_cost, 13 },
- { "arch14", "arch14", PROCESSOR_ARCH14, &zEC12_cost, 14 },
+ { "z16", "arch14", PROCESSOR_3931_Z16, &zEC12_cost, 14 },
{ "native", "", PROCESSOR_NATIVE, NULL, 0 }
};
@@ -853,12 +853,6 @@ s390_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
error ("Builtin %qF requires z15 or higher", fndecl);
return const0_rtx;
}
-
- if ((bflags & B_NNPA) && !TARGET_NNPA)
- {
- error ("Builtin %qF requires arch14 or higher.", fndecl);
- return const0_rtx;
- }
}
if (fcode >= S390_OVERLOADED_BUILTIN_VAR_OFFSET
&& fcode < S390_ALL_BUILTIN_MAX)
@@ -8525,7 +8519,7 @@ s390_issue_rate (void)
case PROCESSOR_2827_ZEC12:
case PROCESSOR_2964_Z13:
case PROCESSOR_3906_Z14:
- case PROCESSOR_ARCH14:
+ case PROCESSOR_3931_Z16:
default:
return 1;
}
@@ -12148,29 +12142,26 @@ s390_function_arg_size (machine_mode mode, const_tree type)
gcc_unreachable ();
}
-/* Return true if a function argument of type TYPE and mode MODE
- is to be passed in a vector register, if available. */
+/* Return true if a variable of TYPE should be passed as single value
+ with type CODE. If STRICT_SIZE_CHECK_P is true the sizes of the
+ record type and the field type must match.
-bool
-s390_function_arg_vector (machine_mode mode, const_tree type)
+ The ABI says that record types with a single member are treated
+ just like that member would be. This function is a helper to
+ detect such cases. The function also produces the proper
+ diagnostics for cases where the outcome might be different
+ depending on the GCC version. */
+static bool
+s390_single_field_struct_p (enum tree_code code, const_tree type,
+ bool strict_size_check_p)
{
- if (!TARGET_VX_ABI)
- return false;
-
- if (s390_function_arg_size (mode, type) > 16)
- return false;
-
- /* No type info available for some library calls ... */
- if (!type)
- return VECTOR_MODE_P (mode);
-
- /* The ABI says that record types with a single member are treated
- just like that member would be. */
int empty_base_seen = 0;
+ bool zero_width_bf_skipped_p = false;
const_tree orig_type = type;
+
while (TREE_CODE (type) == RECORD_TYPE)
{
- tree field, single = NULL_TREE;
+ tree field, single_type = NULL_TREE;
for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
{
@@ -12187,48 +12178,108 @@ s390_function_arg_vector (machine_mode mode, const_tree type)
continue;
}
- if (single == NULL_TREE)
- single = TREE_TYPE (field);
+ if (DECL_FIELD_CXX_ZERO_WIDTH_BIT_FIELD (field))
+ {
+ zero_width_bf_skipped_p = true;
+ continue;
+ }
+
+ if (single_type == NULL_TREE)
+ single_type = TREE_TYPE (field);
else
return false;
}
- if (single == NULL_TREE)
+ if (single_type == NULL_TREE)
return false;
- else
- {
- /* If the field declaration adds extra byte due to
- e.g. padding this is not accepted as vector type. */
- if (int_size_in_bytes (single) <= 0
- || int_size_in_bytes (single) != int_size_in_bytes (type))
- return false;
- type = single;
- }
+
+ /* Reaching this point we have a struct with a single member and
+ zero or more zero-sized bit-fields which have been skipped in the
+ past. */
+
+ /* If ZERO_WIDTH_BF_SKIPPED_P then the struct will not be accepted. In case
+ we are not supposed to emit a warning exit early. */
+ if (zero_width_bf_skipped_p && !warn_psabi)
+ return false;
+
+ /* If the field declaration adds extra bytes due to padding this
+ is not accepted with STRICT_SIZE_CHECK_P. */
+ if (strict_size_check_p
+ && (int_size_in_bytes (single_type) <= 0
+ || int_size_in_bytes (single_type) != int_size_in_bytes (type)))
+ return false;
+
+ type = single_type;
}
- if (!VECTOR_TYPE_P (type))
+ if (TREE_CODE (type) != code)
return false;
- if (warn_psabi && empty_base_seen)
+ if (warn_psabi)
{
- static unsigned last_reported_type_uid;
unsigned uid = TYPE_UID (TYPE_MAIN_VARIANT (orig_type));
- if (uid != last_reported_type_uid)
- {
- const char *url = CHANGES_ROOT_URL "gcc-10/changes.html#empty_base";
- last_reported_type_uid = uid;
- if (empty_base_seen & 1)
- inform (input_location,
- "parameter passing for argument of type %qT when C++17 "
- "is enabled changed to match C++14 %{in GCC 10.1%}",
- orig_type, url);
- else
- inform (input_location,
- "parameter passing for argument of type %qT with "
- "%<[[no_unique_address]]%> members changed "
- "%{in GCC 10.1%}", orig_type, url);
+
+ if (empty_base_seen)
+ {
+ static unsigned last_reported_type_uid_empty_base;
+ if (uid != last_reported_type_uid_empty_base)
+ {
+ last_reported_type_uid_empty_base = uid;
+ const char *url = CHANGES_ROOT_URL "gcc-10/changes.html#empty_base";
+ if (empty_base_seen & 1)
+ inform (input_location,
+ "parameter passing for argument of type %qT when C++17 "
+ "is enabled changed to match C++14 %{in GCC 10.1%}",
+ orig_type, url);
+ else
+ inform (input_location,
+ "parameter passing for argument of type %qT with "
+ "%<[[no_unique_address]]%> members changed "
+ "%{in GCC 10.1%}", orig_type, url);
+ }
+ }
+
+ /* For C++ older GCCs ignored zero width bitfields and therefore
+ passed structs more often as single values than GCC 12 does.
+ So diagnostics are only required in cases where we do NOT
+ accept the struct to be passed as single value. */
+ if (zero_width_bf_skipped_p)
+ {
+ static unsigned last_reported_type_uid_zero_width;
+ if (uid != last_reported_type_uid_zero_width)
+ {
+ last_reported_type_uid_zero_width = uid;
+ inform (input_location,
+ "parameter passing for argument of type %qT with "
+ "zero-width bit fields members changed in GCC 12",
+ orig_type);
+ }
}
}
+
+ return !zero_width_bf_skipped_p;
+}
+
+
+/* Return true if a function argument of type TYPE and mode MODE
+ is to be passed in a vector register, if available. */
+
+static bool
+s390_function_arg_vector (machine_mode mode, const_tree type)
+{
+ if (!TARGET_VX_ABI)
+ return false;
+
+ if (s390_function_arg_size (mode, type) > 16)
+ return false;
+
+ /* No type info available for some library calls ... */
+ if (!type)
+ return VECTOR_MODE_P (mode);
+
+ if (!s390_single_field_struct_p (VECTOR_TYPE, type, true))
+ return false;
+
return true;
}
@@ -12249,64 +12300,9 @@ s390_function_arg_float (machine_mode mode, const_tree type)
if (!type)
return mode == SFmode || mode == DFmode || mode == SDmode || mode == DDmode;
- /* The ABI says that record types with a single member are treated
- just like that member would be. */
- int empty_base_seen = 0;
- const_tree orig_type = type;
- while (TREE_CODE (type) == RECORD_TYPE)
- {
- tree field, single = NULL_TREE;
-
- for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
- {
- if (TREE_CODE (field) != FIELD_DECL)
- continue;
- if (DECL_FIELD_ABI_IGNORED (field))
- {
- if (lookup_attribute ("no_unique_address",
- DECL_ATTRIBUTES (field)))
- empty_base_seen |= 2;
- else
- empty_base_seen |= 1;
- continue;
- }
-
- if (single == NULL_TREE)
- single = TREE_TYPE (field);
- else
- return false;
- }
-
- if (single == NULL_TREE)
- return false;
- else
- type = single;
- }
-
- if (TREE_CODE (type) != REAL_TYPE)
+ if (!s390_single_field_struct_p (REAL_TYPE, type, false))
return false;
- if (warn_psabi && empty_base_seen)
- {
- static unsigned last_reported_type_uid;
- unsigned uid = TYPE_UID (TYPE_MAIN_VARIANT (orig_type));
- if (uid != last_reported_type_uid)
- {
- const char *url = CHANGES_ROOT_URL "gcc-10/changes.html#empty_base";
- last_reported_type_uid = uid;
- if (empty_base_seen & 1)
- inform (input_location,
- "parameter passing for argument of type %qT when C++17 "
- "is enabled changed to match C++14 %{in GCC 10.1%}",
- orig_type, url);
- else
- inform (input_location,
- "parameter passing for argument of type %qT with "
- "%<[[no_unique_address]]%> members changed "
- "%{in GCC 10.1%}", orig_type, url);
- }
- }
-
return true;
}
@@ -14879,7 +14875,6 @@ s390_get_sched_attrmask (rtx_insn *insn)
mask |= S390_SCHED_ATTR_MASK_GROUPOFTWO;
break;
case PROCESSOR_8561_Z15:
- case PROCESSOR_ARCH14:
if (get_attr_z15_cracked (insn))
mask |= S390_SCHED_ATTR_MASK_CRACKED;
if (get_attr_z15_expanded (insn))
@@ -14891,6 +14886,18 @@ s390_get_sched_attrmask (rtx_insn *insn)
if (get_attr_z15_groupoftwo (insn))
mask |= S390_SCHED_ATTR_MASK_GROUPOFTWO;
break;
+ case PROCESSOR_3931_Z16:
+ if (get_attr_z16_cracked (insn))
+ mask |= S390_SCHED_ATTR_MASK_CRACKED;
+ if (get_attr_z16_expanded (insn))
+ mask |= S390_SCHED_ATTR_MASK_EXPANDED;
+ if (get_attr_z16_endgroup (insn))
+ mask |= S390_SCHED_ATTR_MASK_ENDGROUP;
+ if (get_attr_z16_groupalone (insn))
+ mask |= S390_SCHED_ATTR_MASK_GROUPALONE;
+ if (get_attr_z16_groupoftwo (insn))
+ mask |= S390_SCHED_ATTR_MASK_GROUPOFTWO;
+ break;
default:
gcc_unreachable ();
}
@@ -14927,7 +14934,6 @@ s390_get_unit_mask (rtx_insn *insn, int *units)
mask |= 1 << 3;
break;
case PROCESSOR_8561_Z15:
- case PROCESSOR_ARCH14:
*units = 4;
if (get_attr_z15_unit_lsu (insn))
mask |= 1 << 0;
@@ -14938,6 +14944,17 @@ s390_get_unit_mask (rtx_insn *insn, int *units)
if (get_attr_z15_unit_vfu (insn))
mask |= 1 << 3;
break;
+ case PROCESSOR_3931_Z16:
+ *units = 4;
+ if (get_attr_z16_unit_lsu (insn))
+ mask |= 1 << 0;
+ if (get_attr_z16_unit_fxa (insn))
+ mask |= 1 << 1;
+ if (get_attr_z16_unit_fxb (insn))
+ mask |= 1 << 2;
+ if (get_attr_z16_unit_vfu (insn))
+ mask |= 1 << 3;
+ break;
default:
gcc_unreachable ();
}
@@ -14951,7 +14968,7 @@ s390_is_fpd (rtx_insn *insn)
return false;
return get_attr_z13_unit_fpd (insn) || get_attr_z14_unit_fpd (insn)
- || get_attr_z15_unit_fpd (insn);
+ || get_attr_z15_unit_fpd (insn) || get_attr_z16_unit_fpd (insn);
}
static bool
@@ -14961,7 +14978,7 @@ s390_is_fxd (rtx_insn *insn)
return false;
return get_attr_z13_unit_fxd (insn) || get_attr_z14_unit_fxd (insn)
- || get_attr_z15_unit_fxd (insn);
+ || get_attr_z15_unit_fxd (insn) || get_attr_z16_unit_fxd (insn);
}
/* Returns TRUE if INSN is a long-running instruction. */