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]

PR tree-optimization/40585


Hi,
this is mainline fix for th PR 40485.  The (properetary) testcase caused
profiling code to mistakely increase frequency of EH edge that in turn
caused tracer to duplicate RESX instruction that hit limitation of RTL
expansion that limits us to 1 RESX instruction per region.

This patch simply makes expansion to produce list of RESX instructions
if there are multiple. THe testcase no longer reproduce on mainline, but
I hope this is all quite obvious.

Bootstrapped/regtested x86_64-linux, OK?

	PR tree-optimization/40585
	* except.c (expand_resx_expr): When there already is resume
	instruction, produce linked list.
	(build_post_landing_pads): Assert that resume is empty.
	(connect_post_landing_pads): Handle resume lists.
	(dump_eh_tree): Dump resume list.

Index: except.c
===================================================================
*** except.c	(revision 149499)
--- except.c	(working copy)
*************** void
*** 440,451 ****
  expand_resx_expr (tree exp)
  {
    int region_nr = TREE_INT_CST_LOW (TREE_OPERAND (exp, 0));
    struct eh_region_d *reg = VEC_index (eh_region,
  				       cfun->eh->region_array, region_nr);
  
-   gcc_assert (!reg->resume);
    do_pending_stack_adjust ();
!   reg->resume = emit_jump_insn (gen_rtx_RESX (VOIDmode, region_nr));
    emit_barrier ();
  }
  
--- 440,455 ----
  expand_resx_expr (tree exp)
  {
    int region_nr = TREE_INT_CST_LOW (TREE_OPERAND (exp, 0));
+   rtx insn;
    struct eh_region_d *reg = VEC_index (eh_region,
  				       cfun->eh->region_array, region_nr);
  
    do_pending_stack_adjust ();
!   insn = emit_jump_insn (gen_rtx_RESX (VOIDmode, region_nr));
!   if (reg->resume)
!     reg->resume = gen_rtx_INSN_LIST (VOIDmode, insn, reg->resume);
!   else
!     reg->resume = insn;
    emit_barrier ();
  }
  
*************** build_post_landing_pads (void)
*** 2012,2017 ****
--- 2016,2022 ----
  	  /* We delay the generation of the _Unwind_Resume until we generate
  	     landing pads.  We emit a marker here so as to get good control
  	     flow data in the meantime.  */
+ 	  gcc_assert (!region->resume);
  	  region->resume
  	    = emit_jump_insn (gen_rtx_RESX (VOIDmode, region->region_number));
  	  emit_barrier ();
*************** build_post_landing_pads (void)
*** 2040,2045 ****
--- 2045,2051 ----
  	  /* We delay the generation of the _Unwind_Resume until we generate
  	     landing pads.  We emit a marker here so as to get good control
  	     flow data in the meantime.  */
+ 	  gcc_assert (!region->resume);
  	  region->resume
  	    = emit_jump_insn (gen_rtx_RESX (VOIDmode, region->region_number));
  	  emit_barrier ();
*************** connect_post_landing_pads (void)
*** 2080,2085 ****
--- 2086,2092 ----
        struct eh_region_d *outer;
        rtx seq;
        rtx barrier;
+       rtx resume_list;
  
        region = VEC_index (eh_region, cfun->eh->region_array, i);
        /* Mind we don't process a region more than once.  */
*************** connect_post_landing_pads (void)
*** 2088,2094 ****
  
        /* If there is no RESX, or it has been deleted by flow, there's
  	 nothing to fix up.  */
!       if (! region->resume || INSN_DELETED_P (region->resume))
  	continue;
  
        /* Search for another landing pad in this function.  */
--- 2095,2101 ----
  
        /* If there is no RESX, or it has been deleted by flow, there's
  	 nothing to fix up.  */
!       if (! region->resume)
  	continue;
  
        /* Search for another landing pad in this function.  */
*************** connect_post_landing_pads (void)
*** 2096,2141 ****
  	if (outer->post_landing_pad)
  	  break;
  
!       start_sequence ();
  
