rs6000.c (rs6000_mixed_function_arg): Rewrite.
* config/rs6000/rs6000.c (rs6000_mixed_function_arg): Rewrite. (function_arg): Use rs6000_arg_size rather than CLASS_MAX_NREGS in calculating gpr size for altivec. Simplify and correct rs6000_mixed_function_arg calls. Call rs6000_mixed_function_arg for ABI_V4 gpr case too. Fix off-by-one error in long double reg test. Generate the correct PARALLEL to handle long double for ABI_AIX 32-bit. Use this for -m32 -mpowerpc64 fpr case too. (function_arg_partial_nregs): Align before calculating regs left. Don't return info on partial fprs when we need info on gprs. Correct long double fpr off-by-one error. From-SVN: r83951
This commit is contained in:
parent
cde0e59bf2
commit
ec6376abd7
@ -1,3 +1,16 @@
|
||||
2004-07-01 Alan Modra <amodra@bigpond.net.au>
|
||||
|
||||
* config/rs6000/rs6000.c (rs6000_mixed_function_arg): Rewrite.
|
||||
(function_arg): Use rs6000_arg_size rather than CLASS_MAX_NREGS in
|
||||
calculating gpr size for altivec. Simplify and correct
|
||||
rs6000_mixed_function_arg calls. Call rs6000_mixed_function_arg
|
||||
for ABI_V4 gpr case too. Fix off-by-one error in long double
|
||||
reg test. Generate the correct PARALLEL to handle long double
|
||||
for ABI_AIX 32-bit. Use this for -m32 -mpowerpc64 fpr case too.
|
||||
(function_arg_partial_nregs): Align before calculating regs left.
|
||||
Don't return info on partial fprs when we need info on gprs.
|
||||
Correct long double fpr off-by-one error.
|
||||
|
||||
2004-06-30 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
|
||||
|
||||
* pa-protos.h (prefetch_operand): Add prototype.
|
||||
|
@ -425,8 +425,7 @@ static int rs6000_get_some_local_dynamic_name_1 (rtx *, void *);
|
||||
static rtx rs6000_complex_function_value (enum machine_mode);
|
||||
static rtx rs6000_spe_function_arg (CUMULATIVE_ARGS *,
|
||||
enum machine_mode, tree);
|
||||
static rtx rs6000_mixed_function_arg (CUMULATIVE_ARGS *,
|
||||
enum machine_mode, tree, int);
|
||||
static rtx rs6000_mixed_function_arg (enum machine_mode, tree, int);
|
||||
static void rs6000_move_block_from_reg (int regno, rtx x, int nregs);
|
||||
static void setup_incoming_varargs (CUMULATIVE_ARGS *,
|
||||
enum machine_mode, tree,
|
||||
@ -4424,124 +4423,49 @@ rs6000_spe_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
|
||||
/* Determine where to place an argument in 64-bit mode with 32-bit ABI. */
|
||||
|
||||
static rtx
|
||||
rs6000_mixed_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
|
||||
tree type, int align_words)
|
||||
rs6000_mixed_function_arg (enum machine_mode mode, tree type, int align_words)
|
||||
{
|
||||
if (mode == DFmode)
|
||||
{
|
||||
/* -mpowerpc64 with 32bit ABI splits up a DFmode argument
|
||||
in vararg list into zero, one or two GPRs */
|
||||
if (align_words >= GP_ARG_NUM_REG)
|
||||
return gen_rtx_PARALLEL (DFmode,
|
||||
gen_rtvec (2,
|
||||
gen_rtx_EXPR_LIST (VOIDmode,
|
||||
NULL_RTX, const0_rtx),
|
||||
gen_rtx_EXPR_LIST (VOIDmode,
|
||||
gen_rtx_REG (mode,
|
||||
cum->fregno),
|
||||
const0_rtx)));
|
||||
else if (align_words + rs6000_arg_size (mode, type)
|
||||
> GP_ARG_NUM_REG)
|
||||
/* If this is partially on the stack, then we only
|
||||
include the portion actually in registers here. */
|
||||
return gen_rtx_PARALLEL (DFmode,
|
||||
gen_rtvec (2,
|
||||
gen_rtx_EXPR_LIST (VOIDmode,
|
||||
gen_rtx_REG (SImode,
|
||||
GP_ARG_MIN_REG
|
||||
+ align_words),
|
||||
const0_rtx),
|
||||
gen_rtx_EXPR_LIST (VOIDmode,
|
||||
gen_rtx_REG (mode,
|
||||
cum->fregno),
|
||||
const0_rtx)));
|
||||
int n_units;
|
||||
int i, k;
|
||||
rtx rvec[GP_ARG_NUM_REG + 1];
|
||||
|
||||
/* split a DFmode arg into two GPRs */
|
||||
return gen_rtx_PARALLEL (DFmode,
|
||||
gen_rtvec (3,
|
||||
gen_rtx_EXPR_LIST (VOIDmode,
|
||||
gen_rtx_REG (SImode,
|
||||
GP_ARG_MIN_REG
|
||||
+ align_words),
|
||||
const0_rtx),
|
||||
gen_rtx_EXPR_LIST (VOIDmode,
|
||||
gen_rtx_REG (SImode,
|
||||
GP_ARG_MIN_REG
|
||||
+ align_words + 1),
|
||||
GEN_INT (4)),
|
||||
gen_rtx_EXPR_LIST (VOIDmode,
|
||||
gen_rtx_REG (mode, cum->fregno),
|
||||
const0_rtx)));
|
||||
}
|
||||
/* -mpowerpc64 with 32bit ABI splits up a DImode argument into one
|
||||
or two GPRs */
|
||||
else if (mode == DImode)
|
||||
{
|
||||
if (align_words < GP_ARG_NUM_REG - 1)
|
||||
return gen_rtx_PARALLEL (DImode,
|
||||
gen_rtvec (2,
|
||||
gen_rtx_EXPR_LIST (VOIDmode,
|
||||
gen_rtx_REG (SImode,
|
||||
GP_ARG_MIN_REG
|
||||
+ align_words),
|
||||
const0_rtx),
|
||||
gen_rtx_EXPR_LIST (VOIDmode,
|
||||
gen_rtx_REG (SImode,
|
||||
GP_ARG_MIN_REG
|
||||
+ align_words + 1),
|
||||
GEN_INT (4))));
|
||||
else if (align_words == GP_ARG_NUM_REG - 1)
|
||||
return gen_rtx_PARALLEL (DImode,
|
||||
gen_rtvec (2,
|
||||
gen_rtx_EXPR_LIST (VOIDmode,
|
||||
NULL_RTX, const0_rtx),
|
||||
gen_rtx_EXPR_LIST (VOIDmode,
|
||||
gen_rtx_REG (SImode,
|
||||
GP_ARG_MIN_REG
|
||||
+ align_words),
|
||||
const0_rtx)));
|
||||
}
|
||||
else if (ALTIVEC_VECTOR_MODE (mode) && align_words == GP_ARG_NUM_REG - 2)
|
||||
{
|
||||
/* Varargs vector regs must be saved in R9-R10. */
|
||||
return gen_rtx_PARALLEL (mode,
|
||||
gen_rtvec (3,
|
||||
gen_rtx_EXPR_LIST (VOIDmode,
|
||||
NULL_RTX, const0_rtx),
|
||||
gen_rtx_EXPR_LIST (VOIDmode,
|
||||
gen_rtx_REG (SImode,
|
||||
GP_ARG_MIN_REG
|
||||
+ align_words),
|
||||
const0_rtx),
|
||||
gen_rtx_EXPR_LIST (VOIDmode,
|
||||
gen_rtx_REG (SImode,
|
||||
GP_ARG_MIN_REG
|
||||
+ align_words + 1),
|
||||
GEN_INT (4))));
|
||||
}
|
||||
else if ((mode == BLKmode || ALTIVEC_VECTOR_MODE (mode))
|
||||
&& align_words <= (GP_ARG_NUM_REG - 1))
|
||||
{
|
||||
/* AltiVec vector regs are saved in R5-R8. */
|
||||
int k;
|
||||
int size = int_size_in_bytes (type);
|
||||
int no_units = ((size - 1) / 4) + 1;
|
||||
int max_no_words = GP_ARG_NUM_REG - align_words;
|
||||
int rtlvec_len = no_units < max_no_words ? no_units : max_no_words;
|
||||
rtx *rtlvec = (rtx *) alloca (rtlvec_len * sizeof (rtx));
|
||||
if (align_words >= GP_ARG_NUM_REG)
|
||||
return NULL_RTX;
|
||||
|
||||
memset ((char *) rtlvec, 0, rtlvec_len * sizeof (rtx));
|
||||
n_units = rs6000_arg_size (mode, type);
|
||||
|
||||
for (k=0; k < rtlvec_len; k++)
|
||||
rtlvec[k] = gen_rtx_EXPR_LIST (VOIDmode,
|
||||
gen_rtx_REG (SImode,
|
||||
GP_ARG_MIN_REG
|
||||
+ align_words + k),
|
||||
k == 0 ? const0_rtx : GEN_INT (k*4));
|
||||
/* Optimize the simple case where the arg fits in one gpr, except in
|
||||
the case of BLKmode due to assign_parms assuming that registers are
|
||||
BITS_PER_WORD wide. */
|
||||
if (n_units == 0
|
||||
|| (n_units == 1 && mode != BLKmode))
|
||||
return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
|
||||
|
||||
return gen_rtx_PARALLEL (mode, gen_rtvec_v (k, rtlvec));
|
||||
k = 0;
|
||||
if (align_words + n_units > GP_ARG_NUM_REG)
|
||||
/* Not all of the arg fits in gprs. Say that it goes in memory too,
|
||||
using a magic NULL_RTX component.
|
||||
FIXME: This is not strictly correct. Only some of the arg
|
||||
belongs in memory, not all of it. However, there isn't any way
|
||||
to do this currently, apart from building rtx descriptions for
|
||||
the pieces of memory we want stored. Due to bugs in the generic
|
||||
code we can't use the normal function_arg_partial_nregs scheme
|
||||
with the PARALLEL arg description we emit here.
|
||||
In any case, the code to store the whole arg to memory is often
|
||||
more efficient than code to store pieces, and we know that space
|
||||
is available in the right place for the whole arg. */
|
||||
rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
|
||||
|
||||
i = 0;
|
||||
do
|
||||
{
|
||||
rtx r = gen_rtx_REG (SImode, GP_ARG_MIN_REG + align_words);
|
||||
rtx off = GEN_INT (i++ * 4);
|
||||
rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, off);
|
||||
}
|
||||
return NULL_RTX;
|
||||
while (++align_words < GP_ARG_NUM_REG && --n_units != 0);
|
||||
|
||||
return gen_rtx_PARALLEL (mode, gen_rtvec_v (k, rvec));
|
||||
}
|
||||
|
||||
/* Determine where to put an argument to a function.
|
||||
@ -4636,8 +4560,8 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
|
||||
{
|
||||
/* Vector parameters to varargs functions under AIX or Darwin
|
||||
get passed in memory and possibly also in GPRs. */
|
||||
int align, align_words;
|
||||
enum machine_mode part_mode = mode;
|
||||
int align, align_words, n_words;
|
||||
enum machine_mode part_mode;
|
||||
|
||||
/* Vector parameters must be 16-byte aligned. This places them at
|
||||
2 mod 4 in terms of words in 32-bit mode, since the parameter
|
||||
@ -4654,19 +4578,19 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
|
||||
if (align_words >= GP_ARG_NUM_REG)
|
||||
return NULL_RTX;
|
||||
|
||||
if (TARGET_32BIT && TARGET_POWERPC64)
|
||||
return rs6000_mixed_function_arg (mode, type, align_words);
|
||||
|
||||
/* The vector value goes in GPRs. Only the part of the
|
||||
value in GPRs is reported here. */
|
||||
if (align_words + CLASS_MAX_NREGS (mode, GENERAL_REGS)
|
||||
> GP_ARG_NUM_REG)
|
||||
part_mode = mode;
|
||||
n_words = rs6000_arg_size (mode, type);
|
||||
if (align_words + n_words > GP_ARG_NUM_REG)
|
||||
/* Fortunately, there are only two possibilities, the value
|
||||
is either wholly in GPRs or half in GPRs and half not. */
|
||||
part_mode = DImode;
|
||||
|
||||
if (TARGET_32BIT
|
||||
&& (TARGET_POWERPC64 || (align_words == GP_ARG_NUM_REG - 2)))
|
||||
return rs6000_mixed_function_arg (cum, part_mode, type, align_words);
|
||||
else
|
||||
return gen_rtx_REG (part_mode, GP_ARG_MIN_REG + align_words);
|
||||
return gen_rtx_REG (part_mode, GP_ARG_MIN_REG + align_words);
|
||||
}
|
||||
}
|
||||
else if (TARGET_SPE_ABI && TARGET_SPE && SPE_VECTOR_MODE (mode))
|
||||
@ -4693,10 +4617,13 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
|
||||
gregno += (1 - gregno) & 1;
|
||||
|
||||
/* Multi-reg args are not split between registers and stack. */
|
||||
if (gregno + n_words - 1 <= GP_ARG_MAX_REG)
|
||||
return gen_rtx_REG (mode, gregno);
|
||||
else
|
||||
if (gregno + n_words - 1 > GP_ARG_MAX_REG)
|
||||
return NULL_RTX;
|
||||
|
||||
if (TARGET_32BIT && TARGET_POWERPC64)
|
||||
return rs6000_mixed_function_arg (mode, type,
|
||||
gregno - GP_ARG_MIN_REG);
|
||||
return gen_rtx_REG (mode, gregno);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -4706,25 +4633,23 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
|
||||
|
||||
if (USE_FP_FOR_ARG_P (cum, mode, type))
|
||||
{
|
||||
rtx fpr[2];
|
||||
rtx *r;
|
||||
rtx rvec[GP_ARG_NUM_REG + 1];
|
||||
rtx r;
|
||||
int k;
|
||||
bool needs_psave;
|
||||
enum machine_mode fmode = mode;
|
||||
int n;
|
||||
unsigned long n_fpreg = (GET_MODE_SIZE (mode) + 7) >> 3;
|
||||
|
||||
if (cum->fregno + n_fpreg > FP_ARG_MAX_REG + 1)
|
||||
{
|
||||
/* 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)
|
||||
if (cum->fregno != FP_ARG_MAX_REG || fmode != TFmode)
|
||||
abort ();
|
||||
|
||||
/* Long double split over regs and memory. */
|
||||
fmode = DFmode;
|
||||
}
|
||||
fpr[1] = gen_rtx_REG (fmode, cum->fregno);
|
||||
|
||||
/* Do we also need to pass this arg in the parameter save
|
||||
area? */
|
||||
@ -4735,46 +4660,55 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
|
||||
&& align_words >= GP_ARG_NUM_REG)));
|
||||
|
||||
if (!needs_psave && mode == fmode)
|
||||
return fpr[1];
|
||||
|
||||
if (TARGET_32BIT && TARGET_POWERPC64
|
||||
&& mode == DFmode && cum->stdarg)
|
||||
return rs6000_mixed_function_arg (cum, mode, type, align_words);
|
||||
|
||||
/* Describe where this piece goes. */
|
||||
r = fpr + 1;
|
||||
*r = gen_rtx_EXPR_LIST (VOIDmode, *r, const0_rtx);
|
||||
n = 1;
|
||||
return gen_rtx_REG (fmode, cum->fregno);
|
||||
|
||||
k = 0;
|
||||
if (needs_psave)
|
||||
{
|
||||
/* Now describe the part that goes in gprs or the stack.
|
||||
/* Describe the part that goes in gprs or the stack.
|
||||
This piece must come first, before the fprs. */
|
||||
rtx reg = NULL_RTX;
|
||||
if (align_words < GP_ARG_NUM_REG)
|
||||
{
|
||||
unsigned long n_words = rs6000_arg_size (mode, type);
|
||||
enum machine_mode rmode = mode;
|
||||
|
||||
if (align_words + n_words > GP_ARG_NUM_REG)
|
||||
/* If this is partially on the stack, then we only
|
||||
include the portion actually in registers here.
|
||||
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);
|
||||
if (align_words + n_words > GP_ARG_NUM_REG
|
||||
|| (TARGET_32BIT && TARGET_POWERPC64))
|
||||
{
|
||||
/* If this is partially on the stack, then we only
|
||||
include the portion actually in registers here. */
|
||||
enum machine_mode rmode = TARGET_32BIT ? SImode : DImode;
|
||||
rtx off;
|
||||
do
|
||||
{
|
||||
r = gen_rtx_REG (rmode,
|
||||
GP_ARG_MIN_REG + align_words);
|
||||
off = GEN_INT (k * GET_MODE_SIZE (rmode));
|
||||
rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, off);
|
||||
}
|
||||
while (++align_words < GP_ARG_NUM_REG && --n_words != 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The whole arg fits in gprs. */
|
||||
r = gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
|
||||
rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, const0_rtx);
|
||||
}
|
||||
}
|
||||
*--r = gen_rtx_EXPR_LIST (VOIDmode, reg, const0_rtx);
|
||||
++n;
|
||||
else
|
||||
/* It's entirely in memory. */
|
||||
rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
|
||||
}
|
||||
|
||||
return gen_rtx_PARALLEL (mode, gen_rtvec_v (n, r));
|
||||
/* Describe where this piece goes in the fprs. */
|
||||
r = gen_rtx_REG (fmode, cum->fregno);
|
||||
rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, const0_rtx);
|
||||
|
||||
return gen_rtx_PARALLEL (mode, gen_rtvec_v (k, rvec));
|
||||
}
|
||||
else if (align_words < GP_ARG_NUM_REG)
|
||||
{
|
||||
if (TARGET_32BIT && TARGET_POWERPC64
|
||||
&& (mode == DImode || mode == BLKmode))
|
||||
return rs6000_mixed_function_arg (cum, mode, type, align_words);
|
||||
if (TARGET_32BIT && TARGET_POWERPC64)
|
||||
return rs6000_mixed_function_arg (mode, type, align_words);
|
||||
|
||||
return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
|
||||
}
|
||||
@ -4783,15 +4717,20 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
|
||||
}
|
||||
}
|
||||
|
||||
/* For an arg passed partly in registers and partly in memory,
|
||||
this is the number of registers used.
|
||||
For args passed entirely in registers or entirely in memory, zero. */
|
||||
/* For an arg passed partly in registers and partly in memory, this is
|
||||
the number of registers used. For args passed entirely in registers
|
||||
or entirely in memory, zero. When an arg is described by a PARALLEL,
|
||||
perhaps using more than one register type, this function returns the
|
||||
number of registers used by the first element of the PARALLEL. */
|
||||
|
||||
int
|
||||
function_arg_partial_nregs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
|
||||
tree type, int named)
|
||||
{
|
||||
int ret = 0;
|
||||
int align;
|
||||
int parm_offset;
|
||||
int align_words;
|
||||
|
||||
if (DEFAULT_ABI == ABI_V4)
|
||||
return 0;
|
||||
@ -4800,17 +4739,29 @@ function_arg_partial_nregs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
|
||||
&& cum->nargs_prototype >= 0)
|
||||
return 0;
|
||||
|
||||
if (USE_FP_FOR_ARG_P (cum, mode, type))
|
||||
align = function_arg_boundary (mode, type) / PARM_BOUNDARY - 1;
|
||||
parm_offset = TARGET_32BIT ? 2 : 0;
|
||||
align_words = cum->words + ((parm_offset - cum->words) & align);
|
||||
|
||||
if (USE_FP_FOR_ARG_P (cum, mode, type)
|
||||
/* If we are passing this arg in gprs as well, then this function
|
||||
should return the number of gprs (or memory) partially passed,
|
||||
*not* the number of fprs. */
|
||||
&& !(type
|
||||
&& (cum->nargs_prototype <= 0
|
||||
|| (DEFAULT_ABI == ABI_AIX
|
||||
&& TARGET_XL_CALL
|
||||
&& align_words >= GP_ARG_NUM_REG))))
|
||||
{
|
||||
if (cum->fregno + ((GET_MODE_SIZE (mode) + 7) >> 3) > FP_ARG_MAX_REG + 1)
|
||||
ret = FP_ARG_MAX_REG - cum->fregno;
|
||||
ret = FP_ARG_MAX_REG + 1 - cum->fregno;
|
||||
else if (cum->nargs_prototype >= 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cum->words < GP_ARG_NUM_REG
|
||||
&& GP_ARG_NUM_REG < cum->words + rs6000_arg_size (mode, type))
|
||||
ret = GP_ARG_NUM_REG - cum->words;
|
||||
if (align_words < GP_ARG_NUM_REG
|
||||
&& GP_ARG_NUM_REG < align_words + rs6000_arg_size (mode, type))
|
||||
ret = GP_ARG_NUM_REG - align_words;
|
||||
|
||||
if (ret != 0 && TARGET_DEBUG_ARG)
|
||||
fprintf (stderr, "function_arg_partial_nregs: %d\n", ret);
|
||||
|
Loading…
Reference in New Issue
Block a user