Remove RTL EH cleanup code

Jan Hubicka hubicka@ucw.cz
Mon Apr 6 07:03:00 GMT 2009


Hi,
this is updated patch doing EH cleanup before out-of-SSA.  The code for
libgcc/C++ library is same.  Code for libjava grows by 200 bytes (still
it is 30K smaller than mainline) compared to previous version.  I was
looking for reason and it is TERing folding statements into nonthrowing
ones.  It is rare and affects only -fnon-call-exceptions and it is
really a missed optimization case of our gimple optimizers anyway, so I
don't think this is showstopper at all.

Since throwing before out-of-ssa and after RTL expansion does not 100%
match, it is important to not cleanup unreachable blocks before EH
lowering or in rare cases we might end up lowering removed handler.
This does not trigger in bootstrap nor testsuite, but still it is better
to remove delete_unreachable_blocks calls in rest_of_handle_jump that is
artefact of original tailcall lowering anyway (in dark ages we was not
able to do full cfgcleanup at that time).

I did simple checking verifying that throwing stmt exands to RTL where
at least one instruction is throwing too.  There are few very side
cases in testsuite, most common is case where we do something like
  funpointer = (otherfuntype)function;
  funpointer (aaa);
because of type mismatch, on gimple, we never fold it into function(aaa)
and only while after TER function is substituted into call statement.
It remains (otherfuntype)function (aaa);.  While calls.c works hard
enough to find the declaration inside cast, gimple get_call_fndecl does
not and I think it should not either, since what we see is not proper
gimple, just gimplish generic we produce after outof-ssa and probably
want to go away in long term. Surely missed optimizations on those
semi-invalid testcases are not disasterous either.

Bootstrapped/regtested x86_64-linux with and w/o sjlj exceptions. OK?

	* tree-eh.c (cleanup_eh): When not optimizing, do not try EH merging.
	* function.h (rtl_eh): Remove exception_handler_label_map.
	* except.c (ehl_hash, ehl_eq, add_ehl_entry,
	remove_exception_handler_label, for_each_eh_label_1): Remove.
	(rtl_remove_unreachable_regions): Remove.
	(convert_from_eh_region_ranges): Do not remove unreachable regions.
	(find_exception_handler_labels): Don't build the hashtable.
	(maybe_remove_eh_handler): Remove.
	(for_each_eh_label): Rewrite to walk the tree.
	(rest_of_handle_eh): Do not cleanup cfg prior EH construction.
	* except.h (maybe_remove_eh_handler): Remove.
	* passes.c (init_optimization_passes): Schedule second EH cleanup
	after post optimizing cfgcleanup.
	* cfgrtl.c (rtl_delete_block, rtl_merge_blocks,
	cfg_layout_merge_blocks): Do not call maybe_remove_eh_handler.
	* cfgcleanup.c (rest_of_handle_jump): Do not remove unreachable
	blocks.

Index: tree-eh.c
===================================================================
*** tree-eh.c	(revision 145565)
--- tree-eh.c	(working copy)
*************** cleanup_eh (void)
*** 3121,3143 ****
        dump_eh_tree (dump_file, cfun);
      }
  
!   dominance_info_invalidated = false;
!   /* We cannot use FOR_EACH_BB, since the basic blocks may get removed.  */
!   for (i = NUM_FIXED_BLOCKS; i < last_basic_block; i++)
      {
!       bb = BASIC_BLOCK (i);
!       if (bb)
! 	changed |= cleanup_empty_eh (bb);
!     }
!   if (dominance_info_invalidated)
!     {
!       free_dominance_info (CDI_DOMINATORS);
!       free_dominance_info (CDI_POST_DOMINATORS);
!     }
  
!   /* Removing contained cleanup can render MUST_NOT_THROW regions empty.  */
!   if (changed)
!     delete_unreachable_blocks ();
  
    tree_remove_unreachable_handlers ();
    if (dump_file)
--- 3121,3146 ----
        dump_eh_tree (dump_file, cfun);
      }
  
!   if (optimize)
      {
!       dominance_info_invalidated = false;
!       /* We cannot use FOR_EACH_BB, since the basic blocks may get removed.  */
!       for (i = NUM_FIXED_BLOCKS; i < last_basic_block; i++)
! 	{
! 	  bb = BASIC_BLOCK (i);
! 	  if (bb)
! 	    changed |= cleanup_empty_eh (bb);
! 	}
!       if (dominance_info_invalidated)
! 	{
! 	  free_dominance_info (CDI_DOMINATORS);
! 	  free_dominance_info (CDI_POST_DOMINATORS);
! 	}
  
!       /* Removing contained cleanup can render MUST_NOT_THROW regions empty.  */
!       if (changed)
! 	delete_unreachable_blocks ();
!     }
  
    tree_remove_unreachable_handlers ();
    if (dump_file)
