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]

dwarf2 eh for alpha, mark 2


Rather than do objectionable things with return addresses, as
with the previous patch, this one streamlines the exception
handling mechanism itself.

The Idea here is rather than manipulate things piecemeal, trying
to modify return register save slots and generating stubs, we
simply arrange to communicate directly with the epilogue code
so that we just DTRT in the first place.

A second part of the patch has to do with how we find registers in
libgcc2.c.  I can't figure out how what we have ever worked on
anything except Sparc.  I see that Irix defaults to sjlj eh, but
not other MIPSen, so I must presume it does.  But for the Alpha I
found it consistently looking one frame too far back.

Anyway, the following was tested on Alpha, Sparc, and x86.  If it
is acceptable, I'll see about updating the epilogue code for the
other targets.


r~
	* tree.h (BUILT_IN_CALLER_RETURN_ADDRESS): Unused.  Kill it.
	(BUILT_IN_SET_RETURN_ADDR_REG, BUILT_IN_EH_STUB_OLD): Kill.
	(BUILT_IN_EH_STUB, BUILT_IN_SET_EH_REGS): Kill.
	(BUILT_IN_EH_RETURN): New.
	* c-decl.c (init_decl_processing): Remove definitions for dead
	EH builtins.  Add __builtin_eh_return.
	* expr.c (expand_builtin): Likewise.
	* except.c (eh_return_context): New variable.
	(eh_return_stack_pointer, eh_return_handler): New variables.
	(init_eh_for_function): Initialize them.
	(expand_builtin_set_return_addr_reg): Kill.
	(expand_builtin_eh_stub_old): Kill.
	(expand_builtin_eh_stub): Kill.
	(expand_builtin_set_eh_regs): Kill.
	(eh_regs): Grab a third register as well.
	(expand_builtin_eh_return, expand_eh_return): New.
	* except.h: Update protos for functions added and removed above.
	* function.c (expand_function_end): Call expand_eh_return
	immediately before the return insn.

	* libgcc2.c (in_reg_window): For REG_SAVED_REG, check that the
	register number is one that would be in the previous window.
	Provide a dummy definition for non-windowed targets.
	(get_reg_addr): New function.
	(get_reg, put_reg, copy_reg): Use it.
	(__throw): Rely on in_reg_window, not INCOMING_REGNO.  Kill stub
	generating code and use __builtin_eh_return.

	* alpha.c (alpha_eh_epilogue_sp): New variable.
	(alpha_init_expanders): Initialize it.
	(alpha_expand_epilogue): Use it.
	* alpha.h: Declare it.
	* alpha.md (eh_epilogue): New.

Index: gcc/c-decl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/c-decl.c,v
retrieving revision 1.43
diff -c -p -d -r1.43 c-decl.c
*** c-decl.c	1998/08/24 02:08:34	1.43
--- c-decl.c	1998/09/09 06:47:00
*************** init_decl_processing ()
*** 3302,3325 ****
  		    BUILT_IN_FROB_RETURN_ADDR, NULL_PTR);
    builtin_function ("__builtin_extract_return_addr", ptr_ftype_ptr,
  		    BUILT_IN_EXTRACT_RETURN_ADDR, NULL_PTR);
-   builtin_function ("__builtin_set_return_addr_reg",
- 		    build_function_type (void_type_node, 
- 					 tree_cons (NULL_TREE,
- 						    ptr_type_node,
- 						    endlink)),
- 		    BUILT_IN_SET_RETURN_ADDR_REG, NULL_PTR);
-   builtin_function ("__builtin_eh_stub_old", ptr_ftype_void,
- 		    BUILT_IN_EH_STUB_OLD, NULL_PTR);
-   builtin_function ("__builtin_eh_stub", ptr_ftype_void,
- 		    BUILT_IN_EH_STUB, NULL_PTR);
    builtin_function
