* i386.c (ix86_frame): New structure.
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 24 Feb 2001 02:34:05 +0000 (02:34 +0000)
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 24 Feb 2001 02:34:05 +0000 (02:34 +0000)
(ix86_compute_frame_size): Kill.
(ix86_compute_frame_layout): New.
(ix86_save_reg): New.
(ix86_can_use_return_insn_p): Use frame layout stuff.
(ix86_expand_prologue): Likewise.
(ix86_expand_epilogue): Likewise.
(ix86_initial_elimination_offset): Likewise.
(ix86_nsaved_regs): Use ix86_save_reg.
(ix86_emit_save_regs): Likewise.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@40022 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/config/i386/i386.c

index d3f1da5..5699d93 100644 (file)
@@ -1,3 +1,16 @@
+Sat Feb 24 03:32:50 CET 2001  Jan Hubicka  <jh@suse.cz>
+
+       * i386.c (ix86_frame): New structure.
+       (ix86_compute_frame_size): Kill.
+       (ix86_compute_frame_layout): New.
+       (ix86_save_reg): New.
+       (ix86_can_use_return_insn_p): Use frame layout stuff.
+       (ix86_expand_prologue): Likewise.
+       (ix86_expand_epilogue): Likewise.
+       (ix86_initial_elimination_offset): Likewise.
+       (ix86_nsaved_regs): Use ix86_save_reg.
+       (ix86_emit_save_regs): Likewise.
+
 Sat Feb 24 03:30:38 CET 2001  Jan Hubicka  <jh@suse.cz>
 
        * flow.c (find_sub_basic_blocks): New function.
index 7456519..e90cc0d 100644 (file)
@@ -402,6 +402,40 @@ struct machine_function
 
 #define ix86_stack_locals (cfun->machine->stack_locals)
 
+/* Structure describing stack frame layout.
+   Stack grows downward:
+
+   [arguments]
+                                             <- ARG_POINTER
+   saved pc
+
+   saved frame pointer if frame_pointer_needed
+                                             <- HARD_FRAME_POINTER
+   [saved regs]
+
+   [padding1]          \
+                       )
+   [va_arg registers]  (
+                       > to_allocate         <- FRAME_POINTER
+   [frame]            (
+                       )
+   [padding2]         /
+  */
+struct ix86_frame
+{
+  int nregs;
+  int padding1;
+  HOST_WIDE_INT frame;
+  int padding2;
+  int outgoing_arguments_size;
+
+  HOST_WIDE_INT to_allocate;
+  /* The offsets relative to ARG_POINTER.  */
+  HOST_WIDE_INT frame_pointer_offset;
+  HOST_WIDE_INT hard_frame_pointer_offset;
+  HOST_WIDE_INT stack_pointer_offset;
+};
+
 /* which cpu are we scheduling for */
 enum processor_type ix86_cpu;
 
@@ -469,8 +503,6 @@ static void ix86_mark_machine_status PARAMS ((struct function *));
 static void ix86_free_machine_status PARAMS ((struct function *));
 static int ix86_split_to_parts PARAMS ((rtx, rtx *, enum machine_mode));
 static int ix86_safe_length_prefix PARAMS ((rtx));
-static HOST_WIDE_INT ix86_compute_frame_size PARAMS((HOST_WIDE_INT,
-                                                    int *, int *, int *));
 static int ix86_nsaved_regs PARAMS((void));
 static void ix86_emit_save_regs PARAMS((void));
 static void ix86_emit_restore_regs_using_mov PARAMS ((rtx, int));
@@ -508,6 +540,8 @@ static int ix86_fp_comparison_arithmetics_cost PARAMS ((enum rtx_code code));
 static int ix86_fp_comparison_fcomi_cost PARAMS ((enum rtx_code code));
 static int ix86_fp_comparison_sahf_cost PARAMS ((enum rtx_code code));
 static int ix86_fp_comparison_cost PARAMS ((enum rtx_code code));
