OSDN Git Service

* config/rs6000/rs6000.c (rs6000_stack_info): Allocate space
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 28 Mar 2001 11:19:20 +0000 (11:19 +0000)
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 28 Mar 2001 11:19:20 +0000 (11:19 +0000)
        for eh_return data registers.
        (rs6000_emit_prologue): Save eh_return data registers.
        (rs6000_emit_epilogue): Force inline restores if eh_return.
        Restore eh_return data registers.  Mind EH_RETURN_STACKADJ_RTX.
        * config/rs6000/rs6000.h (rs6000_stack_t): Add ehrd_offset.
        (EH_RETURN_DATA_REGNO, EH_RETURN_STACKADJ_RTX): New.
        (EPILOGUE_USES): True for TOC_REGISTER if calls_eh_return and
        the target uses one.
        * config/rs6000/rs6000.md (eh_epilogue, eh_reg_restore): Remove.
        (return_eh_si, return_eh_di): Remove.
        (eh_return): New, from corpse of eh_epilogue.
        (eh_set_lr_si, eh_set_lr_di): New.

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

gcc/ChangeLog
gcc/config/rs6000/rs6000.c
gcc/config/rs6000/rs6000.h
gcc/config/rs6000/rs6000.md

index c94073e..b6d3eb9 100644 (file)
@@ -1,5 +1,19 @@
 2001-03-28  Richard Henderson  <rth@redhat.com>
 
+       * config/rs6000/rs6000.c (rs6000_stack_info): Allocate space
+       for eh_return data registers.
+       (rs6000_emit_prologue): Save eh_return data registers.
+       (rs6000_emit_epilogue): Force inline restores if eh_return.
+       Restore eh_return data registers.  Mind EH_RETURN_STACKADJ_RTX.
+       * config/rs6000/rs6000.h (rs6000_stack_t): Add ehrd_offset.
+       (EH_RETURN_DATA_REGNO, EH_RETURN_STACKADJ_RTX): New.
+       (EPILOGUE_USES): True for TOC_REGISTER if calls_eh_return and
+       the target uses one.
+       * config/rs6000/rs6000.md (eh_epilogue, eh_reg_restore): Remove.
+       (return_eh_si, return_eh_di): Remove.
+       (eh_return): New, from corpse of eh_epilogue.
+       (eh_set_lr_si, eh_set_lr_di): New.
+
        * config/i386/i386.c (general_no_elim_operand): Disallow virtual regs.
        (ix86_save_reg): If maybe_eh_return, true for EH_RETURN_DATA_REGNOs.
        True for pic register if current_function_calls_eh_return.
index ea42bf5..4b24bfb 100644 (file)
@@ -4808,6 +4808,7 @@ rs6000_stack_info ()
   rs6000_stack_t *info_ptr = &info;
   int reg_size = TARGET_POWERPC64 ? 8 : 4;
   enum rs6000_abi abi;
+  int ehrd_size;
   int total_raw_size;
 
   /* Zero all fields portably */
@@ -4860,6 +4861,19 @@ rs6000_stack_info ()
        info_ptr->cr_size = reg_size;
     }
 
+  /* If the current function calls __builtin_eh_return, then we need
+     to allocate stack space for registers that will hold data for
+     the exception handler.  */
+  if (current_function_calls_eh_return)
+    {
+      unsigned int i;
+      for (i = 0; EH_RETURN_DATA_REGNO (i) != INVALID_REGNUM; ++i)
+       continue;
+      ehrd_size = i * UNITS_PER_WORD;
+    }
+  else
+    ehrd_size = 0;
+
   /* Determine various sizes */
   info_ptr->reg_size     = reg_size;
   info_ptr->fixed_size   = RS6000_SAVE_AREA;
@@ -4868,6 +4882,7 @@ rs6000_stack_info ()
   info_ptr->parm_size    = RS6000_ALIGN (current_function_outgoing_args_size, 8);
   info_ptr->save_size    = RS6000_ALIGN (info_ptr->fp_size
                                  + info_ptr->gp_size
+                                 + ehrd_size
                                  + info_ptr->cr_size
                                  + info_ptr->lr_size
                                  + info_ptr->toc_size, 8);
