calls.c (initialize_argument_information): If an argument has no stack space associated with it...

* calls.c (initialize_argument_information): If an argument has no
	stack space associated with it, and BLOCK_REG_PADDING is defined,
	use it to decide at which end the argument should be padded.
	* function.c (assign_parms): Allocate BLKmode stack slots.
	* config/mips/mips-protos.h (mips_pad_arg_upward): Declare.
	(mips_pad_reg_upward): Declare.
	* config/mips/mips.h (PAD_VARARGS_DOWN): Use FUNCTION_ARG_PADDING.
	(CUMULATIVE_ARGS): Remove num_adjusts and adjusts.
	(FUNCTION_ARG_PADDING): Use mips_pad_arg_upward.
	(BLOCK_REG_PADDING): Use mips_pad_reg_upward.
	* config/mips/mips.c (struct mips_arg_info): Remove struct_p.
	(mips_expand_call): Remove code for generating structure shifts.
	(mips_arg_info): Don't set struct_p.  Don't set fpr_p for non-float
	types unless using the EABI.
	(function_arg_advance): Don't generate shift instructions.
	(function_arg): Don't return them.  Don't short-circuit the
	check for double structure chunks for DFmode arguments.
	(mips_pad_arg_upward, mips_pad_reg_upward): New functions.
	(mips_expand_prologue): Remove code to emit structure shifts.
	* config/mips/irix6-libc-compat.c: Remove workarounds for buggy
	structure passing (inet_ntoa, inet_lnaof, inet_netof).  Update
	comments to say that only structure returns are a problem.

From-SVN: r70843
This commit is contained in:
Richard Sandiford 2003-08-27 07:05:18 +00:00 committed by Richard Sandiford
parent 0c7829a97b
commit 648bb15912
7 changed files with 122 additions and 217 deletions

View File

@ -1,3 +1,28 @@
2003-08-27 Richard Sandiford <rsandifo@redhat.com>
* calls.c (initialize_argument_information): If an argument has no
stack space associated with it, and BLOCK_REG_PADDING is defined,
use it to decide at which end the argument should be padded.
* function.c (assign_parms): Allocate BLKmode stack slots.
* config/mips/mips-protos.h (mips_pad_arg_upward): Declare.
(mips_pad_reg_upward): Declare.
* config/mips/mips.h (PAD_VARARGS_DOWN): Use FUNCTION_ARG_PADDING.
(CUMULATIVE_ARGS): Remove num_adjusts and adjusts.
(FUNCTION_ARG_PADDING): Use mips_pad_arg_upward.
(BLOCK_REG_PADDING): Use mips_pad_reg_upward.
* config/mips/mips.c (struct mips_arg_info): Remove struct_p.
(mips_expand_call): Remove code for generating structure shifts.
(mips_arg_info): Don't set struct_p. Don't set fpr_p for non-float
types unless using the EABI.
(function_arg_advance): Don't generate shift instructions.
(function_arg): Don't return them. Don't short-circuit the
check for double structure chunks for DFmode arguments.
(mips_pad_arg_upward, mips_pad_reg_upward): New functions.
(mips_expand_prologue): Remove code to emit structure shifts.
* config/mips/irix6-libc-compat.c: Remove workarounds for buggy
structure passing (inet_ntoa, inet_lnaof, inet_netof). Update
comments to say that only structure returns are a problem.
2003-08-26 Nathanael Nerode <neroden@gcc.gnu.org>
* fixinc/tests/base/string.h, fixinc/tests/base/sys/regset.h:

View File

@ -1238,6 +1238,14 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
#endif
args[i].pass_on_stack ? 0 : args[i].partial,
fndecl, args_size, &args[i].locate);
#ifdef BLOCK_REG_PADDING
else
/* The argument is passed entirely in registers. See at which
end it should be padded. */
args[i].locate.where_pad =
BLOCK_REG_PADDING (mode, type,
int_size_in_bytes (type) <= UNITS_PER_WORD);
#endif
/* Update ARGS_SIZE, the total stack space for args so far. */

View File