!     ("__builtin_set_eh_regs",
       build_function_type (void_type_node,
  			  tree_cons (NULL_TREE, ptr_type_node,
  				     tree_cons (NULL_TREE,
! 						type_for_mode (ptr_mode, 0),
! 						endlink))),
!      BUILT_IN_SET_EH_REGS, NULL_PTR);
  
    builtin_function ("__builtin_alloca",
  		    build_function_type (ptr_type_node,
--- 3302,3317 ----
  		    BUILT_IN_FROB_RETURN_ADDR, NULL_PTR);
    builtin_function ("__builtin_extract_return_addr", ptr_ftype_ptr,
  		    BUILT_IN_EXTRACT_RETURN_ADDR, NULL_PTR);
    builtin_function
!     ("__builtin_eh_return",
       build_function_type (void_type_node,
  			  tree_cons (NULL_TREE, ptr_type_node,
  				     tree_cons (NULL_TREE,
! 						ptr_type_node,
! 					        tree_cons (NULL_TREE,
! 							   ptr_type_node,
! 							   endlink)))),
!      BUILT_IN_EH_RETURN, NULL_PTR);
  
    builtin_function ("__builtin_alloca",
  		    build_function_type (ptr_type_node,
Index: gcc/except.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/except.c,v
retrieving revision 1.62
diff -c -p -d -r1.62 except.c
*** except.c	1998/08/17 09:08:26	1.62
--- except.c	1998/09/09 06:47:00
*************** struct label_node *outer_context_label_s
*** 490,495 ****
--- 490,504 ----
  
  struct label_node *false_label_stack = NULL;
  
+ /* Pseudos used to hold exception return data in the interim between
+    __builtin_eh_return and the end of the function.  */
+ 
+ static rtx eh_return_context;
+ static rtx eh_return_stack_pointer;
+ static rtx eh_return_handler;
+ 
+ /* Prototypes for local functions.  */
+ 
  static void push_eh_entry	PROTO((struct eh_stack *));
  static struct eh_entry * pop_eh_entry		PROTO((struct eh_stack *));
  static void enqueue_eh_entry	PROTO((struct eh_queue *, struct eh_entry *));
*************** static void expand_rethrow	PROTO((rtx));
*** 501,513 ****
  static void output_exception_table_entry	PROTO((FILE *, int));
  static int can_throw		PROTO((rtx));
  static rtx scan_region		PROTO((rtx, int, int *));
! static void eh_regs		PROTO((rtx *, rtx *, int));
  static void set_insn_eh_region	PROTO((rtx *, int));
  #ifdef DONT_USE_BUILTIN_SETJMP
  static void jumpif_rtx		PROTO((rtx, rtx));
  #endif
  
- 
  rtx expand_builtin_return_addr	PROTO((enum built_in_function, int, rtx));
  
  /* Various support routines to manipulate the various data structures
--- 510,521 ----
  static void output_exception_table_entry	PROTO((FILE *, int));
  static int can_throw		PROTO((rtx));
  static rtx scan_region		PROTO((rtx, int, int *));
! static void eh_regs		PROTO((rtx *, rtx *, rtx *, int));
  static void set_insn_eh_region	PROTO((rtx *, int));
  #ifdef DONT_USE_BUILTIN_SETJMP
  static void jumpif_rtx		PROTO((rtx, rtx));
  #endif
  
  rtx expand_builtin_return_addr	PROTO((enum built_in_function, int, rtx));
  
  /* Various support routines to manipulate the various data structures
*************** init_eh_for_function ()
*** 2148,2153 ****
--- 2156,2164 ----
    caught_return_label_stack = 0;
    protect_list = NULL_TREE;
    current_function_ehc = NULL_RTX;
+   eh_return_context = NULL_RTX;
+   eh_return_stack_pointer = NULL_RTX;
+   eh_return_handler = NULL_RTX;
  }
  
  /* Save some of the per-function EH info into the save area denoted by
*************** expand_builtin_frob_return_addr (addr_tr
*** 2403,2483 ****
  #endif
    return addr;
  }
- 
- /* Given an actual address in addr_tree, set the return address register up
-    so the epilogue will return to that address.  If the return address is
-    not in a register, do nothing.  */
- 
- void
- expand_builtin_set_return_addr_reg (addr_tree)
-      tree addr_tree;
- {
-   rtx tmp;
-   rtx ra = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
- 				       0, hard_frame_pointer_rtx);
  
!   if (GET_CODE (ra) != REG || REGNO (ra) >= FIRST_PSEUDO_REGISTER)
!     return;
  
!   tmp = force_operand (expand_builtin_frob_return_addr (addr_tree), ra);
!   if (tmp != ra)
!     emit_move_insn (ra, tmp);
! }
  
! /* Choose two registers for communication between the main body of
!    __throw and the stub for adjusting the stack pointer.  The first register
!    is used to pass the address of the exception handler; the second register
!    is used to pass the stack pointer offset.
  
!    For register 1 we use the return value register for a void *.
!    For register 2 we use the static chain register if it exists and is
!      different from register 1, otherwise some arbitrary call-clobbered
!      register.  */
  
  static void
! eh_regs (r1, r2, outgoing)
!      rtx *r1, *r2;
       int outgoing;
  {
!   rtx reg1, reg2;
  
  #ifdef FUNCTION_OUTGOING_VALUE
    if (outgoing)
!     reg1 = FUNCTION_OUTGOING_VALUE (build_pointer_type (void_type_node),
! 				    current_function_decl);
    else
  #endif
!     reg1 = FUNCTION_VALUE (build_pointer_type (void_type_node),
! 			   current_function_decl);
  
  #ifdef STATIC_CHAIN_REGNUM
    if (outgoing)
!     reg2 = static_chain_incoming_rtx;
    else
!     reg2 = static_chain_rtx;
!   if (REGNO (reg2) == REGNO (reg1))
  #endif /* STATIC_CHAIN_REGNUM */
!     reg2 = NULL_RTX;
  
!   if (reg2 == NULL_RTX)
      {
-       int i;
        for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
! 	if (call_used_regs[i] && ! fixed_regs[i] && i != REGNO (reg1))
! 	  {
! 	    reg2 = gen_rtx_REG (Pmode, i);
! 	    break;
! 	  }
  
!       if (reg2 == NULL_RTX)
! 	abort ();
      }
  
!   *r1 = reg1;
!   *r2 = reg2;
! }
  
  
  /* Retrieve the register which contains the pointer to the eh_context
     structure set the __throw. */
  
--- 2414,2487 ----
  #endif
    return addr;
  }
  
! /* Choose three registers for communication between the main body of
!    __throw and the epilogue (or eh stub) and the exception handler. 
!    We must do this with hard registers because the epilogue itself
!    will be generated after reload, at which point we may not reference
!    pseudos at all.
  
!    The first passes the exception context to the handler.  For this
!    we use the return value register for a void*.
  
!    The second holds the stack pointer value to be restored.  For
!    this we use the static chain register if it exists and is different
!    from the previous, otherwise some arbitrary call-clobbered register.
  
!    The third holds the address of the handler itself.  Here we use
!    some arbitrary call-clobbered register.  */
  
  static void
! eh_regs (pcontext, psp, pra, outgoing)
!      rtx *pcontext, *psp, *pra;
       int outgoing;
  {
!   rtx rcontext, rsp, rra;
!   int i;
  
  #ifdef FUNCTION_OUTGOING_VALUE
    if (outgoing)
!     rcontext = FUNCTION_OUTGOING_VALUE (build_pointer_type (void_type_node),
! 				        current_function_decl);
    else
  #endif
!     rcontext = FUNCTION_VALUE (build_pointer_type (void_type_node),
! 			       current_function_decl);
  
  #ifdef STATIC_CHAIN_REGNUM
    if (outgoing)
!     rsp = static_chain_incoming_rtx;
    else
!     rsp = static_chain_rtx;
!   if (REGNO (rsp) == REGNO (rcontext))
  #endif /* STATIC_CHAIN_REGNUM */
!     rsp = NULL_RTX;
  
!   if (rsp == NULL_RTX)
      {
        for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
! 	if (call_used_regs[i] && ! fixed_regs[i] && i != REGNO (rcontext))
! 	  break;
!       if (i == FIRST_PSEUDO_REGISTER)
! 	abort();
  
!       rsp = gen_rtx_REG (Pmode, i);
      }
  
!   for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
!     if (call_used_regs[i] && ! fixed_regs[i]
! 	&& i != REGNO (rcontext) && i != REGNO (rsp))
!       break;
!   if (i == FIRST_PSEUDO_REGISTER)
!     abort();
  
+   rra = gen_rtx_REG (Pmode, i);
  
+   *pcontext = rcontext;
+   *psp = rsp;
+   *pra = rra;
+ }
+ 
  /* Retrieve the register which contains the pointer to the eh_context
     structure set the __throw. */
  
*************** get_reg_for_handler ()
*** 2489,2568 ****
  			   current_function_decl);
    return reg1;
  }