+static int ix86_save_reg PARAMS ((int));
+static void ix86_compute_frame_layout PARAMS ((struct ix86_frame *));
 \f
 /* Sometimes certain combinations of command options do not make
    sense on a particular target machine.  You can define a macro
@@ -1667,8 +1701,7 @@ symbolic_reference_mentioned_p (op)
 int
 ix86_can_use_return_insn_p ()
 {
-  HOST_WIDE_INT tsize;
-  int nregs;
+  struct ix86_frame frame;
 
 #ifdef NON_SAVING_SETJMP
   if (NON_SAVING_SETJMP && current_function_calls_setjmp)
@@ -1688,8 +1721,8 @@ ix86_can_use_return_insn_p ()
       && current_function_args_size >= 32768)
     return 0;
 
-  tsize = ix86_compute_frame_size (get_frame_size (), &nregs, NULL, NULL);
-  return tsize == 0 && nregs == 0;
+  ix86_compute_frame_layout (&frame);
+  return frame.to_allocate == 0 && frame.nregs == 0;
 }
 
 /* Value should be nonzero if functions must have frame pointers.
@@ -1817,24 +1850,31 @@ gen_push (arg)
                      arg);
 }
 
+/* Return 1 if we need to save REGNO.  */
+static int
+ix86_save_reg (regno)
+       int regno;
+{
+  int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
+                                 || current_function_uses_const_pool);
+  return ((regs_ever_live[regno] && !call_used_regs[regno]
+          && !fixed_regs[regno]
+          && (regno != HARD_FRAME_POINTER_REGNUM || !frame_pointer_needed))
+         || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used));
+
+}
+
 /* Return number of registers to be saved on the stack.  */
 
 static int
 ix86_nsaved_regs ()
 {
   int nregs = 0;
-  int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
-                                 || current_function_uses_const_pool);
-  int limit = (frame_pointer_needed
-              ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
   int regno;
 
-  for (regno = limit - 1; regno >= 0; regno--)
-    if ((regs_ever_live[regno] && ! call_used_regs[regno])
-       || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
-      {
-       nregs ++;
-      }
+  for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--)
+    if (ix86_save_reg (regno))
+      nregs++;
   return nregs;
 }
 
@@ -1846,82 +1886,46 @@ ix86_initial_elimination_offset (from, to)
      int from;
      int to;
 {
-  int padding1;
-  int nregs;
-
-  /* Stack grows downward:
-
-     [arguments]
-                                               <- ARG_POINTER
-     saved pc
-
-     saved frame pointer if frame_pointer_needed
-                                               <- HARD_FRAME_POINTER
-     [saved regs]
-
-     [padding1]   \
-                  |                            <- FRAME_POINTER
-     [frame]      > tsize
-                  |
-     [padding2]   /
-    */
+  struct ix86_frame frame;
+  ix86_compute_frame_layout (&frame);
 
   if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
-    /* Skip saved PC and previous frame pointer.
-       Executed only when frame_pointer_needed.  */
-    return 8;
+    return frame.hard_frame_pointer_offset;
   else if (from == FRAME_POINTER_REGNUM
           && to == HARD_FRAME_POINTER_REGNUM)
-    {
-      ix86_compute_frame_size (get_frame_size (), &nregs, &padding1, (int *) 0);
-      padding1 += nregs * UNITS_PER_WORD;
-      return -padding1;
-    }
+    return frame.hard_frame_pointer_offset - frame.frame_pointer_offset;
   else
     {
-      /* ARG_POINTER or FRAME_POINTER to STACK_POINTER elimination.  */
-      int frame_size = frame_pointer_needed ? 8 : 4;
-      HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (),
-                                                    &nregs, &padding1, (int *) 0);
-
       if (to != STACK_POINTER_REGNUM)
        abort ();
       else if (from == ARG_POINTER_REGNUM)
-       return tsize + nregs * UNITS_PER_WORD + frame_size;
+       return frame.stack_pointer_offset;
       else if (from != FRAME_POINTER_REGNUM)
        abort ();
       else
-       return tsize - padding1;
+       return frame.stack_pointer_offset - frame.frame_pointer_offset;
     }
 }
 
