[patch] for PR 27291

Zdenek Dvorak rakdver@atrey.karlin.mff.cuni.cz
Thu Apr 27 22:20:00 GMT 2006


Hello,

this ICE is caused by the fact that do_compare_rtx_and_jump may
sometimes be able to fold the condition to the constant (and emits
only unconditional jump then, which confuses doloop), even if we
were previously not able to fold it.

In this particular case, the expression looks like reg + MIN_INT <
MIN_INT.  Simplify_relational will first transform it to reg < 0
(correctnes of this transformation is fairly dubious, but let's say it's
fine), and then fail to do anything more about it, so we do not fold the
condition at all.

In do_compare_rtx_and_jump, the subexpressions are forced to be
operands, thus the left side of the comparison becomes a register,
and simplify_relational will fold reg' < MIN_INT to const0_rtx.

Even if it is possible to somehow persuade simplifier to succeed in this
case directly, it is still safer to make doloop handle this case, which
is what this patch does.

Bootstrapped & regtested on ia64 and ppc64.

Zdenek

	PR rtl-optimization/27291
	* loop-doloop.c (add_test, doloop_modify): Handle the case condition is
	folded to a constant.

Index: loop-doloop.c
===================================================================
*** loop-doloop.c	(revision 113295)
--- loop-doloop.c	(working copy)
*************** cleanup:
*** 223,237 ****
    return result;
  }
  
! /* Adds test of COND jumping to DEST to the end of BB.  */
  
! static void
! add_test (rtx cond, basic_block bb, basic_block dest)
  {
    rtx seq, jump, label;
    enum machine_mode mode;
    rtx op0 = XEXP (cond, 0), op1 = XEXP (cond, 1);
    enum rtx_code code = GET_CODE (cond);
  
    mode = GET_MODE (XEXP (cond, 0));
    if (mode == VOIDmode)
--- 223,241 ----
    return result;
  }
  
! /* Adds test of COND jumping to DEST on edge *E and set *E to the new fallthru
!    edge.  If the condition is always false, do not do anything.  If it is always
!    true, redirect E to DEST and return false.  In all other cases, true is
!    returned.  */
  
! static bool
! add_test (rtx cond, edge *e, basic_block dest)
  {
    rtx seq, jump, label;
    enum machine_mode mode;
    rtx op0 = XEXP (cond, 0), op1 = XEXP (cond, 1);
    enum rtx_code code = GET_CODE (cond);
+   basic_block bb;
  
    mode = GET_MODE (XEXP (cond, 0));
    if (mode == VOIDmode)
*************** add_test (rtx cond, basic_block bb, basi
*** 244,265 ****
    do_compare_rtx_and_jump (op0, op1, code, 0, mode, NULL_RTX, NULL_RTX, label);
  
    jump = get_last_insn ();
!   /* It is possible for the jump to be optimized out.  */
!   if (JUMP_P (jump))
      {
!       JUMP_LABEL (jump) = label;
! 
!        /* The jump is supposed to handle an unlikely special case.  */
!       REG_NOTES (jump)
! 	= gen_rtx_EXPR_LIST (REG_BR_PROB,
! 			     const0_rtx, REG_NOTES (jump));
! 
!       LABEL_NUSES (label)++;
      }
  
    seq = get_insns ();
    end_sequence ();
!   emit_insn_after (seq, BB_END (bb));
  }
  
  /* Modify the loop to use the low-overhead looping insn where LOOP
--- 248,283 ----
    do_compare_rtx_and_jump (op0, op1, code, 0, mode, NULL_RTX, NULL_RTX, label);
  
    jump = get_last_insn ();
!   if (!JUMP_P (jump))
      {
!       /* The condition is always false and the jump was optimized out.  */
!       end_sequence ();
!       return true;
      }
  
    seq = get_insns ();
    end_sequence ();