!       if (outer)
! 	{
! 	  edge e;
! 	  basic_block src, dest;
  
! 	  emit_jump (outer->post_landing_pad);
! 	  src = BLOCK_FOR_INSN (region->resume);
! 	  dest = BLOCK_FOR_INSN (outer->post_landing_pad);
! 	  while (EDGE_COUNT (src->succs) > 0)
! 	    remove_edge (EDGE_SUCC (src, 0));
! 	  e = make_edge (src, dest, 0);
! 	  e->probability = REG_BR_PROB_BASE;
! 	  e->count = src->count;
! 	}
!       else
! 	{
! 	  emit_library_call (unwind_resume_libfunc, LCT_THROW,
! 			     VOIDmode, 1, crtl->eh.exc_ptr, ptr_mode);
  
! 	  /* What we just emitted was a throwing libcall, so it got a
! 	     barrier automatically added after it.  If the last insn in
! 	     the libcall sequence isn't the barrier, it's because the
! 	     target emits multiple insns for a call, and there are insns
! 	     after the actual call insn (which are redundant and would be
! 	     optimized away).  The barrier is inserted exactly after the
! 	     call insn, so let's go get that and delete the insns after
! 	     it, because below we need the barrier to be the last insn in
! 	     the sequence.  */
! 	  delete_insns_since (NEXT_INSN (last_call_insn ()));
! 	}
  
!       seq = get_insns ();
!       end_sequence ();
!       barrier = emit_insn_before (seq, region->resume);
!       /* Avoid duplicate barrier.  */
!       gcc_assert (BARRIER_P (barrier));
!       delete_insn (barrier);
!       delete_insn (region->resume);
  
        /* ??? From tree-ssa we can wind up with catch regions whose
  	 label is not instantiated, but whose resx is present.  Now
--- 2103,2157 ----
  	if (outer->post_landing_pad)
  	  break;
  
!       for (resume_list = region->resume; resume_list;
!       	   resume_list = (GET_CODE (resume_list) == INSN_LIST
! 			  ? XEXP (resume_list, 1) : NULL_RTX))
! 	{
! 	  rtx resume = (GET_CODE (resume_list) == INSN_LIST
! 			? XEXP (resume_list, 0) : resume_list);
!           if (INSN_DELETED_P (resume))
! 	    continue;
! 	  start_sequence ();
  
! 	  if (outer)
! 	    {
! 	      edge e;
! 	      basic_block src, dest;
  
! 	      emit_jump (outer->post_landing_pad);
! 	      src = BLOCK_FOR_INSN (resume);
! 	      dest = BLOCK_FOR_INSN (outer->post_landing_pad);
! 	      while (EDGE_COUNT (src->succs) > 0)
! 		remove_edge (EDGE_SUCC (src, 0));
! 	      e = make_edge (src, dest, 0);
! 	      e->probability = REG_BR_PROB_BASE;
! 	      e->count = src->count;
! 	    }
! 	  else
! 	    {
! 	      emit_library_call (unwind_resume_libfunc, LCT_THROW,
! 				 VOIDmode, 1, crtl->eh.exc_ptr, ptr_mode);
  
! 	      /* What we just emitted was a throwing libcall, so it got a
! 		 barrier automatically added after it.  If the last insn in
! 		 the libcall sequence isn't the barrier, it's because the
! 		 target emits multiple insns for a call, and there are insns
! 		 after the actual call insn (which are redundant and would be
! 		 optimized away).  The barrier is inserted exactly after the
! 		 call insn, so let's go get that and delete the insns after
! 		 it, because below we need the barrier to be the last insn in
! 		 the sequence.  */
! 	      delete_insns_since (NEXT_INSN (last_call_insn ()));
! 	    }
  
! 	  seq = get_insns ();
! 	  end_sequence ();
! 	  barrier = emit_insn_before (seq, resume);
! 	  /* Avoid duplicate barrier.  */
! 	  gcc_assert (BARRIER_P (barrier));
! 	  delete_insn (barrier);
! 	  delete_insn (resume);
! 	}
  
        /* ??? From tree-ssa we can wind up with catch regions whose
  	 label is not instantiated, but whose resx is present.  Now
*************** dump_eh_tree (FILE * out, struct functio
*** 4419,4424 ****
--- 4435,4449 ----
  	}
        if (i->resume)
  	{
+ 	  rtx resume_list = i->resume;
+           fprintf (out, " resume:");
+ 	  while (GET_CODE (resume_list) == INSN_LIST)
+ 	    {
+ 	      fprintf (out, "%i,", INSN_UID (XEXP (resume_list, 0)));
+ 	      if (NOTE_P (XEXP (resume_list, 0)))
+ 		fprintf (out, " (deleted)");
+ 	      resume_list = XEXP (resume_list, 1);
+ 	    }
            fprintf (out, " resume:%i", INSN_UID (i->resume));
  	  if (NOTE_P (i->resume))
  	    fprintf (out, " (deleted)");


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