@@ -4883,6 +4898,7 @@ rs6000_stack_info ()
     case ABI_AIX_NODESC:
       info_ptr->fp_save_offset   = - info_ptr->fp_size;
       info_ptr->gp_save_offset   = info_ptr->fp_save_offset - info_ptr->gp_size;
+      info_ptr->ehrd_offset      = info_ptr->gp_save_offset - ehrd_size;
       info_ptr->cr_save_offset   = reg_size; /* first word when 64-bit.  */
       info_ptr->lr_save_offset   = 2*reg_size;
       break;
@@ -4893,6 +4909,7 @@ rs6000_stack_info ()
       info_ptr->gp_save_offset   = info_ptr->fp_save_offset - info_ptr->gp_size;
       info_ptr->cr_save_offset   = info_ptr->gp_save_offset - info_ptr->cr_size;
       info_ptr->toc_save_offset  = info_ptr->cr_save_offset - info_ptr->toc_size;
+      info_ptr->ehrd_offset      = info_ptr->toc_save_offset - ehrd_size;
       info_ptr->lr_save_offset   = reg_size;
       break;
     }
@@ -5585,7 +5602,7 @@ rs6000_frame_related (insn, reg, val, reg2, rreg)
 /* Emit function prologue as insns.  */
 
 void
-rs6000_emit_prologue()
+rs6000_emit_prologue ()
 {
   rs6000_stack_t *info = rs6000_stack_info ();
   enum machine_mode reg_mode = TARGET_POWERPC64 ? DImode : SImode;
@@ -5741,6 +5758,31 @@ rs6000_emit_prologue()
          }
     }
 
+  /* ??? There's no need to emit actual instructions here, but it's the
+     easiest way to get the frame unwind information emitted.  */
+  if (current_function_calls_eh_return)
+    {
+      unsigned int i, regno;
+      for (i = 0; ; ++i)
+       {
+         rtx addr, reg, mem;
+
+         regno = EH_RETURN_DATA_REGNO (i);
+         if (regno == INVALID_REGNUM)
+           break;
+
+         reg = gen_rtx_REG (reg_mode, regno);
+         addr = plus_constant (frame_reg_rtx,
+                               info->ehrd_offset + sp_offset + reg_size * i);
+         mem = gen_rtx_MEM (reg_mode, addr);
+         MEM_ALIAS_SET (mem) = rs6000_sr_alias_set;
+
+         insn = emit_move_insn (mem, reg);
+         rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, 
+                               NULL_RTX, NULL_RTX);
+       }
+    }
+
   /* Save lr if we used it.  */
   if (info->lr_save_p)
     {
@@ -5876,7 +5918,7 @@ output_prolog (file, size)
    need special notes to explain where r11 is in relation to the stack.  */
 
 void
-rs6000_emit_epilogue(sibcall)
+rs6000_emit_epilogue (sibcall)
      int sibcall;
 {
   rs6000_stack_t *info;
@@ -5895,6 +5937,7 @@ rs6000_emit_epilogue(sibcall)
   using_load_multiple = (TARGET_MULTIPLE && ! TARGET_POWERPC64
                         && info->first_gp_reg_save < 31);
   restoring_FPRs_inline = (sibcall
+                          || current_function_calls_eh_return
                           || info->first_fp_reg_save == 64
                           || FP_SAVE_INLINE (info->first_fp_reg_save));
   use_backchain_to_restore_sp = (frame_pointer_needed 
@@ -5960,6 +6003,26 @@ rs6000_emit_epilogue(sibcall)
     emit_move_insn (gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM),
                    gen_rtx_REG (Pmode, 0));
   
+  /* Load exception handler data registers, if needed.  */
+  if (current_function_calls_eh_return)
+    {
+      unsigned int i, regno;
+      for (i = 0; ; ++i)
+       {
+         rtx addr, mem;
+
+         regno = EH_RETURN_DATA_REGNO (i);
+         if (regno == INVALID_REGNUM)
+           break;
+
+         addr = plus_constant (frame_reg_rtx,
+                               info->ehrd_offset + sp_offset + reg_size * i);
+         mem = gen_rtx_MEM (reg_mode, addr);
+         MEM_ALIAS_SET (mem) = rs6000_sr_alias_set;
+
+         emit_move_insn (gen_rtx_REG (reg_mode, regno), mem);
+       }
+    }
   
   /* Restore GPRs.  This is done as a PARALLEL if we are using
      the load-multiple instructions.  */
@@ -6095,6 +6158,14 @@ rs6000_emit_epilogue(sibcall)
        }
     }
 
