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;
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;
}
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)
+ /* 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. */
+
+ rtx loc[8];
+ int i, offset = 0, ub = arg_size;
+
+ /* Align the base register. */
+ gpr_reg_base -= alignment;
+
+ ub = MIN (ub, max_arg_words - cum->words - alignment);
+ for (i = 0; i < ub; i++)
{
- /* First deal with alignment of the doubleword. */
- gpr_reg_base -= (cum->words & 1);
-
- /* 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);
-
- /* FP values behave sanely, except that each FP reg is only
- half of word. */
- fpr_reg_base += ((fpr_reg_base % 2) == 0);
- }
- else
- {
- 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)
{
}
}
- 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)
/* 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.
+
+ 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))
-/* The same information, inverted:
- Return the class number of the smallest class containing
+/* Return the class number of the smallest class containing
reg number REGNO. This could be a conditional expression
or could index an array. */
}
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);
}