Index: function.h
===================================================================
*** function.h	(revision 145565)
--- function.h	(working copy)
*************** struct rtl_eh GTY(())
*** 156,163 ****
    rtx sjlj_fc;
    rtx sjlj_exit_after;
  
-   htab_t GTY ((param_is (struct ehl_map_entry))) exception_handler_label_map;
- 
    VEC(tree,gc) *ttype_data;
    varray_type ehspec_data;
    varray_type action_record_data;
--- 156,161 ----
Index: except.c
===================================================================
*** except.c	(revision 145565)
--- except.c	(working copy)
*************** static void sjlj_emit_function_exit (voi
*** 248,261 ****
  static void sjlj_emit_dispatch_table (rtx, struct sjlj_lp_info *);
  static void sjlj_build_landing_pads (void);
  
- static hashval_t ehl_hash (const void *);
- static int ehl_eq (const void *, const void *);
- static void add_ehl_entry (rtx, struct eh_region *);
- static void remove_exception_handler_label (rtx);
  static void remove_eh_handler (struct eh_region *);
  static void remove_eh_handler_and_replace (struct eh_region *,
  					   struct eh_region *);
- static int for_each_eh_label_1 (void **, void *);
  
  /* The return value of reachable_next_level.  */
  enum reachable_code
--- 248,256 ----
*************** num_eh_regions (void)
*** 894,946 ****
    return cfun->eh->last_region_number + 1;
  }
  
- /* Remove all regions whose labels are not reachable from insns.  */
- 
- static void
- rtl_remove_unreachable_regions (rtx insns)
- {
-   int i, *uid_region_num;
-   sbitmap reachable;
-   struct eh_region *r;
-   rtx insn;
- 
-   uid_region_num = XCNEWVEC (int, get_max_uid ());
-   reachable = sbitmap_alloc (cfun->eh->last_region_number + 1);
-   sbitmap_zero (reachable);
- 
-   for (i = cfun->eh->last_region_number; i > 0; --i)
-     {
-       r = VEC_index (eh_region, cfun->eh->region_array, i);
-       if (!r || r->region_number != i)
- 	continue;
- 
-       if (r->resume)
- 	{
- 	  gcc_assert (!uid_region_num[INSN_UID (r->resume)]);
- 	  uid_region_num[INSN_UID (r->resume)] = i;
- 	}
-       if (r->label)
- 	{
- 	  gcc_assert (!uid_region_num[INSN_UID (r->label)]);
- 	  uid_region_num[INSN_UID (r->label)] = i;
- 	}
-     }
- 
-   for (insn = insns; insn; insn = NEXT_INSN (insn))
-     SET_BIT (reachable, uid_region_num[INSN_UID (insn)]);
- 
-   remove_unreachable_regions (reachable, NULL);
- 
-   sbitmap_free (reachable);
-   free (uid_region_num);
- }
- 
  /* Set up EH labels for RTL.  */
  
  void
  convert_from_eh_region_ranges (void)
  {
-   rtx insns = get_insns ();
    int i, n = cfun->eh->last_region_number;
  
    /* Most of the work is already done at the tree level.  All we need to
--- 889,899 ----
*************** convert_from_eh_region_ranges (void)
*** 955,985 ****
        if (region && region->tree_label)
  	region->label = DECL_RTL_IF_SET (region->tree_label);
      }
- 
-   rtl_remove_unreachable_regions (insns);
- }
- 
- static void
- add_ehl_entry (rtx label, struct eh_region *region)
- {
-   struct ehl_map_entry **slot, *entry;
- 
-   LABEL_PRESERVE_P (label) = 1;
- 
-   entry = GGC_NEW (struct ehl_map_entry);
-   entry->label = label;
-   entry->region = region;
- 
-   slot = (struct ehl_map_entry **)
-     htab_find_slot (crtl->eh.exception_handler_label_map, entry, INSERT);
- 
-   /* Before landing pad creation, each exception handler has its own
-      label.  After landing pad creation, the exception handlers may
-      share landing pads.  This is ok, since maybe_remove_eh_handler
-      only requires the 1-1 mapping before landing pad creation.  */
-   gcc_assert (!*slot || crtl->eh.built_landing_pads);
- 
-   *slot = entry;
  }
  
  void
