HOST_WIDE_INT size, rsize;
tree tmp, pptr_type_node;
rtx addr_rtx, r;
- rtx result;
+ rtx result_ptr, result = NULL_RTX;
int pass_by_ref = MUST_PASS_IN_STACK (TYPE_MODE (type), type);
+ rtx lab_over;
size = int_size_in_bytes (type);
rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
tree f_next_o, f_next_o_limit, f_next_fp, f_next_fp_limit, f_next_stack;
tree next_o, next_o_limit, next_fp, next_fp_limit, next_stack;
int pass_as_float;
- rtx lab_false, lab_over;
+ rtx lab_false;
f_next_o = TYPE_FIELDS (va_list_type_node);
f_next_o_limit = TREE_CHAIN (f_next_o);
next_stack = build (COMPONENT_REF, TREE_TYPE (f_next_stack),
valist, f_next_stack);
+ /* Structures with a single member with a distinct mode are passed
+ like their member. This is relevant if the latter has a REAL_TYPE
+ or COMPLEX_TYPE type. */
+ if (TREE_CODE (type) == RECORD_TYPE
+ && TYPE_FIELDS (type)
+ && TREE_CODE (TYPE_FIELDS (type)) == FIELD_DECL
+ && (TREE_CODE (TREE_TYPE (TYPE_FIELDS (type))) == REAL_TYPE
+ || TREE_CODE (TREE_TYPE (TYPE_FIELDS (type))) == COMPLEX_TYPE)
+ && TREE_CHAIN (TYPE_FIELDS (type)) == NULL_TREE)
+ type = TREE_TYPE (TYPE_FIELDS (type));
if (TARGET_SH4)
{
pass_as_float = ((TREE_CODE (type) == REAL_TYPE && size <= 8)
lab_false = gen_label_rtx ();
lab_over = gen_label_rtx ();
+ tmp = make_tree (pptr_type_node, addr_rtx);
+ valist = build1 (INDIRECT_REF, ptr_type_node, tmp);
+
if (pass_as_float)
{
int first_floatreg
if (r != addr_rtx)
emit_move_insn (addr_rtx, r);
+#ifdef FUNCTION_ARG_SCmode_WART
+ if (TYPE_MODE (type) == SCmode && TARGET_SH4 && TARGET_LITTLE_ENDIAN)
+ {
+ rtx addr, real, imag, result_value, slot;
+ tree subtype = TREE_TYPE (type);
+
+ addr = std_expand_builtin_va_arg (valist, subtype);
+#ifdef POINTERS_EXTEND_UNSIGNED
+ if (GET_MODE (addr) != Pmode)
+ addr = convert_memory_address (Pmode, addr);
+#endif
+ imag = gen_rtx_MEM (TYPE_MODE (type), addr);
+ set_mem_alias_set (imag, get_varargs_alias_set ());
+
+ addr = std_expand_builtin_va_arg (valist, subtype);
+#ifdef POINTERS_EXTEND_UNSIGNED
+ if (GET_MODE (addr) != Pmode)
+ addr = convert_memory_address (Pmode, addr);
+#endif
+ real = gen_rtx_MEM (TYPE_MODE (type), addr);
+ set_mem_alias_set (real, get_varargs_alias_set ());
+
+ result_value = gen_rtx_CONCAT (SCmode, real, imag);
+ /* ??? this interface is stupid - why require a pointer? */
+ result = gen_reg_rtx (Pmode);
+ slot = assign_stack_temp (SCmode, 8, 0);
+ emit_move_insn (slot, result_value);
+ emit_move_insn (result, XEXP (slot, 0));
+ }
+#endif /* FUNCTION_ARG_SCmode_WART */
+
emit_jump_insn (gen_jump (lab_over));
emit_barrier ();
emit_label (lab_false);
emit_move_insn (addr_rtx, r);
}
- emit_label (lab_over);
-
- tmp = make_tree (pptr_type_node, addr_rtx);
- valist = build1 (INDIRECT_REF, ptr_type_node, tmp);
+ if (! result)
+ emit_label (lab_over);
}
/* ??? In va-sh.h, there had been code to make values larger than
size 8 indirect. This does not match the FUNCTION_ARG macros. */
- result = std_expand_builtin_va_arg (valist, type);
+ result_ptr = std_expand_builtin_va_arg (valist, type);
+ if (result)
+ {
+ emit_move_insn (result, result_ptr);
+ emit_label (lab_over);
+ }
+ else
+ result = result_ptr;
+
if (pass_by_ref)
{
#ifdef POINTERS_EXTEND_UNSIGNED
(CUM).outgoing = 0; \
} while (0)
-#define OLD_ARG_MODE(MODE, TYPE) \
- (((TYPE) \
- && (TREE_CODE (TYPE) == RECORD_TYPE || TREE_CODE (TYPE) == UNION_TYPE) \
- && (MODE) != BLKmode && GET_MODE_CLASS (MODE) != MODE_INT) \
- ? int_mode_for_mode (MODE) : (MODE))
-
/* Update the data in CUM to advance over an argument
of mode MODE and data type TYPE.
(TYPE is null for libcalls where that information may not be
available.) */
#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \
-do { \
- enum machine_mode MODE_ = OLD_ARG_MODE ((MODE), (TYPE));\
if ((CUM).force_mem) \
(CUM).force_mem = 0; \
else if (TARGET_SH5) \
tree TYPE_ = ((CUM).byref && (TYPE) \
? TREE_TYPE (TYPE) \
: (TYPE)); \
- int dwords, numregs; \
+ enum machine_mode MODE_ = ((CUM).byref && (TYPE) \
+ ? TYPE_MODE (TYPE_) \
+ : (MODE)); \
+ int dwords = (((CUM).byref \
+ ? (CUM).byref \
+ : (MODE_) == BLKmode \
+ ? int_size_in_bytes (TYPE_) \
+ : GET_MODE_SIZE (MODE_)) + 7) / 8; \
+ int numregs = MIN (dwords, NPARM_REGS (SImode) \
+ - (CUM).arg_count[(int) SH_ARG_INT]); \
\
- MODE_ = ((CUM).byref && (TYPE) \
- ? TYPE_MODE (TYPE_) : (MODE_)); \
- dwords = (((CUM).byref \
- ? (CUM).byref \
- : (MODE_) == BLKmode \
- ? int_size_in_bytes (TYPE_) \
- : GET_MODE_SIZE (MODE_)) + 7) / 8; \
- numregs = MIN (dwords, NPARM_REGS (SImode) \
- - (CUM).arg_count[(int) SH_ARG_INT]); \
if (numregs) \
{ \
(CUM).arg_count[(int) SH_ARG_INT] += numregs; \
} \
} \
} \
- else if (! TARGET_SH4 || PASS_IN_REG_P ((CUM), (MODE_), (TYPE))) \
- ((CUM).arg_count[(int) GET_SH_ARG_CLASS (MODE_)] \
- = (ROUND_REG ((CUM), (MODE_)) \
- + ((MODE_) == BLKmode \
+ else if (! TARGET_SH4 || PASS_IN_REG_P ((CUM), (MODE), (TYPE))) \
+ ((CUM).arg_count[(int) GET_SH_ARG_CLASS (MODE)] \
+ = (ROUND_REG ((CUM), (MODE)) \
+ + ((MODE) == BLKmode \
? ROUND_ADVANCE (int_size_in_bytes (TYPE)) \
- : ROUND_ADVANCE (GET_MODE_SIZE (MODE_))))); \
-} while (0)
+ : ROUND_ADVANCE (GET_MODE_SIZE (MODE)))))
/* Return boolean indicating arg of mode MODE will be passed in a reg.
This macro is only used in this file. */
<= NPARM_REGS (MODE))) \
: ROUND_REG ((CUM), (MODE)) < NPARM_REGS (MODE)))
+/* By accident we got stuck with passing SCmode on SH4 little endian
+ in two registers that are nominally successive - which is different from
+ two single SFmode values, where we take endianness translation into
+ account. That does not work at all if an odd number of registers is
+ already in use, so that got fixed, but library functions are still more
+ likely to use complex numbers without mixing them with SFmode arguments
+ (which in C would have to be structures), so for the sake of ABI
+ compatibility the way SCmode values are passed when an even number of
+ FP registers is in use remains different from a pair of SFmode values for
+ now.
+ I.e.:
+ foo (double); a: fr5,fr4
+ foo (float a, float b); a: fr5 b: fr4
+ foo (__complex float a); a.real fr4 a.imag: fr5 - for consistency,
+ this should be the other way round...
+ foo (float a, __complex float b); a: fr5 b.real: fr4 b.imag: fr7 */
+#define FUNCTION_ARG_SCmode_WART 1
+
/* Define where to put the arguments to a function.
Value is zero to push the argument on the stack,
or a hard register in which to store the argument.
its data type forbids. */
#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
- FUNCTION_ARG_1 ((CUM), OLD_ARG_MODE ((MODE), (TYPE)), (MODE), (TYPE), (NAMED))
-
-#define FUNCTION_ARG_1(CUM, MODE, NEW_MODE, TYPE, NAMED) \
((! TARGET_SH5 \
&& PASS_IN_REG_P ((CUM), (MODE), (TYPE)) \
&& ((NAMED) || !TARGET_HITACHI)) \
- ? gen_rtx_REG ((NEW_MODE), \
- ((BASE_ARG_REG (MODE) + ROUND_REG ((CUM), (MODE))) \
- ^ ((MODE) == SFmode && TARGET_SH4 \
- && TARGET_LITTLE_ENDIAN != 0))) \
+ ? (((MODE) == SCmode && TARGET_SH4 && TARGET_LITTLE_ENDIAN \
+ && (! FUNCTION_ARG_SCmode_WART || (ROUND_REG ((CUM), (MODE)) & 1)))\
+ ? (gen_rtx_PARALLEL \
+ (SCmode, \
+ (gen_rtvec \
+ (2, \
+ (gen_rtx_EXPR_LIST \
+ (VOIDmode, \
+ gen_rtx_REG (SFmode, \
+ BASE_ARG_REG (MODE) \
+ + ROUND_REG ((CUM), (MODE)) ^ 1), \
+ const0_rtx)), \
+ (gen_rtx_EXPR_LIST \
+ (VOIDmode, \
+ gen_rtx_REG (SFmode, \
+ BASE_ARG_REG (MODE) \
+ + (ROUND_REG ((CUM), (MODE)) + 1) ^ 1), \
+ GEN_INT (4))))))) \
+ : gen_rtx_REG ((MODE), \
+ ((BASE_ARG_REG (MODE) + ROUND_REG ((CUM), (MODE))) \
+ ^ ((MODE) == SFmode && TARGET_SH4 \
+ && TARGET_LITTLE_ENDIAN != 0)))) \
: TARGET_SH5 \
? ((MODE) == VOIDmode && TARGET_SHCOMPACT \
? GEN_INT ((CUM).call_cookie) \
/* The following test assumes unnamed arguments are promoted to \
DFmode. */ \
: (MODE) == SFmode && (CUM).free_single_fp_reg \
- ? SH5_PROTOTYPED_FLOAT_ARG ((CUM), (NEW_MODE), (CUM).free_single_fp_reg) \
+ ? SH5_PROTOTYPED_FLOAT_ARG ((CUM), (MODE), (CUM).free_single_fp_reg) \
: (GET_SH_ARG_CLASS (MODE) == SH_ARG_FLOAT \
&& ((NAMED) || ! (CUM).prototype_p) \
&& (CUM).arg_count[(int) SH_ARG_FLOAT] < NPARM_REGS (SFmode)) \
? ((! (CUM).prototype_p && TARGET_SHMEDIA) \
- ? SH5_PROTOTYPELESS_FLOAT_ARG ((CUM), (NEW_MODE)) \
- : SH5_PROTOTYPED_FLOAT_ARG ((CUM), (NEW_MODE), \
+ ? SH5_PROTOTYPELESS_FLOAT_ARG ((CUM), (MODE)) \
+ : SH5_PROTOTYPED_FLOAT_ARG ((CUM), (MODE), \
FIRST_FP_PARM_REG \
+ (CUM).arg_count[(int) SH_ARG_FLOAT])) \
: ((CUM).arg_count[(int) SH_ARG_INT] < NPARM_REGS (SImode) \
|| (! SHCOMPACT_FORCE_ON_STACK ((MODE), (TYPE)) \
&& ! SH5_WOULD_BE_PARTIAL_NREGS ((CUM), (MODE), \
(TYPE), (NAMED))))) \
- ? gen_rtx_REG ((NEW_MODE), (FIRST_PARM_REG \
+ ? gen_rtx_REG ((MODE), (FIRST_PARM_REG \
+ (CUM).arg_count[(int) SH_ARG_INT])) \
: 0) \
: 0)
loads them into the full 64-bits registers. */
#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM,MODE,TYPE,NAMED) \
(MUST_PASS_IN_STACK ((MODE), (TYPE)) \
- || SHCOMPACT_BYREF ((CUM), OLD_ARG_MODE ((MODE), (TYPE)), (TYPE), (NAMED)))
+ || SHCOMPACT_BYREF ((CUM), (MODE), (TYPE), (NAMED)))
#define SHCOMPACT_BYREF(CUM, MODE, TYPE, NAMED) \
((CUM).byref \