This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: PATCH [mainline] - Fix passing of zero-sized structs in apple-ppc-darwin mixed mode
Here's the complete revised patch.
* 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.
diff -crp -xCVS -x'*~' gcc-virgin/gcc/config/rs6000/rs6000.c gcc-mainline/gcc/config/rs6000/rs6000.c
*** gcc-virgin/gcc/config/rs6000/rs6000.c 2004-06-24 14:24:16.000000000 +0930
--- gcc-mainline/gcc/config/rs6000/rs6000.c 2004-06-28 09:19:48.099524794 +0930
*************** static rtx rs6000_dwarf_register_span (r
*** 425,432 ****
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 void rs6000_move_block_from_reg (int regno, rtx x, int nregs);
static void setup_incoming_varargs (CUMULATIVE_ARGS *,
enum machine_mode, tree,
--- 425,431 ----
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 (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,
*************** rs6000_spe_function_arg (CUMULATIVE_ARGS
*** 4418,4541 ****
/* 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)
{
! 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)));
!
! /* 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));
!
! memset ((char *) rtlvec, 0, rtlvec_len * sizeof (rtx));
!
! 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));
! return gen_rtx_PARALLEL (mode, gen_rtvec_v (k, rtlvec));
! }
! return NULL_RTX;
}
/* Determine where to put an argument to a function.
--- 4417,4465 ----
/* Determine where to place an argument in 64-bit mode with 32-bit ABI. */
static rtx
! rs6000_mixed_function_arg (enum machine_mode mode, tree type, int align_words)
{
! int n_units;
! int i, k;
! rtx rvec[GP_ARG_NUM_REG + 1];
!
! if (align_words >= GP_ARG_NUM_REG)
! return NULL_RTX;
!
! n_units = rs6000_arg_size (mode, type);
!
! /* 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);
!
! 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);
}
! 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.
*************** function_arg (CUMULATIVE_ARGS *cum, enum
*** 4630,4637 ****
{
/* 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;
/* 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
--- 4554,4561 ----
{
/* Vector parameters to varargs functions under AIX or Darwin
get passed in memory and possibly also in GPRs. */
! 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
*************** function_arg (CUMULATIVE_ARGS *cum, enum
*** 4647,4666 ****
/* Out of registers? Memory, then. */
if (align_words >= GP_ARG_NUM_REG)
return NULL_RTX;
!
/* 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)
/* 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);
}
}
else if (TARGET_SPE_ABI && TARGET_SPE && SPE_VECTOR_MODE (mode))
--- 4571,4590 ----
/* Out of registers? Memory, then. */
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. */
! 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;
!
! return gen_rtx_REG (part_mode, GP_ARG_MIN_REG + align_words);
}
}
else if (TARGET_SPE_ABI && TARGET_SPE && SPE_VECTOR_MODE (mode))
*************** function_arg (CUMULATIVE_ARGS *cum, enum
*** 4687,4696 ****
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
return NULL_RTX;
}
}
else
--- 4611,4623 ----
gregno += (1 - gregno) & 1;
/* Multi-reg args are not split between registers and stack. */
! 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
*************** function_arg (CUMULATIVE_ARGS *cum, enum
*** 4700,4724 ****
if (USE_FP_FOR_ARG_P (cum, mode, type))
{
! rtx fpr[2];
! rtx *r;
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)
abort ();
}
- fpr[1] = gen_rtx_REG (fmode, cum->fregno);
/* Do we also need to pass this arg in the parameter save
area? */
--- 4627,4649 ----
if (USE_FP_FOR_ARG_P (cum, mode, type))
{
! rtx rvec[GP_ARG_NUM_REG + 1];
! rtx r;
! int k;
bool needs_psave;
enum machine_mode fmode = mode;
unsigned long n_fpreg = (GET_MODE_SIZE (mode) + 7) >> 3;
if (cum->fregno + n_fpreg > FP_ARG_MAX_REG + 1)
{
/* Currently, we only ever need one reg here because complex
doubles are split. */
! if (cum->fregno != FP_ARG_MAX_REG || fmode != TFmode)
abort ();
+
+ /* Long double split over regs and memory. */
+ fmode = DFmode;
}
/* Do we also need to pass this arg in the parameter save
area? */
*************** function_arg (CUMULATIVE_ARGS *cum, enum
*** 4729,4774 ****
&& 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;
if (needs_psave)
{
! /* Now 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);
}
! *--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)
{
! if (TARGET_32BIT && TARGET_POWERPC64
! && (mode == DImode || mode == BLKmode))
! return rs6000_mixed_function_arg (cum, mode, type, align_words);
return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
}
--- 4654,4708 ----
&& align_words >= GP_ARG_NUM_REG)));
if (!needs_psave && mode == fmode)
! return gen_rtx_REG (fmode, cum->fregno);
+ k = 0;
if (needs_psave)
{
! /* Describe the part that goes in gprs or the stack.
This piece must come first, before the fprs. */
if (align_words < GP_ARG_NUM_REG)
{
unsigned long n_words = rs6000_arg_size (mode, type);
! 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);
! }
}
! else
! /* It's entirely in memory. */
! rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
}
! /* 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)
! return rs6000_mixed_function_arg (mode, type, align_words);
return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
}
*************** function_arg (CUMULATIVE_ARGS *cum, enum
*** 4777,4791 ****
}
}
! /* 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. */
int
function_arg_partial_nregs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
tree type, int named)
{
int ret = 0;
if (DEFAULT_ABI == ABI_V4)
return 0;
--- 4711,4730 ----
}
}
! /* 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;
*************** function_arg_partial_nregs (CUMULATIVE_A
*** 4794,4810 ****
&& cum->nargs_prototype >= 0)
return 0;
! if (USE_FP_FOR_ARG_P (cum, mode, type))
{
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;
}
! 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 (ret != 0 && TARGET_DEBUG_ARG)
fprintf (stderr, "function_arg_partial_nregs: %d\n", ret);
--- 4733,4761 ----
&& cum->nargs_prototype >= 0)
return 0;
! 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 + 1 - cum->fregno;
else if (cum->nargs_prototype >= 0)
return 0;
}
! 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);
--
Alan Modra
IBM OzLabs - Linux Technology Centre