- 
  
! /* Emit inside of __throw a stub which adjusts the stack pointer and jumps
!    to the exception handler.  __throw will set up the necessary values
!    and then return to the stub.  */
  
! rtx
! expand_builtin_eh_stub_old ()
  {
!   rtx stub_start = gen_label_rtx ();
!   rtx after_stub = gen_label_rtx ();
!   rtx handler, offset;
! 
!   emit_jump (after_stub);
!   emit_label (stub_start);
! 
!   eh_regs (&handler, &offset, 0);
  
!   adjust_stack (offset);
!   emit_indirect_jump (handler);
!   emit_label (after_stub);
!   return gen_rtx_LABEL_REF (Pmode, stub_start);
  }
  
! rtx
! expand_builtin_eh_stub ()
  {
!   rtx stub_start = gen_label_rtx ();
!   rtx after_stub = gen_label_rtx ();
!   rtx handler, offset;
!   rtx temp;
! 
!   emit_jump (after_stub);
!   emit_label (stub_start);
  
!   eh_regs (&handler, &offset, 0);
  
!   adjust_stack (offset);
  
!   /* Handler is in fact a pointer to the _eh_context structure, we need 
!      to pick out the handler field (first element), and jump to there, 
!      leaving the pointer to _eh_conext in the same hardware register. */
  
!   temp = gen_rtx_MEM (Pmode, handler);
!   MEM_IN_STRUCT_P (temp) = 1;
!   RTX_UNCHANGING_P (temp) = 1;
!   emit_move_insn (offset, temp);
!   emit_insn (gen_rtx_USE (Pmode, handler));
  
!   emit_indirect_jump (offset);
!    
!   emit_label (after_stub);
!   return gen_rtx_LABEL_REF (Pmode, stub_start);
! }
  
! /* Set up the registers for passing the handler address and stack offset
!    to the stub above.  */
  
