Commit c53bdcf5 by Alan Modra

re PR target/14567 ([3.4 only] long double and va_arg complex args)

	PR target/14567
	* config/rs6000/rs6000.h (UNITS_PER_ARG, RS6000_ARG_SIZE): Delete.
	(HARD_REGNO_MODE_OK): Disallow TFmode for fp31.
	* config/rs6000/rs6000.c (rs6000_arg_size): New function.
	Update all users of RS6000_ARG_SIZE.
	(function_arg_advance): Count fregno using mode size.
	(function_arg): Handle long double split over regs and memory.
	(function_arg_partial_nregs): Likewise.
	(rs6000_va_arg): Repackage complex args.

From-SVN: r79436
parent 8b0d6051
2004-03-13 Alan Modra <amodra@bigpond.net.au>
PR target/14567
* config/rs6000/rs6000.h (UNITS_PER_ARG, RS6000_ARG_SIZE): Delete.
(HARD_REGNO_MODE_OK): Disallow TFmode for fp31.
* config/rs6000/rs6000.c (rs6000_arg_size): New function.
Update all users of RS6000_ARG_SIZE.
(function_arg_advance): Count fregno using mode size.
(function_arg): Handle long double split over regs and memory.
(function_arg_partial_nregs): Likewise.
(rs6000_va_arg): Repackage complex args.
2004-03-13 Dean Ferreyra <dferreyra@igc.org> 2004-03-13 Dean Ferreyra <dferreyra@igc.org>
PR target/14047 PR target/14047
...@@ -310,7 +322,7 @@ ...@@ -310,7 +322,7 @@
and gt_pch_use_address. and gt_pch_use_address.
* config/host-linux.c, config/host-solaris.c: New files. * config/host-linux.c, config/host-solaris.c: New files.
* config/x-linux, config/x-solaris: New files. * config/x-linux, config/x-solaris: New files.
* config/rs6000/host-darwin.c darwin_rs6000_gt_pch_get_address): * config/rs6000/host-darwin.c (darwin_rs6000_gt_pch_get_address):
Update for changed definition. Update for changed definition.
(darwin_rs6000_gt_pch_use_address): Likewise. (darwin_rs6000_gt_pch_use_address): Likewise.
* doc/hostconfig.texi: Update docs. * doc/hostconfig.texi: Update docs.
......
...@@ -3980,6 +3980,24 @@ function_arg_boundary (enum machine_mode mode, tree type ATTRIBUTE_UNUSED) ...@@ -3980,6 +3980,24 @@ function_arg_boundary (enum machine_mode mode, tree type ATTRIBUTE_UNUSED)
return PARM_BOUNDARY; return PARM_BOUNDARY;
} }
/* Compute the size (in words) of a function argument. */
static unsigned long
rs6000_arg_size (enum machine_mode mode, tree type)
{
unsigned long size;
if (mode != BLKmode)
size = GET_MODE_SIZE (mode);
else
size = int_size_in_bytes (type);
if (TARGET_32BIT)
return (size + 3) >> 2;
else
return (size + 7) >> 3;
}
/* Update the data in CUM to advance over an argument /* Update the data in CUM to advance over an argument
of mode MODE and data type TYPE. of mode MODE and data type TYPE.
(TYPE is null for libcalls where that information may not be available.) */ (TYPE is null for libcalls where that information may not be available.) */
...@@ -4019,7 +4037,7 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, ...@@ -4019,7 +4037,7 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
align = ((6 - (cum->words & 3)) & 3); align = ((6 - (cum->words & 3)) & 3);
else else
align = cum->words & 1; align = cum->words & 1;
cum->words += align + RS6000_ARG_SIZE (mode, type); cum->words += align + rs6000_arg_size (mode, type);
if (TARGET_DEBUG_ARG) if (TARGET_DEBUG_ARG)
{ {
...@@ -4046,7 +4064,7 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, ...@@ -4046,7 +4064,7 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
{ {
if (mode == DFmode) if (mode == DFmode)
cum->words += cum->words & 1; cum->words += cum->words & 1;
cum->words += RS6000_ARG_SIZE (mode, type); cum->words += rs6000_arg_size (mode, type);
} }
} }
else else
...@@ -4059,7 +4077,7 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, ...@@ -4059,7 +4077,7 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
|| mode == TFmode) || mode == TFmode)
n_words = 1; n_words = 1;
else else
n_words = RS6000_ARG_SIZE (mode, type); n_words = rs6000_arg_size (mode, type);
/* Long long and SPE vectors are put in odd registers. */ /* Long long and SPE vectors are put in odd registers. */
if (n_words == 2 && (gregno & 1) == 0) if (n_words == 2 && (gregno & 1) == 0)
...@@ -4096,11 +4114,11 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, ...@@ -4096,11 +4114,11 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
int align = (TARGET_32BIT && (cum->words & 1) != 0 int align = (TARGET_32BIT && (cum->words & 1) != 0
&& function_arg_boundary (mode, type) == 64) ? 1 : 0; && function_arg_boundary (mode, type) == 64) ? 1 : 0;
cum->words += align + RS6000_ARG_SIZE (mode, type); cum->words += align + rs6000_arg_size (mode, type);
if (GET_MODE_CLASS (mode) == MODE_FLOAT if (GET_MODE_CLASS (mode) == MODE_FLOAT
&& TARGET_HARD_FLOAT && TARGET_FPRS) && TARGET_HARD_FLOAT && TARGET_FPRS)
cum->fregno += (mode == TFmode ? 2 : 1); cum->fregno += (GET_MODE_SIZE (mode) + 7) >> 3;
if (TARGET_DEBUG_ARG) if (TARGET_DEBUG_ARG)
{ {
...@@ -4122,7 +4140,7 @@ rs6000_spe_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, ...@@ -4122,7 +4140,7 @@ rs6000_spe_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
if (cum->stdarg) if (cum->stdarg)
{ {
int gregno = cum->sysv_gregno; int gregno = cum->sysv_gregno;
int n_words = RS6000_ARG_SIZE (mode, type); int n_words = rs6000_arg_size (mode, type);
/* SPE vectors are put in odd registers. */ /* SPE vectors are put in odd registers. */
if (n_words == 2 && (gregno & 1) == 0) if (n_words == 2 && (gregno & 1) == 0)
...@@ -4170,7 +4188,7 @@ rs6000_mixed_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, ...@@ -4170,7 +4188,7 @@ rs6000_mixed_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
gen_rtx_REG (mode, gen_rtx_REG (mode,
cum->fregno), cum->fregno),
const0_rtx))); const0_rtx)));
else if (align_words + RS6000_ARG_SIZE (mode, type) else if (align_words + rs6000_arg_size (mode, type)
> GP_ARG_NUM_REG) > GP_ARG_NUM_REG)
/* If this is partially on the stack, then we only /* If this is partially on the stack, then we only
include the portion actually in registers here. */ include the portion actually in registers here. */
...@@ -4394,13 +4412,13 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, ...@@ -4394,13 +4412,13 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
|| mode == TFmode) || mode == TFmode)
n_words = 1; n_words = 1;
else else
n_words = RS6000_ARG_SIZE (mode, type); n_words = rs6000_arg_size (mode, type);
/* Long long and SPE vectors are put in odd registers. */ /* Long long and SPE vectors are put in odd registers. */
if (n_words == 2 && (gregno & 1) == 0) if (n_words == 2 && (gregno & 1) == 0)
gregno += 1; gregno += 1;
/* Long long do not split between registers and stack. */ /* Long long does not split between registers and stack. */
if (gregno + n_words - 1 <= GP_ARG_MAX_REG) if (gregno + n_words - 1 <= GP_ARG_MAX_REG)
return gen_rtx_REG (mode, gregno); return gen_rtx_REG (mode, gregno);
else else
...@@ -4422,39 +4440,69 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, ...@@ -4422,39 +4440,69 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
if (USE_FP_FOR_ARG_P (cum, mode, type)) if (USE_FP_FOR_ARG_P (cum, mode, type))
{ {
if (! type rtx fpr[2];
|| ((cum->nargs_prototype > 0) rtx *r;
/* IBM AIX extended its linkage convention definition always bool needs_psave;
to require FP args after register save area hole on the enum machine_mode fmode = mode;
stack. */ int n;
&& (DEFAULT_ABI != ABI_AIX unsigned long n_fpreg = (GET_MODE_SIZE (mode) + 7) >> 3;
|| ! TARGET_XL_CALL
|| (align_words < GP_ARG_NUM_REG)))) if (cum->fregno + n_fpreg > FP_ARG_MAX_REG + 1)
return gen_rtx_REG (mode, cum->fregno); {
/* Long double split over regs and memory. */
if (fmode == TFmode)
fmode = DFmode;
/* Currently, we only ever need one reg here because complex
doubles are split. */
if (cum->fregno != FP_ARG_MAX_REG - 1)
abort ();
}
fpr[1] = gen_rtx_REG (fmode, cum->fregno);
/* Do we also need to pass this arg in the parameter save
area? */
needs_psave = (type
&& (cum->nargs_prototype <= 0
|| (DEFAULT_ABI == ABI_AIX
&& TARGET_XL_CALL
&& align_words >= GP_ARG_NUM_REG)));
if (!needs_psave && mode == fmode)
return fpr[1];
if (TARGET_32BIT && TARGET_POWERPC64 if (TARGET_32BIT && TARGET_POWERPC64
&& mode == DFmode && cum->stdarg) && mode == DFmode && cum->stdarg)
return rs6000_mixed_function_arg (cum, mode, type, align_words); return rs6000_mixed_function_arg (cum, mode, type, align_words);
return gen_rtx_PARALLEL (mode, /* Describe where this piece goes. */
gen_rtvec (2, r = fpr + 1;
gen_rtx_EXPR_LIST (VOIDmode, *r = gen_rtx_EXPR_LIST (VOIDmode, *r, const0_rtx);
((align_words >= GP_ARG_NUM_REG) n = 1;
? NULL_RTX
: (align_words if (needs_psave)
+ RS6000_ARG_SIZE (mode, type) {
> GP_ARG_NUM_REG /* Now describe the part that goes in gprs or the stack.
/* If this is partially on the stack, then This piece must come first, before the fprs. */
we only include the portion actually rtx reg = NULL_RTX;
in registers here. */ if (align_words < GP_ARG_NUM_REG)
? gen_rtx_REG (Pmode, {
GP_ARG_MIN_REG + align_words) unsigned long n_words = rs6000_arg_size (mode, type);
: gen_rtx_REG (mode, enum machine_mode rmode = mode;
GP_ARG_MIN_REG + align_words))),
const0_rtx), if (align_words + n_words > GP_ARG_NUM_REG)
gen_rtx_EXPR_LIST (VOIDmode, /* If this is partially on the stack, then we only
gen_rtx_REG (mode, cum->fregno), include the portion actually in registers here.
const0_rtx))); We know this can only be one register because
complex doubles are splt. */
rmode = Pmode;
reg = gen_rtx_REG (rmode, GP_ARG_MIN_REG + align_words);
}
*--r = gen_rtx_EXPR_LIST (VOIDmode, reg, const0_rtx);
++n;
}
return gen_rtx_PARALLEL (mode, gen_rtvec_v (n, r));
} }
else if (align_words < GP_ARG_NUM_REG) else if (align_words < GP_ARG_NUM_REG)
return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words); return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
...@@ -4471,27 +4519,31 @@ int ...@@ -4471,27 +4519,31 @@ int
function_arg_partial_nregs (CUMULATIVE_ARGS *cum, enum machine_mode mode, function_arg_partial_nregs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
tree type, int named) tree type, int named)
{ {
int ret = 0;
if (DEFAULT_ABI == ABI_V4) if (DEFAULT_ABI == ABI_V4)
return 0; return 0;
if (USE_FP_FOR_ARG_P (cum, mode, type) if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named)
|| USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named)) && cum->nargs_prototype >= 0)
return 0;
if (USE_FP_FOR_ARG_P (cum, mode, type))
{ {
if (cum->nargs_prototype >= 0) if (cum->fregno + ((GET_MODE_SIZE (mode) + 7) >> 3) > FP_ARG_MAX_REG + 1)
ret = FP_ARG_MAX_REG - cum->fregno;
else if (cum->nargs_prototype >= 0)
return 0; return 0;
} }
if (cum->words < GP_ARG_NUM_REG if (cum->words < GP_ARG_NUM_REG
&& GP_ARG_NUM_REG < (cum->words + RS6000_ARG_SIZE (mode, type))) && GP_ARG_NUM_REG < cum->words + rs6000_arg_size (mode, type))
{ ret = GP_ARG_NUM_REG - cum->words;
int ret = GP_ARG_NUM_REG - cum->words;
if (ret && TARGET_DEBUG_ARG) if (ret != 0 && TARGET_DEBUG_ARG)
fprintf (stderr, "function_arg_partial_nregs: %d\n", ret); fprintf (stderr, "function_arg_partial_nregs: %d\n", ret);
return ret; return ret;
}
return 0;
} }
/* A C expression that indicates when an argument must be passed by /* A C expression that indicates when an argument must be passed by
...@@ -4597,7 +4649,7 @@ setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode, ...@@ -4597,7 +4649,7 @@ setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
cfun->machine->sysv_varargs_p = 0; cfun->machine->sysv_varargs_p = 0;
if (MUST_PASS_IN_STACK (mode, type)) if (MUST_PASS_IN_STACK (mode, type))
first_reg_offset += RS6000_ARG_SIZE (TYPE_MODE (type), type); first_reg_offset += rs6000_arg_size (TYPE_MODE (type), type);
} }
set = get_varargs_alias_set (); set = get_varargs_alias_set ();
...@@ -4787,7 +4839,41 @@ rs6000_va_arg (tree valist, tree type) ...@@ -4787,7 +4839,41 @@ rs6000_va_arg (tree valist, tree type)
return expand_expr (t, NULL_RTX, VOIDmode, EXPAND_NORMAL); return expand_expr (t, NULL_RTX, VOIDmode, EXPAND_NORMAL);
} }
else if (SPLIT_COMPLEX_ARGS
&& TREE_CODE (type) == COMPLEX_TYPE)
{
tree elem_type = TREE_TYPE (type);
enum machine_mode elem_mode = TYPE_MODE (elem_type);
int elem_size = GET_MODE_SIZE (elem_mode);
if (elem_size < UNITS_PER_WORD)
{
rtx real_part, imag_part, dest_real, rr;
real_part = rs6000_va_arg (valist, elem_type);
imag_part = rs6000_va_arg (valist, elem_type);
/* We're not returning the value here, but the address.
real_part and imag_part are not contiguous, and we know
there is space available to pack real_part next to
imag_part. float _Complex is not promoted to
double _Complex by the default promotion rules that
promote float to double. */
if (2 * elem_size > UNITS_PER_WORD)
abort ();
real_part = gen_rtx_MEM (elem_mode, real_part);
imag_part = gen_rtx_MEM (elem_mode, imag_part);
dest_real = adjust_address (imag_part, elem_mode, -elem_size);
rr = gen_reg_rtx (elem_mode);
emit_move_insn (rr, real_part);
emit_move_insn (dest_real, rr);
return XEXP (dest_real, 0);
}
}
return std_expand_builtin_va_arg (valist, type); return std_expand_builtin_va_arg (valist, type);
} }
......
...@@ -1065,7 +1065,8 @@ extern const char *rs6000_warn_altivec_long_switch; ...@@ -1065,7 +1065,8 @@ extern const char *rs6000_warn_altivec_long_switch;
(INT_REGNO_P (REGNO) ? \ (INT_REGNO_P (REGNO) ? \
INT_REGNO_P (REGNO + HARD_REGNO_NREGS (REGNO, MODE) - 1) \ INT_REGNO_P (REGNO + HARD_REGNO_NREGS (REGNO, MODE) - 1) \
: FP_REGNO_P (REGNO) ? \ : FP_REGNO_P (REGNO) ? \
(GET_MODE_CLASS (MODE) == MODE_FLOAT \ ((GET_MODE_CLASS (MODE) == MODE_FLOAT \
&& FP_REGNO_P (REGNO + HARD_REGNO_NREGS (REGNO, MODE) - 1)) \
|| (GET_MODE_CLASS (MODE) == MODE_INT \ || (GET_MODE_CLASS (MODE) == MODE_INT \
&& GET_MODE_SIZE (MODE) == UNITS_PER_FP_WORD)) \ && GET_MODE_SIZE (MODE) == UNITS_PER_FP_WORD)) \
: ALTIVEC_REGNO_P (REGNO) ? ALTIVEC_VECTOR_MODE (MODE) \ : ALTIVEC_REGNO_P (REGNO) ? ALTIVEC_VECTOR_MODE (MODE) \
...@@ -1762,16 +1763,6 @@ typedef struct rs6000_args ...@@ -1762,16 +1763,6 @@ typedef struct rs6000_args
int sysv_gregno; /* next available GP register */ int sysv_gregno; /* next available GP register */
} CUMULATIVE_ARGS; } CUMULATIVE_ARGS;
/* Define intermediate macro to compute the size (in registers) of an argument
for the RS/6000. */
#define UNITS_PER_ARG (TARGET_32BIT ? 4 : 8)
#define RS6000_ARG_SIZE(MODE, TYPE) \
((MODE) != BLKmode \
? (GET_MODE_SIZE (MODE) + (UNITS_PER_ARG - 1)) / UNITS_PER_ARG \
: (int_size_in_bytes (TYPE) + (UNITS_PER_ARG - 1)) / UNITS_PER_ARG)
/* Initialize a variable CUM of type CUMULATIVE_ARGS /* Initialize a variable CUM of type CUMULATIVE_ARGS
for a call to a function whose data type is FNTYPE. for a call to a function whose data type is FNTYPE.
For a library call, FNTYPE is 0. */ For a library call, FNTYPE is 0. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment