static void s390_encode_section_info (tree, rtx, int);
static bool s390_cannot_force_const_mem (rtx);
static rtx s390_delegitimize_address (rtx);
+static bool s390_return_in_memory (tree, tree);
static void s390_init_builtins (void);
static rtx s390_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
static void s390_output_mi_thunk (FILE *, tree, HOST_WIDE_INT,
#undef TARGET_DELEGITIMIZE_ADDRESS
#define TARGET_DELEGITIMIZE_ADDRESS s390_delegitimize_address
+#undef TARGET_RETURN_IN_MEMORY
+#define TARGET_RETURN_IN_MEMORY s390_return_in_memory
+
#undef TARGET_INIT_BUILTINS
#define TARGET_INIT_BUILTINS s390_init_builtins
#undef TARGET_EXPAND_BUILTIN
static bool
s390_function_arg_float (enum machine_mode mode, tree type)
{
+ int size = s390_function_arg_size (mode, type);
+ if (size > 8)
+ return false;
+
/* Soft-float changes the ABI: no floating-point registers are used. */
if (TARGET_SOFT_FLOAT)
return false;
return TREE_CODE (type) == REAL_TYPE;
}
+/* Return true if a function argument of type TYPE and mode MODE
+ is to be passed in an integer register, or a pair of integer
+ registers, if available. */
+
+static bool
+s390_function_arg_integer (enum machine_mode mode, tree type)
+{
+ int size = s390_function_arg_size (mode, type);
+ if (size > 8)
+ return false;
+
+ /* No type info available for some library calls ... */
+ if (!type)
+ return GET_MODE_CLASS (mode) == MODE_INT
+ || (TARGET_SOFT_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT);
+
+ /* We accept small integral (and similar) types. */
+ if (INTEGRAL_TYPE_P (type)
+ || POINTER_TYPE_P (type)
+ || TREE_CODE (type) == OFFSET_TYPE
+ || (TARGET_SOFT_FLOAT && TREE_CODE (type) == REAL_TYPE))
+ return true;
+
+ /* We also accept structs of size 1, 2, 4, 8 that are not
+ passed in floating-point registers. */
+ if (AGGREGATE_TYPE_P (type)
+ && exact_log2 (size) >= 0
+ && !s390_function_arg_float (mode, type))
+ return true;
+
+ return false;
+}
+
/* Return 1 if a function argument of type TYPE and mode MODE
is to be passed by reference. The ABI specifies that only
structures of size 1, 2, 4, or 8 bytes are passed by value,
s390_function_arg_pass_by_reference (enum machine_mode mode, tree type)
{
int size = s390_function_arg_size (mode, type);
+ if (size > 8)
+ return true;
if (type)
{
- if (AGGREGATE_TYPE_P (type) &&
- size != 1 && size != 2 && size != 4 && size != 8
- && !s390_function_arg_float (mode, type))
+ if (AGGREGATE_TYPE_P (type) && exact_log2 (size) < 0)
return 1;
- if (TREE_CODE (type) == COMPLEX_TYPE)
+ if (TREE_CODE (type) == COMPLEX_TYPE
+ || TREE_CODE (type) == VECTOR_TYPE)
return 1;
}
{
cum->fprs += 1;
}
- else
+ else if (s390_function_arg_integer (mode, type))
{
int size = s390_function_arg_size (mode, type);
cum->gprs += ((size + UNITS_PER_WORD-1) / UNITS_PER_WORD);
}
+ else
+ abort ();
}
/* Define where to put the arguments to a function.
else
return gen_rtx (REG, mode, cum->fprs + 16);
}
- else
+ else if (s390_function_arg_integer (mode, type))
{
int size = s390_function_arg_size (mode, type);
int n_gprs = (size + UNITS_PER_WORD-1) / UNITS_PER_WORD;
else
return gen_rtx (REG, mode, cum->gprs + 2);
}
+
+ /* After the real arguments, expand_call calls us once again
+ with a void_type_node type. Whatever we return here is
+ passed as operand 2 to the call expanders.
+
+ We don't need this feature ... */
+ else if (type == void_type_node)
+ return const0_rtx;
+
+ abort ();
+}
+
+/* Return true if return values of type TYPE should be returned
+ in a memory buffer whose address is passed by the caller as
+ hidden first argument. */
+
+static bool
+s390_return_in_memory (tree type, tree fundecl ATTRIBUTE_UNUSED)
+{
+ /* We accept small integral (and similar) types. */
+ if (INTEGRAL_TYPE_P (type)
+ || POINTER_TYPE_P (type)
+ || TREE_CODE (type) == OFFSET_TYPE
+ || TREE_CODE (type) == REAL_TYPE)
+ return int_size_in_bytes (type) > 8;
+
+ /* Aggregates and similar constructs are always returned
+ in memory. */
+ if (AGGREGATE_TYPE_P (type)
+ || TREE_CODE (type) == COMPLEX_TYPE
+ || TREE_CODE (type) == VECTOR_TYPE)
+ return true;
+
+ /* ??? We get called on all sorts of random stuff from
+ aggregate_value_p. We can't abort, but it's not clear
+ what's safe to return. Pretend it's a struct I guess. */
+ return true;
+}
+
+/* Define where to return a (scalar) value of type TYPE.
+ If TYPE is null, define where to return a (scalar)
+ value of mode MODE from a libcall. */
+
+rtx
+s390_function_value (tree type, enum machine_mode mode)
+{
+ if (type)
+ {
+ int unsignedp = TREE_UNSIGNED (type);
+ mode = promote_mode (type, TYPE_MODE (type), &unsignedp, 1);
+ }
+
+ if (GET_MODE_CLASS (mode) != MODE_INT
+ && GET_MODE_CLASS (mode) != MODE_FLOAT)
+ abort ();
+ if (GET_MODE_SIZE (mode) > 8)
+ abort ();
+
+ if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT)
+ return gen_rtx_REG (mode, 16);
+ else
+ return gen_rtx_REG (mode, 2);
}
/* Scalar return values. */
-/* We return scalars in general purpose register 2 for integral values,
- and floating point register 0 for fp values. */
-#define FUNCTION_VALUE(VALTYPE, FUNC) \
- gen_rtx_REG ((INTEGRAL_TYPE_P (VALTYPE) \
- && TYPE_PRECISION (VALTYPE) < BITS_PER_WORD) \
- || POINTER_TYPE_P (VALTYPE) \
- ? word_mode : TYPE_MODE (VALTYPE), \
- TREE_CODE (VALTYPE) == REAL_TYPE && TARGET_HARD_FLOAT ? 16 : 2)
-
-/* Define how to find the value returned by a library function assuming
- the value has mode MODE. */
-#define RET_REG(MODE) ((GET_MODE_CLASS (MODE) == MODE_INT \
- || TARGET_SOFT_FLOAT ) ? 2 : 16)
-#define LIBCALL_VALUE(MODE) gen_rtx (REG, MODE, RET_REG (MODE))
+#define FUNCTION_VALUE(VALTYPE, FUNC) \
+ s390_function_value ((VALTYPE), VOIDmode)
+
+#define LIBCALL_VALUE(MODE) \
+ s390_function_value (NULL, (MODE))
/* Only gpr 2 and fpr 0 are ever used as return registers. */
#define FUNCTION_VALUE_REGNO_P(N) ((N) == 2 || (N) == 16)
-
-/* Aggregate return values. */
-
-/* The definition of this macro implies that there are cases where
- a scalar value cannot be returned in registers. */
-#define RETURN_IN_MEMORY(type) \
- (TYPE_MODE (type) == BLKmode || \
- GET_MODE_CLASS (TYPE_MODE (type)) == MODE_COMPLEX_INT || \
- GET_MODE_CLASS (TYPE_MODE (type)) == MODE_COMPLEX_FLOAT)
-
/* Structure value address is passed as invisible first argument (gpr 2). */
#define STRUCT_VALUE 0