+  if (current_function_calls_eh_return)
+    {
+      rtx sa = EH_RETURN_STACKADJ_RTX;
+      emit_insn (Pmode == SImode
+                ? gen_addsi3 (sp_reg_rtx, sp_reg_rtx, sa)
+                : gen_adddi3 (sp_reg_rtx, sp_reg_rtx, sa));
+    }
+
   if (!sibcall)
     {
       rtvec p;
index fc70c50..a520b57 100644 (file)
@@ -1180,6 +1180,7 @@ typedef struct rs6000_stack {
   int cr_save_offset;          /* offset to save CR from initial SP */
   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 */
@@ -1569,8 +1570,11 @@ typedef struct rs6000_args
    and frame pointer registers are already be assumed to be used as
    needed.  */
 
-#define        EPILOGUE_USES(REGNO)    \
-  (reload_completed && (REGNO) == LINK_REGISTER_REGNUM)
+#define        EPILOGUE_USES(REGNO)                                    \
+  ((reload_completed && (REGNO) == LINK_REGISTER_REGNUM)       \
+   || (current_function_calls_eh_return                                \
+       && TARGET_TOC                                           \
+       && (REGNO) == TOC_REGISTER))
 
 /* This macro generates the assembly code for function exit,
    on machines that need it.  If FUNCTION_EPILOGUE is not defined
@@ -2641,6 +2645,10 @@ do {                                                                     \
 #define INCOMING_RETURN_ADDR_RTX   gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)
 #define DWARF_FRAME_RETURN_COLUMN  DWARF_FRAME_REGNUM (LINK_REGISTER_REGNUM)
 
+/* Describe how we implement __builtin_eh_return.  */
+#define EH_RETURN_DATA_REGNO(N) ((N) < 4 ? (N) + 3 : INVALID_REGNUM)
+#define EH_RETURN_STACKADJ_RTX  gen_rtx_REG (Pmode, 10)
+
 /* Define results of standard character escape sequences.  */
 #define TARGET_BELL 007
 #define TARGET_BS 010
index 1629d0a..e92cbc8 100644 (file)
@@ -13381,118 +13381,66 @@ operands[2] = GEN_INT (INTVAL (operands[1]) >> 32);
  "TARGET_64BIT"
  "b %z2")
 
-; This is used in compiling the routines __throw and __rethrow.
-; It's a little different to the usual definition...
-
-(define_expand "eh_epilogue"
-  [(use (match_operand 0 "general_operand" "r"))
-   (use (match_operand 1 "general_operand" "r"))
-   (use (match_operand 2 "general_operand" "c"))]
+; This is used in compiling the unwind routines.
+(define_expand "eh_return"
+  [(use (match_operand 0 "general_operand" ""))
+   (use (match_operand 1 "general_operand" ""))]
   ""
   "
 {
-  rtx stack_reg = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
-  rtx insn;
-
-  /* This is required for binary compatibility.  If it's wrong,
-     it probably means that eh_regs() in except.c is broken.  */
-  if (GET_CODE (operands[0]) != REG || REGNO (operands[0]) != 3)
-    abort();
-
-  /* These can be anything that doesn't interfere with the epilogue.  */
-  if (GET_CODE (operands[1]) != REG || REGNO (operands[1]) != 4)
-    {
-      rtx r = gen_rtx_REG (Pmode, 4);
-      emit_move_insn (r, operands[1]);
-      operands[1] = r;
-    }
-
-  if (GET_CODE (operands[2]) != REG 
-       || REGNO (operands[2]) != COUNT_REGISTER_REGNUM)
-    {
-      rtx r = gen_rtx_REG (Pmode, COUNT_REGISTER_REGNUM);
-      emit_move_insn (r, operands[2]);
-      operands[2] = r;
-    }
-
-#if TARGET_AIX
-    rs6000_emit_eh_toc_restore (operands[1]);
-#endif
-
-  emit_insn (gen_eh_reg_restore ());
-
-  if (Pmode == SImode)
-    emit_insn (gen_addsi3 (stack_reg, stack_reg, operands[1]));
-  else
-    emit_insn (gen_adddi3 (stack_reg, stack_reg, operands[1]));
-  
-  if (Pmode == SImode)
-    insn = emit_jump_insn (gen_return_eh_si (operands[2]));
+  if (TARGET_TOC)
+    rs6000_emit_eh_toc_restore (operands[0]);
+  if (TARGET_32BIT)
+    emit_insn (gen_eh_set_lr_si (operands[1]));
   else
-    insn = emit_jump_insn (gen_return_eh_di (operands[2]));
-  emit_barrier_after (insn);
-
+    emit_insn (gen_eh_set_lr_di (operands[1]));
+  emit_move_insn (EH_RETURN_STACKADJ_RTX, operands[0]);
   DONE;
 }")
 
-; We can't expand this before we know which registers are restored,
-; but we do want to expand it before flow2 because that way flow2 can
-; remove the redundant loads of the link register.
-(define_expand "eh_reg_restore"
-  [(unspec_volatile [(const_int 0)] 9)]
-  ""
-  "")
+; We can't expand this before we know where the link register is stored.
+(define_insn "eh_set_lr_si"
+  [(unspec_volatile [(match_operand:SI 0 "register_operand" "r")] 9)
+   (clobber (match_scratch:SI 1 "=&r"))]
+  "TARGET_32BIT"
+  "#")
+
+(define_insn "eh_set_lr_di"
+  [(unspec_volatile [(match_operand:DI 0 "register_operand" "r")] 9)
+   (clobber (match_scratch:DI 1 "=&r"))]
+  "TARGET_64BIT"
+  "#")
 
 (define_split
-  [(unspec_volatile [(const_int 0)] 9)]
-  "reload_completed && TARGET_SCHED_PROLOG"
-  [(unspec_volatile [(const_int 0)] 9)]
+  [(unspec_volatile [(match_operand 0 "register_operand" "")] 9)
+   (clobber (match_scratch 1 ""))]
+  "reload_completed"
+  [(const_int 0)]
   "
 {
-  rs6000_emit_epilogue (TRUE);
-  DONE;
-}")
-
-(define_insn ""
-  [(unspec_volatile [(const_int 0)] 9)]
-  ""
-  "*
-{
-  if (TARGET_SCHED_PROLOG)
-    return \"#\";
-
-  /* This is slightly ugly, but at least we don't have multiple
-     copies of the epilogue-emitting code.  */
-  start_sequence ();
-
-  /* A NOTE_INSN_DELETED is supposed to be at the start
-     and end of the \"toplevel\" insn chain.  */
-  emit_note (0, NOTE_INSN_DELETED);
-  rs6000_emit_epilogue (TRUE);
-  emit_note (0, NOTE_INSN_DELETED);
-
-  if (TARGET_DEBUG_STACK)
-    debug_rtx_list (get_insns(), 100);
-  final (get_insns(), asm_out_file, FALSE, FALSE);
-  end_sequence ();
-  return \"\";
-}")
+  rs6000_stack_t *info = rs6000_stack_info ();
 
+  if (info->lr_save_p)
+    {
+      rtx frame_rtx = stack_pointer_rtx;
+      int sp_offset = 0;
+      rtx tmp;
 
-(define_insn "return_eh_si"
-  [(return)
-   (use (match_operand:SI 0 "register_operand" "lc"))
-   (use (reg:SI 2))
-   (use (reg:SI 3))]
-  "TARGET_32BIT"
-  "b%T0"
-  [(set_attr "type" "jmpreg")])
+      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;
 
-(define_insn "return_eh_di"
-  [(return)
-   (use (match_operand:DI 0 "register_operand" "lc"))
-   (use (reg:DI 2))
-   (use (reg:DI 3))]
-  "TARGET_64BIT"
-  "b%T0"
-  [(set_attr "type" "jmpreg")])
+      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]);
+  DONE;
+}")