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]
Other format: [Raw text]

NOTHROW handling fixes


Hi,
the following check in stmt_could_throw_p:
  else if (is_gimple_call (stmt))
    {
      tree t = gimple_call_fndecl (stmt);

      /* Assume that calls to weak functions may trap.  */
      if (!t || !DECL_P (t) || DECL_WEAK (t))
	return true;

      return (gimple_call_flags (stmt) & ECF_NOTHROW) == 0;
    }
cause us to assume that all C++ inline comdat functions are throwing.  This results
in _a lot_ of redundant EH on tramp3d.

This patch cleans up the stiuation somewhat:

1) gimple_call_fndecl are always safe to trust.  For DECL_WEAK functions explicitly declared
as nothrow, we are still safe to assume nothrow
2) dwarf2out.c can assume NOTHROW even if the function body can be overwritten when emitting
function's EH tables, because the EH tables will be overwritten too.  This is fixed by adding
crtl->nothrow flag that is set even for WEAK (not C++ COMDAT)
3) updated RTL nothorw pas to set crtl->nothrow.  TREE_NOTRHOW is set too, but only
in case function is not overwritable in cgraph sense.  This is same test as we do
for other similar changes (pure/const discovery or inlining, for instance)

Bootstrapped/regtested x86_64-linux both mainline and pretty-ipa.  Comitting to pretty-ipa
OK for mainline?

Honza

	* dwarf2out.c (dwarf2out_begin_prologue): Use crtl->nothrow
	* tree-eh.c (stmt_could_throw_p): Remove check for WEAK decls.
	* function.h (rtl_data): Add nothrow flag.
	* except.c (set_nothrow_function_flags): Use crtl->nothrow;
	set DECL_NOTHROW for AVAILABLE functions.
Index: dwarf2out.c
===================================================================
*** dwarf2out.c	(revision 145121)
--- dwarf2out.c	(working copy)
*************** dwarf2out_begin_prologue (unsigned int l
*** 3232,3238 ****
    fde->dw_fde_end = NULL;
    fde->dw_fde_cfi = NULL;
    fde->funcdef_number = current_function_funcdef_no;
!   fde->nothrow = TREE_NOTHROW (current_function_decl);
    fde->uses_eh_lsda = crtl->uses_eh_lsda;
    fde->all_throwers_are_sibcalls = crtl->all_throwers_are_sibcalls;
    fde->drap_reg = INVALID_REGNUM;
--- 3232,3238 ----
    fde->dw_fde_end = NULL;
    fde->dw_fde_cfi = NULL;
    fde->funcdef_number = current_function_funcdef_no;
!   fde->nothrow = crtl->nothrow;
    fde->uses_eh_lsda = crtl->uses_eh_lsda;
    fde->all_throwers_are_sibcalls = crtl->all_throwers_are_sibcalls;
    fde->drap_reg = INVALID_REGNUM;
Index: tree-eh.c
===================================================================
*** tree-eh.c	(revision 145121)
--- tree-eh.c	(working copy)
*************** stmt_could_throw_p (gimple stmt)
*** 2368,2382 ****
    if (code == GIMPLE_ASSIGN || code == GIMPLE_COND)
      return stmt_could_throw_1_p (stmt);
    else if (is_gimple_call (stmt))
!     {
!       tree t = gimple_call_fndecl (stmt);
! 
!       /* Assume that calls to weak functions may trap.  */
!       if (!t || !DECL_P (t) || DECL_WEAK (t))
! 	return true;
! 
!       return (gimple_call_flags (stmt) & ECF_NOTHROW) == 0;
!     }
    else if (gimple_code (stmt) == GIMPLE_ASM)
      return (gimple_asm_volatile_p (stmt));
    else
--- 2368,2374 ----
    if (code == GIMPLE_ASSIGN || code == GIMPLE_COND)
      return stmt_could_throw_1_p (stmt);
    else if (is_gimple_call (stmt))
!     return (gimple_call_flags (stmt) & ECF_NOTHROW) == 0;
    else if (gimple_code (stmt) == GIMPLE_ASM)
      return (gimple_asm_volatile_p (stmt));
    else
Index: function.h
===================================================================
*** function.h	(revision 145121)
--- function.h	(working copy)
*************** struct rtl_data GTY(())
*** 441,446 ****
--- 441,451 ----
  
    /* True if dbr_schedule has already been called for this function.  */
    bool dbr_scheduled_p;
+ 
+   /* True if current function can not throw.  Unlike TREE_NOTHROW (current_function_decl)
+      it is set even for overwrittable function where currently compiled version of
+      it is nothrow.  */
+   bool nothrow;
  };
  
  #define return_label (crtl->x_return_label)
Index: except.c
===================================================================
*** except.c	(revision 145121)
--- except.c	(working copy)
*************** set_nothrow_function_flags (void)
*** 2823,2835 ****
  {
    rtx insn;
  
!   /* If we don't know that this implementation of the function will
!      actually be used, then we must not set TREE_NOTHROW, since
!      callers must not assume that this function does not throw.  */
!   if (DECL_REPLACEABLE_P (current_function_decl))
!     return 0;
! 
!   TREE_NOTHROW (current_function_decl) = 1;
  
    /* Assume crtl->all_throwers_are_sibcalls until we encounter
       something that can throw an exception.  We specifically exempt
--- 2823,2829 ----
  {
    rtx insn;
  
!   crtl->nothrow = 1;
  
    /* Assume crtl->all_throwers_are_sibcalls until we encounter
       something that can throw an exception.  We specifically exempt
*************** set_nothrow_function_flags (void)
*** 2839,2851 ****
  
    crtl->all_throwers_are_sibcalls = 1;
  
    if (! flag_exceptions)
      return 0;
  
    for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
      if (can_throw_external (insn))
        {
!         TREE_NOTHROW (current_function_decl) = 0;
  
  	if (!CALL_P (insn) || !SIBLING_CALL_P (insn))
  	  {
--- 2833,2851 ----
  
    crtl->all_throwers_are_sibcalls = 1;
  
+   /* If we don't know that this implementation of the function will
+      actually be used, then we must not set TREE_NOTHROW, since
+      callers must not assume that this function does not throw.  */
+   if (TREE_NOTHROW (current_function_decl))
+     return 0;
+ 
    if (! flag_exceptions)
      return 0;
  
    for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
      if (can_throw_external (insn))
        {
!         crtl->nothrow = 0;
  
  	if (!CALL_P (insn) || !SIBLING_CALL_P (insn))
  	  {
*************** set_nothrow_function_flags (void)
*** 2858,2864 ****
         insn = XEXP (insn, 1))
      if (can_throw_external (insn))
        {
!         TREE_NOTHROW (current_function_decl) = 0;
  
  	if (!CALL_P (insn) || !SIBLING_CALL_P (insn))
  	  {
--- 2858,2864 ----
         insn = XEXP (insn, 1))
      if (can_throw_external (insn))
        {
!         crtl->nothrow = 0;
  
  	if (!CALL_P (insn) || !SIBLING_CALL_P (insn))
  	  {
*************** set_nothrow_function_flags (void)
*** 2866,2871 ****
--- 2866,2875 ----
  	    return 0;
  	  }
        }
+   if (crtl->nothrow
+       && (cgraph_function_body_availability (cgraph_node (current_function_decl))
+           >= AVAIL_AVAILABLE))
+     TREE_NOTHROW (current_function_decl) = 1;
    return 0;
  }
  


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