! void
! expand_builtin_set_eh_regs (handler, offset)
!      tree handler, offset;
! {
!   rtx reg1, reg2;
  
!   eh_regs (&reg1, &reg2, 1);
  
!   store_expr (offset,  reg2, 0);
!   store_expr (handler, reg1, 0);
  
!   /* These will be used by the stub.  */
    emit_insn (gen_rtx_USE (VOIDmode, reg1));
    emit_insn (gen_rtx_USE (VOIDmode, reg2));
! }
  
  
  
  /* This contains the code required to verify whether arbitrary instructions
--- 2493,2578 ----
  			   current_function_decl);
    return reg1;
  }
  
! /* Set up the epilogue with the magic bits we'll need to return to the
!    exception handler.  */
  
! void
! expand_builtin_eh_return (context, stack, handler)
!     tree context, stack, handler;
  {
!   if (eh_return_context)
!     error("Duplicate call to __builtin_eh_return");
  
!   eh_return_context
!     = copy_to_reg (expand_expr (context, NULL_RTX, VOIDmode, 0));
!   eh_return_stack_pointer
!     = copy_to_reg (expand_expr (stack, NULL_RTX, VOIDmode, 0));
!   eh_return_handler
!     = copy_to_reg (expand_expr (handler, NULL_RTX, VOIDmode, 0));
  }
  
! void
! expand_eh_return ()
  {
!   rtx reg1, reg2, reg3;
!   rtx stub_start, after_stub;
!   rtx ra, tmp;
  
!   if (!eh_return_context)
!     return;
  
!   eh_regs (&reg1, &reg2, &reg3, 1);
!   emit_move_insn (reg1, eh_return_context);
!   emit_move_insn (reg2, eh_return_stack_pointer);
!   emit_move_insn (reg3, eh_return_handler);
  
!   /* Talk directly to the target's epilogue code when possible.  */
  
! #ifdef HAVE_eh_epilogue
!   if (HAVE_eh_epilogue)
!     {
!       emit_insn (gen_eh_epilogue (reg1, reg2, reg3));
!       return;
!     }
! #endif
  
!   /* Otherwise, use the same stub technique we had before.  */
  
!   stub_start = gen_label_rtx ();
!   after_stub = gen_label_rtx ();
  
!   /* Set the return address to the stub label.  */
  
!   ra = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
! 				   0, hard_frame_pointer_rtx);
!   if (GET_CODE (ra) == REG && REGNO (ra) >= FIRST_PSEUDO_REGISTER)
!     abort();
  
!   tmp = memory_address (Pmode, gen_rtx_LABEL_REF (Pmode, stub_start)); 
! #ifdef RETURN_ADDR_OFFSET
!   tmp = plus_constant (tmp, -RETURN_ADDR_OFFSET);
! #endif
!   emit_move_insn (ra, tmp);
  
!   /* Indicate that the registers are in fact used.  */
    emit_insn (gen_rtx_USE (VOIDmode, reg1));
    emit_insn (gen_rtx_USE (VOIDmode, reg2));
!   emit_insn (gen_rtx_USE (VOIDmode, reg3));
!   if (GET_CODE (ra) == REG)
!     emit_insn (gen_rtx_USE (VOIDmode, ra));
! 
!   /* Generate the stub.  */
! 
!   emit_jump (after_stub);
!   emit_label (stub_start);
  
+   eh_regs (&reg1, &reg2, &reg3, 0);
+   emit_move_insn (stack_pointer_rtx, reg2);
+   emit_indirect_jump (reg3);
+ 
+   emit_label (after_stub);
+ }
  
  
  /* This contains the code required to verify whether arbitrary instructions
Index: gcc/except.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/except.h,v
retrieving revision 1.21
diff -c -p -d -r1.21 except.h
*** except.h	1998/08/17 09:08:27	1.21
--- except.h	1998/09/09 06:47:00
*************** extern void expand_fixup_region_end	PROT
*** 363,377 ****
  
  void expand_builtin_unwind_init		PROTO((void));
  rtx expand_builtin_dwarf_fp_regnum	PROTO((void));
- rtx expand_builtin_eh_stub		PROTO((void));
- rtx expand_builtin_eh_stub_old          PROTO((void));
  #ifdef TREE_CODE
  rtx expand_builtin_frob_return_addr	PROTO((tree));
  rtx expand_builtin_extract_return_addr	PROTO((tree));
- void expand_builtin_set_return_addr_reg PROTO((tree));
- void expand_builtin_set_eh_regs		PROTO((tree, tree));
  rtx expand_builtin_dwarf_reg_size	PROTO((tree, rtx));
  #endif
  
  
  /* Checking whether 2 instructions are within the same exception region. */
--- 363,375 ----
  
  void expand_builtin_unwind_init		PROTO((void));
  rtx expand_builtin_dwarf_fp_regnum	PROTO((void));
  #ifdef TREE_CODE
  rtx expand_builtin_frob_return_addr	PROTO((tree));
  rtx expand_builtin_extract_return_addr	PROTO((tree));
  rtx expand_builtin_dwarf_reg_size	PROTO((tree, rtx));
+ void expand_builtin_eh_return		PROTO((tree, tree, tree));
  #endif
+ void expand_eh_return			PROTO((void));
  
  
  /* Checking whether 2 instructions are within the same exception region. */
Index: gcc/expr.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/expr.c,v
retrieving revision 1.95
diff -c -p -d -r1.95 expr.c
*** expr.c	1998/09/08 22:47:54	1.95
--- expr.c	1998/09/09 06:47:01
*************** expand_builtin (exp, target, subtarget, 
*** 9384,9399 ****
        return expand_builtin_frob_return_addr (TREE_VALUE (arglist));
      case BUILT_IN_EXTRACT_RETURN_ADDR:
        return expand_builtin_extract_return_addr (TREE_VALUE (arglist));
!     case BUILT_IN_SET_RETURN_ADDR_REG:
!       expand_builtin_set_return_addr_reg (TREE_VALUE (arglist));
!       return const0_rtx;
!     case BUILT_IN_EH_STUB_OLD:
!       return expand_builtin_eh_stub_old ();
!     case BUILT_IN_EH_STUB:
!       return expand_builtin_eh_stub ();
!     case BUILT_IN_SET_EH_REGS:
!       expand_builtin_set_eh_regs (TREE_VALUE (arglist),
! 				  TREE_VALUE (TREE_CHAIN (arglist)));
        return const0_rtx;
  
      default:			/* just do library call, if unknown builtin */
--- 9384,9393 ----
        return expand_builtin_frob_return_addr (TREE_VALUE (arglist));
      case BUILT_IN_EXTRACT_RETURN_ADDR:
        return expand_builtin_extract_return_addr (TREE_VALUE (arglist));
!     case BUILT_IN_EH_RETURN:
!       expand_builtin_eh_return (TREE_VALUE (arglist),
! 				TREE_VALUE (TREE_CHAIN (arglist)),
! 				TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))));
        return const0_rtx;
  
      default:			/* just do library call, if unknown builtin */
Index: gcc/function.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/function.c,v
retrieving revision 1.39
diff -c -p -d -r1.39 function.c
*** function.c	1998/07/30 10:38:13	1.39
--- function.c	1998/09/09 06:47:01
*************** expand_function_end (filename, line, end
*** 5981,5986 ****
--- 5981,5990 ----
        use_variable (outgoing);
      }
  
+   /* If this is an implementation of __throw, do what's necessary to 
+      communicate between __builtin_eh_return and the epilogue.  */
+   expand_eh_return ();
+ 
    /* Output a return insn if we are using one.
       Otherwise, let the rtl chain end here, to drop through
       into the epilogue.  */
Index: gcc/libgcc2.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/libgcc2.c,v
retrieving revision 1.46
diff -c -p -d -r1.46 libgcc2.c
*** libgcc2.c	1998/07/06 23:52:21	1.46
--- libgcc2.c	1998/09/09 06:47:02
*************** find_exception_handler (void *pc, except
*** 3477,3507 ****
  
  typedef int ptr_type __attribute__ ((mode (pointer)));
  
! /* Get the value of register REG as saved in UDATA, where SUB_UDATA is a
     frame called by UDATA or 0.  */
  
! static void*
! get_reg (unsigned reg, frame_state *udata, frame_state *sub_udata)
  {
    if (udata->saved[reg] == REG_SAVED_OFFSET)
!     return (void *)(ptr_type)
!       *(word_type *)(udata->cfa + udata->reg_or_offset[reg]);
!   else if (udata->saved[reg] == REG_SAVED_REG && sub_udata)
!     return get_reg (udata->reg_or_offset[reg], sub_udata, 0);
    else
      abort ();
  }
  
  /* Overwrite the saved value for register REG in frame UDATA with VAL.  */
  
! static void
  put_reg (unsigned reg, void *val, frame_state *udata)
  {
!   if (udata->saved[reg] == REG_SAVED_OFFSET)
!     *(word_type *)(udata->cfa + udata->reg_or_offset[reg])
!       = (word_type)(ptr_type) val;
!   else
!     abort ();
  }
  
  /* Copy the saved value for register REG from frame UDATA to frame
--- 3477,3547 ----
  
  typedef int ptr_type __attribute__ ((mode (pointer)));
  
! #ifdef INCOMING_REGNO
! /* Is the saved value for register REG in frame UDATA stored in a register
!    window in the previous frame?  */
! 
! /* ??? The Sparc INCOMING_REGNO references TARGET_FLAT.  This allows us
!    to use the macro here.  One wonders, though, that perhaps TARGET_FLAT
!    compiled functions won't work with the frame-unwind stuff here.  
!    Perhaps the entireity of in_reg_window should be conditional on having
!    seen a DW_CFA_GNU_window_save?  */
! #define target_flags 0
! 
! static int
! in_reg_window (int reg, frame_state *udata)
! {
!   if (udata->saved[reg] == REG_SAVED_REG)
!     return INCOMING_REGNO (reg) == reg;
!   if (udata->saved[reg] != REG_SAVED_OFFSET)
!     return 0;
! 
! #ifdef STACK_GROWS_DOWNWARD
!   return udata->reg_or_offset[reg] > 0;
! #else
!   return udata->reg_or_offset[reg] < 0;
! #endif
! }
! #else
! static inline int in_reg_window (int reg, frame_state *udata) { return 0; }
! #endif /* INCOMING_REGNO */
! 
! /* Get the address of register REG as saved in UDATA, where SUB_UDATA is a
     frame called by UDATA or 0.  */
  
! static word_type *
! get_reg_addr (unsigned reg, frame_state *udata, frame_state *sub_udata)
  {
+   while (udata->saved[reg] == REG_SAVED_REG)
+     {
+       reg = udata->reg_or_offset[reg];
+       if (in_reg_window (reg, udata))
+ 	{
+           udata = sub_udata;
+ 	  sub_udata = NULL;
+ 	}
+     }
    if (udata->saved[reg] == REG_SAVED_OFFSET)
!     return (word_type *)(udata->cfa + udata->reg_or_offset[reg]);
    else
      abort ();
  }
  
+ /* Get the value of register REG as saved in UDATA, where SUB_UDATA is a
+    frame called by UDATA or 0.  */
+ 
+ static inline void *
+ get_reg (unsigned reg, frame_state *udata, frame_state *sub_udata)
+ {
+   return (void *)(ptr_type) *get_reg_addr (reg, udata, sub_udata);
+ }
+ 
  /* Overwrite the saved value for register REG in frame UDATA with VAL.  */
  
! static inline void
  put_reg (unsigned reg, void *val, frame_state *udata)
  {
!   *get_reg_addr (reg, udata, NULL) = (word_type)(ptr_type) val;
  }
  
  /* Copy the saved value for register REG from frame UDATA to frame
*************** put_reg (unsigned reg, void *val, frame_
*** 3511,3527 ****
  static void
  copy_reg (unsigned reg, frame_state *udata, frame_state *target_udata)
  {
!   if (udata->saved[reg] == REG_SAVED_OFFSET
!       && target_udata->saved[reg] == REG_SAVED_OFFSET)
!     memcpy (target_udata->cfa + target_udata->reg_or_offset[reg],
! 	    udata->cfa + udata->reg_or_offset[reg],
! 	    __builtin_dwarf_reg_size (reg));
!   else
!     abort ();
  }
  
! /* Retrieve the return address for frame UDATA, where SUB_UDATA is a
!    frame called by UDATA or 0.  */
  
  static inline void *
  get_return_addr (frame_state *udata, frame_state *sub_udata)
--- 3551,3563 ----
  static void
  copy_reg (unsigned reg, frame_state *udata, frame_state *target_udata)
  {
!   word_type *preg = get_reg_addr (reg, udata, NULL);
!   word_type *ptreg = get_reg_addr (reg, target_udata, NULL);
! 
!   memcpy (ptreg, preg, __builtin_dwarf_reg_size (reg));
  }
  
! /* Retrieve the return address for frame UDATA.  */
  
  static inline void *
  get_return_addr (frame_state *udata, frame_state *sub_udata)
*************** next_stack_level (void *pc, frame_state 
*** 3561,3584 ****
    return caller_udata;
  }
  
- #ifdef INCOMING_REGNO
- /* Is the saved value for register REG in frame UDATA stored in a register
-    window in the previous frame?  */
- 
- static int
- in_reg_window (int reg, frame_state *udata)
- {
-   if (udata->saved[reg] != REG_SAVED_OFFSET)
-     return 0;
- 
- #ifdef STACK_GROWS_DOWNWARD
-   return udata->reg_or_offset[reg] > 0;
- #else
-   return udata->reg_or_offset[reg] < 0;
- #endif
- }
- #endif /* INCOMING_REGNO */
- 
  /* We first search for an exception handler, and if we don't find
     it, we call __terminate on the current stack frame so that we may
     use the debugger to walk the stack and understand why no handler
--- 3597,3602 ----
*************** void
*** 3591,3597 ****
  __throw ()
  {
    struct eh_context *eh = (*get_eh_context) ();
!   void *saved_pc, *pc, *handler, *retaddr;
    frame_state ustruct, ustruct2;
    frame_state *udata = &ustruct;
    frame_state *sub_udata = &ustruct2;
--- 3609,3615 ----
  __throw ()
  {
    struct eh_context *eh = (*get_eh_context) ();
!   void *saved_pc, *pc, *handler;
    frame_state ustruct, ustruct2;
    frame_state *udata = &ustruct;
    frame_state *sub_udata = &ustruct2;
*************** label:
*** 3697,3703 ****
  	  for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
  	    if (i != udata->retaddr_column && udata->saved[i])
  	      {
- #ifdef INCOMING_REGNO
  		/* If you modify the saved value of the return address
  		   register on the SPARC, you modify the return address for
  		   your caller's frame.  Don't do that here, as it will
--- 3715,3720 ----
*************** label:
*** 3706,3719 ****
  		    && udata->saved[udata->retaddr_column] == REG_SAVED_REG
  		    && udata->reg_or_offset[udata->retaddr_column] == i)
  		  continue;
- #endif
  		copy_reg (i, udata, my_udata);
  	      }
  
  	  pc = get_return_addr (udata, sub_udata) - 1;
  	}
  
- #ifdef INCOMING_REGNO
        /* But we do need to update the saved return address register from
  	 the last frame we unwind, or the handler frame will have the wrong
  	 return address.  */
--- 3723,3734 ----
*************** label:
*** 3723,3764 ****
  	  if (in_reg_window (i, udata))
  	    copy_reg (i, udata, my_udata);
  	}