-/* Compute the size of local storage taking into consideration the
-   desired stack alignment which is to be maintained.  Also determine
-   the number of registers saved below the local storage.
+/* Fill structure ix86_frame about frame of currently computed function.  */
 
-   PADDING1 returns padding before stack frame and PADDING2 returns
-   padding after stack frame;
- */
-
-static HOST_WIDE_INT
-ix86_compute_frame_size (size, nregs_on_stack, rpadding1, rpadding2)
-     HOST_WIDE_INT size;
-     int *nregs_on_stack;
-     int *rpadding1;
-     int *rpadding2;
+static void
+ix86_compute_frame_layout (frame)
+     struct ix86_frame *frame;
 {
-  int nregs;
-  int padding1 = 0;
-  int padding2 = 0;
   HOST_WIDE_INT total_size;
   int stack_alignment_needed = cfun->stack_alignment_needed / BITS_PER_UNIT;
   int offset;
   int preferred_alignment = cfun->preferred_stack_boundary / BITS_PER_UNIT;
+  HOST_WIDE_INT size = get_frame_size ();
 
-  nregs = ix86_nsaved_regs ();
+  frame->nregs = ix86_nsaved_regs ();
   total_size = size;
 
-  offset = frame_pointer_needed ? 8 : 4;
+  /* Skip return value and save base pointer.  */
+  offset = frame_pointer_needed ? UNITS_PER_WORD * 2 : UNITS_PER_WORD;
+
+  frame->hard_frame_pointer_offset = offset;
 
   /* Do some sanity checking of stack_alignment_needed and
      preferred_alignment, since i386 port is the only using those features
@@ -1936,36 +1940,58 @@ ix86_compute_frame_size (size, nregs_on_stack, rpadding1, rpadding2)
   if (stack_alignment_needed > PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT)
     abort ();
 
-  if (stack_alignment_needed < 4)
-    stack_alignment_needed = 4;
+  if (stack_alignment_needed < STACK_BOUNDARY / BITS_PER_UNIT)
+    stack_alignment_needed = STACK_BOUNDARY / BITS_PER_UNIT;
 
-  offset += nregs * UNITS_PER_WORD;
+  /* Register save area */
+  offset += frame->nregs * UNITS_PER_WORD;
 
-  if (ACCUMULATE_OUTGOING_ARGS)
-    total_size += current_function_outgoing_args_size;
+  /* Align start of frame for local function.  */
+  frame->padding1 = ((offset + stack_alignment_needed - 1)
+                    & -stack_alignment_needed) - offset;
 
-  total_size += offset;
+  offset += frame->padding1;
 
-  /* Align start of frame for local function.  */
-  padding1 = ((offset + stack_alignment_needed - 1)
-             & -stack_alignment_needed) - offset;
-  total_size += padding1;
+  /* Frame pointer points here.  */
+  frame->frame_pointer_offset = offset;
 
-  /* Align stack boundary.  */
-  padding2 = ((total_size + preferred_alignment - 1)
-             & -preferred_alignment) - total_size;
+  offset += size;
 
+  /* Add outgoing arguments area.  */
   if (ACCUMULATE_OUTGOING_ARGS)
-    padding2 += current_function_outgoing_args_size;
-
-  if (nregs_on_stack)
-    *nregs_on_stack = nregs;
-  if (rpadding1)
-    *rpadding1 = padding1;
-  if (rpadding2)
-    *rpadding2 = padding2;
+    {
+      offset += current_function_outgoing_args_size;
+      frame->outgoing_arguments_size = current_function_outgoing_args_size;
+    }
+  else
+    frame->outgoing_arguments_size = 0;
 
-  return size + padding1 + padding2;
+  /* Align stack boundary.  */
+  frame->padding2 = ((offset + preferred_alignment - 1)
+                    & -preferred_alignment) - offset;
+
+  offset += frame->padding2;
+
+  /* We've reached end of stack frame.  */
+  frame->stack_pointer_offset = offset;
+
+  /* Size prologue needs to allocate.  */
+  frame->to_allocate =
+    (size + frame->padding1 + frame->padding2
+     + frame->outgoing_arguments_size);
+
+#if 0
+  fprintf (stderr, "nregs: %i\n", frame->nregs);
+  fprintf (stderr, "size: %i\n", size);
+  fprintf (stderr, "alignment1: %i\n", stack_alignment_needed);
+  fprintf (stderr, "padding1: %i\n", frame->padding1);
+  fprintf (stderr, "padding2: %i\n", frame->padding2);
+  fprintf (stderr, "to_allocate: %i\n", frame->to_allocate);
+  fprintf (stderr, "frame_pointer_offset: %i\n", frame->frame_pointer_offset);
+  fprintf (stderr, "hard_frame_pointer_offset: %i\n",
+          frame->hard_frame_pointer_offset);
+  fprintf (stderr, "stack_pointer_offset: %i\n", frame->stack_pointer_offset);
+#endif
 }
 
 /* Emit code to save registers in the prologue.  */
