tm.texi (BLOCK_REG_PADDING): Describe.
* doc/tm.texi (BLOCK_REG_PADDING): Describe. * expr.h (struct locate_and_pad_arg_data): Add where_pad. (emit_group_load, emit_group_store): Adjust declarations. Remove most occurrences of #ifdef TREE_CODE. * expr.c (emit_group_load): Add "type" param, and use BLOCK_REG_PADDING to determine need for a shift. Optimize non- aligned accesses if !SLOW_UNALIGNED_ACCESS. (emit_group_store): Likewise. (emit_push_insn, expand_assignment, store_expr, expand_expr): Adjust emit_group_load and emit_group_store calls. * calls.c (store_unaligned_arguments_into_pseudos): Tidy. Use BLOCK_REG_PADDING to determine whether we need endian_correction. (load_register_parameters): Localize vars. Handle shifting of small values to the correct end of regs. Adjust emit_group_load call. (expand_call, emit_library_call_value_1): Adjust emit_group_load and emit_group_store calls. * function.c (assign_parms): Set mem alignment for stack slots. Adjust emit_group_store call. Store values at the "wrong" end of regs to the stack. Use BLOCK_REG_PADDING. (locate_and_pad_parm): Save where_pad. (expand_function_end): Adjust emit_group_load call. * stmt.c (expand_value_return): Adjust emit_group_load call. * Makefile.in (calls.o): Depend on $(OPTABS_H). * config/rs6000/linux64.h (TARGET_LITTLE_ENDIAN): Redefine as 0. (AGGREGATE_PADDING_FIXED, AGGREGATES_PAD_UPWARD_ALWAYS): Define. (MUST_PASS_IN_STACK): Define. (BLOCK_REG_PADDING): Define. * config/rs6000/rs6000.h (struct rs6000_args): Remove orig_nargs. (PAD_VARARGS_DOWN): Define in terms of FUNCTION_ARG_PADDING. * config/rs6000/rs6000.c (init_cumulative_args): Don't set orig_nargs. (function_arg_padding): !AGGREGATE_PADDING_FIXED compatibility code. Act on AGGREGATES_PAD_UPWARD_ALWAYS. From-SVN: r69318
This commit is contained in:
parent
a3d8777127
commit
6e98504002
11 changed files with 291 additions and 95 deletions
|
@ -1,3 +1,39 @@
|
|||
2003-07-14 Alan Modra <amodra@bigpond.net.au>
|
||||
|
||||
* doc/tm.texi (BLOCK_REG_PADDING): Describe.
|
||||
* expr.h (struct locate_and_pad_arg_data): Add where_pad.
|
||||
(emit_group_load, emit_group_store): Adjust declarations.
|
||||
Remove most occurrences of #ifdef TREE_CODE.
|
||||
* expr.c (emit_group_load): Add "type" param, and use
|
||||
BLOCK_REG_PADDING to determine need for a shift. Optimize non-
|
||||
aligned accesses if !SLOW_UNALIGNED_ACCESS.
|
||||
(emit_group_store): Likewise.
|
||||
(emit_push_insn, expand_assignment, store_expr, expand_expr): Adjust
|
||||
emit_group_load and emit_group_store calls.
|
||||
* calls.c (store_unaligned_arguments_into_pseudos): Tidy. Use
|
||||
BLOCK_REG_PADDING to determine whether we need endian_correction.
|
||||
(load_register_parameters): Localize vars. Handle shifting of
|
||||
small values to the correct end of regs. Adjust emit_group_load
|
||||
call.
|
||||
(expand_call, emit_library_call_value_1): Adjust emit_group_load
|
||||
and emit_group_store calls.
|
||||
* function.c (assign_parms): Set mem alignment for stack slots.
|
||||
Adjust emit_group_store call. Store values at the "wrong" end
|
||||
of regs to the stack. Use BLOCK_REG_PADDING.
|
||||
(locate_and_pad_parm): Save where_pad.
|
||||
(expand_function_end): Adjust emit_group_load call.
|
||||
* stmt.c (expand_value_return): Adjust emit_group_load call.
|
||||
* Makefile.in (calls.o): Depend on $(OPTABS_H).
|
||||
* config/rs6000/linux64.h (TARGET_LITTLE_ENDIAN): Redefine as 0.
|
||||
(AGGREGATE_PADDING_FIXED, AGGREGATES_PAD_UPWARD_ALWAYS): Define.
|
||||
(MUST_PASS_IN_STACK): Define.
|
||||
(BLOCK_REG_PADDING): Define.
|
||||
* config/rs6000/rs6000.h (struct rs6000_args): Remove orig_nargs.
|
||||
(PAD_VARARGS_DOWN): Define in terms of FUNCTION_ARG_PADDING.
|
||||
* config/rs6000/rs6000.c (init_cumulative_args): Don't set orig_nargs.
|
||||
(function_arg_padding): !AGGREGATE_PADDING_FIXED compatibility code.
|
||||
Act on AGGREGATES_PAD_UPWARD_ALWAYS.
|
||||
|
||||
2003-07-13 Aaron W. LaFramboise <awlaframboise@aol.com>
|
||||
|
||||
* config/i386/gthr-win32.c (__GTHREAD_HIDE_WIN32API): Define to 1.
|
||||
|
|
|
@ -1547,7 +1547,7 @@ builtins.o : builtins.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(T
|
|||
$(RECOG_H) output.h typeclass.h hard-reg-set.h toplev.h hard-reg-set.h \
|
||||
except.h $(TM_P_H) $(PREDICT_H) libfuncs.h real.h langhooks.h
|
||||
calls.o : calls.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) flags.h \
|
||||
$(EXPR_H) langhooks.h $(TARGET_H) \
|
||||
$(EXPR_H) $(OPTABS_H) langhooks.h $(TARGET_H) \
|
||||
libfuncs.h $(REGS_H) toplev.h output.h function.h $(TIMEVAR_H) $(TM_P_H) cgraph.h except.h
|
||||
expmed.o : expmed.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \
|
||||
flags.h insn-config.h $(EXPR_H) $(OPTABS_H) $(RECOG_H) real.h \
|
||||
|
|
120
gcc/calls.c
120
gcc/calls.c
|
@ -27,6 +27,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
|||
#include "tree.h"
|
||||
#include "flags.h"
|
||||
#include "expr.h"
|
||||
#include "optabs.h"
|
||||
#include "libfuncs.h"
|
||||
#include "function.h"
|
||||
#include "regs.h"
|
||||
|
@ -934,22 +935,27 @@ store_unaligned_arguments_into_pseudos (struct arg_data *args, int num_actuals)
|
|||
< (unsigned int) MIN (BIGGEST_ALIGNMENT, BITS_PER_WORD)))
|
||||
{
|
||||
int bytes = int_size_in_bytes (TREE_TYPE (args[i].tree_value));
|
||||
int big_endian_correction = 0;
|
||||
|
||||
args[i].n_aligned_regs
|
||||
= args[i].partial ? args[i].partial
|
||||
: (bytes + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD;
|
||||
int nregs = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
|
||||
int endian_correction = 0;
|
||||
|
||||
args[i].n_aligned_regs = args[i].partial ? args[i].partial : nregs;
|
||||
args[i].aligned_regs = (rtx *) xmalloc (sizeof (rtx)
|
||||
* args[i].n_aligned_regs);
|
||||
|
||||
/* Structures smaller than a word are aligned to the least
|
||||
significant byte (to the right). On a BYTES_BIG_ENDIAN machine,
|
||||
/* Structures smaller than a word are normally aligned to the
|
||||
least significant byte. On a BYTES_BIG_ENDIAN machine,
|
||||
this means we must skip the empty high order bytes when
|
||||
calculating the bit offset. */
|
||||
if (BYTES_BIG_ENDIAN
|
||||
&& bytes < UNITS_PER_WORD)
|
||||
big_endian_correction = (BITS_PER_WORD - (bytes * BITS_PER_UNIT));
|
||||
if (bytes < UNITS_PER_WORD
|
||||
#ifdef BLOCK_REG_PADDING
|
||||
&& (BLOCK_REG_PADDING (args[i].mode,
|
||||
TREE_TYPE (args[i].tree_value), 1)
|
||||
== downward)
|
||||
#else
|
||||
&& BYTES_BIG_ENDIAN
|
||||
#endif
|
||||
)
|
||||
endian_correction = BITS_PER_WORD - bytes * BITS_PER_UNIT;
|
||||
|
||||
for (j = 0; j < args[i].n_aligned_regs; j++)
|
||||
{
|
||||
|
@ -958,6 +964,8 @@ store_unaligned_arguments_into_pseudos (struct arg_data *args, int num_actuals)
|
|||
int bitsize = MIN (bytes * BITS_PER_UNIT, BITS_PER_WORD);
|
||||
|
||||
args[i].aligned_regs[j] = reg;
|
||||
word = extract_bit_field (word, bitsize, 0, 1, NULL_RTX,
|
||||
word_mode, word_mode, BITS_PER_WORD);
|
||||
|
||||
/* There is no need to restrict this code to loading items
|
||||
in TYPE_ALIGN sized hunks. The bitfield instructions can
|
||||
|
@ -973,11 +981,8 @@ store_unaligned_arguments_into_pseudos (struct arg_data *args, int num_actuals)
|
|||
emit_move_insn (reg, const0_rtx);
|
||||
|
||||
bytes -= bitsize / BITS_PER_UNIT;
|
||||
store_bit_field (reg, bitsize, big_endian_correction, word_mode,
|
||||
extract_bit_field (word, bitsize, 0, 1, NULL_RTX,
|
||||
word_mode, word_mode,
|
||||
BITS_PER_WORD),
|
||||
BITS_PER_WORD);
|
||||
store_bit_field (reg, bitsize, endian_correction, word_mode,
|
||||
word, BITS_PER_WORD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1580,34 +1585,48 @@ load_register_parameters (struct arg_data *args, int num_actuals,
|
|||
{
|
||||
rtx reg = ((flags & ECF_SIBCALL)
|
||||
? args[i].tail_call_reg : args[i].reg);
|
||||
int partial = args[i].partial;
|
||||
int nregs;
|
||||
|
||||
if (reg)
|
||||
{
|
||||
int partial = args[i].partial;
|
||||
int nregs;
|
||||
int size = 0;
|
||||
rtx before_arg = get_last_insn ();
|
||||
/* Set to non-negative if must move a word at a time, even if just
|
||||
one word (e.g, partial == 1 && mode == DFmode). Set to -1 if
|
||||
we just use a normal move insn. This value can be zero if the
|
||||
argument is a zero size structure with no fields. */
|
||||
nregs = (partial ? partial
|
||||
: (TYPE_MODE (TREE_TYPE (args[i].tree_value)) == BLKmode
|
||||
? ((int_size_in_bytes (TREE_TYPE (args[i].tree_value))
|
||||
+ (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)
|
||||
: -1));
|
||||
nregs = -1;
|
||||
if (partial)
|
||||
nregs = partial;
|
||||
else if (TYPE_MODE (TREE_TYPE (args[i].tree_value)) == BLKmode)
|
||||
{
|
||||
size = int_size_in_bytes (TREE_TYPE (args[i].tree_value));
|
||||
nregs = (size + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD;
|
||||
}
|
||||
else
|
||||
size = GET_MODE_SIZE (args[i].mode);
|
||||
|
||||
/* Handle calls that pass values in multiple non-contiguous
|
||||
locations. The Irix 6 ABI has examples of this. */
|
||||
|
||||
if (GET_CODE (reg) == PARALLEL)
|
||||
emit_group_load (reg, args[i].value,
|
||||
int_size_in_bytes (TREE_TYPE (args[i].tree_value)));
|
||||
{
|
||||
tree type = TREE_TYPE (args[i].tree_value);
|
||||
emit_group_load (reg, args[i].value, type,
|
||||
int_size_in_bytes (type));
|
||||
}
|
||||
|
||||
/* If simple case, just do move. If normal partial, store_one_arg
|
||||
has already loaded the register for us. In all other cases,
|
||||
load the register(s) from memory. */
|
||||
|
||||
else if (nregs == -1)
|
||||
else if (nregs == -1
|
||||
#ifdef BLOCK_REG_PADDING
|
||||
&& !(size < UNITS_PER_WORD
|
||||
&& (args[i].locate.where_pad
|
||||
== (BYTES_BIG_ENDIAN ? upward : downward)))
|
||||
#endif
|
||||
)
|
||||
emit_move_insn (reg, args[i].value);
|
||||
|
||||
/* If we have pre-computed the values to put in the registers in
|
||||
|
@ -1619,9 +1638,44 @@ load_register_parameters (struct arg_data *args, int num_actuals,
|
|||
args[i].aligned_regs[j]);
|
||||
|
||||
else if (partial == 0 || args[i].pass_on_stack)
|
||||
move_block_to_reg (REGNO (reg),
|
||||
validize_mem (args[i].value), nregs,
|
||||
args[i].mode);
|
||||
{
|
||||
rtx mem = validize_mem (args[i].value);
|
||||
|
||||
#ifdef BLOCK_REG_PADDING
|
||||
/* Handle case where we have a value that needs shifting
|
||||
up to the msb. eg. a QImode value and we're padding
|
||||
upward on a BYTES_BIG_ENDIAN machine. */
|
||||
if (nregs == -1)
|
||||
{
|
||||
rtx ri = gen_rtx_REG (word_mode, REGNO (reg));
|
||||
rtx x;
|
||||
int shift = (UNITS_PER_WORD - size) * BITS_PER_UNIT;
|
||||
x = expand_binop (word_mode, ashl_optab, mem,
|
||||
GEN_INT (shift), ri, 1, OPTAB_WIDEN);
|
||||
if (x != ri)
|
||||
emit_move_insn (ri, x);
|
||||
}
|
||||
|
||||
/* Handle a BLKmode that needs shifting. */
|
||||
else if (nregs == 1 && size < UNITS_PER_WORD
|
||||
&& args[i].locate.where_pad == downward)
|
||||
{
|
||||
rtx tem = operand_subword_force (mem, 0, args[i].mode);
|
||||
rtx ri = gen_rtx_REG (word_mode, REGNO (reg));
|
||||
rtx x = gen_reg_rtx (word_mode);
|
||||
int shift = (UNITS_PER_WORD - size) * BITS_PER_UNIT;
|
||||
optab dir = BYTES_BIG_ENDIAN ? lshr_optab : ashl_optab;
|
||||
|
||||
emit_move_insn (x, tem);
|
||||
x = expand_binop (word_mode, dir, x, GEN_INT (shift),
|
||||
ri, 1, OPTAB_WIDEN);
|
||||
if (x != ri)
|
||||
emit_move_insn (ri, x);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
move_block_to_reg (REGNO (reg), mem, nregs, args[i].mode);
|
||||
}
|
||||
|
||||
/* When a parameter is a block, and perhaps in other cases, it is
|
||||
possible that it did a load from an argument slot that was
|
||||
|
@ -3144,7 +3198,7 @@ expand_call (tree exp, rtx target, int ignore)
|
|||
}
|
||||
|
||||
if (! rtx_equal_p (target, valreg))
|
||||
emit_group_store (target, valreg,
|
||||
emit_group_store (target, valreg, TREE_TYPE (exp),
|
||||
int_size_in_bytes (TREE_TYPE (exp)));
|
||||
|
||||
/* We can not support sibling calls for this case. */
|
||||
|
@ -3989,7 +4043,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
|
|||
/* Handle calls that pass values in multiple non-contiguous
|
||||
locations. The PA64 has examples of this for library calls. */
|
||||
if (reg != 0 && GET_CODE (reg) == PARALLEL)
|
||||
emit_group_load (reg, val, GET_MODE_SIZE (GET_MODE (val)));
|
||||
emit_group_load (reg, val, NULL_TREE, GET_MODE_SIZE (GET_MODE (val)));
|
||||
else if (reg != 0 && partial == 0)
|
||||
emit_move_insn (reg, val);
|
||||
|
||||
|
@ -4093,7 +4147,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
|
|||
if (GET_CODE (valreg) == PARALLEL)
|
||||
{
|
||||
temp = gen_reg_rtx (outmode);
|
||||
emit_group_store (temp, valreg, outmode);
|
||||
emit_group_store (temp, valreg, NULL_TREE, outmode);
|
||||
valreg = temp;
|
||||
}
|
||||
|
||||
|
@ -4136,7 +4190,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
|
|||
{
|
||||
if (value == 0)
|
||||
value = gen_reg_rtx (outmode);
|
||||
emit_group_store (value, valreg, outmode);
|
||||
emit_group_store (value, valreg, NULL_TREE, outmode);
|
||||
}
|
||||
else if (value != 0)
|
||||
emit_move_insn (value, valreg);
|
||||
|
|
|
@ -160,6 +160,10 @@
|
|||
|
||||
#ifndef RS6000_BI_ARCH
|
||||
|
||||
/* 64-bit PowerPC Linux is always big-endian. */
|
||||
#undef TARGET_LITTLE_ENDIAN
|
||||
#define TARGET_LITTLE_ENDIAN 0
|
||||
|
||||
/* 64-bit PowerPC Linux always has a TOC. */
|
||||
#undef TARGET_TOC
|
||||
#define TARGET_TOC 1
|
||||
|
@ -232,6 +236,35 @@
|
|||
#undef JUMP_TABLES_IN_TEXT_SECTION
|
||||
#define JUMP_TABLES_IN_TEXT_SECTION TARGET_64BIT
|
||||
|
||||
/* The linux ppc64 ABI isn't explicit on whether aggregates smaller
|
||||
than a doubleword should be padded upward or downward. You could
|
||||
reasonably assume that they follow the normal rules for structure
|
||||
layout treating the parameter area as any other block of memory,
|
||||
then map the reg param area to registers. ie. pad updard.
|
||||
Setting both of the following defines results in this behaviour.
|
||||
Setting just the first one will result in aggregates that fit in a
|
||||
doubleword being padded downward, and others being padded upward.
|
||||
Not a bad idea as this results in struct { int x; } being passed
|
||||
the same way as an int. */
|
||||
#define AGGREGATE_PADDING_FIXED TARGET_64BIT
|
||||
#define AGGREGATES_PAD_UPWARD_ALWAYS 0
|
||||
|
||||
/* We don't want anything in the reg parm area being passed on the
|
||||
stack. */
|
||||
#define MUST_PASS_IN_STACK(MODE, TYPE) \
|
||||
((TARGET_64BIT \
|
||||
&& (TYPE) != 0 \
|
||||
&& (TREE_CODE (TYPE_SIZE (TYPE)) != INTEGER_CST \
|
||||
|| TREE_ADDRESSABLE (TYPE))) \
|
||||
|| (!TARGET_64BIT \
|
||||
&& default_must_pass_in_stack ((MODE), (TYPE))))
|
||||
|
||||
/* Specify padding for the last element of a block move between
|
||||
registers and memory. FIRST is nonzero if this is the only
|
||||
element. */
|
||||
#define BLOCK_REG_PADDING(MODE, TYPE, FIRST) \
|
||||
(!(FIRST) ? upward : FUNCTION_ARG_PADDING (MODE, TYPE))
|
||||
|
||||
/* __throw will restore its own return address to be the same as the
|
||||
return address of the function that the throw is being made to.
|
||||
This is unfortunate, because we want to check the original
|
||||
|
|
|
@ -3702,8 +3702,6 @@ init_cumulative_args (cum, fntype, libname, incoming, libcall)
|
|||
else
|
||||
cum->nargs_prototype = 0;
|
||||
|
||||
cum->orig_nargs = cum->nargs_prototype;
|
||||
|
||||
/* Check for a longcall attribute. */
|
||||
if (fntype
|
||||
&& lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype))
|
||||
|
@ -3742,8 +3740,47 @@ function_arg_padding (mode, type)
|
|||
enum machine_mode mode;
|
||||
tree type;
|
||||
{
|
||||
if (type != 0 && AGGREGATE_TYPE_P (type))
|
||||
return upward;
|
||||
#ifndef AGGREGATE_PADDING_FIXED
|
||||
#define AGGREGATE_PADDING_FIXED 0
|
||||
#endif
|
||||
#ifndef AGGREGATES_PAD_UPWARD_ALWAYS
|
||||
#define AGGREGATES_PAD_UPWARD_ALWAYS 0
|
||||
#endif
|
||||
|
||||
if (!AGGREGATE_PADDING_FIXED)
|
||||
{
|
||||
/* GCC used to pass structures of the same size as integer types as
|
||||
if they were in fact integers, ignoring FUNCTION_ARG_PADDING.
|
||||
ie. Structures of size 1 or 2 (or 4 when TARGET_64BIT) were
|
||||
passed padded downward, except that -mstrict-align further
|
||||
muddied the water in that multi-component structures of 2 and 4
|
||||
bytes in size were passed padded upward.
|
||||
|
||||
The following arranges for best compatibility with previous
|
||||
versions of gcc, but removes the -mstrict-align dependency. */
|
||||
if (BYTES_BIG_ENDIAN)
|
||||
{
|
||||
HOST_WIDE_INT size = 0;
|
||||
|
||||
if (mode == BLKmode)
|
||||
{
|
||||
if (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)
|
||||
size = int_size_in_bytes (type);
|
||||
}
|
||||
else
|
||||
size = GET_MODE_SIZE (mode);
|
||||
|
||||
if (size == 1 || size == 2 || size == 4)
|
||||
return downward;
|
||||
}
|
||||
return upward;
|
||||
}
|
||||
|
||||
if (AGGREGATES_PAD_UPWARD_ALWAYS)
|
||||
{
|
||||
if (type != 0 && AGGREGATE_TYPE_P (type))
|
||||
return upward;
|
||||
}
|
||||
|
||||
/* This is the default definition. */
|
||||
return (! BYTES_BIG_ENDIAN
|
||||
|
|
|
@ -1734,7 +1734,6 @@ typedef struct rs6000_args
|
|||
int fregno; /* next available FP register */
|
||||
int vregno; /* next available AltiVec register */
|
||||
int nargs_prototype; /* # args left in the current prototype */
|
||||
int orig_nargs; /* Original value of nargs_prototype */
|
||||
int prototype; /* Whether a prototype was defined */
|
||||
int stdarg; /* Whether function is a stdarg function. */
|
||||
int call_cookie; /* Do special things for this call */
|
||||
|
@ -1878,13 +1877,8 @@ typedef struct rs6000_args
|
|||
#define EXPAND_BUILTIN_VA_ARG(valist, type) \
|
||||
rs6000_va_arg (valist, type)
|
||||
|
||||
/* For AIX, the rule is that structures are passed left-aligned in
|
||||
their stack slot. However, GCC does not presently do this:
|
||||
structures which are the same size as integer types are passed
|
||||
right-aligned, as if they were in fact integers. This only
|
||||
matters for structures of size 1 or 2, or 4 when TARGET_64BIT.
|
||||
ABI_V4 does not use std_expand_builtin_va_arg. */
|
||||
#define PAD_VARARGS_DOWN (TYPE_MODE (type) != BLKmode)
|
||||
#define PAD_VARARGS_DOWN \
|
||||
(FUNCTION_ARG_PADDING (TYPE_MODE (type), type) == downward)
|
||||
|
||||
/* Define this macro to be a nonzero value if the location where a function
|
||||
argument is passed depends on whether or not it is a named argument. */
|
||||
|
|
|
@ -3762,6 +3762,17 @@ controlled by @code{PARM_BOUNDARY}. If this macro is not defined, all such
|
|||
arguments are padded down if @code{BYTES_BIG_ENDIAN} is true.
|
||||
@end defmac
|
||||
|
||||
@defmac BLOCK_REG_PADDING (@var{mode}, @var{type}, @var{first})
|
||||
Specify padding for the last element of a block move between registers and
|
||||
memory. @var{first} is nonzero if this is the only element. Defining this
|
||||
macro allows better control of register function parameters on big-endian
|
||||
machines, without using @code{PARALLEL} rtl. In particular,
|
||||
@code{MUST_PASS_IN_STACK} need not test padding and mode of types in
|
||||
registers, as there is no longer a "wrong" part of a register; For example,
|
||||
a three byte aggregate may be passed in the high part of a register if so
|
||||
required.
|
||||
@end defmac
|
||||
|
||||
@defmac FUNCTION_ARG_BOUNDARY (@var{mode}, @var{type})
|
||||
If defined, a C expression that gives the alignment boundary, in bits,
|
||||
of an argument with the specified mode and type. If it is not defined,
|
||||
|
|
72
gcc/expr.c
72
gcc/expr.c
|
@ -2240,18 +2240,13 @@ gen_group_rtx (rtx orig)
|
|||
return gen_rtx_PARALLEL (GET_MODE (orig), gen_rtvec_v (length, tmps));
|
||||
}
|
||||
|
||||
/* Emit code to move a block SRC to a block DST, where DST is non-consecutive
|
||||
registers represented by a PARALLEL. SSIZE represents the total size of
|
||||
block SRC in bytes, or -1 if not known. */
|
||||
/* ??? If SSIZE % UNITS_PER_WORD != 0, we make the blatant assumption that
|
||||
the balance will be in what would be the low-order memory addresses, i.e.
|
||||
left justified for big endian, right justified for little endian. This
|
||||
happens to be true for the targets currently using this support. If this
|
||||
ever changes, a new target macro along the lines of FUNCTION_ARG_PADDING
|
||||
would be needed. */
|
||||
/* Emit code to move a block ORIG_SRC of type TYPE to a block DST,
|
||||
where DST is non-consecutive registers represented by a PARALLEL.
|
||||
SSIZE represents the total size of block ORIG_SRC in bytes, or -1
|
||||
if not known. */
|
||||
|
||||
void
|
||||
emit_group_load (rtx dst, rtx orig_src, int ssize)
|
||||
emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
|
||||
{
|
||||
rtx *tmps, src;
|
||||
int start, i;
|
||||
|
@ -2279,7 +2274,17 @@ emit_group_load (rtx dst, rtx orig_src, int ssize)
|
|||
/* Handle trailing fragments that run over the size of the struct. */
|
||||
if (ssize >= 0 && bytepos + (HOST_WIDE_INT) bytelen > ssize)
|
||||
{
|
||||
shift = (bytelen - (ssize - bytepos)) * BITS_PER_UNIT;
|
||||
/* Arrange to shift the fragment to where it belongs.
|
||||
extract_bit_field loads to the lsb of the reg. */
|
||||
if (
|
||||
#ifdef BLOCK_REG_PADDING
|
||||
BLOCK_REG_PADDING (GET_MODE (orig_src), type, i == start)
|
||||
== (BYTES_BIG_ENDIAN ? upward : downward)
|
||||
#else
|
||||
BYTES_BIG_ENDIAN
|
||||
#endif
|
||||
)
|
||||
shift = (bytelen - (ssize - bytepos)) * BITS_PER_UNIT;
|
||||
bytelen = ssize - bytepos;
|
||||
if (bytelen <= 0)
|
||||
abort ();
|
||||
|
@ -2304,7 +2309,8 @@ emit_group_load (rtx dst, rtx orig_src, int ssize)
|
|||
|
||||
/* Optimize the access just a bit. */
|
||||
if (GET_CODE (src) == MEM
|
||||
&& MEM_ALIGN (src) >= GET_MODE_ALIGNMENT (mode)
|
||||
&& (! SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (src))
|
||||
|| MEM_ALIGN (src) >= GET_MODE_ALIGNMENT (mode))
|
||||
&& bytepos * BITS_PER_UNIT % GET_MODE_ALIGNMENT (mode) == 0
|
||||
&& bytelen == GET_MODE_SIZE (mode))
|
||||
{
|
||||
|
@ -2360,7 +2366,7 @@ emit_group_load (rtx dst, rtx orig_src, int ssize)
|
|||
bytepos * BITS_PER_UNIT, 1, NULL_RTX,
|
||||
mode, mode, ssize);
|
||||
|
||||
if (BYTES_BIG_ENDIAN && shift)
|
||||
if (shift)
|
||||
expand_binop (mode, ashl_optab, tmps[i], GEN_INT (shift),
|
||||
tmps[i], 0, OPTAB_WIDEN);
|
||||
}
|
||||
|
@ -2391,12 +2397,13 @@ emit_group_move (rtx dst, rtx src)
|
|||
XEXP (XVECEXP (src, 0, i), 0));
|
||||
}
|
||||
|
||||
/* Emit code to move a block SRC to a block DST, where SRC is non-consecutive
|
||||
registers represented by a PARALLEL. SSIZE represents the total size of
|
||||
block DST, or -1 if not known. */
|
||||
/* Emit code to move a block SRC to a block ORIG_DST of type TYPE,
|
||||
where SRC is non-consecutive registers represented by a PARALLEL.
|
||||
SSIZE represents the total size of block ORIG_DST, or -1 if not
|
||||
known. */
|
||||
|
||||
void
|
||||
emit_group_store (rtx orig_dst, rtx src, int ssize)
|
||||
emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize)
|
||||
{
|
||||
rtx *tmps, dst;
|
||||
int start, i;
|
||||
|
@ -2440,8 +2447,8 @@ emit_group_store (rtx orig_dst, rtx src, int ssize)
|
|||
the temporary. */
|
||||
|
||||
temp = assign_stack_temp (GET_MODE (dst), ssize, 0);
|
||||
emit_group_store (temp, src, ssize);
|
||||
emit_group_load (dst, temp, ssize);
|
||||
emit_group_store (temp, src, type, ssize);
|
||||
emit_group_load (dst, temp, type, ssize);
|
||||
return;
|
||||
}
|
||||
else if (GET_CODE (dst) != MEM && GET_CODE (dst) != CONCAT)
|
||||
|
@ -2462,7 +2469,16 @@ emit_group_store (rtx orig_dst, rtx src, int ssize)
|
|||
/* Handle trailing fragments that run over the size of the struct. */
|
||||
if (ssize >= 0 && bytepos + (HOST_WIDE_INT) bytelen > ssize)
|
||||
{
|
||||
if (BYTES_BIG_ENDIAN)
|
||||
/* store_bit_field always takes its value from the lsb.
|
||||
Move the fragment to the lsb if it's not already there. */
|
||||
if (
|
||||
#ifdef BLOCK_REG_PADDING
|
||||
BLOCK_REG_PADDING (GET_MODE (orig_dst), type, i == start)
|
||||
== (BYTES_BIG_ENDIAN ? upward : downward)
|
||||
#else
|
||||
BYTES_BIG_ENDIAN
|
||||
#endif
|
||||
)
|
||||
{
|
||||
int shift = (bytelen - (ssize - bytepos)) * BITS_PER_UNIT;
|
||||
expand_binop (mode, ashr_optab, tmps[i], GEN_INT (shift),
|
||||
|
@ -2495,7 +2511,8 @@ emit_group_store (rtx orig_dst, rtx src, int ssize)
|
|||
|
||||
/* Optimize the access just a bit. */
|
||||
if (GET_CODE (dest) == MEM
|
||||
&& MEM_ALIGN (dest) >= GET_MODE_ALIGNMENT (mode)
|
||||
&& (! SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (dest))
|
||||
|| MEM_ALIGN (dest) >= GET_MODE_ALIGNMENT (mode))
|
||||
&& bytepos * BITS_PER_UNIT % GET_MODE_ALIGNMENT (mode) == 0
|
||||
&& bytelen == GET_MODE_SIZE (mode))
|
||||
emit_move_insn (adjust_address (dest, mode, bytepos), tmps[i]);
|
||||
|
@ -4076,7 +4093,7 @@ emit_push_insn (rtx x, enum machine_mode mode, tree type, rtx size,
|
|||
/* Handle calls that pass values in multiple non-contiguous locations.
|
||||
The Irix 6 ABI has examples of this. */
|
||||
if (GET_CODE (reg) == PARALLEL)
|
||||
emit_group_load (reg, x, -1); /* ??? size? */
|
||||
emit_group_load (reg, x, type, -1);
|
||||
else
|
||||
move_block_to_reg (REGNO (reg), x, partial, mode);
|
||||
}
|
||||
|
@ -4276,7 +4293,8 @@ expand_assignment (tree to, tree from, int want_value,
|
|||
/* Handle calls that return values in multiple non-contiguous locations.
|
||||
The Irix 6 ABI has examples of this. */
|
||||
if (GET_CODE (to_rtx) == PARALLEL)
|
||||
emit_group_load (to_rtx, value, int_size_in_bytes (TREE_TYPE (from)));
|
||||
emit_group_load (to_rtx, value, TREE_TYPE (from),
|
||||
int_size_in_bytes (TREE_TYPE (from)));
|
||||
else if (GET_MODE (to_rtx) == BLKmode)
|
||||
emit_block_move (to_rtx, value, expr_size (from), BLOCK_OP_NORMAL);
|
||||
else
|
||||
|
@ -4310,7 +4328,8 @@ expand_assignment (tree to, tree from, int want_value,
|
|||
temp = expand_expr (from, 0, GET_MODE (to_rtx), 0);
|
||||
|
||||
if (GET_CODE (to_rtx) == PARALLEL)
|
||||
emit_group_load (to_rtx, temp, int_size_in_bytes (TREE_TYPE (from)));
|
||||
emit_group_load (to_rtx, temp, TREE_TYPE (from),
|
||||
int_size_in_bytes (TREE_TYPE (from)));
|
||||
else
|
||||
emit_move_insn (to_rtx, temp);
|
||||
|
||||
|
@ -4720,7 +4739,8 @@ store_expr (tree exp, rtx target, int want_value)
|
|||
/* Handle calls that return values in multiple non-contiguous locations.
|
||||
The Irix 6 ABI has examples of this. */
|
||||
else if (GET_CODE (target) == PARALLEL)
|
||||
emit_group_load (target, temp, int_size_in_bytes (TREE_TYPE (exp)));
|
||||
emit_group_load (target, temp, TREE_TYPE (exp),
|
||||
int_size_in_bytes (TREE_TYPE (exp)));
|
||||
else if (GET_MODE (temp) == BLKmode)
|
||||
emit_block_move (target, temp, expr_size (exp),
|
||||
(want_value & 2
|
||||
|
@ -9268,7 +9288,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
|
|||
/* Handle calls that pass values in multiple
|
||||
non-contiguous locations. The Irix 6 ABI has examples
|
||||
of this. */
|
||||
emit_group_store (memloc, op0,
|
||||
emit_group_store (memloc, op0, inner_type,
|
||||
int_size_in_bytes (inner_type));
|
||||
else
|
||||
emit_move_insn (memloc, op0);
|
||||
|
|
25
gcc/expr.h
25
gcc/expr.h
|
@ -68,7 +68,6 @@ enum expand_modifier {EXPAND_NORMAL = 0, EXPAND_STACK_PARM = 2, EXPAND_SUM,
|
|||
|
||||
enum direction {none, upward, downward};
|
||||
|
||||
#ifdef TREE_CODE /* Don't lose if tree.h not included. */
|
||||
/* Structure to record the size of a sequence of arguments
|
||||
as the sum of a tree-expression and a constant. This structure is
|
||||
also used to store offsets from the stack, which might be negative,
|
||||
|
@ -96,8 +95,9 @@ struct locate_and_pad_arg_data
|
|||
/* The amount that the stack pointer needs to be adjusted to
|
||||
force alignment for the next argument. */
|
||||
struct args_size alignment_pad;
|
||||
/* Which way we should pad this arg. */
|
||||
enum direction where_pad;
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Add the value of the tree INC to the `struct args_size' TO. */
|
||||
|
||||
|
@ -427,7 +427,7 @@ extern rtx gen_group_rtx (rtx);
|
|||
|
||||
/* Load a BLKmode value into non-consecutive registers represented by a
|
||||
PARALLEL. */
|
||||
extern void emit_group_load (rtx, rtx, int);
|
||||
extern void emit_group_load (rtx, rtx, tree, int);
|
||||
|
||||
/* Move a non-consecutive group of registers represented by a PARALLEL into
|
||||
a non-consecutive group of registers represented by a PARALLEL. */
|
||||
|
@ -435,12 +435,10 @@ extern void emit_group_move (rtx, rtx);
|
|||
|
||||
/* Store a BLKmode value from non-consecutive registers represented by a
|
||||
PARALLEL. */
|
||||
extern void emit_group_store (rtx, rtx, int);
|
||||
extern void emit_group_store (rtx, rtx, tree, int);
|
||||
|
||||
#ifdef TREE_CODE
|
||||
/* Copy BLKmode object from a set of registers. */
|
||||
extern rtx copy_blkmode_from_reg (rtx, rtx, tree);
|
||||
#endif
|
||||
|
||||
/* Mark REG as holding a parameter for the next CALL_INSN. */
|
||||
extern void use_reg (rtx *, rtx);
|
||||
|
@ -490,7 +488,6 @@ extern rtx emit_move_insn_1 (rtx, rtx);
|
|||
and return an rtx to address the beginning of the block. */
|
||||
extern rtx push_block (rtx, int, int);
|
||||
|
||||
#ifdef TREE_CODE
|
||||
/* Generate code to push something onto the stack, given its mode and type. */
|
||||
extern void emit_push_insn (rtx, enum machine_mode, tree, rtx, unsigned int,
|
||||
int, rtx, int, rtx, rtx, int, rtx);
|
||||
|
@ -503,7 +500,6 @@ extern rtx expand_assignment (tree, tree, int, int);
|
|||
If SUGGEST_REG is nonzero, copy the value through a register
|
||||
and return that register, if that is possible. */
|
||||
extern rtx store_expr (tree, rtx, int);
|
||||
#endif
|
||||
|
||||
/* Given an rtx that may include add and multiply operations,
|
||||
generate them as insns and return a pseudo-reg containing the value.
|
||||
|
@ -535,7 +531,6 @@ extern void clear_pending_stack_adjust (void);
|
|||
/* Pop any previously-pushed arguments that have not been popped yet. */
|
||||
extern void do_pending_stack_adjust (void);
|
||||
|
||||
#ifdef TREE_CODE
|
||||
/* Return the tree node and offset if a given argument corresponds to
|
||||
a string constant. */
|
||||
extern tree string_constant (tree, tree *);
|
||||
|
@ -549,7 +544,6 @@ extern void jumpif (tree, rtx);
|
|||
/* Generate code to evaluate EXP and jump to IF_FALSE_LABEL if
|
||||
the result is zero, or IF_TRUE_LABEL if the result is one. */
|
||||
extern void do_jump (tree, rtx, rtx);
|
||||
#endif
|
||||
|
||||
/* Generate rtl to compare two rtx's, will call emit_cmp_insn. */
|
||||
extern rtx compare_from_rtx (rtx, rtx, enum rtx_code, int, enum machine_mode,
|
||||
|
@ -566,7 +560,6 @@ extern int try_tablejump (tree, tree, tree, tree, rtx, rtx);
|
|||
extern unsigned int case_values_threshold (void);
|
||||
|
||||
|
||||
#ifdef TREE_CODE
|
||||
/* rtl.h and tree.h were included. */
|
||||
/* Return an rtx for the size in bytes of the value of an expr. */
|
||||
extern rtx expr_size (tree);
|
||||
|
@ -592,10 +585,13 @@ extern rtx prepare_call_address (rtx, tree, rtx *, int, int);
|
|||
|
||||
extern rtx expand_call (tree, rtx, int);
|
||||
|
||||
#ifdef TREE_CODE
|
||||
extern rtx expand_shift (enum tree_code, enum machine_mode, rtx, tree, rtx,
|
||||
int);
|
||||
extern rtx expand_divmod (int, enum tree_code, enum machine_mode, rtx, rtx,
|
||||
rtx, int);
|
||||
#endif
|
||||
|
||||
extern void locate_and_pad_parm (enum machine_mode, tree, int, int, tree,
|
||||
struct args_size *,
|
||||
struct locate_and_pad_arg_data *);
|
||||
|
@ -608,7 +604,6 @@ extern rtx label_rtx (tree);
|
|||
list of its containing function (i.e. it is treated as reachable even
|
||||
if how is not obvious). */
|
||||
extern rtx force_label_rtx (tree);
|
||||
#endif
|
||||
|
||||
/* Indicate how an input argument register was promoted. */
|
||||
extern rtx promoted_input_arg (unsigned int, enum machine_mode *, int *);
|
||||
|
@ -691,7 +686,6 @@ extern rtx widen_memory_access (rtx, enum machine_mode, HOST_WIDE_INT);
|
|||
valid address. */
|
||||
extern rtx validize_mem (rtx);
|
||||
|
||||
#ifdef TREE_CODE
|
||||
/* Given REF, either a MEM or a REG, and T, either the type of X or
|
||||
the expression corresponding to REF, set RTX_UNCHANGING_P if
|
||||
appropriate. */
|
||||
|
@ -706,7 +700,6 @@ extern void set_mem_attributes (rtx, tree, int);
|
|||
we alter MEM_OFFSET according to T then we should subtract BITPOS
|
||||
expecting that it'll be added back in later. */
|
||||
extern void set_mem_attributes_minus_bitpos (rtx, tree, int, HOST_WIDE_INT);
|
||||
#endif
|
||||
|
||||
/* Assemble the static constant template for function entry trampolines. */
|
||||
extern rtx assemble_trampoline_template (void);
|
||||
|
@ -738,10 +731,8 @@ extern rtx force_reg (enum machine_mode, rtx);
|
|||
/* Return given rtx, copied into a new temp reg if it was in memory. */
|
||||
extern rtx force_not_mem (rtx);
|
||||
|
||||
#ifdef TREE_CODE
|
||||
/* Return mode and signedness to use when object is promoted. */
|
||||
extern enum machine_mode promote_mode (tree, enum machine_mode, int *, int);
|
||||
#endif
|
||||
|
||||
/* Remove some bytes from the stack. An rtx says how many. */
|
||||
extern void adjust_stack (rtx);
|
||||
|
@ -812,9 +803,7 @@ extern void do_jump_by_parts_equality_rtx (rtx, rtx, rtx);
|
|||
extern void do_jump_by_parts_greater_rtx (enum machine_mode, int, rtx, rtx,
|
||||
rtx, rtx);
|
||||
|
||||
#ifdef TREE_CODE /* Don't lose if tree.h not included. */
|
||||
extern void mark_seen_cases (tree, unsigned char *, HOST_WIDE_INT, int);
|
||||
#endif
|
||||
|
||||
extern int vector_mode_valid_p (enum machine_mode);
|
||||
|
||||
|
|
|
@ -4507,6 +4507,8 @@ assign_parms (tree fndecl)
|
|||
offset_rtx));
|
||||
|
||||
set_mem_attributes (stack_parm, parm, 1);
|
||||
if (entry_parm && MEM_ATTRS (stack_parm)->align < PARM_BOUNDARY)
|
||||
set_mem_align (stack_parm, PARM_BOUNDARY);
|
||||
|
||||
/* Set also REG_ATTRS if parameter was passed in a register. */
|
||||
if (entry_parm)
|
||||
|
@ -4538,6 +4540,7 @@ assign_parms (tree fndecl)
|
|||
locations. The Irix 6 ABI has examples of this. */
|
||||
if (GET_CODE (entry_parm) == PARALLEL)
|
||||
emit_group_store (validize_mem (stack_parm), entry_parm,
|
||||
TREE_TYPE (parm),
|
||||
int_size_in_bytes (TREE_TYPE (parm)));
|
||||
|
||||
else
|
||||
|
@ -4644,7 +4647,12 @@ assign_parms (tree fndecl)
|
|||
|
||||
Set DECL_RTL to that place. */
|
||||
|
||||
if (nominal_mode == BLKmode || GET_CODE (entry_parm) == PARALLEL)
|
||||
if (nominal_mode == BLKmode
|
||||
#ifdef BLOCK_REG_PADDING
|
||||
|| (locate.where_pad == (BYTES_BIG_ENDIAN ? upward : downward)
|
||||
&& GET_MODE_SIZE (promoted_mode) < UNITS_PER_WORD)
|
||||
#endif
|
||||
|| GET_CODE (entry_parm) == PARALLEL)
|
||||
{
|
||||
/* If a BLKmode arrives in registers, copy it to a stack slot.
|
||||
Handle calls that pass values in multiple non-contiguous
|
||||
|
@ -4680,7 +4688,7 @@ assign_parms (tree fndecl)
|
|||
/* Handle calls that pass values in multiple non-contiguous
|
||||
locations. The Irix 6 ABI has examples of this. */
|
||||
if (GET_CODE (entry_parm) == PARALLEL)
|
||||
emit_group_store (mem, entry_parm, size);
|
||||
emit_group_store (mem, entry_parm, TREE_TYPE (parm), size);
|
||||
|
||||
else if (size == 0)
|
||||
;
|
||||
|
@ -4692,7 +4700,13 @@ assign_parms (tree fndecl)
|
|||
enum machine_mode mode
|
||||
= mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
|
||||
|
||||
if (mode != BLKmode)
|
||||
if (mode != BLKmode
|
||||
#ifdef BLOCK_REG_PADDING
|
||||
&& (size == UNITS_PER_WORD
|
||||
|| (BLOCK_REG_PADDING (mode, TREE_TYPE (parm), 1)
|
||||
!= (BYTES_BIG_ENDIAN ? upward : downward)))
|
||||
#endif
|
||||
)
|
||||
{
|
||||
rtx reg = gen_rtx_REG (mode, REGNO (entry_parm));
|
||||
emit_move_insn (change_address (mem, mode, 0), reg);
|
||||
|
@ -4703,7 +4717,13 @@ assign_parms (tree fndecl)
|
|||
to memory. Note that the previous test doesn't
|
||||
handle all cases (e.g. SIZE == 3). */
|
||||
else if (size != UNITS_PER_WORD
|
||||
&& BYTES_BIG_ENDIAN)
|
||||
#ifdef BLOCK_REG_PADDING
|
||||
&& (BLOCK_REG_PADDING (mode, TREE_TYPE (parm), 1)
|
||||
== downward)
|
||||
#else
|
||||
&& BYTES_BIG_ENDIAN
|
||||
#endif
|
||||
)
|
||||
{
|
||||
rtx tem, x;
|
||||
int by = (UNITS_PER_WORD - size) * BITS_PER_UNIT;
|
||||
|
@ -5367,6 +5387,7 @@ locate_and_pad_parm (enum machine_mode passed_mode, tree type, int in_regs,
|
|||
= type ? size_in_bytes (type) : size_int (GET_MODE_SIZE (passed_mode));
|
||||
where_pad = FUNCTION_ARG_PADDING (passed_mode, type);
|
||||
boundary = FUNCTION_ARG_BOUNDARY (passed_mode, type);
|
||||
locate->where_pad = where_pad;
|
||||
|
||||
#ifdef ARGS_GROW_DOWNWARD
|
||||
locate->slot_offset.constant = -initial_offset_ptr->constant;
|
||||
|
@ -7036,6 +7057,7 @@ expand_function_end (void)
|
|||
emit_group_move (real_decl_rtl, decl_rtl);
|
||||
else
|
||||
emit_group_load (real_decl_rtl, decl_rtl,
|
||||
TREE_TYPE (decl_result),
|
||||
int_size_in_bytes (TREE_TYPE (decl_result)));
|
||||
}
|
||||
else
|
||||
|
|
|
@ -2955,7 +2955,7 @@ expand_value_return (rtx val)
|
|||
val = convert_modes (mode, old_mode, val, unsignedp);
|
||||
#endif
|
||||
if (GET_CODE (return_reg) == PARALLEL)
|
||||
emit_group_load (return_reg, val, int_size_in_bytes (type));
|
||||
emit_group_load (return_reg, val, type, int_size_in_bytes (type));
|
||||
else
|
||||
emit_move_insn (return_reg, val);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue