mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-09 01:27:13 +08:00
expr.c (emit_group_load): Revise to allow splitting TCmode source into DImode pieces.
* expr.c (emit_group_load): Revise to allow splitting TCmode source into DImode pieces. * pa-64.h (LONG_DOUBLE_TYPE_SIZE): Define to 128. * pa64-regs.h (CLASS_CANNOT_CHANGE_MODE_P): Inhibit changes from SImode for floating-point register class. * pa.c (function_arg): Fix handling of modes wider than one word for TARGET_64BIT. From-SVN: r56805
This commit is contained in:
parent
b10f218708
commit
015b1ad1df
@ -1,3 +1,14 @@
|
||||
2002-09-04 John David Anglin <dave@hiauly1.hia.nrc.ca>
|
||||
|
||||
* expr.c (emit_group_load): Revise to allow splitting TCmode source
|
||||
into DImode pieces.
|
||||
|
||||
* pa-64.h (LONG_DOUBLE_TYPE_SIZE): Define to 128.
|
||||
* pa64-regs.h (CLASS_CANNOT_CHANGE_MODE_P): Inhibit changes from SImode
|
||||
for floating-point register class.
|
||||
* pa.c (function_arg): Fix handling of modes wider than one word for
|
||||
TARGET_64BIT.
|
||||
|
||||
Wed Sep 4 18:48:10 2002 J"orn Rennecke <joern.rennecke@superh.com>
|
||||
|
||||
* combine.c (make_compound_operation): Don't generate zero / sign
|
||||
|
@ -65,10 +65,8 @@ Boston, MA 02111-1307, USA. */
|
||||
#define FLOAT_TYPE_SIZE 32
|
||||
#undef DOUBLE_TYPE_SIZE
|
||||
#define DOUBLE_TYPE_SIZE 64
|
||||
/* This should be 128, but until we work out the ABI for the 128bit
|
||||
FP codes supplied by HP we'll keep it at 64 bits. */
|
||||
#undef LONG_DOUBLE_TYPE_SIZE
|
||||
#define LONG_DOUBLE_TYPE_SIZE 64
|
||||
#define LONG_DOUBLE_TYPE_SIZE 128
|
||||
|
||||
/* Temporary until we figure out what to do with those *(&@$ 32bit
|
||||
relocs which appear in stabs. */
|
||||
|
@ -7446,6 +7446,8 @@ function_arg (cum, mode, type, named, incoming)
|
||||
int incoming;
|
||||
{
|
||||
int max_arg_words = (TARGET_64BIT ? 8 : 4);
|
||||
int arg_size = FUNCTION_ARG_SIZE (mode, type);
|
||||
int alignment = 0;
|
||||
int fpr_reg_base;
|
||||
int gpr_reg_base;
|
||||
rtx retval;
|
||||
@ -7456,16 +7458,15 @@ function_arg (cum, mode, type, named, incoming)
|
||||
this routine should return zero. FUNCTION_ARG_PARTIAL_NREGS will
|
||||
handle arguments which are split between regs and stack slots if
|
||||
the ABI mandates split arguments. */
|
||||
if (cum->words + FUNCTION_ARG_SIZE (mode, type) > max_arg_words
|
||||
if (cum->words + arg_size > max_arg_words
|
||||
|| mode == VOIDmode)
|
||||
return NULL_RTX;
|
||||
}
|
||||
else
|
||||
{
|
||||
int offset = 0;
|
||||
if (FUNCTION_ARG_SIZE (mode, type) > 1 && (cum->words & 1))
|
||||
offset = 1;
|
||||
if (cum->words + offset >= max_arg_words
|
||||
if (arg_size > 1)
|
||||
alignment = cum->words & 1;
|
||||
if (cum->words + alignment >= max_arg_words
|
||||
|| mode == VOIDmode)
|
||||
return NULL_RTX;
|
||||
}
|
||||
@ -7474,70 +7475,54 @@ function_arg (cum, mode, type, named, incoming)
|
||||
particularly in their handling of FP registers. We might
|
||||
be able to cleverly share code between them, but I'm not
|
||||
going to bother in the hope that splitting them up results
|
||||
in code that is more easily understood.
|
||||
in code that is more easily understood. */
|
||||
|
||||
The 64bit code probably is very wrong for structure passing. */
|
||||
if (TARGET_64BIT)
|
||||
{
|
||||
/* Advance the base registers to their current locations.
|
||||
|
||||
Remember, gprs grow towards smaller register numbers while
|
||||
fprs grow to higher register numbers. Also remember FP regs
|
||||
are always 4 bytes wide, while the size of an integer register
|
||||
varies based on the size of the target word. */
|
||||
fprs grow to higher register numbers. Also remember that
|
||||
although FP regs are 32-bit addressable, we pretend that
|
||||
the registers are 64-bits wide. */
|
||||
gpr_reg_base = 26 - cum->words;
|
||||
fpr_reg_base = 32 + cum->words;
|
||||
|
||||
/* If the argument is more than a word long, then we need to align
|
||||
the base registers. Same caveats as above. */
|
||||
if (FUNCTION_ARG_SIZE (mode, type) > 1)
|
||||
/* Arguments wider than one word need special treatment. */
|
||||
if (arg_size > 1)
|
||||
{
|
||||
if (mode != BLKmode)
|
||||
{
|
||||
/* First deal with alignment of the doubleword. */
|
||||
gpr_reg_base -= (cum->words & 1);
|
||||
/* Double-extended precision (80-bit), quad-precision (128-bit)
|
||||
and aggregates including complex numbers are aligned on
|
||||
128-bit boundaries. The first eight 64-bit argument slots
|
||||
are associated one-to-one, with general registers r26
|
||||
through r19, and also with floating-point registers fr4
|
||||
through fr11. Arguments larger than one word are always
|
||||
passed in general registers. */
|
||||
|
||||
/* This seems backwards, but it is what HP specifies. We need
|
||||
gpr_reg_base to point to the smaller numbered register of
|
||||
the integer register pair. So if we have an even register
|
||||
number, then decrement the gpr base. */
|
||||
gpr_reg_base -= ((gpr_reg_base % 2) == 0);
|
||||
rtx loc[8];
|
||||
int i, offset = 0, ub = arg_size;
|
||||
|
||||
/* FP values behave sanely, except that each FP reg is only
|
||||
half of word. */
|
||||
fpr_reg_base += ((fpr_reg_base % 2) == 0);
|
||||
}
|
||||
else
|
||||
/* Align the base register. */
|
||||
gpr_reg_base -= alignment;
|
||||
|
||||
ub = MIN (ub, max_arg_words - cum->words - alignment);
|
||||
for (i = 0; i < ub; i++)
|
||||
{
|
||||
rtx loc[8];
|
||||
int i, offset = 0, ub;
|
||||
ub = FUNCTION_ARG_SIZE (mode, type);
|
||||
ub = MIN (ub,
|
||||
MAX (0, max_arg_words - cum->words - (cum->words & 1)));
|
||||
gpr_reg_base -= (cum->words & 1);
|
||||
for (i = 0; i < ub; i++)
|
||||
{
|
||||
loc[i] = gen_rtx_EXPR_LIST (VOIDmode,
|
||||
gen_rtx_REG (DImode,
|
||||
gpr_reg_base),
|
||||
GEN_INT (offset));
|
||||
gpr_reg_base -= 1;
|
||||
offset += 8;
|
||||
}
|
||||
if (ub == 0)
|
||||
return NULL_RTX;
|
||||
else if (ub == 1)
|
||||
return XEXP (loc[0], 0);
|
||||
else
|
||||
return gen_rtx_PARALLEL (mode, gen_rtvec_v (ub, loc));
|
||||
loc[i] = gen_rtx_EXPR_LIST (VOIDmode,
|
||||
gen_rtx_REG (DImode, gpr_reg_base),
|
||||
GEN_INT (offset));
|
||||
gpr_reg_base -= 1;
|
||||
offset += 8;
|
||||
}
|
||||
|
||||
return gen_rtx_PARALLEL (mode, gen_rtvec_v (ub, loc));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If the argument is larger than a word, then we know precisely
|
||||
which registers we must use. */
|
||||
if (FUNCTION_ARG_SIZE (mode, type) > 1)
|
||||
if (arg_size > 1)
|
||||
{
|
||||
if (cum->words)
|
||||
{
|
||||
@ -7559,19 +7544,6 @@ function_arg (cum, mode, type, named, incoming)
|
||||
}
|
||||
}
|
||||
|
||||
if (TARGET_64BIT && mode == TFmode)
|
||||
{
|
||||
return
|
||||
gen_rtx_PARALLEL
|
||||
(mode,
|
||||
gen_rtvec (2,
|
||||
gen_rtx_EXPR_LIST (VOIDmode,
|
||||
gen_rtx_REG (DImode, gpr_reg_base + 1),
|
||||
const0_rtx),
|
||||
gen_rtx_EXPR_LIST (VOIDmode,
|
||||
gen_rtx_REG (DImode, gpr_reg_base),
|
||||
GEN_INT (8))));
|
||||
}
|
||||
/* Determine if the argument needs to be passed in both general and
|
||||
floating point registers. */
|
||||
if (((TARGET_PORTABLE_RUNTIME || TARGET_64BIT || TARGET_ELF32)
|
||||
|
@ -234,16 +234,21 @@ enum reg_class { NO_REGS, R1_REGS, GENERAL_REGS, FPUPPER_REGS, FP_REGS,
|
||||
|
||||
/* If defined, gives a class of registers that cannot be used as the
|
||||
operand of a SUBREG that changes the mode of the object illegally. */
|
||||
/* ??? This may not actually be necessary anymore. But until I can prove
|
||||
otherwise it will stay. */
|
||||
|
||||
#define CLASS_CANNOT_CHANGE_MODE (FP_REGS)
|
||||
|
||||
/* Defines illegal mode changes for CLASS_CANNOT_CHANGE_MODE. */
|
||||
#define CLASS_CANNOT_CHANGE_MODE_P(FROM,TO) \
|
||||
(GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO))
|
||||
/* Defines illegal mode changes for CLASS_CANNOT_CHANGE_MODE.
|
||||
|
||||
/* The same information, inverted:
|
||||
Return the class number of the smallest class containing
|
||||
SImode loads to floating-point registers are not zero-extended.
|
||||
The definition for LOAD_EXTEND_OP specifies that integer loads
|
||||
narrower than BITS_PER_WORD will be zero-extended. As a result,
|
||||
we inhibit changes from SImode unless they are to a mode that is
|
||||
identical in size. */
|
||||
|
||||
#define CLASS_CANNOT_CHANGE_MODE_P(FROM,TO) \
|
||||
((FROM) == SImode && GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO))
|
||||
|
||||
/* Return the class number of the smallest class containing
|
||||
reg number REGNO. This could be a conditional expression
|
||||
or could index an array. */
|
||||
|
||||
|
21
gcc/expr.c
21
gcc/expr.c
@ -2265,21 +2265,26 @@ emit_group_load (dst, orig_src, ssize)
|
||||
}
|
||||
else if (GET_CODE (src) == CONCAT)
|
||||
{
|
||||
if ((bytepos == 0
|
||||
&& bytelen == GET_MODE_SIZE (GET_MODE (XEXP (src, 0))))
|
||||
|| (bytepos == (HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (XEXP (src, 0)))
|
||||
&& bytelen == GET_MODE_SIZE (GET_MODE (XEXP (src, 1)))))
|
||||
unsigned int slen = GET_MODE_SIZE (GET_MODE (src));
|
||||
unsigned int slen0 = GET_MODE_SIZE (GET_MODE (XEXP (src, 0)));
|
||||
|
||||
if ((bytepos == 0 && bytelen == slen0)
|
||||
|| (bytepos != 0 && bytepos + bytelen <= slen))
|
||||
{
|
||||
tmps[i] = XEXP (src, bytepos != 0);
|
||||
/* The following assumes that the concatenated objects all
|
||||
have the same size. In this case, a simple calculation
|
||||
can be used to determine the object and the bit field
|
||||
to be extracted. */
|
||||
tmps[i] = XEXP (src, bytepos / slen0);
|
||||
if (! CONSTANT_P (tmps[i])
|
||||
&& (GET_CODE (tmps[i]) != REG || GET_MODE (tmps[i]) != mode))
|
||||
tmps[i] = extract_bit_field (tmps[i], bytelen * BITS_PER_UNIT,
|
||||
0, 1, NULL_RTX, mode, mode, ssize);
|
||||
(bytepos % slen0) * BITS_PER_UNIT,
|
||||
1, NULL_RTX, mode, mode, ssize);
|
||||
}
|
||||
else if (bytepos == 0)
|
||||
{
|
||||
rtx mem = assign_stack_temp (GET_MODE (src),
|
||||
GET_MODE_SIZE (GET_MODE (src)), 0);
|
||||
rtx mem = assign_stack_temp (GET_MODE (src), slen, 0);
|
||||
emit_move_insn (mem, src);
|
||||
tmps[i] = adjust_address (mem, mode, 0);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user