summaryrefslogtreecommitdiff
path: root/gcc/config/rs6000
diff options
context:
space:
mode:
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>1999-07-21 00:26:00 +0000
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>1999-07-21 00:26:00 +0000
commit036c1d46d4d7c7f7605293a0d047a1171d68b4a1 (patch)
tree0ebaa8fa73357ac49f1fcc4fdc21804f89cd70f7 /gcc/config/rs6000
parentf1bf91b635c19a257b9466b6689183a6c0798633 (diff)
downloadgcc-036c1d46d4d7c7f7605293a0d047a1171d68b4a1.tar.gz
* rs6000.h (struct rs6000_args): Add sysv_gregno.
* rs6000.c (init_cumulative_args): Init sysv_gregno. (function_arg_boundary): Align DFmode. (function_arg_advance): Restructure for ABI_V4; use sysv_gregno to get fp reg and stack overflow correct. (function_arg): Likewise. (function_arg_pass_by_reference): True for TFmode for ABI_V4. (setup_incoming_varargs): Restructure for ABI_V4; use function_arg_advance to skip final named argument. (expand_builtin_saveregs): Properly unskip the last integer arg when doing varargs. Adjust overflow location calculation. * ginclude/va-ppc.h (struct __va_list_tag): Make gpr and fpr explicitly unsigned. (__VA_FP_REGSAVE): Use new OFS argument instead of AP->fpr directly. (__VA_GP_REGSAVE): Similarly. (__va_longlong_p): Delete. (__va_arg_type_violation): New declaration. (va_arg): Restructure. Flag promotion errors. Align double. TFmode passed by reference. * rs6000.md (movdi_32+1): Use GEN_INT after arithmetic in the HOST_BITS_PER_WIDE_INT > 32 case. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@28199 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/rs6000')
-rw-r--r--gcc/config/rs6000/rs6000.c340
-rw-r--r--gcc/config/rs6000/rs6000.h9
-rw-r--r--gcc/config/rs6000/rs6000.md4
3 files changed, 217 insertions, 136 deletions
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index f568bed9a4c..1215c13a054 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -1253,6 +1253,7 @@ init_cumulative_args (cum, fntype, libname, incoming)
cum->fregno = FP_ARG_MIN_REG;
cum->prototype = (fntype && TYPE_ARG_TYPES (fntype));
cum->call_cookie = CALL_NORMAL;
+ cum->sysv_gregno = GP_ARG_MIN_REG;
if (incoming)
cum->nargs_prototype = 1000; /* don't return a PARALLEL */
@@ -1338,7 +1339,8 @@ function_arg_boundary (mode, type)
enum machine_mode mode;
tree type;
{
- if ((DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) && mode == DImode)
+ if ((DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)
+ && (mode == DImode || mode == DFmode))
return 64;
if (DEFAULT_ABI != ABI_NT || TARGET_64BIT)
@@ -1361,48 +1363,85 @@ function_arg_advance (cum, mode, type, named)
tree type;
int named;
{
- int align = (TARGET_32BIT && (cum->words & 1) != 0
- && function_arg_boundary (mode, type) == 64) ? 1 : 0;
- cum->words += align;
cum->nargs_prototype--;
if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)
{
- /* Long longs must not be split between registers and stack */
- if ((GET_MODE_CLASS (mode) != MODE_FLOAT || TARGET_SOFT_FLOAT)
- && type && !AGGREGATE_TYPE_P (type)
- && cum->words < GP_ARG_NUM_REG
- && cum->words + RS6000_ARG_SIZE (mode, type, named) > GP_ARG_NUM_REG)
+ if (TARGET_HARD_FLOAT
+ && (mode == SFmode || mode == DFmode))
{
- cum->words = GP_ARG_NUM_REG;
+ if (cum->fregno <= FP_ARG_V4_MAX_REG)
+ cum->fregno++;
+ else
+ {
+ if (mode == DFmode)
+ cum->words += cum->words & 1;
+ cum->words += RS6000_ARG_SIZE (mode, type, 1);
+ }
}
+ else
+ {
+ int n_words;
+ int gregno = cum->sysv_gregno;
+
+ /* Aggregates and IEEE quad get passed by reference. */
+ if ((type && AGGREGATE_TYPE_P (type))
+ || mode == TFmode)
+ n_words = 1;
+ else
+ n_words = RS6000_ARG_SIZE (mode, type, 1);
+
+ /* Long long is put in odd registers. */
+ if (n_words == 2 && (gregno & 1) == 0)
+ gregno += 1;
+
+ /* Long long is not split between registers and stack. */
+ if (gregno + n_words - 1 > GP_ARG_MAX_REG)
+ {
+ /* Long long is aligned on the stack. */
+ if (n_words == 2)
+ cum->words += cum->words & 1;
+ cum->words += n_words;
+ }
- /* Aggregates get passed as pointers */
- if (type && AGGREGATE_TYPE_P (type))
- cum->words++;
-
- /* Floats go in registers, & don't occupy space in the GP registers
- like they do for AIX unless software floating point. */
- else if (GET_MODE_CLASS (mode) == MODE_FLOAT
- && TARGET_HARD_FLOAT
- && cum->fregno <= FP_ARG_V4_MAX_REG)
- cum->fregno++;
+ /* Note: continuing to accumulate gregno past when we've started
+ spilling to the stack indicates the fact that we've started
+ spilling to the stack to expand_builtin_saveregs. */
+ cum->sysv_gregno = gregno + n_words;
+ }
- else
- cum->words += RS6000_ARG_SIZE (mode, type, 1);
+ if (TARGET_DEBUG_ARG)
+ {
+ fprintf (stderr, "function_adv: words = %2d, fregno = %2d, ",
+ cum->words, cum->fregno);
+ fprintf (stderr, "gregno = %2d, nargs = %4d, proto = %d, ",
+ cum->sysv_gregno, cum->nargs_prototype, cum->prototype);
+ fprintf (stderr, "mode = %4s, named = %d\n",
+ GET_MODE_NAME (mode), named);
+ }
}
else
- if (named)
- {
- cum->words += RS6000_ARG_SIZE (mode, type, named);
- if (GET_MODE_CLASS (mode) == MODE_FLOAT && TARGET_HARD_FLOAT)
- cum->fregno++;
- }
+ {
+ int align = (TARGET_32BIT && (cum->words & 1) != 0
+ && function_arg_boundary (mode, type) == 64) ? 1 : 0;
+ cum->words += align;
- if (TARGET_DEBUG_ARG)
- fprintf (stderr,
- "function_adv: words = %2d, fregno = %2d, nargs = %4d, proto = %d, mode = %4s, named = %d, align = %d\n",
- cum->words, cum->fregno, cum->nargs_prototype, cum->prototype, GET_MODE_NAME (mode), named, align);
+ if (named)
+ {
+ cum->words += RS6000_ARG_SIZE (mode, type, named);
+ if (GET_MODE_CLASS (mode) == MODE_FLOAT && TARGET_HARD_FLOAT)
+ cum->fregno++;
+ }
+
+ if (TARGET_DEBUG_ARG)
+ {
+ fprintf (stderr, "function_adv: words = %2d, fregno = %2d, ",
+ cum->words, cum->fregno);
+ fprintf (stderr, "nargs = %4d, proto = %d, mode = %4s, ",
+ cum->nargs_prototype, cum->prototype, GET_MODE_NAME (mode));
+ fprintf (stderr, "named = %d, align = %d\n", named, align);
+ }
+ }
}
/* Determine where to put an argument to a function.
@@ -1435,22 +1474,14 @@ function_arg (cum, mode, type, named)
tree type;
int named;
{
- int align = (TARGET_32BIT && (cum->words & 1) != 0
- && function_arg_boundary (mode, type) == 64) ? 1 : 0;
- int align_words = cum->words + align;
-
- if (TARGET_DEBUG_ARG)
- fprintf (stderr,
- "function_arg: words = %2d, fregno = %2d, nargs = %4d, proto = %d, mode = %4s, named = %d, align = %d\n",
- cum->words, cum->fregno, cum->nargs_prototype, cum->prototype, GET_MODE_NAME (mode), named, align);
+ enum rs6000_abi abi = DEFAULT_ABI;
- /* Return a marker to indicate whether CR1 needs to set or clear the bit that V.4
- uses to say fp args were passed in registers. Assume that we don't need the
- marker for software floating point, or compiler generated library calls. */
+ /* Return a marker to indicate whether CR1 needs to set or clear the bit
+ that V.4 uses to say fp args were passed in registers. Assume that we
+ don't need the marker for software floating point, or compiler generated
+ library calls. */
if (mode == VOIDmode)
{
- enum rs6000_abi abi = DEFAULT_ABI;
-
if ((abi == ABI_V4 || abi == ABI_SOLARIS)
&& TARGET_HARD_FLOAT
&& cum->nargs_prototype < 0
@@ -1465,31 +1496,65 @@ function_arg (cum, mode, type, named)
return GEN_INT (cum->call_cookie);
}
- if (!named)
+ if (abi == ABI_V4 || abi == ABI_SOLARIS)
{
- if (DEFAULT_ABI != ABI_V4 && DEFAULT_ABI != ABI_SOLARIS)
- return NULL_RTX;
+ if (TARGET_HARD_FLOAT
+ && (mode == SFmode || mode == DFmode))
+ {
+ if (cum->fregno <= FP_ARG_V4_MAX_REG)
+ return gen_rtx_REG (mode, cum->fregno);
+ else
+ return NULL;
+ }
+ else
+ {
+ int n_words;
+ int gregno = cum->sysv_gregno;
+
+ /* Aggregates and IEEE quad get passed by reference. */
+ if ((type && AGGREGATE_TYPE_P (type))
+ || mode == TFmode)
+ n_words = 1;
+ else
+ n_words = RS6000_ARG_SIZE (mode, type, 1);
+
+ /* Long long is put in odd registers. */
+ if (n_words == 2 && (gregno & 1) == 0)
+ gregno += 1;
+
+ /* Long long is not split between registers and stack. */
+ if (gregno + n_words - 1 <= GP_ARG_MAX_REG)
+ return gen_rtx_REG (mode, gregno);
+ else
+ return NULL;
+ }
}
+ else
+ {
+ int align = (TARGET_32BIT && (cum->words & 1) != 0
+ && function_arg_boundary (mode, type) == 64) ? 1 : 0;
+ int align_words = cum->words + align;
- if (type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
- return NULL_RTX;
+ if (!named)
+ return NULL_RTX;
- if (USE_FP_FOR_ARG_P (*cum, mode, type))
- {
- if (DEFAULT_ABI == ABI_V4 /* V.4 never passes FP values in GP registers */
- || DEFAULT_ABI == ABI_SOLARIS
- || ! type
- || ((cum->nargs_prototype > 0)
- /* IBM AIX extended its linkage convention definition always to
- require FP args after register save area hole on the stack. */
- && (DEFAULT_ABI != ABI_AIX
- || ! TARGET_XL_CALL
- || (align_words < GP_ARG_NUM_REG))))
- return gen_rtx_REG (mode, cum->fregno);
-
- return gen_rtx_PARALLEL (mode,
- gen_rtvec
- (2,
+ if (type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
+ return NULL_RTX;
+
+ if (USE_FP_FOR_ARG_P (*cum, mode, type))
+ {
+ if (! type
+ || ((cum->nargs_prototype > 0)
+ /* IBM AIX extended its linkage convention definition always
+ to require FP args after register save area hole on the
+ stack. */
+ && (DEFAULT_ABI != ABI_AIX
+ || ! TARGET_XL_CALL
+ || (align_words < GP_ARG_NUM_REG))))
+ return gen_rtx_REG (mode, cum->fregno);
+
+ return gen_rtx_PARALLEL (mode,
+ gen_rtvec (2,
gen_rtx_EXPR_LIST (VOIDmode,
((align_words >= GP_ARG_NUM_REG)
? NULL_RTX
@@ -1507,21 +1572,12 @@ function_arg (cum, mode, type, named)
gen_rtx_EXPR_LIST (VOIDmode,
gen_rtx_REG (mode, cum->fregno),
const0_rtx)));
+ }
+ else if (align_words < GP_ARG_NUM_REG)
+ return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
+ else
+ return NULL_RTX;
}
-
- /* Long longs won't be split between register and stack;
- FP arguments get passed on the stack if they didn't get a register. */
- else if ((DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) &&
- (align_words + RS6000_ARG_SIZE (mode, type, named) > GP_ARG_NUM_REG
- || (GET_MODE_CLASS (mode) == MODE_FLOAT && TARGET_HARD_FLOAT)))
- {
- return NULL_RTX;
- }
-
- else if (align_words < GP_ARG_NUM_REG)
- return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
-
- return NULL_RTX;
}
/* For an arg passed partly in registers and partly in memory,
@@ -1576,7 +1632,8 @@ function_arg_pass_by_reference (cum, mode, type, named)
int named ATTRIBUTE_UNUSED;
{
if ((DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)
- && type && AGGREGATE_TYPE_P (type))
+ && ((type && AGGREGATE_TYPE_P (type))
+ || mode == TFmode))
{
if (TARGET_DEBUG_ARG)
fprintf (stderr, "function_arg_pass_by_reference: aggregate\n");
@@ -1611,73 +1668,87 @@ setup_incoming_varargs (cum, mode, type, pretend_size, no_rtl)
int no_rtl;
{
- rtx save_area = virtual_incoming_args_rtx;
- int reg_size = TARGET_32BIT ? 4 : 8;
-
- if (TARGET_DEBUG_ARG)
- fprintf (stderr,
- "setup_vararg: words = %2d, fregno = %2d, nargs = %4d, proto = %d, mode = %4s, no_rtl= %d\n",
- cum->words, cum->fregno, cum->nargs_prototype, cum->prototype, GET_MODE_NAME (mode), no_rtl);
+ CUMULATIVE_ARGS next_cum;
+ int reg_size = TARGET_32BIT ? 4 : 8;
+ rtx save_area;
+ int first_reg_offset;
if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)
{
+ tree fntype;
+ int stdarg_p;
+
+ fntype = TREE_TYPE (current_function_decl);
+ stdarg_p = (TYPE_ARG_TYPES (fntype) != 0
+ && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
+ != void_type_node));
+
+ /* For varargs, we do not want to skip the dummy va_dcl argument.
+ For stdargs, we do want to skip the last named argument. */
+ next_cum = *cum;
+ if (stdarg_p)
+ function_arg_advance (&next_cum, mode, type, 1);
+
+ /* Indicate to allocate space on the stack for varargs save area. */
+ /* ??? Does this really have to be located at a magic spot on the
+ stack, or can we allocate this with assign_stack_local instead. */
rs6000_sysv_varargs_p = 1;
if (! no_rtl)
save_area = plus_constant (virtual_stack_vars_rtx,
- RS6000_VARARGS_SIZE);
+
+ first_reg_offset = next_cum.sysv_gregno - GP_ARG_MIN_REG;
}
else
- rs6000_sysv_varargs_p = 0;
-
- if (cum->words < 8)
{
- int first_reg_offset = cum->words;
+ save_area = virtual_incoming_args_rtx;
+ rs6000_sysv_varargs_p = 0;
+ first_reg_offset = cum->words;
if (MUST_PASS_IN_STACK (mode, type))
first_reg_offset += RS6000_ARG_SIZE (TYPE_MODE (type), type, 1);
+ }
- if (first_reg_offset > GP_ARG_NUM_REG)
- first_reg_offset = GP_ARG_NUM_REG;
-
- if (!no_rtl && first_reg_offset != GP_ARG_NUM_REG)
- move_block_from_reg
- (GP_ARG_MIN_REG + first_reg_offset,
- gen_rtx_MEM (BLKmode,
- plus_constant (save_area, first_reg_offset * reg_size)),
- GP_ARG_NUM_REG - first_reg_offset,
- (GP_ARG_NUM_REG - first_reg_offset) * UNITS_PER_WORD);
-
+ if (!no_rtl && first_reg_offset < GP_ARG_NUM_REG)
+ {
+ move_block_from_reg
+ (GP_ARG_MIN_REG + first_reg_offset,
+ gen_rtx_MEM (BLKmode,
+ plus_constant (save_area, first_reg_offset * reg_size)),
+ GP_ARG_NUM_REG - first_reg_offset,
+ (GP_ARG_NUM_REG - first_reg_offset) * UNITS_PER_WORD);
+
+ /* ??? Does ABI_V4 need this at all? */
*pretend_size = (GP_ARG_NUM_REG - first_reg_offset) * UNITS_PER_WORD;
}
/* Save FP registers if needed. */
- if ((DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) && TARGET_HARD_FLOAT && !no_rtl)
+ if ((DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)
+ && TARGET_HARD_FLOAT && !no_rtl
+ && next_cum.fregno <= FP_ARG_V4_MAX_REG)
{
- int fregno = cum->fregno;
- int num_fp_reg = FP_ARG_V4_MAX_REG + 1 - fregno;
+ int fregno = next_cum.fregno;
+ rtx cr1 = gen_rtx_REG (CCmode, 69);
+ rtx lab = gen_label_rtx ();
+ int off = (GP_ARG_NUM_REG * reg_size) + ((fregno - FP_ARG_MIN_REG) * 8);
- if (num_fp_reg >= 0)
- {
- rtx cr1 = gen_rtx_REG (CCmode, 69);
- rtx lab = gen_label_rtx ();
- int off = (GP_ARG_NUM_REG * reg_size) + ((fregno - FP_ARG_MIN_REG) * 8);
-
- emit_jump_insn (gen_rtx_SET (VOIDmode,
+ emit_jump_insn (gen_rtx_SET (VOIDmode,
pc_rtx,
gen_rtx_IF_THEN_ELSE (VOIDmode,
- gen_rtx_NE (VOIDmode, cr1, const0_rtx),
+ gen_rtx_NE (VOIDmode, cr1,
+ const0_rtx),
gen_rtx_LABEL_REF (VOIDmode, lab),
pc_rtx)));
- while ( num_fp_reg-- >= 0)
- {
- emit_move_insn (gen_rtx_MEM (DFmode, plus_constant (save_area, off)),
- gen_rtx_REG (DFmode, fregno++));
- off += 8;
- }
-
- emit_label (lab);
+ while (fregno <= FP_ARG_V4_MAX_REG)
+ {
+ emit_move_insn (gen_rtx_MEM (DFmode, plus_constant (save_area, off)),
+ gen_rtx_REG (DFmode, fregno));
+ fregno++;
+ off += 8;
}
+
+ emit_label (lab);
}
}
@@ -1733,9 +1804,18 @@ expand_builtin_saveregs (args)
2 * UNITS_PER_WORD));
/* Construct the two characters of `gpr' and `fpr' as a unit. */
- words = current_function_args_info.words - !stdarg_p;
- gpr = (words > 8 ? 8 : words);
- fpr = current_function_args_info.fregno - 33;
+ words = current_function_args_info.words;
+ gpr = current_function_args_info.sysv_gregno - GP_ARG_MIN_REG;
+ fpr = current_function_args_info.fregno - FP_ARG_MIN_REG;
+
+ /* Varargs has the va_dcl argument, but we don't count it. */
+ if (!stdarg_p)
+ {
+ if (gpr > GP_ARG_NUM_REG)
+ words -= 1;
+ else
+ gpr -= 1;
+ }
if (BYTES_BIG_ENDIAN)
{
@@ -1754,12 +1834,9 @@ expand_builtin_saveregs (args)
emit_move_insn (mem_gpr_fpr, tmp);
/* Find the overflow area. */
- if (words <= 8)
- tmp = virtual_incoming_args_rtx;
- else
- tmp = expand_binop (Pmode, add_optab, virtual_incoming_args_rtx,
- GEN_INT ((words - 8) * UNITS_PER_WORD),
- mem_overflow, 0, OPTAB_WIDEN);
+ tmp = expand_binop (Pmode, add_optab, virtual_incoming_args_rtx,
+ GEN_INT (words * UNITS_PER_WORD),
+ mem_overflow, 0, OPTAB_WIDEN);
if (tmp != mem_overflow)
emit_move_insn (mem_overflow, tmp);
@@ -1773,7 +1850,6 @@ expand_builtin_saveregs (args)
/* Return the address of the va_list constructor. */
return XEXP (block, 0);
}
-
/* Generate a memory reference for expand_block_move, copying volatile,
and other bits from an original memory reference. */
diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h
index 4e221314e42..4e5c9ac8af8 100644
--- a/gcc/config/rs6000/rs6000.h
+++ b/gcc/config/rs6000/rs6000.h
@@ -1435,17 +1435,22 @@ extern int rs6000_sysv_varargs_p;
floating-point register number, and the third says how many more args we
have prototype types for.
+ For ABI_V4, we treat these slightly differently -- `sysv_gregno' is
+ the next availible GP register, `fregno' is the next available FP
+ register, and `words' is the number of words used on the stack.
+
The varargs/stdarg support requires that this structure's size
- be a multiple of sizeof(int). */
+ be a multiple of sizeof(int). */
typedef struct rs6000_args
{
- int words; /* # words uses for passing GP registers */
+ int words; /* # words used for passing GP registers */
int fregno; /* next available FP 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 call_cookie; /* Do special things for this call */
+ int sysv_gregno; /* next available GP register */
} CUMULATIVE_ARGS;
/* Define intermediate macro to compute the size (in registers) of an argument
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index d9e82a815a3..bb23a1a32a2 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -6624,8 +6624,8 @@
#if HOST_BITS_PER_WIDE_INT == 32
operands[4] = (INTVAL (operands[1]) & 0x80000000) ? constm1_rtx : const0_rtx;
#else
- operands[4] = (HOST_WIDE_INT) INTVAL (operands[1]) >> 32;
- operands[1] = INTVAL (operands[1]) & 0xffffffff;
+ operands[4] = GEN_INT ((HOST_WIDE_INT) INTVAL (operands[1]) >> 32);
+ operands[1] = GEN_INT (INTVAL (operands[1]) & 0xffffffff);
#endif
}")