This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

ia64 eh fix


Not quite sure how things were working before, however...

It is necessary that the address we start from correspond 
to the initial register state.  Using the address of a label
no longer has this affect, since it is now allowed to float.
Using __builtin_return_address is much better for multiple
reasons.

Except that it didn't work reliably on ia64, due to having
two different RTL names for the same hard register.  Which
causes sched2 to mess things up.

Fixed thus.



r~



        * libgcc2.c (ia64_throw_helper): Use __builtin_return_address. 
        (__throw): Don't pass the address of a label.

        * config/ia64/ia64.c (ia64_compute_frame_size): Use
        current_function_is_leaf.
        (ia64_expand_prologue): Likewise.  Modify return_address_pointer_rtx
        instead of reg_names[RETURN_ADDRESS_REGNUM].
        (ia64_init_machine_status): Reset return_address_pointer_rtx.
        * config/ia64/ia64.h (RETURN_ADDRESS_POINTER_REGNUM): Rename
        from RETURN_ADDRESS_REGNUM.  Update all uses.
        (RETURN_ADDR_RTX): Use return_address_pointer_rtx; return
        zero instead of null on failure.
        (ELIMINABLE_REGS): Add ra->b0 elimination.
        (CAN_ELIMINATE): Update accordingly.
        (INITIAL_ELIMINATION_OFFSET): Likewise.
        (REGISTER_NAMES): Use an illegal assembler name for
        RETURN_ADDRESS_POINTER_REGNUM.

Index: libgcc2.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/libgcc2.c,v
retrieving revision 1.95
diff -c -p -d -r1.95 libgcc2.c
*** libgcc2.c	2000/06/06 16:38:48	1.95
--- libgcc2.c	2000/06/13 23:25:11
*************** __ia64_personality_v1 (void *pc, old_exc
*** 4043,4054 ****
  }
  
  static void
! ia64_throw_helper (throw_pc, throw_frame, caller, throw_bsp)
!      void *throw_pc;
       ia64_frame_state *throw_frame;
       ia64_frame_state *caller;
       void *throw_bsp;
  {
    unwind_info_ptr *info;
    void *pc, *handler = NULL;
    void *pc_base;
--- 4043,4054 ----
  }
  
  static void
