This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the EGCS project.
va_list: ppc
- To: gcc-patches@gcc.gnu.org
- Subject: va_list: ppc
- From: Richard Henderson <rth@cygnus.com>
- Date: Thu, 29 Jul 1999 02:14:22 -0700
- Cc: Franz.Sirl-kernel@lauterbach.com, Geoffrey Keating <geoffk@cygnus.com>, Michael Meissner <meissner@cygnus.com>, edelsohn@gnu.org
Eyeballed. Would one of the ppc-linux folks sick the test suite
on this for good measure?
r~
* rs6000.c (setup_incoming_varargs): Use get_varargs_alias_set
and tag the spill mems.
(rs6000_expand_builtin_saveregs): Delete.
(rs6000_build_va_list): New.
(rs6000_va_start): New.
(rs6000_va_arg): New.
* rs6000.h (EXPAND_BUILTIN_SAVEREGS): Delete.
(BUILD_VA_LIST_TYPE): New.
(EXPAND_BUILTIN_VA_START): New.
(EXPAND_BUILTIN_VA_ARG): New.
Index: rs6000/rs6000.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.84
diff -c -p -d -r1.84 rs6000.c
*** rs6000.c 1999/07/27 20:10:38 1.84
--- rs6000.c 1999/07/29 09:08:33
*************** Boston, MA 02111-1307, USA. */
*** 31,39 ****
#include "insn-attr.h"
#include "flags.h"
#include "recog.h"
- #include "expr.h"
#include "obstack.h"
#include "tree.h"
#include "except.h"
#include "function.h"
#include "output.h"
--- 31,39 ----
#include "insn-attr.h"
#include "flags.h"
#include "recog.h"
#include "obstack.h"
#include "tree.h"
+ #include "expr.h"
#include "except.h"
#include "function.h"
#include "output.h"
*************** setup_incoming_varargs (cum, mode, type,
*** 1679,1686 ****
{
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)
{
--- 1679,1686 ----
{
CUMULATIVE_ARGS next_cum;
int reg_size = TARGET_32BIT ? 4 : 8;
! rtx save_area, mem;
! int first_reg_offset, set;
if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)
{
*************** setup_incoming_varargs (cum, mode, type,
*** 1718,1729 ****
first_reg_offset += RS6000_ARG_SIZE (TYPE_MODE (type), type, 1);
}
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);
--- 1718,1733 ----
first_reg_offset += RS6000_ARG_SIZE (TYPE_MODE (type), type, 1);
}
+ set = get_varargs_alias_set ();
if (!no_rtl && first_reg_offset < GP_ARG_NUM_REG)
{
+ mem = gen_rtx_MEM (BLKmode,
+ plus_constant (save_area,
+ first_reg_offset * reg_size)),
+ MEM_ALIAS_SET (mem) = set;
+
move_block_from_reg
! (GP_ARG_MIN_REG + first_reg_offset, mem,
GP_ARG_NUM_REG - first_reg_offset,
(GP_ARG_NUM_REG - first_reg_offset) * UNITS_PER_WORD);
*************** setup_incoming_varargs (cum, mode, type,
*** 1751,1758 ****
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;
}
--- 1755,1763 ----
while (fregno <= FP_ARG_V4_MAX_REG)
{
! mem = gen_rtx_MEM (DFmode, plus_constant (save_area, off));
! MEM_ALIAS_SET (mem) = set;
! emit_move_insn (mem, gen_rtx_REG (DFmode, fregno));
fregno++;
off += 8;
}
*************** setup_incoming_varargs (cum, mode, type,
*** 1760,1856 ****
emit_label (lab);
}
}
-
- /* If defined, is a C expression that produces the machine-specific
- code for a call to `__builtin_saveregs'. This code will be moved
- to the very beginning of the function, before any parameter access
- are made. The return value of this function should be an RTX that
- contains the value to use as the return of `__builtin_saveregs'.
-
- On the Power/PowerPC return the address of the area on the stack
- used to hold arguments. Under AIX, this includes the 8 word register
- save area.
! Under V.4, things are more complicated. We do not have access to
! all of the virtual registers required for va_start to do its job,
! so we construct the va_list in its entirity here, and reduce va_start
! to a block copy. This is similar to the way we do things on Alpha. */
! struct rtx_def *
! rs6000_expand_builtin_saveregs ()
{
! rtx block, mem_gpr_fpr, mem_reg_save_area, mem_overflow, tmp;
! tree fntype;
! int stdarg_p;
! HOST_WIDE_INT words, gpr, fpr;
if (DEFAULT_ABI != ABI_V4 && DEFAULT_ABI != ABI_SOLARIS)
! return virtual_incoming_args_rtx;
! fntype = TREE_TYPE (current_function_decl);
! stdarg_p = (TYPE_ARG_TYPES (fntype) != 0
! && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
! != void_type_node));
! /* Allocate the va_list constructor. */
! block = assign_stack_local (BLKmode, 3 * UNITS_PER_WORD, BITS_PER_WORD);
! RTX_UNCHANGING_P (block) = 1;
! RTX_UNCHANGING_P (XEXP (block, 0)) = 1;
! mem_gpr_fpr = change_address (block, word_mode, XEXP (block, 0));
! mem_overflow = change_address (block, ptr_mode,
! plus_constant (XEXP (block, 0),
! UNITS_PER_WORD));
! mem_reg_save_area = change_address (block, ptr_mode,
! plus_constant (XEXP (block, 0),
! 2 * UNITS_PER_WORD));
! /* Construct the two characters of `gpr' and `fpr' as a unit. */
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)
{
! HOST_WIDE_INT bits = gpr << 8 | fpr;
! if (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD)
! tmp = GEN_INT (bits << (BITS_PER_WORD - 16));
! else
! {
! bits <<= BITS_PER_WORD - HOST_BITS_PER_WIDE_INT - 16;
! tmp = immed_double_const (0, bits, word_mode);
! }
}
else
! tmp = GEN_INT (fpr << 8 | gpr);
! emit_move_insn (mem_gpr_fpr, tmp);
! /* Find the overflow area. */
! 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);
! /* Find the register save area. */
! tmp = expand_binop (Pmode, add_optab, virtual_stack_vars_rtx,
! GEN_INT (-RS6000_VARARGS_SIZE),
! mem_reg_save_area, 0, OPTAB_WIDEN);
! if (tmp != mem_reg_save_area)
! emit_move_insn (mem_reg_save_area, tmp);
! /* Return the address of the va_list constructor. */
! return XEXP (block, 0);
}
/* Generate a memory reference for expand_block_move, copying volatile,
--- 1765,2022 ----
emit_label (lab);
}
}
! /* Create the va_list data type. */
! tree
! rs6000_build_va_list ()
{
! tree f_gpr, f_fpr, f_ovf, f_sav, record;
! tree uchar_type_node;
+ /* Only SVR4 needs something special. */
if (DEFAULT_ABI != ABI_V4 && DEFAULT_ABI != ABI_SOLARIS)
! return ptr_type_node;
! record = make_node (RECORD_TYPE);
! uchar_type_node = make_unsigned_type (CHAR_TYPE_SIZE);
!
! f_gpr = build_decl (FIELD_DECL, get_identifier ("gpr"), uchar_type_node);
! f_fpr = build_decl (FIELD_DECL, get_identifier ("fpr"), uchar_type_node);
! f_ovf = build_decl (FIELD_DECL, get_identifier ("overflow_arg_area"),
! ptr_type_node);
! f_sav = build_decl (FIELD_DECL, get_identifier ("reg_save_area"),
! ptr_type_node);
! DECL_FIELD_CONTEXT (f_gpr) = record;
! DECL_FIELD_CONTEXT (f_fpr) = record;
! DECL_FIELD_CONTEXT (f_ovf) = record;
! DECL_FIELD_CONTEXT (f_sav) = record;
! TYPE_FIELDS (record) = f_gpr;
! TREE_CHAIN (f_gpr) = f_fpr;
! TREE_CHAIN (f_fpr) = f_ovf;
! TREE_CHAIN (f_ovf) = f_sav;
! layout_type (record);
!
! return record;
! }
!
! /* Implement va_start. */
!
! void
! rs6000_va_start (stdarg_p, valist, nextarg)
! int stdarg_p;
! tree valist;
! rtx nextarg;
! {
! HOST_WIDE_INT words, n_gpr, n_fpr;
! tree f_gpr, f_fpr, f_ovf, f_sav;
! tree gpr, fpr, ovf, sav, t;
!
! /* Only SVR4 needs something special. */
! if (DEFAULT_ABI != ABI_V4 && DEFAULT_ABI != ABI_SOLARIS)
! {
! std_expand_builtin_va_start (stdarg_p, valist, nextarg);
! return;
! }
!
! f_gpr = TYPE_FIELDS (va_list_type_node);
! f_fpr = TREE_CHAIN (f_gpr);
! f_ovf = TREE_CHAIN (f_fpr);
! f_sav = TREE_CHAIN (f_ovf);
!
! gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
! fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
! ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
! sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
!
! /* Count number of gp and fp argument registers used. */
words = current_function_args_info.words;
! n_gpr = current_function_args_info.sysv_gregno - GP_ARG_MIN_REG;
! n_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 (n_gpr > GP_ARG_NUM_REG)
words -= 1;
else
! n_gpr -= 1;
}
! t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr, build_int_2 (n_gpr, 0));
! TREE_SIDE_EFFECTS (t) = 1;
! expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
!
! t = build (MODIFY_EXPR, TREE_TYPE (fpr), fpr, build_int_2 (n_fpr, 0));
! TREE_SIDE_EFFECTS (t) = 1;
! expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
!
! /* Find the overflow area. */
! t = make_tree (TREE_TYPE (ovf), virtual_incoming_args_rtx);
! if (words != 0)
! t = build (PLUS_EXPR, TREE_TYPE (ovf), t,
! build_int_2 (words * UNITS_PER_WORD, 0));
! t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
! TREE_SIDE_EFFECTS (t) = 1;
! expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
!
! /* Find the register save area. */
! t = make_tree (TREE_TYPE (sav), virtual_stack_vars_rtx);
! t = build (PLUS_EXPR, TREE_TYPE (sav), t,
! build_int_2 (-RS6000_VARARGS_SIZE, -1));
! t = build (MODIFY_EXPR, TREE_TYPE (sav), sav, t);
! TREE_SIDE_EFFECTS (t) = 1;
! expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
! }
!
! /* Implement va_arg. */
!
! rtx
! rs6000_va_arg (valist, type)
! tree valist, type;
! {
! tree f_gpr, f_fpr, f_ovf, f_sav;
! tree gpr, fpr, ovf, sav, reg, t, u;
! int indirect_p, size, rsize, n_reg, sav_ofs, sav_scale;
! rtx lab_false, lab_over, addr_rtx, r;
!
! /* Only SVR4 needs something special. */
! if (DEFAULT_ABI != ABI_V4 && DEFAULT_ABI != ABI_SOLARIS)
! return std_expand_builtin_va_arg (valist, type);
!
! f_gpr = TYPE_FIELDS (va_list_type_node);
! f_fpr = TREE_CHAIN (f_gpr);
! f_ovf = TREE_CHAIN (f_fpr);
! f_sav = TREE_CHAIN (f_ovf);
!
! gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
! fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
! ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
! sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
!
! size = int_size_in_bytes (type);
! rsize = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
!
! if (AGGREGATE_TYPE_P (type) || TYPE_MODE (type) == TFmode)
{
! /* Aggregates and long doubles are passed by reference. */
! indirect_p = 1;
! reg = gpr;
! n_reg = 1;
! sav_ofs = 0;
! sav_scale = 4;
! size = rsize = UNITS_PER_WORD;
}
+ else if (FLOAT_TYPE_P (type) && ! TARGET_SOFT_FLOAT)
+ {
+ /* FP args go in FP registers, if present. */
+ indirect_p = 0;
+ reg = fpr;
+ n_reg = 1;
+ sav_ofs = 8*4;
+ sav_scale = 8;
+ }
else
! {
! /* Otherwise into GP registers. */
! indirect_p = 0;
! reg = gpr;
! n_reg = rsize;
! sav_ofs = 0;
! sav_scale = 4;
! }
! /*
! * Pull the value out of the saved registers ...
! */
! lab_false = gen_label_rtx ();
! lab_over = gen_label_rtx ();
! addr_rtx = gen_reg_rtx (Pmode);
! emit_cmp_and_jump_insns (expand_expr (reg, NULL_RTX, QImode, EXPAND_NORMAL),
! GEN_INT (8 - n_reg + 1),
! GE, const1_rtx, QImode, 1, 1, lab_false);
! /* Long long is aligned in the registers. */
! if (n_reg > 1)
! {
! u = build (BIT_AND_EXPR, TREE_TYPE (reg), reg,
! build_int_2 (n_reg - 1, 0));
! u = build (PLUS_EXPR, TREE_TYPE (reg), reg, u);
! u = build (MODIFY_EXPR, TREE_TYPE (reg), reg, u);
! TREE_SIDE_EFFECTS (u) = 1;
! expand_expr (u, const0_rtx, VOIDmode, EXPAND_NORMAL);
! }
!
! if (sav_ofs)
! t = build (PLUS_EXPR, ptr_type_node, sav, build_int_2 (sav_ofs, 0));
! else
! t = sav;
!
! u = build (POSTINCREMENT_EXPR, TREE_TYPE (reg), reg, build_int_2 (n_reg, 0));
! TREE_SIDE_EFFECTS (u) = 1;
!
! u = build1 (CONVERT_EXPR, integer_type_node, u);
! TREE_SIDE_EFFECTS (u) = 1;
!
! u = build (MULT_EXPR, integer_type_node, u, build_int_2 (sav_scale, 0));
! TREE_SIDE_EFFECTS (u) = 1;
!
! t = build (PLUS_EXPR, ptr_type_node, t, u);
! TREE_SIDE_EFFECTS (t) = 1;
!
! r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
! if (r != addr_rtx)
! emit_move_insn (addr_rtx, r);
!
! emit_jump_insn (gen_jump (lab_over));
! emit_barrier ();
! emit_label (lab_false);
!
! /*
! * ... otherwise out of the overflow area.
! */
!
! /* Make sure we don't find reg 7 for the next int arg. */
! if (n_reg > 1)
! {
! t = build (MODIFY_EXPR, TREE_TYPE (reg), reg, build_int_2 (8, 0));
! TREE_SIDE_EFFECTS (t) = 1;
! }
!
! /* Care for on-stack alignment if needed. */
! if (rsize <= 1)
! t = ovf;
! else
! {
! t = build (PLUS_EXPR, TREE_TYPE (ovf), ovf, build_int_2 (7, 0));
! t = build (BIT_AND_EXPR, TREE_TYPE (t), t, build_int_2 (-8, -1));
! }
! t = save_expr (t);
!
! r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
! if (r != addr_rtx)
! emit_move_insn (addr_rtx, r);
!
! t = build (PLUS_EXPR, TREE_TYPE (t), t, build_int_2 (size, 0));
! t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
! TREE_SIDE_EFFECTS (t) = 1;
! expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
!
! emit_label (lab_over);
!
! if (indirect_p)
! {
! r = gen_rtx_MEM (Pmode, addr_rtx);
! MEM_ALIAS_SET (r) = get_varargs_alias_set ();
! emit_move_insn (addr_rtx, r);
! }
!
! return addr_rtx;
}
/* Generate a memory reference for expand_block_move, copying volatile,
Index: rs6000/rs6000.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/config/rs6000/rs6000.h,v
retrieving revision 1.56
diff -c -p -d -r1.56 rs6000.h
*** rs6000.h 1999/07/27 20:10:38 1.56
--- rs6000.h 1999/07/29 09:08:33
*************** typedef struct rs6000_args
*** 1566,1579 ****
#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \
setup_incoming_varargs (&CUM, MODE, TYPE, &PRETEND_SIZE, NO_RTL)
! /* If defined, is a C expression that produces the machine-specific
! code for a call to `__builtin_saveregs'. This code will be moved
! to the very beginning of the function, before any parameter access
! are made. The return value of this function should be an RTX that
! contains the value to use as the return of `__builtin_saveregs'. */
! #define EXPAND_BUILTIN_SAVEREGS() \
! rs6000_expand_builtin_saveregs ()
/* This macro generates the assembly code for function entry.
FILE is a stdio stream to output the code to.
--- 1566,1582 ----
#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \
setup_incoming_varargs (&CUM, MODE, TYPE, &PRETEND_SIZE, NO_RTL)
! /* Define the `__builtin_va_list' type for the ABI. */
! #define BUILD_VA_LIST_TYPE(VALIST) \
! (VALIST) = rs6000_build_va_list ()
! /* Implement `va_start' for varargs and stdarg. */
! #define EXPAND_BUILTIN_VA_START(stdarg, valist, nextarg) \
! rs6000_va_start (stdarg, valist, nextarg)
!
! /* Implement `va_arg'. */
! #define EXPAND_BUILTIN_VA_ARG(valist, type) \
! rs6000_va_arg (valist, type)
/* This macro generates the assembly code for function entry.
FILE is a stdio stream to output the code to.
*************** extern struct rtx_def *function_arg ();
*** 3297,3303 ****
extern int function_arg_partial_nregs ();
extern int function_arg_pass_by_reference ();
extern void setup_incoming_varargs ();
! extern struct rtx_def *rs6000_expand_builtin_saveregs ();
extern struct rtx_def *rs6000_stack_temp ();
extern int expand_block_move ();
extern int load_multiple_operation ();
--- 3300,3308 ----
extern int function_arg_partial_nregs ();
extern int function_arg_pass_by_reference ();
extern void setup_incoming_varargs ();
! extern union tree_node *rs6000_va_list ();
! extern void rs6000_va_start ();
! extern struct rtx_def *rs6000_va_arg ();
extern struct rtx_def *rs6000_stack_temp ();
extern int expand_block_move ();
extern int load_multiple_operation ();