--- 908,913 ----
*************** find_exception_handler_labels (void)
*** 987,1003 ****
  {
    int i;
  
-   if (crtl->eh.exception_handler_label_map)
-     htab_empty (crtl->eh.exception_handler_label_map);
-   else
-     {
-       /* ??? The expansion factor here (3/2) must be greater than the htab
- 	 occupancy factor (4/3) to avoid unnecessary resizing.  */
-       crtl->eh.exception_handler_label_map
-         = htab_create_ggc (cfun->eh->last_region_number * 3 / 2,
- 			   ehl_hash, ehl_eq, NULL);
-     }
- 
    if (cfun->eh->region_tree == NULL)
      return;
  
--- 915,920 ----
*************** find_exception_handler_labels (void)
*** 1013,1027 ****
  	lab = region->landing_pad;
        else
  	lab = region->label;
- 
-       if (lab)
- 	add_ehl_entry (lab, region);
      }
- 
-   /* For sjlj exceptions, need the return label to remain live until
-      after landing pad generation.  */
-   if (USING_SJLJ_EXCEPTIONS && ! crtl->eh.built_landing_pads)
-     add_ehl_entry (return_label, NULL);
  }
  
  /* Returns true if the current function has exception handling regions.  */
--- 930,936 ----
*************** finish_eh_generation (void)
*** 2386,2435 ****
      }
  }
  
- static hashval_t
- ehl_hash (const void *pentry)
- {
-   const struct ehl_map_entry *const entry
-     = (const struct ehl_map_entry *) pentry;
- 
-   /* 2^32 * ((sqrt(5) - 1) / 2) */
-   const hashval_t scaled_golden_ratio = 0x9e3779b9;
-   return CODE_LABEL_NUMBER (entry->label) * scaled_golden_ratio;
- }
- 
- static int
- ehl_eq (const void *pentry, const void *pdata)
- {
-   const struct ehl_map_entry *const entry
-     = (const struct ehl_map_entry *) pentry;
-   const struct ehl_map_entry *const data
-     = (const struct ehl_map_entry *) pdata;
- 
-   return entry->label == data->label;
- }
- 
  /* This section handles removing dead code for flow.  */
  
- /* Remove LABEL from exception_handler_label_map.  */
- 
- static void
- remove_exception_handler_label (rtx label)
- {
-   struct ehl_map_entry **slot, tmp;
- 
-   /* If exception_handler_label_map was not built yet,
-      there is nothing to do.  */
-   if (crtl->eh.exception_handler_label_map == NULL)
-     return;
- 
-   tmp.label = label;
-   slot = (struct ehl_map_entry **)
-     htab_find_slot (crtl->eh.exception_handler_label_map, &tmp, NO_INSERT);
-   gcc_assert (slot);
- 
-   htab_clear_slot (crtl->eh.exception_handler_label_map, (void **) slot);
- }
- 
  /* Splice REGION from the region tree and replace it by REPLACE etc.  */
  
  static void
