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]

[patch] for PR 26254


Hello,

on sh4, the only possible target of assignment of result of a compare
is a fixed hard register, which makes it impossible to store the result
to a temporary pseudoregister using standard functions.  There seems to
be no easy way how to handle this, except for verifying that the
produced insns are correct and failing if they are not.  While there
are other possible solutions (like implementing a new target hook as in
the second patch proposed for this PR), it seems likely that there are
similar special cases that are not handled by force_operand and
emit_move_insn; so this solution seems safer to me.

Bootstrapped & regtested on i686.  Verified to fix the ICE on sh4-linux
from crosscompiler.

Zdenek

	PR rtl-optimization/26254
	* loop-invariant.c (find_identical_invariants): Fix dump format.
	(seq_insns_valid_p): New function.
	(move_invariant_reg): Only emit new code if it is valid.

Index: loop-invariant.c
===================================================================
*** loop-invariant.c	(revision 110912)
--- loop-invariant.c	(working copy)
*************** find_identical_invariants (htab_t eq, st
*** 465,471 ****
  
    if (dump_file && inv->eqto != inv->invno)
      fprintf (dump_file,
! 	     "Invariant %d is equivalent to invariant %d.\n ",
  	     inv->invno, inv->eqto);
  }
  
--- 465,471 ----
  
    if (dump_file && inv->eqto != inv->invno)
      fprintf (dump_file,
! 	     "Invariant %d is equivalent to invariant %d.\n",
  	     inv->invno, inv->eqto);
  }
  
*************** find_invariants_to_move (void)
*** 1066,1087 ****
      }
  }
  
! /* Move invariant INVNO out of the LOOP.  */
  
! static void
  move_invariant_reg (struct loop *loop, unsigned invno)
  {
    struct invariant *inv = VEC_index (invariant_p, invariants, invno);
    struct invariant *repr = VEC_index (invariant_p, invariants, inv->eqto);
    unsigned i;
    basic_block preheader = loop_preheader_edge (loop)->src;
!   rtx reg, set, seq, op;
    struct use *use;
    bitmap_iterator bi;
  
!   if (inv->reg
!       || !repr->move)
!     return;
  
    /* If this is a representative of the class of equivalent invariants,
       really move the invariant.  Otherwise just replace its use with
--- 1066,1103 ----
      }
  }
  
! /* Returns true if all insns in SEQ are valid.  */
  
! static bool
! seq_insns_valid_p (rtx seq)
! {
!   rtx x;
! 
!   for (x = seq; x; x = NEXT_INSN (x))
!     if (insn_invalid_p (x))
!       return false;
! 
!   return true;
! }
! 
! /* Move invariant INVNO out of the LOOP.  Returns true if this succeeds, false
!    otherwise.  */
! 
! static bool
  move_invariant_reg (struct loop *loop, unsigned invno)
  {
    struct invariant *inv = VEC_index (invariant_p, invariants, invno);
    struct invariant *repr = VEC_index (invariant_p, invariants, inv->eqto);
    unsigned i;
    basic_block preheader = loop_preheader_edge (loop)->src;
!   rtx reg, set, dest, seq, op;
    struct use *use;
    bitmap_iterator bi;
  
!   if (inv->reg)
!     return true;
!   if (!repr->move)
!     return false;
  
    /* If this is a representative of the class of equivalent invariants,
       really move the invariant.  Otherwise just replace its use with
*************** move_invariant_reg (struct loop *loop, u
*** 1092,1098 ****
  	{
  	  EXECUTE_IF_SET_IN_BITMAP (inv->depends_on, 0, i, bi)
  	    {
! 	      move_invariant_reg (loop, i);
  	    }
  	}
  
--- 1108,1115 ----
  	{
  	  EXECUTE_IF_SET_IN_BITMAP (inv->depends_on, 0, i, bi)
  	    {
! 	      if (!move_invariant_reg (loop, i))
! 		goto fail;
  	    }
  	}
  
*************** move_invariant_reg (struct loop *loop, u
*** 1102,1115 ****
  	 would not be dominated by it, we may just move it (TODO).  Otherwise we
  	 need to create a temporary register.  */
        set = single_set (inv->insn);
!       reg = gen_reg_rtx (GET_MODE (SET_DEST (set)));
!       emit_insn_after (gen_move_insn (SET_DEST (set), reg), inv->insn);
  
!       /* If the SET_DEST of the invariant insn is a reg, we can just move
  	 the insn out of the loop.  Otherwise, we have to use gen_move_insn
  	 to let emit_move_insn produce a valid instruction stream.  */
!       if (REG_P (SET_DEST (set)))
  	{
  	  SET_DEST (set) = reg;
  	  reorder_insns (inv->insn, inv->insn, BB_END (preheader));
  	}
--- 1119,1133 ----
  	 would not be dominated by it, we may just move it (TODO).  Otherwise we
  	 need to create a temporary register.  */
        set = single_set (inv->insn);
!       dest = SET_DEST (set);
!       reg = gen_reg_rtx (GET_MODE (dest));
  
!       /* If the SET_DEST of the invariant insn is a pseudo, we can just move
  	 the insn out of the loop.  Otherwise, we have to use gen_move_insn
  	 to let emit_move_insn produce a valid instruction stream.  */
!       if (REG_P (dest) && !HARD_REGISTER_P (dest))
  	{
+ 	  emit_insn_after (gen_move_insn (dest, reg), inv->insn);
  	  SET_DEST (set) = reg;
  	  reorder_insns (inv->insn, inv->insn, BB_END (preheader));
  	}
*************** move_invariant_reg (struct loop *loop, u
*** 1122,1134 ****
  	  seq = get_insns ();
  	  end_sequence ();
  
  	  emit_insn_after (seq, BB_END (preheader));
  	  delete_insn (inv->insn);
  	}
      }
    else
      {
!       move_invariant_reg (loop, repr->invno);
        reg = repr->reg;
        set = single_set (inv->insn);
        emit_insn_after (gen_move_insn (SET_DEST (set), reg), inv->insn);
--- 1140,1157 ----
  	  seq = get_insns ();
  	  end_sequence ();
  
+ 	  if (!seq_insns_valid_p (seq))
+ 	    goto fail;
  	  emit_insn_after (seq, BB_END (preheader));
+       
+ 	  emit_insn_after (gen_move_insn (dest, reg), inv->insn);
  	  delete_insn (inv->insn);
  	}
      }
    else
      {
!       if (!move_invariant_reg (loop, repr->invno))
! 	goto fail;
        reg = repr->reg;
        set = single_set (inv->insn);
        emit_insn_after (gen_move_insn (SET_DEST (set), reg), inv->insn);
*************** move_invariant_reg (struct loop *loop, u
*** 1145,1150 ****
--- 1168,1184 ----
        for (use = inv->def->uses; use; use = use->next)
  	*use->pos = reg;
      }
+ 
+   return true;
+ 
+ fail:
+   /* If we failed, clear move flag, so that we do not try to move inv
+      again.  */
+   if (dump_file)
+     fprintf (dump_file, "Failed to move invariant %d\n", invno);
+   inv->move = false;
+   inv->reg = NULL_RTX;
+   return false;
  }
  
  /* Move selected invariant out of the LOOP.  Newly created regs are marked


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