[PATCH] powerpc64 very large stack frames

Janis Johnson janis187@us.ibm.com
Wed Nov 12 16:55:00 GMT 2003


On Mon, Nov 10, 2003 at 03:13:02PM -0800, Richard Henderson wrote:
> On Mon, Nov 10, 2003 at 03:03:38PM -0800, Janis Johnson wrote:
> > The patch uses "long long" rather than "HOST_WIDE_INT" because struct
> > rs6000_stack is defined in a header file that is included for library
> > and startup file builds as well as for compiler builds.
> 
> This is not acceptable, as long long is not ISO C90.  If you need
> to use ifdefs because of the library/startup issue, then do so.

Here's a new approach to providing support in powerpc64 for stack frames
whose sizes require more than 32 bits.  We have a user who wants this.

This patch moves things around so that rs6000_stack_t members total_size
and vars_size can be defined using HOST_WIDE_INT.  The struct definition
has moved out of rs6000.h, which is included for builds of library and
startup code, into rs6000.c.  A macro that is used from reload now
invokes a function rather than accessing rs6000_stack_t directly, and a
chunk of code from rs6000.md has been moved to a new function, again so
that rs6000_stack_t can be private to rs6000.c.  Geoff Keating suggested
this approach.

There is currently no macro defined when startup code is being compiled,
and no generic macro indicating that the compilation is for target code.
IN_LIBGCC is not defined when compiling crtstuff.  IN_TARGET_LIBS is
only defined for building libobjc, and it's not clear whether it would
be appropriate to use it for other purposes as well.  A generic
IN_TARGET_CODE would be useful, but I'm taking the easy way out instead.

Bootstrapped and regtested on powerpc-linux and tested with cross
compilers for powerpc64-linux.  Test gcc.c-torture/compile/20031023-4.c
ICEs without this patch but passes with it.  Executing tests that have
large variables on stack works.

Two things that don't work are passing huge structs by value, which I
doubt anyone would actually want, and unwinding past a huge stack frame,
which I haven't looked into.

OK for mainline?  How about for the 3.3 branch, since it only affects
the rs6000 backend?

2003-11-12  Janis Johnson  <janis187@us.ibm.com>

	* rs6000-protos.h (rs6000_initial_elimination_offset): Add.
	(rs6000_stack_info): Remove.  (debug_stack_info): Remove.
	(rs6000_emit_eh_reg_restore): Add
	* rs6000.c (rs6000_stack_t): Move from rs6000.h, change data type
	of vars_size and total_size to HOST_WIDE_INT.
	(emit_frame_save): Change parameter size to HOST_WIDE_INT.
	(rs6000_stack_info): Make static; change data size to HOST_WIDE_INT.
	(debug_stack_info): Make static; change output format of HOST_WIDE_INT
	values.
	(rs6000_emit_eh_reg_restore): New, with code formerly in rs6000.md.
	(rs6000_initial_elimination_offset): New, with code formerly in
	INITIAL_ELIMINATION_OFFSET.
	* rs6000.h (rs6000_stack_t): Remove.
	(INITIAL_ELIMINATION_OFFSET): Replace code with call to function
	rs6000_initial_elimination_offset.
	* rs6000.md (UNSPECV_EH_RR split): Replace code with call to
	rs6000_emit_eh_reg_restore.

Index: gcc/config/rs6000/rs6000-protos.h
===================================================================
RCS file: /home/janis/gcc_rsync/gcc-cvs/gcc/gcc/config/rs6000/rs6000-protos.h,v
retrieving revision 1.65
diff -u -p -r1.65 rs6000-protos.h
--- gcc/config/rs6000/rs6000-protos.h	30 Oct 2003 02:02:44 -0000	1.65
+++ gcc/config/rs6000/rs6000-protos.h	11 Nov 2003 17:52:40 -0000
@@ -134,6 +134,7 @@ extern int rs6000_legitimate_address (en
 extern bool rs6000_mode_dependent_address (rtx);
 extern rtx rs6000_return_addr (int, rtx);
 extern void rs6000_output_symbol_ref (FILE*, rtx);
+extern HOST_WIDE_INT rs6000_initial_elimination_offset (int, int);
 
 extern rtx rs6000_machopic_legitimize_pic_address (rtx orig, 
                             enum machine_mode mode, rtx reg);
@@ -168,7 +169,6 @@ extern void rs6000_override_options (con
 extern int direct_return (void);
 extern int first_reg_to_save (void);
 extern int first_fp_reg_to_save (void);
-extern rs6000_stack_t *rs6000_stack_info (void);
 extern void output_ascii (FILE *, const char *, int);
 extern void rs6000_gen_section_name (char **, const char *, const char *);
 extern void output_function_profiler (FILE *, int);
@@ -187,7 +187,7 @@ extern void rs6000_emit_prologue (void);
 extern void rs6000_emit_load_toc_table (int);
 extern void rs6000_aix_emit_builtin_unwind_init (void);
 extern void rs6000_emit_epilogue (int);
-extern void debug_stack_info (rs6000_stack_t *);
+extern void rs6000_emit_eh_reg_restore (rtx, rtx);
 extern const char * output_isel (rtx *);
 extern int vrsave_operation (rtx, enum machine_mode);
 extern int rs6000_register_move_cost (enum machine_mode,
Index: gcc/config/rs6000/rs6000.c
===================================================================
RCS file: /home/janis/gcc_rsync/gcc-cvs/gcc/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.546
diff -u -p -r1.546 rs6000.c
--- gcc/config/rs6000/rs6000.c	8 Nov 2003 02:21:01 -0000	1.546
+++ gcc/config/rs6000/rs6000.c	11 Nov 2003 21:44:48 -0000
@@ -70,6 +70,49 @@
 #define min(A,B)	((A) < (B) ? (A) : (B))
 #define max(A,B)	((A) > (B) ? (A) : (B))
 
+/* Structure used to define the rs6000 stack */
+typedef struct rs6000_stack {
+  int first_gp_reg_save;	/* first callee saved GP register used */
+  int first_fp_reg_save;	/* first callee saved FP register used */
+  int first_altivec_reg_save;	/* first callee saved AltiVec register used */
+  int lr_save_p;		/* true if the link reg needs to be saved */
+  int cr_save_p;		/* true if the CR reg needs to be saved */
+  unsigned int vrsave_mask;	/* mask of vec registers to save */
+  int toc_save_p;		/* true if the TOC needs to be saved */
+  int push_p;			/* true if we need to allocate stack space */
+  int calls_p;			/* true if the function makes any calls */
+  enum rs6000_abi abi;		/* which ABI to use */
+  int gp_save_offset;		/* offset to save GP regs from initial SP */
+  int fp_save_offset;		/* offset to save FP regs from initial SP */
+  int altivec_save_offset;	/* offset to save AltiVec regs from initial SP */
+  int lr_save_offset;		/* offset to save LR from initial SP */
+  int cr_save_offset;		/* offset to save CR from initial SP */
+  int vrsave_save_offset;	/* offset to save VRSAVE from initial SP */
+  int spe_gp_save_offset;	/* offset to save spe 64-bit gprs  */
+  int toc_save_offset;		/* offset to save the TOC pointer */
+  int varargs_save_offset;	/* offset to save the varargs registers */
+  int ehrd_offset;		/* offset to EH return data */
+  int reg_size;			/* register size (4 or 8) */
+  int varargs_size;		/* size to hold V.4 args passed in regs */
+  HOST_WIDE_INT vars_size;	/* variable save area size */
+  int parm_size;		/* outgoing parameter size */
+  int save_size;		/* save area size */
+  int fixed_size;		/* fixed size of stack frame */
+  int gp_size;			/* size of saved GP registers */
+  int fp_size;			/* size of saved FP registers */
+  int altivec_size;		/* size of saved AltiVec registers */
+  int cr_size;			/* size to hold CR if not in save_size */
+  int lr_size;			/* size to hold LR if not in save_size */
+  int vrsave_size;		/* size to hold VRSAVE if not in save_size */
+  int altivec_padding_size;	/* size of altivec alignment padding if
+				   not in save_size */
+  int spe_gp_size;		/* size of 64-bit GPR save size for SPE */
+  int spe_padding_size;
+  int toc_size;			/* size to hold TOC if not in save_size */
+  HOST_WIDE_INT total_size;	/* total bytes allocated for stack */
+  int spe_64bit_regs_used;
+} rs6000_stack_t;
+
 /* Target cpu type */
 
 enum processor_type rs6000_cpu;
@@ -222,7 +265,7 @@ static void rs6000_frame_related (rtx, r
 static rtx spe_synthesize_frame_save (rtx);
 static bool spe_func_has_64bit_regs_p (void);
 static void emit_frame_save (rtx, rtx, enum machine_mode, unsigned int,
-			     int, int);
+			     int, HOST_WIDE_INT);
 static rtx gen_frame_mem_offset (enum machine_mode, rtx, int);
 static void rs6000_emit_allocate_stack (HOST_WIDE_INT, int);
 static unsigned rs6000_hash_constant (rtx);
@@ -316,6 +359,8 @@ static rtx spe_expand_builtin (tree, rtx
 static rtx spe_expand_predicate_builtin (enum insn_code, tree, rtx);
 static rtx spe_expand_evsel_builtin (enum insn_code, tree, rtx);
 static int rs6000_emit_int_cmove (rtx, rtx, rtx, rtx);
+static rs6000_stack_t *rs6000_stack_info (void);
+static void debug_stack_info (rs6000_stack_t *);
 
 static rtx altivec_expand_builtin (tree, rtx, bool *);
 static rtx altivec_expand_ld_builtin (tree, rtx, bool *);
@@ -10248,14 +10293,14 @@ is_altivec_return_reg (rtx reg, void *xy
 #define ABI_STACK_BOUNDARY STACK_BOUNDARY
 #endif
 
-rs6000_stack_t *
+static rs6000_stack_t *
 rs6000_stack_info (void)
 {
   static rs6000_stack_t info, zero_info;
   rs6000_stack_t *info_ptr = &info;
   int reg_size = TARGET_POWERPC64 ? 8 : 4;
   int ehrd_size;
-  int total_raw_size;
+  HOST_WIDE_INT total_raw_size;
 
   /* Zero all fields portably.  */
   info = zero_info;
@@ -10587,7 +10632,7 @@ spe_func_has_64bit_regs_p (void)
   return false;
 }
 
-void
+static void
 debug_stack_info (rs6000_stack_t *info)
 {
   const char *abi_string;
@@ -10676,13 +10721,15 @@ debug_stack_info (rs6000_stack_t *info)
     fprintf (stderr, "\tvarargs_save_offset = %5d\n", info->varargs_save_offset);
 
   if (info->total_size)
-    fprintf (stderr, "\ttotal_size          = %5d\n", info->total_size);
+    fprintf (stderr, "\ttotal_size          = "HOST_WIDE_INT_PRINT_DEC"\n",
+	     info->total_size);
 
   if (info->varargs_size)
     fprintf (stderr, "\tvarargs_size        = %5d\n", info->varargs_size);
 
   if (info->vars_size)
-    fprintf (stderr, "\tvars_size           = %5d\n", info->vars_size);
+    fprintf (stderr, "\tvars_size           = "HOST_WIDE_INT_PRINT_DEC"\n",
+	     info->vars_size);
 
   if (info->parm_size)
     fprintf (stderr, "\tparm_size           = %5d\n", info->parm_size);
@@ -10955,6 +11002,42 @@ rs6000_emit_load_toc_table (int fromprol
     abort ();
 }
 
+/* Emit instructions to restore the link register after determining where
+   its value has been stored.  */
+
+void
+rs6000_emit_eh_reg_restore (rtx source, rtx scratch)
+{
+  rs6000_stack_t *info = rs6000_stack_info ();
+  rtx operands[2];
+
+  operands[0] = source;
+  operands[1] = scratch;
+
+  if (info->lr_save_p)
+    {
+      rtx frame_rtx = stack_pointer_rtx;
+      HOST_WIDE_INT sp_offset = 0;
+      rtx tmp;
+
+      if (frame_pointer_needed
+	  || current_function_calls_alloca
+	  || info->total_size > 32767)
+	{
+	  emit_move_insn (operands[1], gen_rtx_MEM (Pmode, frame_rtx));
+	  frame_rtx = operands[1];
+	}
+      else if (info->push_p)
+	sp_offset = info->total_size;
+
+      tmp = plus_constant (frame_rtx, info->lr_save_offset + sp_offset);
+      tmp = gen_rtx_MEM (Pmode, tmp);
+      emit_move_insn (tmp, operands[0]);
+    }
+  else
+    emit_move_insn (gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM), operands[0]);
+}
+
 int   
 get_TOC_alias_set (void)
 {
@@ -11353,7 +11436,7 @@ generate_set_vrsave (rtx reg, rs6000_sta
 
 static void
 emit_frame_save (rtx frame_reg, rtx frame_ptr, enum machine_mode mode, 
-		 unsigned int regno, int offset, int total_size)
+		 unsigned int regno, int offset, HOST_WIDE_INT total_size)
 {
   rtx reg, offset_rtx, insn, mem, addr, int_rtx;
   rtx replacea, replaceb;
@@ -15552,6 +15635,28 @@ rs6000_libcall_value (enum machine_mode 
     regno = GP_ARG_RETURN;
 
   return gen_rtx_REG (mode, regno);
+}
+
+/* Define the offset between two registers, FROM to be eliminated and its
+   replacement TO, at the start of a routine.  */
+HOST_WIDE_INT
+rs6000_initial_elimination_offset (int from, int to)
+{
+  rs6000_stack_t *info = rs6000_stack_info ();
+  HOST_WIDE_INT offset;
+
+  if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
+    offset = info->push_p ? 0 : -info->total_size;
+  else if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
+    offset = info->total_size;
+  else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
+    offset = info->push_p ? info->total_size : 0;
+  else if (from == RS6000_PIC_OFFSET_TABLE_REGNUM)
+    offset = 0;
+  else
+    abort ();
+
+  return offset;
 }
 
 /* Return true if TYPE is of type __ev64_opaque__.  */
Index: gcc/config/rs6000/rs6000.h
===================================================================
RCS file: /home/janis/gcc_rsync/gcc-cvs/gcc/gcc/config/rs6000/rs6000.h,v
retrieving revision 1.298
diff -u -p -r1.298 rs6000.h
--- gcc/config/rs6000/rs6000.h	6 Nov 2003 21:52:32 -0000	1.298
+++ gcc/config/rs6000/rs6000.h	11 Nov 2003 17:49:37 -0000
@@ -1491,49 +1491,6 @@ enum rs6000_abi {
 
 extern enum rs6000_abi rs6000_current_abi;	/* available for use by subtarget */
 
-/* Structure used to define the rs6000 stack */
-typedef struct rs6000_stack {
-  int first_gp_reg_save;	/* first callee saved GP register used */
-  int first_fp_reg_save;	/* first callee saved FP register used */
-  int first_altivec_reg_save;	/* first callee saved AltiVec register used */
-  int lr_save_p;		/* true if the link reg needs to be saved */
-  int cr_save_p;		/* true if the CR reg needs to be saved */
-  unsigned int vrsave_mask;	/* mask of vec registers to save */
-  int toc_save_p;		/* true if the TOC needs to be saved */
-  int push_p;			/* true if we need to allocate stack space */
-  int calls_p;			/* true if the function makes any calls */
-  enum rs6000_abi abi;		/* which ABI to use */
-  int gp_save_offset;		/* offset to save GP regs from initial SP */
-  int fp_save_offset;		/* offset to save FP regs from initial SP */
-  int altivec_save_offset;	/* offset to save AltiVec regs from initial SP */
-  int lr_save_offset;		/* offset to save LR from initial SP */
-  int cr_save_offset;		/* offset to save CR from initial SP */
-  int vrsave_save_offset;	/* offset to save VRSAVE from initial SP */
-  int spe_gp_save_offset;	/* offset to save spe 64-bit gprs  */
-  int toc_save_offset;		/* offset to save the TOC pointer */
-  int varargs_save_offset;	/* offset to save the varargs registers */
-  int ehrd_offset;		/* offset to EH return data */
-  int reg_size;			/* register size (4 or 8) */
-  int varargs_size;		/* size to hold V.4 args passed in regs */
-  int vars_size;		/* variable save area size */
-  int parm_size;		/* outgoing parameter size */
-  int save_size;		/* save area size */
-  int fixed_size;		/* fixed size of stack frame */
-  int gp_size;			/* size of saved GP registers */
-  int fp_size;			/* size of saved FP registers */
-  int altivec_size;		/* size of saved AltiVec registers */
-  int cr_size;			/* size to hold CR if not in save_size */
-  int lr_size;			/* size to hold LR if not in save_size */
-  int vrsave_size;		/* size to hold VRSAVE if not in save_size */
-  int altivec_padding_size;	/* size of altivec alignment padding if
-				   not in save_size */
-  int spe_gp_size;		/* size of 64-bit GPR save size for SPE */
-  int spe_padding_size;
-  int toc_size;			/* size to hold TOC if not in save_size */
-  int total_size;		/* total bytes allocated for stack */
-  int spe_64bit_regs_used;
-} rs6000_stack_t;
-
 /* Define this if pushing a word on the stack
    makes the stack pointer a smaller address.  */
 #define STACK_GROWS_DOWNWARD
@@ -1984,21 +1941,8 @@ typedef struct rs6000_args
 
 /* Define the offset between two registers, one to be eliminated, and the other
    its replacement, at the start of a routine.  */
-#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET)			\
-{									\
-  rs6000_stack_t *info = rs6000_stack_info ();				\
-									\
- if ((FROM) == FRAME_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM)	\
-   (OFFSET) = (info->push_p) ? 0 : - info->total_size;			\
- else if ((FROM) == ARG_POINTER_REGNUM && (TO) == FRAME_POINTER_REGNUM)	\
-   (OFFSET) = info->total_size;						\
- else if ((FROM) == ARG_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM)	\
-   (OFFSET) = (info->push_p) ? info->total_size : 0;			\
-  else if ((FROM) == RS6000_PIC_OFFSET_TABLE_REGNUM)			\
-    (OFFSET) = 0;							\
-  else									\
-    abort ();								\
-}
+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
+  ((OFFSET) = rs6000_initial_elimination_offset(FROM,TO))
 
 /* Addressing modes, and classification of registers for them.  */
 
Index: gcc/config/rs6000/rs6000.md
===================================================================
RCS file: /home/janis/gcc_rsync/gcc-cvs/gcc/gcc/config/rs6000/rs6000.md,v
retrieving revision 1.271
diff -u -p -r1.271 rs6000.md
--- gcc/config/rs6000/rs6000.md	29 Oct 2003 23:31:54 -0000	1.271
+++ gcc/config/rs6000/rs6000.md	11 Nov 2003 17:49:42 -0000
@@ -14684,30 +14684,7 @@
   [(const_int 0)]
   "
 {
-  rs6000_stack_t *info = rs6000_stack_info ();
-
-  if (info->lr_save_p)
-    {
-      rtx frame_rtx = stack_pointer_rtx;
-      int sp_offset = 0;
-      rtx tmp;
-
-      if (frame_pointer_needed
-	  || current_function_calls_alloca
-	  || info->total_size > 32767)
-	{
-	  emit_move_insn (operands[1], gen_rtx_MEM (Pmode, frame_rtx));
-	  frame_rtx = operands[1];
-	}
-      else if (info->push_p)
-	sp_offset = info->total_size;
-
-      tmp = plus_constant (frame_rtx, info->lr_save_offset + sp_offset);
-      tmp = gen_rtx_MEM (Pmode, tmp);
-      emit_move_insn (tmp, operands[0]);
-    }
-  else
-    emit_move_insn (gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM), operands[0]);
+  rs6000_emit_eh_reg_restore (operands[0], operands[1]);
   DONE;
 }")
 



More information about the Gcc-patches mailing list