@@ -1974,16 +2000,10 @@ static void
 ix86_emit_save_regs ()
 {
   register int regno;
-  int limit;
   rtx insn;
-  int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
-                                 || current_function_uses_const_pool);
-  limit = (frame_pointer_needed
-          ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
 
-  for (regno = limit - 1; regno >= 0; regno--)
-    if ((regs_ever_live[regno] && !call_used_regs[regno])
-       || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
+  for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--)
+    if (ix86_save_reg (regno))
       {
        insn = emit_insn (gen_push (gen_rtx_REG (SImode, regno)));
        RTX_FRAME_RELATED_P (insn) = 1;
@@ -1995,11 +2015,12 @@ ix86_emit_save_regs ()
 void
 ix86_expand_prologue ()
 {
-  HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (), (int *) 0,
-                                                (int *) 0, (int *) 0);
   rtx insn;
   int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
                                  || current_function_uses_const_pool);
+  struct ix86_frame frame;
+
+  ix86_compute_frame_layout (&frame);
 
   /* Note: AT&T enter does NOT have reversed args.  Enter is probably
      slower on all targets.  Also sdb doesn't like it.  */
@@ -2015,17 +2036,17 @@ ix86_expand_prologue ()
 
   ix86_emit_save_regs ();
 
-  if (tsize == 0)
+  if (frame.to_allocate == 0)
     ;
-  else if (! TARGET_STACK_PROBE || tsize < CHECK_STACK_LIMIT)
+  else if (! TARGET_STACK_PROBE || frame.to_allocate < CHECK_STACK_LIMIT)
     {
       if (frame_pointer_needed)
        insn = emit_insn (gen_pro_epilogue_adjust_stack
                          (stack_pointer_rtx, stack_pointer_rtx,
-                          GEN_INT (-tsize), hard_frame_pointer_rtx));
+                          GEN_INT (-frame.to_allocate), hard_frame_pointer_rtx));
       else
         insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
-                                     GEN_INT (-tsize)));
+                                     GEN_INT (-frame.to_allocate)));
       RTX_FRAME_RELATED_P (insn) = 1;
     }
   else
@@ -2035,7 +2056,7 @@ ix86_expand_prologue ()
       rtx arg0, sym;
 
       arg0 = gen_rtx_REG (SImode, 0);
-      emit_move_insn (arg0, GEN_INT (tsize));
+      emit_move_insn (arg0, GEN_INT (frame.to_allocate));
 
       sym = gen_rtx_MEM (FUNCTION_MODE,
                         gen_rtx_SYMBOL_REF (Pmode, "_alloca"));