@ -1,4 +1,4 @@
/* Compensate for inconsistent structure passing conventions on IRIX 6. */
/* Compensate for inconsistent structure return conventions on IRIX 6. */
/* Compile this one with gcc. */
/* Copyright (C) 2001 Free Software Foundation, Inc.
@ -28,7 +28,7 @@ along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* GCC doesn't correctly implement the structure and union passing and return
/* GCC doesn't correctly implement the structure and union return
conventions of the N32 and N64 ABIs on IRIX 6, as described in the
MIPSpro N32 ABI Handbook, ch. 2, Calling Convention Implementations, p.7.
The ABI requires that structures (or trailing parts of structures) smaller
@ -38,17 +38,15 @@ Boston, MA 02111-1307, USA. */
While GCC is internally consistent, calling routines compiled with a
compiler that does implement the documented ABI (like SGIs MIPSpro C
compiler) doesn't work. This is primarily an issue for system libraries
like libc. Fortunately, there exist only very few routines that take
structure value arguments or return structures by value, so until the
underlying bug is fixed, it is possible to work around it by providing
wrapper functions for the few affected routines that compensate for the
inconsistent alignment.
like libc. Fortunately, there exist only very few routines that return
structures by value, so until the underlying bug is fixed, it is possible
to work around it by providing wrappers for the few affected routines.
These wrappers rely on the fact that e.g. libc contains weak versions of
those routines, and the real implementation is provided by _-prefixed
variants. So we can provide our own versions, which will only be linked
if the application uses any of the affected functions, calling the private
variants after shifting the arguments or results as required.
variants and then shifting the result as required.
This is a rewrite of code created by Andy Polyakov. */
@ -61,60 +59,15 @@ Boston, MA 02111-1307, USA. */
#if _MIPS_SIM == _ABIN32 || _MIPS_SIM == _ABI64
/* The affected arguments need to be shifted by
/* The affected return values need to be shifted by
BITS_PER_WORD - (sizeof (arg) * BITS_PER_UNIT).
BITS_PER_WORD - (sizeof (value) * BITS_PER_UNIT).
Since only 32-bit args and results are involved, the shift count is
always 32. */
Since only 32-bit results are involved, the shift count is always 32. */
#define SHIFT_BITS 32
extern machreg_t inet_ntoa (machreg_t);
extern machreg_t inet_lnaof (machreg_t);
extern machreg_t inet_netof (machreg_t);
extern machreg_t inet_makeaddr (machreg_t, machreg_t);
extern machreg_t _inet_ntoa (machreg_t);
extern machreg_t _inet_lnaof (machreg_t);
extern machreg_t _inet_netof (machreg_t);
extern machreg_t _inet_makeaddr (machreg_t, machreg_t);
/* <arpa/inet.h> has
char *inet_ntoa (struct in_addr);
on both IRIX 6.2 and 6.5, with struct in_addr containing a 32-bit int. */
machreg_t
inet_ntoa (machreg_t in)
{
return _inet_ntoa (in << SHIFT_BITS);
}
/* <arpa/inet.h> has
unsigned long inet_lnaof (struct in_addr); (IRIX 6.2)
in_addr_t inet_lnaof (struct in_addr); (IRIX 6.5)
in_addr_t is a 32-bit int. */
machreg_t
inet_lnaof (machreg_t in)
{
return _inet_lnaof (in << SHIFT_BITS);
}
/* <arpa/inet.h> has
unsigned long inet_netof (struct in_addr); (IRIX 6.2)
in_addr_t inet_netof (struct in_addr); (IRIX 6.5) */
machreg_t
inet_netof (machreg_t in)
{
return _inet_netof (in << SHIFT_BITS);
}
/* <arpa/inet.h> has
struct in_addr inet_makeaddr (int, int); (IRIX 6.2)
@ -126,23 +79,4 @@ inet_makeaddr (machreg_t net, machreg_t lna)
return _inet_makeaddr (net, lna) >> SHIFT_BITS;
}
#if _MIPS_SIM == _ABIN32
extern machreg_t semctl (machreg_t, machreg_t, machreg_t, machreg_t);
extern machreg_t _semctl (machreg_t, machreg_t, machreg_t, machreg_t);
/* <sys/sem.h> has
int semctl (int, int, int, ...);
where the variadic argument is union semun if used. union semun contains
an int and two pointers, so the union is already 64 bits wide under the
N64 ABI and alignment is not an issue. */
machreg_t
semctl (machreg_t semid, machreg_t semnum, machreg_t cmd, machreg_t arg)
{
return _semctl(semid, semnum, cmd, arg << SHIFT_BITS);
}
#endif /* _ABIN32 */
#endif /* _ABIN32 || _ABI64 */

View File