- #endif
      }
-   /* udata now refers to the frame called by the handler frame.  */
  
!   /* Emit the stub to adjust sp and jump to the handler.  */
!   if (new_exception_model)
!     retaddr = __builtin_eh_stub ();
!   else
!     retaddr =  __builtin_eh_stub_old ();
! 
!   /* And then set our return address to point to the stub.  */
!   if (my_udata->saved[my_udata->retaddr_column] == REG_SAVED_OFFSET)
!     put_return_addr (retaddr, my_udata);
!   else
!     __builtin_set_return_addr_reg (retaddr);
! 
!   /* Set up the registers we use to communicate with the stub.
!      We check STACK_GROWS_DOWNWARD so the stub can use adjust_stack.  */
! 
!   if (new_exception_model)
!     __builtin_set_eh_regs ((void *)eh,
! #ifdef STACK_GROWS_DOWNWARD
! 			 udata->cfa - my_udata->cfa
! #else
! 			 my_udata->cfa - udata->cfa
! #endif
! 			 + args_size);
!   else
!     __builtin_set_eh_regs (handler,
  
! #ifdef STACK_GROWS_DOWNWARD
! 			 udata->cfa - my_udata->cfa
! #else
! 			 my_udata->cfa - udata->cfa
! #endif
! 			 + args_size);
  
    /* Epilogue:  restore the handler frame's register values and return
       to the stub.  */
--- 3738,3748 ----
  	  if (in_reg_window (i, udata))
  	    copy_reg (i, udata, my_udata);
  	}
      }
  
!   /* Now go!  */
  
!   __builtin_eh_return ((void *)eh, udata->cfa, handler);
  
    /* Epilogue:  restore the handler frame's register values and return
       to the stub.  */
Index: gcc/tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/tree.h,v
retrieving revision 1.51
diff -c -p -d -r1.51 tree.h
*** tree.h	1998/08/21 19:32:16	1.51
--- tree.h	1998/09/09 06:47:02
*************** enum built_in_function
*** 101,107 ****
    BUILT_IN_FRAME_ADDRESS,
    BUILT_IN_RETURN_ADDRESS,
    BUILT_IN_AGGREGATE_INCOMING_ADDRESS,
-   BUILT_IN_CALLER_RETURN_ADDRESS,
    BUILT_IN_APPLY_ARGS,
    BUILT_IN_APPLY,
    BUILT_IN_RETURN,
--- 101,106 ----
*************** enum built_in_function
*** 116,125 ****
    BUILT_IN_DWARF_REG_SIZE,
    BUILT_IN_FROB_RETURN_ADDR,
    BUILT_IN_EXTRACT_RETURN_ADDR,
!   BUILT_IN_SET_RETURN_ADDR_REG,
!   BUILT_IN_EH_STUB_OLD,
!   BUILT_IN_EH_STUB,
!   BUILT_IN_SET_EH_REGS,
  
    /* C++ extensions */
    BUILT_IN_NEW,
--- 115,121 ----
    BUILT_IN_DWARF_REG_SIZE,
    BUILT_IN_FROB_RETURN_ADDR,
    BUILT_IN_EXTRACT_RETURN_ADDR,
!   BUILT_IN_EH_RETURN,
  
    /* C++ extensions */
    BUILT_IN_NEW,
Index: gcc/config/alpha/alpha.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/config/alpha/alpha.c,v
retrieving revision 1.55
diff -c -p -d -r1.55 alpha.c
*** alpha.c	1998/09/05 22:22:01	1.55
--- alpha.c	1998/09/09 06:47:02
*************** char *alpha_mlat_string;	/* -mmemory-lat
*** 79,84 ****
--- 79,88 ----
  rtx alpha_compare_op0, alpha_compare_op1;
  int alpha_compare_fp_p;
  
+ /* Define the information needed to modify the epilogue for EH.  */
+ 
+ rtx alpha_eh_epilogue_sp;
+ 
  /* Non-zero if inside of a function, because the Alpha asm can't
     handle .files inside of functions.  */
  