!   bb = loop_split_edge_with (*e, seq);
!   *e = single_succ_edge (bb);
! 
!   if (any_uncondjump_p (jump))
!     {
!       /* The condition is always true.  */
!       delete_insn (jump);
!       redirect_edge_and_branch_force (*e, dest);
!       return false;
!     }
!       
!   JUMP_LABEL (jump) = label;
! 
!   /* The jump is supposed to handle an unlikely special case.  */
!   REG_NOTES (jump)
! 	  = gen_rtx_EXPR_LIST (REG_BR_PROB,
! 			       const0_rtx, REG_NOTES (jump));
!   LABEL_NUSES (label)++;
! 
!   make_edge (bb, dest, (*e)->flags & ~EDGE_FALLTHRU);
!   return true;
  }
  
  /* Modify the loop to use the low-overhead looping insn where LOOP
*************** doloop_modify (struct loop *loop, struct
*** 277,283 ****
    rtx sequence;
    rtx jump_insn;
    rtx jump_label;
!   int nonneg = 0, irr;
    bool increment_count;
    basic_block loop_end = desc->out_edge->src;
    enum machine_mode mode;
--- 295,301 ----
    rtx sequence;
    rtx jump_insn;
    rtx jump_label;
!   int nonneg = 0;
    bool increment_count;
    basic_block loop_end = desc->out_edge->src;
    enum machine_mode mode;
*************** doloop_modify (struct loop *loop, struct
*** 357,395 ****
  	      = loop_split_edge_with (loop_preheader_edge (loop), NULL_RTX);
        basic_block new_preheader
  	      = loop_split_edge_with (loop_preheader_edge (loop), NULL_RTX);
-       basic_block bb;
        edge te;
-       gcov_type cnt;
  
        /* Expand the condition testing the assumptions and if it does not pass,
  	 reset the count register to 0.  */
!       add_test (XEXP (ass, 0), preheader, set_zero);
!       single_succ_edge (preheader)->flags &= ~EDGE_FALLTHRU;
!       cnt = single_succ_edge (preheader)->count;
!       single_succ_edge (preheader)->probability = 0;
!       single_succ_edge (preheader)->count = 0;
!       irr = single_succ_edge (preheader)->flags & EDGE_IRREDUCIBLE_LOOP;
!       te = make_edge (preheader, new_preheader, EDGE_FALLTHRU | irr);
!       te->probability = REG_BR_PROB_BASE;
!       te->count = cnt;
        set_immediate_dominator (CDI_DOMINATORS, new_preheader, preheader);
  
        set_zero->count = 0;
        set_zero->frequency = 0;
  
!       for (ass = XEXP (ass, 1); ass; ass = XEXP (ass, 1))
  	{
! 	  bb = loop_split_edge_with (te, NULL_RTX);
! 	  te = single_succ_edge (bb);
! 	  add_test (XEXP (ass, 0), bb, set_zero);
! 	  make_edge (bb, set_zero, irr);
  	}
!   
!       start_sequence ();
!       convert_move (counter_reg, noloop, 0);
!       sequence = get_insns ();
!       end_sequence ();
!       emit_insn_after (sequence, BB_END (set_zero));
      }
  
    /* Some targets (eg, C4x) need to initialize special looping
--- 375,431 ----
  	      = loop_split_edge_with (loop_preheader_edge (loop), NULL_RTX);
        basic_block new_preheader
  	      = loop_split_edge_with (loop_preheader_edge (loop), NULL_RTX);
        edge te;
  
        /* Expand the condition testing the assumptions and if it does not pass,
  	 reset the count register to 0.  */
!       redirect_edge_and_branch_force (single_succ_edge (preheader), new_preheader);
        set_immediate_dominator (CDI_DOMINATORS, new_preheader, preheader);
  
        set_zero->count = 0;
        set_zero->frequency = 0;
  
!       te = single_succ_edge (preheader);
!       for (; ass; ass = XEXP (ass, 1))
! 	if (!add_test (XEXP (ass, 0), &te, set_zero))
! 	  break;
! 
!       if (ass)
  	{
! 	  /* We reached a condition that is always true.  This is very hard to
! 	     reproduce (such a loop does not roll, and thus it would most
! 	     likely get optimized out by some of the preceding optimizations).
! 	     In fact, I do not have any testcase for it.  However, it would
! 	     also be very hard to show that it is impossible, so we must
! 	     handle this case.  */
! 	  set_zero->count = preheader->count;
! 	  set_zero->frequency = preheader->frequency;
  	}
!  
!       if (EDGE_COUNT (set_zero->preds) == 0)
! 	{
! 	  /* All the conditions were simplified to false, remove the
! 	     unreachable set_zero block.  */
! 	  remove_bb_from_loops (set_zero);
! 	  delete_basic_block (set_zero);
! 	}
!       else
! 	{
! 	  /* Reset the counter to zero in the set_zero block.  */
! 	  start_sequence ();
! 	  convert_move (counter_reg, noloop, 0);
! 	  sequence = get_insns ();
! 	  end_sequence ();
! 	  emit_insn_after (sequence, BB_END (set_zero));
!       
! 	  set_immediate_dominator (CDI_DOMINATORS, set_zero,
! 				   recount_dominator (CDI_DOMINATORS,
! 						      set_zero));
! 	}
! 
!       set_immediate_dominator (CDI_DOMINATORS, new_preheader,
! 			       recount_dominator (CDI_DOMINATORS,
! 						  new_preheader));
      }
  
    /* Some targets (eg, C4x) need to initialize special looping



More information about the Gcc-patches mailing list