@ -80,6 +80,8 @@ extern struct rtx_def *function_arg (const CUMULATIVE_ARGS *,
enum machine_mode, tree, int);
extern int function_arg_partial_nregs (const CUMULATIVE_ARGS *,
enum machine_mode, tree, int);
extern bool mips_pad_arg_upward (enum machine_mode, tree);
extern bool mips_pad_reg_upward (enum machine_mode, tree);
extern int mips_setup_incoming_varargs (const CUMULATIVE_ARGS *,
enum machine_mode, tree, int);
extern tree mips_build_va_list (void);

View File

@ -317,9 +317,6 @@ struct machine_function GTY(()) {
/* Information about a single argument. */
struct mips_arg_info
{
/* True if the argument is a record or union type. */
bool struct_p;
/* True if the argument is passed in a floating-point register, or
would have been if we hadn't run out of registers. */
bool fpr_p;
@ -3208,8 +3205,6 @@ mips_gen_conditional_trap (rtx *operands)
void
mips_expand_call (rtx result, rtx addr, rtx args_size, rtx aux, int sibcall_p)
{
int i;
if (!call_insn_operand (addr, VOIDmode))
{
/* When generating PIC, try to allow global functions to be
@ -3226,16 +3221,6 @@ mips_expand_call (rtx result, rtx addr, rtx args_size, rtx aux, int sibcall_p)
addr = force_reg (Pmode, addr);
}
/* In order to pass small structures by value in registers
compatibly with the MIPS compiler, we need to shift the value
into the high part of the register. Function_arg has encoded
a PARALLEL rtx, holding a vector of adjustments to be made
as the next_arg_reg variable, so we split up the insns,
and emit them separately. */
if (aux != 0 && GET_CODE (aux) == PARALLEL)
for (i = 0; i < XVECLEN (aux, 0); i++)
emit_insn (XVECEXP (aux, 0, i));
if (TARGET_MIPS16
&& mips16_hard_float
&& build_mips16_call_stub (result, addr, args_size,
@ -3557,34 +3542,27 @@ mips_arg_info (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
bool even_reg_p;
unsigned int num_words, max_regs;
info->struct_p = (type != 0
&& (TREE_CODE (type) == RECORD_TYPE
|| TREE_CODE (type) == UNION_TYPE
|| TREE_CODE (type) == QUAL_UNION_TYPE));
/* Decide whether this argument should go in a floating-point register,
assuming one is free. Later code checks for availability. */
info->fpr_p = false;
if (GET_MODE_CLASS (mode) == MODE_FLOAT
&& GET_MODE_SIZE (mode) <= UNITS_PER_FPVALUE)
{
switch (mips_abi)
{
case ABI_32:
case ABI_O64:
info->fpr_p = (!cum->gp_reg_found && cum->arg_number < 2);
break;
info->fpr_p = (GET_MODE_CLASS (mode) == MODE_FLOAT
&& GET_MODE_SIZE (mode) <= UNITS_PER_FPVALUE);
case ABI_EABI:
info->fpr_p = true;
break;
if (info->fpr_p)
switch (mips_abi)
{
case ABI_32:
case ABI_O64:
info->fpr_p = (!cum->gp_reg_found
&& cum->arg_number < 2
&& (type == 0 || FLOAT_TYPE_P (type)));
break;
default:
info->fpr_p = named;
break;
}
}
case ABI_N32:
case ABI_64:
info->fpr_p = (named && (type == 0 || FLOAT_TYPE_P (type)));
break;
}
/* Now decide whether the argument must go in an even-numbered register. */
@ -3648,36 +3626,6 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
mips_arg_info (cum, mode, type, named, &info);
/* The following is a hack in order to pass 1 byte structures
the same way that the MIPS compiler does (namely by passing
the structure in the high byte or half word of the register).
This also makes varargs work. If we have such a structure,
we save the adjustment RTL, and the call define expands will
emit them. For the VOIDmode argument (argument after the
last real argument), pass back a parallel vector holding each
of the adjustments. */
/* ??? This scheme requires everything smaller than the word size to
shifted to the left, but when TARGET_64BIT and ! TARGET_INT64,
that would mean every int needs to be shifted left, which is very
inefficient. Let's not carry this compatibility to the 64 bit
calling convention for now. */
if (info.struct_p
&& info.reg_words == 1
&& info.num_bytes < UNITS_PER_WORD
&& !TARGET_64BIT
&& mips_abi != ABI_EABI)
{
rtx amount = GEN_INT (BITS_PER_WORD - info.num_bytes * BITS_PER_UNIT);
rtx reg = gen_rtx_REG (word_mode, GP_ARG_FIRST + info.reg_offset);
if (TARGET_64BIT)
cum->adjust[cum->num_adjusts++] = PATTERN (gen_ashldi3 (reg, reg, amount));
else
cum->adjust[cum->num_adjusts++] = PATTERN (gen_ashlsi3 (reg, reg, amount));
}
if (!info.fpr_p)
cum->gp_reg_found = true;
@ -3708,18 +3656,11 @@ function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
/* We will be called with a mode of VOIDmode after the last argument
has been seen. Whatever we return will be passed to the call
insn. If we need any shifts for small structures, return them in
a PARALLEL; in that case, stuff the mips16 fp_code in as the
mode. Otherwise, if we need a mips16 fp_code, return a REG
with the code stored as the mode. */
insn. If we need a mips16 fp_code, return a REG with the code
stored as the mode. */
if (mode == VOIDmode)
{
if (cum->num_adjusts > 0)
return gen_rtx_PARALLEL ((enum machine_mode) cum->fp_code,
gen_rtvec_v (cum->num_adjusts,
(rtx *) cum->adjust));
else if (TARGET_MIPS16 && cum->fp_code != 0)
if (TARGET_MIPS16 && cum->fp_code != 0)
return gen_rtx_REG ((enum machine_mode) cum->fp_code, 0);
else
@ -3737,8 +3678,7 @@ function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
&& (mips_abi == ABI_N32 || mips_abi == ABI_64)
&& TYPE_SIZE_UNIT (type)
&& host_integerp (TYPE_SIZE_UNIT (type), 1)
&& named
&& mode != DFmode)
&& named)
{
/* The Irix 6 n32/n64 ABIs say that if any 64 bit chunk of the
structure contains a double in its entirety, then that 64 bit
@ -3815,6 +3755,55 @@ function_arg_partial_nregs (const CUMULATIVE_ARGS *cum,
mips_arg_info (cum, mode, type, named, &info);
return info.stack_words > 0 ? info.reg_words : 0;
}
/* Return true if FUNCTION_ARG_PADDING (MODE, TYPE) should return
upward rather than downward. In other words, return true if the
first byte of the stack slot has useful data, false if the last
byte does. */
bool
mips_pad_arg_upward (enum machine_mode mode, tree type)
{
/* On little-endian targets, the first byte of every stack argument
is passed in the first byte of the stack slot. */
if (!BYTES_BIG_ENDIAN)
return true;
/* Otherwise, integral types are padded downward: the last byte of a
stack argument is passed in the last byte of the stack slot. */
if (type != 0
? INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type)
: GET_MODE_CLASS (mode) == MODE_INT)
return false;
/* Other types are padded upward for o32, o64, n32 and n64. */
if (mips_abi != ABI_EABI)
return true;
/* Arguments smaller than a stack slot are padded downward. */
if (mode != BLKmode)
return (GET_MODE_BITSIZE (mode) >= PARM_BOUNDARY);
else
return (int_size_in_bytes (type) >= (PARM_BOUNDARY / BITS_PER_UNIT));
}
/* Likewise BLOCK_REG_PADDING (MODE, TYPE, ...). Return !BYTES_BIG_ENDIAN
if the least significant byte of the register has useful data. Return
the opposite if the most significant byte does. */
bool
mips_pad_reg_upward (enum machine_mode mode, tree type)
{
/* No shifting is required for floating-point arguments. */
if (type != 0 ? FLOAT_TYPE_P (type) : GET_MODE_CLASS (mode) == MODE_FLOAT)
return !BYTES_BIG_ENDIAN;
/* Otherwise, apply the same padding to register arguments as we do
to stack arguments. */
return mips_pad_arg_upward (mode, type);
}
int
mips_setup_incoming_varargs (const CUMULATIVE_ARGS *cum,
@ -6716,8 +6705,6 @@ mips_expand_prologue (void)
tree fndecl = current_function_decl;
tree fntype = TREE_TYPE (fndecl);
tree fnargs = DECL_ARGUMENTS (fndecl);
rtx next_arg_reg;
int i;
tree cur_arg;
CUMULATIVE_ARGS args_so_far;
rtx reg_18_save = NULL_RTX;
@ -6757,39 +6744,6 @@ mips_expand_prologue (void)
FUNCTION_ARG_ADVANCE (args_so_far, passed_mode, passed_type, 1);
}
/* In order to pass small structures by value in registers compatibly with
the MIPS compiler, we need to shift the value into the high part of the
register. Function_arg has encoded a PARALLEL rtx, holding a vector of
adjustments to be made as the next_arg_reg variable, so we split up the
insns, and emit them separately. */
next_arg_reg = FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1);
if (next_arg_reg != 0 && GET_CODE (next_arg_reg) == PARALLEL)
{
rtvec adjust = XVEC (next_arg_reg, 0);
int num = GET_NUM_ELEM (adjust);
for (i = 0; i < num; i++)
{
rtx insn, pattern;
pattern = RTVEC_ELT (adjust, i);
if (GET_CODE (pattern) != SET
|| GET_CODE (SET_SRC (pattern)) != ASHIFT)
fatal_insn ("insn is not a shift", pattern);
PUT_CODE (SET_SRC (pattern), ASHIFTRT);
insn = emit_insn (pattern);
/* Global life information isn't valid at this point, so we
can't check whether these shifts are actually used. Mark
them MAYBE_DEAD so that flow2 will remove them, and not
complain about dead code in the prologue. */
REG_NOTES(insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX,
REG_NOTES (insn));
}
}
tsize = compute_frame_size (get_frame_size ());
/* If we are using the entry pseudo instruction, it will

View File

@ -1399,9 +1399,8 @@ extern const struct mips_cpu_info *mips_tune_info;
|| TREE_CODE (TYPE) == RECORD_TYPE)) ? BITS_PER_WORD : (ALIGN))
/* Force right-alignment for small varargs in 32 bit little_endian mode */
#define PAD_VARARGS_DOWN (TARGET_64BIT ? BYTES_BIG_ENDIAN : !BYTES_BIG_ENDIAN)
#define PAD_VARARGS_DOWN \
(FUNCTION_ARG_PADDING (TYPE_MODE (type), type) == downward)
/* Arguments declared as 'char' or 'short' in a prototype should be
passed as 'int's. */
@ -2295,15 +2294,6 @@ typedef struct mips_args {
/* True if the function has a prototype. */
int prototype;
/* When a structure does not take up a full register, the argument
should sometimes be shifted left so that it occupies the high part
of the register. These two fields describe an array of ashl
patterns for doing this. See function_arg_advance, which creates
the shift patterns, and function_arg, which returns them when given
a VOIDmode argument. */
unsigned int num_adjusts;
rtx adjust[BIGGEST_MAX_ARGS_IN_REGISTERS];
} CUMULATIVE_ARGS;
/* Initialize a variable CUM of type CUMULATIVE_ARGS
@ -2361,18 +2351,11 @@ typedef struct mips_args {
#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) \
function_arg_pass_by_reference (&CUM, MODE, TYPE, NAMED)
#define FUNCTION_ARG_PADDING(MODE, TYPE) \
(! BYTES_BIG_ENDIAN \
? upward \
: (((MODE) == BLKmode \
? ((TYPE) && TREE_CODE (TYPE_SIZE (TYPE)) == INTEGER_CST \
&& int_size_in_bytes (TYPE) < (PARM_BOUNDARY / BITS_PER_UNIT))\
: (GET_MODE_BITSIZE (MODE) < PARM_BOUNDARY \
&& (mips_abi == ABI_32 \
|| mips_abi == ABI_O64 \
|| mips_abi == ABI_EABI \
|| GET_MODE_CLASS (MODE) == MODE_INT))) \
? downward : upward))
#define FUNCTION_ARG_PADDING(MODE, TYPE) \
(mips_pad_arg_upward (MODE, TYPE) ? upward : downward)
#define BLOCK_REG_PADDING(MODE, TYPE, FIRST) \
(mips_pad_reg_upward (MODE, TYPE) ? upward : downward)
#define FUNCTION_ARG_CALLEE_COPIES(CUM, MODE, TYPE, NAMED) \
(mips_abi == ABI_EABI && (NAMED) \

View File

@ -4674,9 +4674,8 @@ assign_parms (tree fndecl)
if (stack_parm == 0)
{
stack_parm
= assign_stack_local (GET_MODE (entry_parm),
size_stored, 0);
stack_parm = assign_stack_local (BLKmode, size_stored, 0);
PUT_MODE (stack_parm, GET_MODE (entry_parm));
set_mem_attributes (stack_parm, parm, 1);
}