@@ -2087,20 +2108,15 @@ ix86_emit_restore_regs_using_mov (pointer, offset)
        int offset;
 {
   int regno;
-  int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
-                                 || current_function_uses_const_pool);
-  int limit = (frame_pointer_needed
-              ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
 
-  for (regno = 0; regno < limit; regno++)
-    if ((regs_ever_live[regno] && !call_used_regs[regno])
-       || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
+  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+    if (ix86_save_reg (regno))
       {
-       emit_move_insn (gen_rtx_REG (SImode, regno),
-                       adj_offsettable_operand (gen_rtx_MEM (SImode,
+       emit_move_insn (gen_rtx_REG (Pmode, regno),
+                       adj_offsettable_operand (gen_rtx_MEM (Pmode,
                                                              pointer),
                                                 offset));
-       offset += 4;
+       offset += UNITS_PER_WORD;
       }
 }
 
@@ -2110,18 +2126,15 @@ void
 ix86_expand_epilogue (emit_return)
      int emit_return;
 {
-  int nregs;
   int regno;
-
-  int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
-                                 || current_function_uses_const_pool);
   int sp_valid = !frame_pointer_needed || current_function_sp_is_unchanging;
+  struct ix86_frame frame;
   HOST_WIDE_INT offset;
-  HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (), &nregs,
-                                                (int *) 0, (int *) 0);
+
+  ix86_compute_frame_layout (&frame);
 
   /* Calculate start of saved registers relative to ebp.  */
-  offset = -nregs * UNITS_PER_WORD;
+  offset = -frame.nregs * UNITS_PER_WORD;
 
 #ifdef FUNCTION_BLOCK_PROFILER_EXIT
   if (profile_block_flag == 2)
@@ -2140,10 +2153,10 @@ ix86_expand_epilogue (emit_return)
      are no registers to restore.  We also use this code when TARGET_USE_LEAVE
      and there is exactly one register to pop. This heruistic may need some
      tuning in future.  */
-  if ((!sp_valid && nregs <= 1)
-      || (frame_pointer_needed && !nregs && tsize)
+  if ((!sp_valid && frame.nregs <= 1)
+      || (frame_pointer_needed && !frame.nregs && frame.to_allocate)
       || (frame_pointer_needed && TARGET_USE_LEAVE && !optimize_size
-         && nregs == 1))
+         && frame.nregs == 1))
     {
       /* Restore registers.  We can use ebp or esp to address the memory
         locations.  If both are available, default to ebp, since offsets
@@ -2151,13 +2164,14 @@ ix86_expand_epilogue (emit_return)
         end of block of saved registers, where we may simplify addressing
         mode.  */
 
-      if (!frame_pointer_needed || (sp_valid && !tsize))
-       ix86_emit_restore_regs_using_mov (stack_pointer_rtx, tsize);
+      if (!frame_pointer_needed || (sp_valid && !frame.to_allocate))
+       ix86_emit_restore_regs_using_mov (stack_pointer_rtx, frame.to_allocate);
       else
        ix86_emit_restore_regs_using_mov (hard_frame_pointer_rtx, offset);
 
       if (!frame_pointer_needed)
-       ix86_emit_epilogue_esp_adjustment (tsize + nregs * UNITS_PER_WORD);
+       ix86_emit_epilogue_esp_adjustment (frame.to_allocate
+                                          + frame.nregs * UNITS_PER_WORD);
       /* If not an i386, mov & pop is faster than "leave".  */
       else if (TARGET_USE_LEAVE || optimize_size)
        emit_insn (gen_leave ());
@@ -2183,13 +2197,14 @@ ix86_expand_epilogue (emit_return)
                                                    GEN_INT (offset),
                                                    hard_frame_pointer_rtx));
        }
-      else if (tsize)
-       ix86_emit_epilogue_esp_adjustment (tsize);
+      else if (frame.to_allocate)
+       ix86_emit_epilogue_esp_adjustment (frame.to_allocate);
 
-      for (regno = 0; regno < STACK_POINTER_REGNUM; regno++)
-       if ((regs_ever_live[regno] && !call_used_regs[regno])
-           || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
+      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+       if (ix86_save_reg (regno))
          emit_insn (gen_popsi1 (gen_rtx_REG (SImode, regno)));
+      if (frame_pointer_needed)
+       emit_insn (gen_popsi1 (hard_frame_pointer_rtx));
     }
 
   /* Sibcall epilogues don't want a return instruction.  */