! ia64_throw_helper (throw_frame, caller, throw_bsp)
       ia64_frame_state *throw_frame;
       ia64_frame_state *caller;
       void *throw_bsp;
  {
+   void *throw_pc = __builtin_return_address (0);
    unwind_info_ptr *info;
    void *pc, *handler = NULL;
    void *pc_base;
*************** __throw ()
*** 4146,4152 ****
      __terminate ();
  
    __builtin_unwind_init ();
- label_ia64:
    /* We have to call another routine to actually process the frame 
       information, which will force all of __throw's local registers into
       backing store.  */
--- 4146,4151 ----
*************** label_ia64:
*** 4154,4160 ****
    /* Get the value of ar.bsp while we're here.  */
  
    bsp = __builtin_ia64_bsp ();
!   ia64_throw_helper (&&label_ia64, &my_frame, &originator, bsp);
  
    /* Now we have to fudge the bsp by the amount in our (__throw)
       frame marker, since the return is going to adjust it by that much. */
--- 4153,4159 ----
    /* Get the value of ar.bsp while we're here.  */
  
    bsp = __builtin_ia64_bsp ();
!   ia64_throw_helper (&my_frame, &originator, bsp);
  
    /* Now we have to fudge the bsp by the amount in our (__throw)
       frame marker, since the return is going to adjust it by that much. */
Index: config/ia64/ia64.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/ia64/ia64.c,v
retrieving revision 1.23
diff -c -p -d -r1.23 ia64.c
*** ia64.c	2000/06/13 23:19:50	1.23
--- ia64.c	2000/06/13 23:25:12
*************** ia64_compute_frame_size (size)
*** 607,616 ****
    total_size = IA64_STACK_ALIGN (tmp);
    extra_size = total_size - tmp + 16;
  
!   /* If this is a leaf routine (BR_REG (0) is not live), and if there is no
!      stack space needed for register saves, then don't allocate the 16 byte
!      scratch area.  */
!   if (total_size == 16 && ! regs_ever_live[BR_REG (0)])
      {
        total_size = 0;
        extra_size = 0;
--- 607,615 ----
    total_size = IA64_STACK_ALIGN (tmp);
    extra_size = total_size - tmp + 16;
  
!   /* If this is a leaf routine, and if there is no stack space needed for
!      register saves, then don't allocate the 16 byte scratch area.  */
!   if (total_size == 16 && current_function_is_leaf)
      {
        total_size = 0;
        extra_size = 0;
*************** ia64_expand_prologue ()
*** 812,829 ****
    rtx insn, offset;
    int i, locals, inputs, outputs, rotates;
    int frame_size = ia64_compute_frame_size (get_frame_size ());
-   int leaf_function;
    int epilogue_p;
    edge e;
  
-   /* ??? This seems like a leaf_function_p bug.  It calls get_insns which
-      returns the first insn of the current sequence, not the first insn
-      of the function.  We work around this by pushing to the topmost
-      sequence first.  */
-   push_topmost_sequence ();
-   leaf_function = leaf_function_p ();
-   pop_topmost_sequence ();
- 
    /* If there is no epilogue, then we don't need some prologue insns.  We
       need to avoid emitting the dead prologue insns, because flow will complain
       about them.  */
--- 811,819 ----
*************** ia64_expand_prologue ()
*** 941,947 ****
       locals and outputs are both zero sized.  Since we have already allocated
       two locals for rp and ar.pfs, we check for two locals.  */
    /* Leaf functions can use output registers as call-clobbered temporaries.  */
!   if (locals == 2 && outputs == 0 && leaf_function)
      {
        /* If there is no alloc, but there are input registers used, then we
  	 need a .regstk directive.  */
--- 931,937 ----
       locals and outputs are both zero sized.  Since we have already allocated
       two locals for rp and ar.pfs, we check for two locals.  */
    /* Leaf functions can use output registers as call-clobbered temporaries.  */
!   if (locals == 2 && outputs == 0 && current_function_is_leaf)
      {
        /* If there is no alloc, but there are input registers used, then we
  	 need a .regstk directive.  */
*************** ia64_expand_prologue ()
*** 966,978 ****
        /* Emit a save of BR_REG (0) if we call other functions.
  	 Do this even if this function doesn't return, as EH
           depends on this to be able to unwind the stack.  */
!       if (! leaf_function)
  	{
  	  rtx ia64_rp_reg;
  
  	  ia64_rp_regno = LOC_REG (locals - 2);
- 	  reg_names[RETURN_ADDRESS_REGNUM] = reg_names[ia64_rp_regno];
- 
  	  ia64_rp_reg = gen_rtx_REG (DImode, ia64_rp_regno);
  	  insn = emit_move_insn (ia64_rp_reg, gen_rtx_REG (DImode,
  							   BR_REG (0)));
--- 956,966 ----
        /* Emit a save of BR_REG (0) if we call other functions.
  	 Do this even if this function doesn't return, as EH
           depends on this to be able to unwind the stack.  */
!       if (! current_function_is_leaf)
  	{
  	  rtx ia64_rp_reg;
  
  	  ia64_rp_regno = LOC_REG (locals - 2);
  	  ia64_rp_reg = gen_rtx_REG (DImode, ia64_rp_regno);
  	  insn = emit_move_insn (ia64_rp_reg, gen_rtx_REG (DImode,
  							   BR_REG (0)));
*************** ia64_expand_prologue ()
*** 984,989 ****
--- 972,981 ----
  		 appear dead and will elicit a warning from flow.  */
  	      emit_insn (gen_rtx_USE (VOIDmode, ia64_rp_reg));
  	    }
+ 
+ 	  /* Fix up the return address placeholder.  */
+ 	  if (regs_ever_live[RETURN_ADDRESS_POINTER_REGNUM])
+ 	    XINT (return_address_pointer_rtx, 0) = ia64_rp_regno;
  	}
        else
  	ia64_rp_regno = 0;
*************** ia64_init_machine_status (p)
*** 2113,2118 ****
--- 2105,2113 ----
  {
    p->machine =
      (struct machine_function *) xcalloc (1, sizeof (struct machine_function));
+ 
+   /* Reset from the previous function's potential modifications.  */
+   XINT (return_address_pointer_rtx, 0) = RETURN_ADDRESS_POINTER_REGNUM;
  }
  
  static void
Index: config/ia64/ia64.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/ia64/ia64.h,v
retrieving revision 1.19
diff -c -p -d -r1.19 ia64.h
*** ia64.h	2000/06/13 23:19:50	1.19
--- ia64.h	2000/06/13 23:25:12
*************** while (0)
*** 551,557 ****
  #define GENERAL_REGNO_P(REGNO) \
    (GR_REGNO_P (REGNO)							\
     || (REGNO) == FRAME_POINTER_REGNUM					\
!    || (REGNO) == RETURN_ADDRESS_REGNUM)
  
  #define GR_REG(REGNO) ((REGNO) + 0)
  #define FR_REG(REGNO) ((REGNO) + 128)
--- 551,557 ----
  #define GENERAL_REGNO_P(REGNO) \
    (GR_REGNO_P (REGNO)							\
     || (REGNO) == FRAME_POINTER_REGNUM					\
!    || (REGNO) == RETURN_ADDRESS_POINTER_REGNUM)
  
  #define GR_REG(REGNO) ((REGNO) + 0)
  #define FR_REG(REGNO) ((REGNO) + 128)
*************** while (0)
*** 788,794 ****
    /* Special branch registers.  */					   \
    R_BR (0),								   \
    /* Frame pointer.  Return address.  */				   \
!   FRAME_POINTER_REGNUM, RETURN_ADDRESS_REGNUM,				   \
  }
  
  
--- 788,794 ----
    /* Special branch registers.  */					   \
    R_BR (0),								   \
    /* Frame pointer.  Return address.  */				   \
!   FRAME_POINTER_REGNUM, RETURN_ADDRESS_POINTER_REGNUM,			   \
  }
  
  
*************** enum reg_class
*** 1110,1122 ****
     unwind info, so we don't try to support them.  We would also need to define
     DYNAMIC_CHAIN_ADDRESS and SETUP_FRAME_ADDRESS (for the reg stack flush).  */
  
! /* ??? This only works for non-leaf functions.  In a leaf function, the return
!    address would be in b0 (rp).  */
! 
! #define RETURN_ADDR_RTX(COUNT, FRAMEADDR) \
!   (((COUNT) == 0)							\
!    ? gen_rtx_REG (Pmode, RETURN_ADDRESS_REGNUM)				\
!    : (rtx) 0)
  
  /* A C expression whose value is RTL representing the location of the incoming
     return address at the beginning of any function, before the prologue.  This
--- 1110,1117 ----
     unwind info, so we don't try to support them.  We would also need to define
     DYNAMIC_CHAIN_ADDRESS and SETUP_FRAME_ADDRESS (for the reg stack flush).  */
  
! #define RETURN_ADDR_RTX(COUNT, FRAME) \
!   ((COUNT) == 0 ? return_address_pointer_rtx : const0_rtx)
  
  /* A C expression whose value is RTL representing the location of the incoming
     return address at the beginning of any function, before the prologue.  This
*************** extern int ia64_local_regs;
*** 1177,1186 ****
     in it.  */
  #define ARG_POINTER_REGNUM R_GR(0)
  
! /* The register number for the return address register.  This is modified by
!    ia64_expand_prologue to point to the real return address save register.  */
  
! #define RETURN_ADDRESS_REGNUM 329
  
  /* Register numbers used for passing a function's static chain pointer.  */
  
--- 1172,1183 ----
     in it.  */
  #define ARG_POINTER_REGNUM R_GR(0)
  
! /* The register number for the return address register.  This is not actually
!    a pointer as the name suggests, but that's a name that gen_rtx_REG 
!    already takes care to keep unique.  We modify return_address_pointer_rtx
!    in ia64_expand_prologue to reference the final output regnum.  */
  
! #define RETURN_ADDRESS_POINTER_REGNUM 329
  
  /* Register numbers used for passing a function's static chain pointer.  */
  
*************** extern int ia64_local_regs;
*** 1202,1215 ****
  {									\
    {ARG_POINTER_REGNUM,	 STACK_POINTER_REGNUM},				\
    {ARG_POINTER_REGNUM,	 FRAME_POINTER_REGNUM},				\
!   {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}				\
  }
  
  /* A C expression that returns non-zero if the compiler is allowed to try to
!    replace register number FROM with register number TO.  There are no ia64
!    specific restrictions.  */
  
! #define CAN_ELIMINATE(FROM, TO) 1
  
  /* This macro is similar to `INITIAL_FRAME_POINTER_OFFSET'.  It specifies the
     initial difference between the specified pair of registers.  This macro must
--- 1199,1213 ----
  {									\
    {ARG_POINTER_REGNUM,	 STACK_POINTER_REGNUM},				\
    {ARG_POINTER_REGNUM,	 FRAME_POINTER_REGNUM},				\
!   {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM},				\
!   {RETURN_ADDRESS_POINTER_REGNUM, BR_REG (0)}				\
  }
  
  /* A C expression that returns non-zero if the compiler is allowed to try to
!    replace register number FROM with register number TO.  */
  
! #define CAN_ELIMINATE(FROM, TO) \
!   (TO == BR_REG (0) ? current_function_is_leaf : 1)
  
  /* This macro is similar to `INITIAL_FRAME_POINTER_OFFSET'.  It specifies the
     initial difference between the specified pair of registers.  This macro must
*************** extern int ia64_local_regs;
*** 1238,1243 ****
--- 1236,1243 ----
  	  abort ();							\
  	}								\
      }									\
+   else if ((TO) == BR_REG (0))						\
+     (OFFSET) = 0;							\
    else									\
      abort ();								\
  }
*************** do {									\
*** 2324,2330 ****
    /* Branch registers.  */						\
    "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7",			\
    /* Frame pointer.  Return address.  */				\
!   "fp", "ra"								\
  }
  
  /* If defined, a C initializer for an array of structures containing a name and
--- 2324,2330 ----
    /* Branch registers.  */						\
    "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7",			\
    /* Frame pointer.  Return address.  */				\
!   "sfp", "retaddr"							\
  }
  
  /* If defined, a C initializer for an array of structures containing a name and

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]