--- 2295,2302 ----
*************** remove_eh_handler_and_replace (struct eh
*** 2472,2480 ****
      lab = region->landing_pad;
    else
      lab = region->label;
-   if (lab)
-     remove_exception_handler_label (lab);
- 
    if (outer)
      pp_start = &outer->inner;
    else
--- 2339,2344 ----
*************** remove_eh_handler (struct eh_region *reg
*** 2535,2579 ****
    remove_eh_handler_and_replace (region, region->outer);
  }
  
- /* LABEL heads a basic block that is about to be deleted.  If this
-    label corresponds to an exception region, we may be able to
-    delete the region.  */
- 
- void
- maybe_remove_eh_handler (rtx label)
- {
-   struct ehl_map_entry **slot, tmp;
-   struct eh_region *region;
- 
-   /* ??? After generating landing pads, it's not so simple to determine
-      if the region data is completely unused.  One must examine the
-      landing pad and the post landing pad, and whether an inner try block
-      is referencing the catch handlers directly.  */
-   if (crtl->eh.built_landing_pads)
-     return;
- 
-   tmp.label = label;
-   slot = (struct ehl_map_entry **)
-     htab_find_slot (crtl->eh.exception_handler_label_map, &tmp, NO_INSERT);
-   if (! slot)
-     return;
-   region = (*slot)->region;
-   if (! region)
-     return;
- 
-   /* Flow will want to remove MUST_NOT_THROW regions as unreachable
-      because there is no path to the fallback call to terminate.
-      But the region continues to affect call-site data until there
-      are no more contained calls, which we don't see here.  */
-   if (region->type == ERT_MUST_NOT_THROW)
-     {
-       htab_clear_slot (crtl->eh.exception_handler_label_map, (void **) slot);
-       region->label = NULL_RTX;
-     }
-   else
-     remove_eh_handler (region);
- }
- 
  /* Remove Eh region R that has turned out to have no code in its handler.  */
  
  void
--- 2399,2404 ----
*************** remove_eh_region (int r)
*** 2591,2608 ****
  void
  for_each_eh_label (void (*callback) (rtx))
  {
!   htab_traverse (crtl->eh.exception_handler_label_map, for_each_eh_label_1,
! 		 (void *) &callback);
! }
! 
! static int
! for_each_eh_label_1 (void **pentry, void *data)
! {
!   struct ehl_map_entry *entry = *(struct ehl_map_entry **)pentry;
!   void (*callback) (rtx) = *(void (**) (rtx)) data;
! 
!   (*callback) (entry->label);
!   return 1;
  }
  
  /* Invoke CALLBACK for every exception region in the current function.  */
--- 2416,2429 ----
  void
  for_each_eh_label (void (*callback) (rtx))
  {
!   int i;
!   for (i = 0; i < cfun->eh->last_region_number; i++)
!     {
!       struct eh_region *r = VEC_index (eh_region, cfun->eh->region_array, i);
!       if (r && r->region_number == i && r->label
!           && GET_CODE (r->label) == CODE_LABEL)
! 	(*callback) (r->label);
!     }
  }
  
  /* Invoke CALLBACK for every exception region in the current function.  */
*************** gate_handle_eh (void)
*** 4332,4338 ****
  static unsigned int
  rest_of_handle_eh (void)
  {
-   cleanup_cfg (CLEANUP_NO_INSN_DEL);
    finish_eh_generation ();
    cleanup_cfg (CLEANUP_NO_INSN_DEL);
    return 0;
--- 4153,4158 ----
Index: except.h
===================================================================
*** except.h	(revision 145565)
--- except.h	(working copy)
*************** extern void init_eh (void);
*** 62,68 ****
  extern void init_eh_for_function (void);
  
  extern rtx reachable_handlers (rtx);
- extern void maybe_remove_eh_handler (rtx);
  void remove_eh_region (int);
  
  extern void convert_from_eh_region_ranges (void);
--- 62,67 ----
Index: cfgcleanup.c
===================================================================
*** cfgcleanup.c	(revision 145565)
--- cfgcleanup.c	(working copy)
*************** cleanup_cfg (int mode)
*** 2198,2205 ****
  static unsigned int
  rest_of_handle_jump (void)
  {
-   delete_unreachable_blocks ();
- 
    if (crtl->tail_call_emit)
      fixup_tail_calls ();
    return 0;
--- 2198,2203 ----
Index: passes.c
===================================================================
*** passes.c	(revision 145565)
--- passes.c	(working copy)
*************** init_optimization_passes (void)
*** 706,711 ****
--- 706,712 ----
        NEXT_PASS (pass_uncprop);
        NEXT_PASS (pass_local_pure_const);
      }
+   NEXT_PASS (pass_cleanup_eh);
    NEXT_PASS (pass_del_ssa);
    NEXT_PASS (pass_nrv);
    NEXT_PASS (pass_mark_used_blocks);
Index: cfgrtl.c
===================================================================
*** cfgrtl.c	(revision 145565)
--- cfgrtl.c	(working copy)
*************** rtl_delete_block (basic_block b)
*** 379,386 ****
       label for an exception handler which can't be reached.  We need
       to remove the label from the exception_handler_label list.  */
    insn = BB_HEAD (b);
-   if (LABEL_P (insn))
-     maybe_remove_eh_handler (insn);
  
    end = get_last_bb_insn (b);
  
--- 379,384 ----
*************** rtl_merge_blocks (basic_block a, basic_b
*** 572,581 ****
    /* If there was a CODE_LABEL beginning B, delete it.  */
    if (LABEL_P (b_head))
      {
-       /* This might have been an EH label that no longer has incoming
- 	 EH edges.  Update data structures to match.  */
-       maybe_remove_eh_handler (b_head);
- 
        /* Detect basic blocks with nothing but a label.  This can happen
  	 in particular at the end of a function.  */
        if (b_head == b_end)
--- 570,575 ----
*************** cfg_layout_merge_blocks (basic_block a, 
*** 2598,2607 ****
    /* If there was a CODE_LABEL beginning B, delete it.  */
    if (LABEL_P (BB_HEAD (b)))
      {
-       /* This might have been an EH label that no longer has incoming
- 	 EH edges.  Update data structures to match.  */
-       maybe_remove_eh_handler (BB_HEAD (b));
- 
        delete_insn (BB_HEAD (b));
      }
  
--- 2592,2597 ----



More information about the Gcc-patches mailing list