*************** void
*** 2431,2436 ****
--- 2435,2441 ----
  alpha_init_expanders ()
  {
    alpha_return_addr_rtx = NULL_RTX;
+   alpha_eh_epilogue_sp = NULL_RTX;
  
    /* Arrange to save and restore machine status around nested functions.  */
    save_machine_status = alpha_save_machine_status;
*************** alpha_expand_epilogue ()
*** 3731,3739 ****
  	  
        /* Restore registers in order, excepting a true frame pointer. */
  
!       FRP (emit_move_insn (gen_rtx_REG (DImode, REG_RA),
! 		           gen_rtx_MEM (DImode, plus_constant(sa_reg,
! 							      reg_offset))));
        reg_offset += 8;
        imask &= ~(1L << REG_RA);
  
--- 3738,3750 ----
  	  
        /* Restore registers in order, excepting a true frame pointer. */
  
!       if (! alpha_eh_epilogue_sp)
! 	{
!           FRP (emit_move_insn (gen_rtx_REG (DImode, REG_RA),
! 		               gen_rtx_MEM (DImode,
! 					    plus_constant(sa_reg,
! 							  reg_offset))));
! 	}
        reg_offset += 8;
        imask &= ~(1L << REG_RA);
  
*************** alpha_expand_epilogue ()
*** 3763,3770 ****
  	  }
      }
  
!   if (frame_size)
      {
        /* If the stack size is large, begin computation into a temporary
  	 register so as not to interfere with a potential fp restore,
  	 which must be consecutive with an SP restore.  */
--- 3774,3801 ----
  	  }
      }
  
!   if (alpha_eh_epilogue_sp)
      {
+       /* From now on, things must be in order.  So emit blockages.  */
+ 
+       /* Restore the frame pointer.  */
+       if (fp_is_frame_pointer)
+ 	{
+ 	  emit_insn (gen_blockage ());
+ 	  FRP (emit_move_insn (hard_frame_pointer_rtx,
+ 			       gen_rtx_MEM (DImode,
+ 				            plus_constant(sa_reg, fp_offset))));
+ 	}
+ 
+       /* Humor OSF/1 calling conventions and adjust the stack with 
+ 	 an add instruction.  */
+       emit_insn (gen_blockage ());
+       emit_insn (gen_rtx_SET (VOIDmode, stack_pointer_rtx,
+ 			      gen_rtx_PLUS (Pmode, alpha_eh_epilogue_sp,
+ 					    const0_rtx)));
+     }
+   else if (frame_size)
+     {
        /* If the stack size is large, begin computation into a temporary
  	 register so as not to interfere with a potential fp restore,
  	 which must be consecutive with an SP restore.  */
Index: gcc/config/alpha/alpha.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/config/alpha/alpha.h,v
retrieving revision 1.47
diff -c -p -d -r1.47 alpha.h
*** alpha.h	1998/09/08 22:47:56	1.47
--- alpha.h	1998/09/09 06:47:02
*************** extern struct rtx_def *alpha_builtin_sav
*** 1180,1185 ****
--- 1180,1189 ----
  extern struct rtx_def *alpha_compare_op0, *alpha_compare_op1;
  extern int alpha_compare_fp_p;
  
+ /* Define the information needed to modify the epilogue for EH.  */
+ 
+ extern struct rtx_def *alpha_eh_epilogue_sp;
+ 
  /* Make (or fake) .linkage entry for function call.
     IS_LOCAL is 0 if name is used in call, 1 if name is used in definition.  */
  extern void alpha_need_linkage ();
Index: gcc/config/alpha/alpha.md
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/config/alpha/alpha.md,v
retrieving revision 1.53
diff -c -p -d -r1.53 alpha.md
*** alpha.md	1998/09/05 22:22:04	1.53
--- alpha.md	1998/09/09 06:47:03
***************
*** 5144,5149 ****
--- 5144,5165 ----
    ""
    "alpha_expand_epilogue (); DONE;")
  
+ (define_expand "eh_epilogue"
+   [(use (match_operand:DI 0 "register_operand" "r"))
+    (use (match_operand:DI 1 "register_operand" "r"))
+    (use (match_operand:DI 2 "register_operand" "r"))]
+   "! TARGET_OPEN_VMS"
+   "
+ {
+   alpha_eh_epilogue_sp = operands[1];
+   if (GET_CODE (operands[2]) != REG || REGNO (operands[2]) != 26)
+     {
+       rtx ra = gen_rtx_REG (Pmode, 26);
+       emit_move_insn (ra, operands[2]);
+       operands[2] = ra;
+     }
+ }")
+ 
  (define_expand "builtin_longjmp"
    [(unspec_volatile [(match_operand 0 "register_operand" "r")] 3)]
    "! TARGET_OPEN_VMS && ! TARGET_WINDOWS_NT"

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